> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 拡張機能の管理

> VillageSQL 拡張機能の監視、トラブルシューティング、管理

## インストール済み拡張機能の表示

INFORMATION\_SCHEMA ビューを使用して、インストールされた拡張機能をクエリします：

```sql theme={null}
SELECT * FROM INFORMATION_SCHEMA.EXTENSIONS;
```

**出力:**

```
+------------------+-------------------+
| EXTENSION_NAME   | EXTENSION_VERSION |
+------------------+-------------------+
| vsql_complex     | 0.0.1             |
| vsql_uuid        | 0.0.3             |
+------------------+-------------------+
```

**使用方法:**

* インタラクティブセッションとスクリプトの両方で使用可能
* MySQL ツールと互換性のある標準 SQL インターフェース

***

## 拡張機能関数の確認

インストール後に拡張機能関数が正常に動作することを確認します：

```sql theme={null}
-- Test a function directly
SELECT complex_abs('(1.0,2.0)');
```

***

## 拡張機能ディレクトリ

VillageSQL が `.veb` ファイルを検索する場所を確認します：

```sql theme={null}
SHOW VARIABLES LIKE 'veb_dir';
```

**利用可能な拡張機能の一覧表示:**

```bash theme={null}
ls -la /path/to/veb_dir/*.veb
```

<h3 id="configuring-veb_dir">
  veb\_dir の設定
</h3>

拡張機能ディレクトリの場所を変更するには、MySQL 設定ファイルに `veb_dir` を設定します：

**my.cnf / my.ini:**

```ini theme={null}
[mysqld]
veb_dir=/custom/path/to/extensions/
```

**要件:**

* パスは絶対パスである必要があります（相対パス不可）
* ディレクトリはサーバー起動前に存在している必要があります
* MySQL ユーザーはディレクトリに対して読み取り権限を持っている必要があります
* 設定できる `veb_dir` は 1 つのみです（複数のパスは設定不可）
* 変更を有効にするにはサーバーの再起動が必要です

**再起動後の確認:**

```sql theme={null}
SHOW VARIABLES LIKE 'veb_dir';
```

***

## トラブルシューティング

### クイックリファレンス

| 問題                   | クイック解決策                                                       |
| -------------------- | ------------------------------------------------------------- |
| 拡張機能が見つからない          | `veb_dir` に正しい名前の `.veb` ファイルが存在するか確認                         |
| アクセス拒否               | 権限を確認: `chmod 644 extension.veb`                              |
| アンインストールできない：型が使用中   | `UNINSTALL EXTENSION` を実行; エラーメッセージでブロックしている列名が特定されます         |
| バージョンの不一致            | キャッシュをクリアするためにサーバーを再起動                                        |
| アップデート後に拡張機能が古い動作をする | `UNINSTALL` 後に `INSTALL`; 必要に応じて `.veb_expansion_cache/` をクリア |
| 型 X と Y を比較できない      | 両方の側で同じカスタム型を使用する必要があります                                      |
| 非カスタム型を暗黙的にキャストできない  | 比較対象のリテラルまたは列が、カスタム型と互換性がありません                                |

### 拡張機能が見つからない

**Error:** `Extension 'my_extension' not found`

**デバッグ手順:**

```bash theme={null}
# 1. Check veb_dir location
mysql -u root -p -e "SHOW VARIABLES LIKE 'veb_dir';"

# 2. List .veb files
ls -la /path/to/veb_dir/

# 3. Verify filename matches extension name
# File: my_extension.veb
# Install: INSTALL EXTENSION my_extension;

# 4. Check permissions
ls -l /path/to/veb_dir/my_extension.veb
sudo chmod 644 /path/to/veb_dir/my_extension.veb
```

### インストール後に関数が利用できない

**Error:** `FUNCTION my_func does not exist`

**デバッグ手順:**

```sql theme={null}
-- 1. Verify extension installed
SELECT * FROM INFORMATION_SCHEMA.EXTENSIONS WHERE EXTENSION_NAME = 'my_extension';
```

### アップデート後に拡張機能が古い動作をする

**症状:** `.veb` ファイルを置き換えて再インストールした後、拡張機能がまだ
古いコードを実行しています。

**原因:** VillageSQL は初回読み込み時に `.veb` ファイルを `{datadir}/.veb_expansion_cache/` に展開します。`UNINSTALL EXTENSION` を実行せずに新しい `.veb` をコピーした場合、サーバーはメモリに既に読み込まれている以前に展開された `.so` の使用を続けます。

**解決策:** 常に完全な UNINSTALL → 置き換え → INSTALL のサイクルに従ってください：

```sql theme={null}
UNINSTALL EXTENSION my_extension;
```

次に `veb_dir` 内の `.veb` ファイルを置き換えて再インストールします：

```sql theme={null}
INSTALL EXTENSION my_extension;
```

拡張機能がまだ古い動作をする場合は、再インストールする前に展開キャッシュをクリアします：

```bash theme={null}
rm -rf {datadir}/.veb_expansion_cache/my_extension/
```

```sql theme={null}
INSTALL EXTENSION my_extension;
```

***

### 拡張機能をアンインストールできない

**Error:** `Cannot uninstall extension: types in use`

**解決策:**

```sql theme={null}
-- Attempt uninstall; the error identifies blocking columns by name
UNINSTALL EXTENSION my_extension;
-- If blocked: ERROR HY000: Cannot drop extension `my_extension` as 1 column(s) depend on it,
--             e.g. mydb.mytable.my_column has type MYTYPE

-- Drop or alter the identified column(s), then retry
DROP TABLE mydb.mytable;
-- OR
ALTER TABLE mydb.mytable DROP COLUMN my_column;

UNINSTALL EXTENSION my_extension;
```

### ライブラリの読み込みエラー

**Error:** `Cannot load library: undefined symbol`

**原因:**

* 必要なライブラリ依存関係の欠如
* ABI 互換性の不一致
* 間違った MySQL バージョン

**デバッグ:**

```bash theme={null}
# Check library dependencies (Linux)
ldd {datadir}/.veb_expansion_cache/my_extension/<sha256>/lib/my_extension.so

# Check library dependencies (macOS)
otool -L {datadir}/.veb_expansion_cache/my_extension/<sha256>/lib/my_extension.so
```

### 拡張機能名の検証エラー

**Error:** `Failed to load VEF extension 'extension_name'` with log message `Extension name mismatch`

**原因:** `manifest.json` 内の拡張機能名が VEB ファイル名と一致していません。

**デバッグ手順:**

1. **VEB ファイル名がマニフェストと一致するか確認:**
   ```bash theme={null}
   # VEB filename: my_extension.veb
   # manifest.json should have:
   {
     "name": "my_extension",  # Must match VEB filename (without .veb)
     ...
   }
   ```

2. **manifest.json の name フィールドを確認:**
   ```bash theme={null}
   # Extract and check manifest from VEB
   tar -xOf /path/to/veb_dir/my_extension.veb manifest.json | grep name
   ```

**解決策:**

両方の名前は一致している必要があり、アンダースコアを使用します（[拡張機能の命名規則](/docs/ja/mysql-8.4/0.0.5/install#extension-naming-conventions) を参照）:

* VEB ファイル名: `my_extension.veb`
* manifest.json: `"name": "my_extension"`

**一般的なミス:**

* マニフェストでハイフンを使用: `"name": "my-extension"` ❌
* VEB ファイル名が一致しない: `my-extension.veb` vs `"name": "my_extension"` ❌

**正しい例:**

```json theme={null}
// manifest.json
{
  "name": "my_extension",
  "version": "1.0.0"
}
```

```cpp theme={null}
// extension.cc
VEF_GENERATE_ENTRY_POINTS(
  make_extension()
    .func(...)
)
```

```bash theme={null}
# VEB filename
my_extension.veb
```

### カスタム型の比較エラー

**Error:** `Cannot compare types X and Y in =`

**原因:** 比較の両側がカスタム型ですが、異なる型または拡張機能に属しています。

```sql theme={null}
-- Example: comparing COMPLEX with UUID in a WHERE clause
SELECT * FROM t WHERE complex_col = uuid_col;
-- ERROR: Cannot compare types vsql_complex.COMPLEX and vsql_uuid.UUID in =
```

**解決策:** 比較の両側で同じカスタム型を使用していることを確認してください。型間で比較する必要がある場合は、適切な型変換関数を使用して明示的に変換してください。

***

**Error:** `Unable to implicitly cast a non-custom type during compare with a custom type in =`

**原因:** 比較の片側がカスタム型の列で、もう片側がその型に自動的に変換できない値（リテラルまたは列）です。

```sql theme={null}
-- Example: comparing a custom type with an integer literal
SELECT * FROM t WHERE complex_col = 42;
-- ERROR: Unable to implicitly cast a non-custom type during compare...
```

**解決策:** 文字列リテラルは、型の encode 関数を使用して自動的にカスタム型にキャストされます。他の型（整数、浮動小数点数）には、明示的な変換関数を使用してください：

```sql theme={null}
-- Use a string literal instead (auto-cast works)
SELECT * FROM t WHERE complex_col = '(1.0,2.0)';

-- Or use the type's from_string method explicitly
SELECT * FROM t WHERE complex_col = COMPLEX::from_string('(1.0,2.0)');
```

***

## 拡張機能の使用状況の監視

### クエリパフォーマンス

performance\_schema を使用して VDF の実行時間を追跡します：

```sql theme={null}
-- Enable statement instrumentation
UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME LIKE '%statement%';

-- Query VDF execution times
SELECT
    DIGEST_TEXT,
    COUNT_STAR as executions,
    ROUND(SUM_TIMER_WAIT/1000000000, 2) as total_ms,
    ROUND(AVG_TIMER_WAIT/1000000000, 2) as avg_ms
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT LIKE '%complex_%'
ORDER BY total_ms DESC
LIMIT 10;
```

### カスタム型の使用状況

カスタム型を使用しているテーブルを追跡します：

```sql theme={null}
-- Find all columns using custom extension types
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE LIKE '%.%'
ORDER BY DATA_TYPE, TABLE_SCHEMA, TABLE_NAME;
```

***

## 拡張機能の更新

インストール済みの拡張機能を別のバージョンに変更するには、`ALTER EXTENSION` を使用します。
これは既存のデータに対して新しいバージョンを検証し、次回サーバーが再起動したときに
変更を適用します。代替手段として、手動でのアンインストールと再インストールも
引き続き利用できます。

<h3 id="changing-an-extension-version">
  拡張機能のバージョン変更
</h3>

`ALTER EXTENSION` はインストール済みの拡張機能を別のバージョンに変更し、
次回のサーバー再起動時に適用します：

```sql theme={null}
ALTER EXTENSION update_test VERSION '1.2.0' AT RESTART;
```

VillageSQL は対象バージョンをディスク上で解決し、変更を受け入れる前に
互換性の事前チェックを実行します。対象の VEB は拡張機能ディレクトリに
`<name>-<version>.veb`（ここでは `update_test-1.2.0.veb`）として存在している
必要があります。ファイルが存在しない場合は拒否されます：

```
ERROR 3219 (HY000): VEB file not found: update_test-9.9.9.veb
```

事前チェックは、保存済みデータを破損させる既知の非互換性を探します。
たとえば、カスタム型の永続化長の変更などです：

```
ERROR 3219 (HY000): Cannot update extension 'update_test': type 'COUNTER'
persisted_length changed from 4 to 8 -- existing stored data would be corrupted
```

受け入れられると、変更は次回の再起動時に適用されます。それまでの間、
`INFORMATION_SCHEMA.EXTENSIONS` は現在のバージョンと、変更予定の対象バージョンを
並べて報告します：

```sql theme={null}
SELECT EXTENSION_NAME, EXTENSION_VERSION, PENDING_VERSION
FROM INFORMATION_SCHEMA.EXTENSIONS
WHERE EXTENSION_NAME = 'update_test';
```

```
+----------------+-------------------+-----------------+
| EXTENSION_NAME | EXTENSION_VERSION | PENDING_VERSION |
+----------------+-------------------+-----------------+
| update_test    | 1.0.0             | 1.2.0           |
+----------------+-------------------+-----------------+
```

`INFORMATION_SCHEMA.EXTENSIONS` は予定された変更を 4 つの列で報告します：

| 列                       | 意味                                 |
| ----------------------- | ---------------------------------- |
| `PENDING_VERSION`       | 次回の再起動時に拡張機能が変更されるバージョン、または `NULL` |
| `PENDING_REQUESTED_AT`  | 変更が要求された日時                         |
| `PENDING_LAST_ERROR`    | 失敗した変更のメッセージ、または `NULL`            |
| `PENDING_LAST_ERROR_AT` | その失敗が記録された日時、または `NULL`            |

予定された変更は一度に 1 つだけ追跡されます：

* **予定された変更をキャンセルする**には、現在のバージョンを再度要求します：
  ```sql theme={null}
  ALTER EXTENSION update_test VERSION '1.0.0' AT RESTART;
  -- Note: Cleared pending update for extension 'update_test'
  --       (target matches current version '1.0.0')
  ```
* **何も予定されていないときに現在のバージョンを要求しても**何も起こりません：
  ```sql theme={null}
  ALTER EXTENSION update_test VERSION '1.0.0' AT RESTART;
  -- Note: Extension 'update_test' is already at version '1.0.0'
  ```
* **変更が予定されている間は別の対象は拒否されます** — まず既存のものを
  キャンセルしてください：
  ```
  ERROR 3219 (HY000): Extension 'update_test' already has a pending update;
  clear it with ALTER EXTENSION update_test VERSION '1.0.0' AT RESTART before
  queueing a different version
  ```

`AT RESTART` 句は、次回のサーバー起動時に変更を適用します。

### 再起動が成功した後

次回の再起動時に、保留中の変更が適用されます。`EXTENSION_VERSION` が対象バージョンになり、
`PENDING_VERSION` がクリアされます。上記で予定した変更
（`update_test` `1.0.0` → 保留中 `1.2.0`）の場合：

```sql theme={null}
SELECT EXTENSION_NAME, EXTENSION_VERSION, PENDING_VERSION
FROM INFORMATION_SCHEMA.EXTENSIONS
WHERE EXTENSION_NAME = 'update_test';
```

```
+----------------+-------------------+-----------------+
| EXTENSION_NAME | EXTENSION_VERSION | PENDING_VERSION |
+----------------+-------------------+-----------------+
| update_test    | 1.2.0             | NULL            |
+----------------+-------------------+-----------------+
```

古いバージョンを参照する `custom_columns` およびストアドプロシージャのパラメータの
行は、同じ再起動中にすべて書き換えられるため、依存するテーブルとルーチンは
手動での移行なしに動作を継続します。

<Note>
  変更はライブ接続上ではなく再起動中に適用されます — 上記の値は
  再起動後の状態です。
</Note>

### 起動時の保留中バージョン変更からの回復

予定されたバージョン変更は、次回のサーバー起動時に適用されます。保留中の
アクションを適用できない場合、サーバーは保留中の更新に関する判断内容をディスクに記録したまま、起動に失敗することがあります。キューに入れられた `ALTER EXTENSION ... AT RESTART`
が起動をブロックしていて、それをクリアする前にサーバーを起動する必要がある場合は、
`--villagesql-skip-extension-updates` を使用してください。

`--villagesql-skip-extension-updates` は `mysqld` の起動フラグです。設定すると、
サーバーは保留中の `ALTER EXTENSION ... AT RESTART` アクションの処理を
バイパスします。各拡張機能は現在インストールされているバージョンで読み込まれ、
その保留中のアクションはディスク上にそのまま残されます。このフラグ自体は何も
変更しません — その 1 回の起動に対して保留中のアクションの適用をスキップするだけです。

フラグが設定され、少なくとも 1 つの拡張機能に保留中のアクションがある場合、
サーバーは起動時に、バイパスされた数を示す単一の警告をログに記録します：

```text theme={null}
--villagesql-skip-extension-updates is set: bypassing N pending extension update(s). Extensions load at their currently-installed version. Query INFORMATION_SCHEMA.EXTENSIONS to see the pending actions; clear each via ALTER EXTENSION <name> VERSION '<current>' AT RESTART, then restart without the flag.
```

<Steps>
  <Step title="フラグ付きでサーバーを起動する">
    本番環境では、通常の `mysqld` コマンドラインオプションとして渡すか、
    `my.cnf` の `[mysqld]` の下に追加します：

    ```bash theme={null}
    mysqld --villagesql-skip-extension-updates
    ```

    開発ハーネスでは、`--` を使って渡します：

    ```bash theme={null}
    ./villagesql start -- --villagesql-skip-extension-updates
    ```

    **成功のサイン:** サーバーが起動し、エラーログに上記の
    `bypassing N pending extension update(s)` 警告が含まれます。
  </Step>

  <Step title="保留中のアクションを特定する">
    ```sql theme={null}
    SELECT EXTENSION_NAME, EXTENSION_VERSION, PENDING_VERSION, PENDING_LAST_ERROR
    FROM INFORMATION_SCHEMA.EXTENSIONS
    WHERE PENDING_VERSION IS NOT NULL;
    ```

    ```text theme={null}
    +--------------+-------------------+-----------------+--------------------+
    | EXTENSION_NAME | EXTENSION_VERSION | PENDING_VERSION | PENDING_LAST_ERROR |
    +--------------+-------------------+-----------------+--------------------+
    | my_extension   | 1.0.0             | 2.0.0           | NULL               |
    +--------------+-------------------+-----------------+--------------------+
    ```

    **成功のサイン:** 各行の `PENDING_VERSION` はクリアが必要な対象です。
    `PENDING_LAST_ERROR` は適用に失敗した理由を示します。
  </Step>

  <Step title="各保留中アクションをクリアする">
    上記で返された各拡張機能について、現在のバージョンを要求してキューに
    入れられた変更をキャンセルします（[拡張機能のバージョン変更](#changing-an-extension-version)
    で説明したキャンセルの仕組み）：

    ```sql theme={null}
    ALTER EXTENSION my_extension VERSION '1.0.0' AT RESTART;
    ```

    **成功のサイン:** `Cleared pending update for extension '<name>'
            (target matches current version '<current>')` というノートが返され、
    前のクエリを再実行すると `PENDING_VERSION` が `NULL` になっています。
  </Step>

  <Step title="フラグなしで再起動する">
    `--villagesql-skip-extension-updates` を省略して、サーバーを通常どおり再起動します。

    **成功のサイン:** サーバーが起動し、ログに
    `bypassing N pending extension update(s)` 警告が表示されなくなります。
  </Step>
</Steps>

### 手動更新プロセス

1. **現在のバージョンをアンインストールします：**
   ```sql theme={null}
   UNINSTALL EXTENSION extension_name;
   ```

2. **.veb ファイルを置き換えます：**
   ```bash theme={null}
   # Remove old .veb file
   sudo rm /path/to/veb_dir/extension_name.veb

   # Copy new .veb file
   sudo cp new_extension_name.veb /path/to/veb_dir/
   ```

3. **新しいバージョンをインストールします：**
   ```sql theme={null}
   INSTALL EXTENSION extension_name;
   ```

4. **更新を確認します：**
   ```sql theme={null}
   SELECT EXTENSION_VERSION
   FROM INFORMATION_SCHEMA.EXTENSIONS
   WHERE EXTENSION_NAME = 'extension_name';
   ```

<Warning>
  **データの安全性：** テーブルが拡張機能のカスタム型を使用している場合、アンインストールする前にそれらのテーブルをドロップまたは変更する必要があります。まずデータをバックアップしてください。
</Warning>

**例：**

```sql theme={null}
-- Find columns using vsql_complex types before updating
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE LIKE 'vsql_complex.%';

-- If columns exist, back up data and drop/alter them first
-- Then proceed with update
UNINSTALL EXTENSION vsql_complex;
-- (replace .veb file)
INSTALL EXTENSION vsql_complex;
```

***

## クリーンアップ

### 孤立した展開ディレクトリの削除

VillageSQL は `.veb` ファイルを `{datadir}/.veb_expansion_cache/{name}/{sha256}/` に展開します。古いバージョンは時間とともに蓄積されます。

```bash theme={null}
# List expansion directories (replace {datadir} with your actual datadir path)
ls -la {datadir}/.veb_expansion_cache/

# Compare with installed extensions
mysql -u root -p -e "SELECT EXTENSION_NAME FROM INFORMATION_SCHEMA.EXTENSIONS;"

# Find the actual SHA256 directory name for a specific extension
ls {datadir}/.veb_expansion_cache/my_extension/

# Remove the unused SHA256 directory using the name shown above
rm -rf {datadir}/.veb_expansion_cache/my_extension/<sha256-from-ls>/
```

<Note>
  サーバーの再起動により、孤立した展開ディレクトリは自動的にクリーンアップされます。
</Note>

***

<h2 id="replication">
  レプリケーション
</h2>

カスタム型には ROW 形式のバイナリログが必要です。STATEMENT および MIXED モードは、
カスタム型のカラムを持つテーブルではサポートされていません。カスタム型カラムに対する
INSERT、UPDATE、DELETE、および ALTER TABLE 操作は、すべて ROW 形式で正しく
レプリケートされます。

`INSTALL EXTENSION` はレプリケートされません — 各サーバーは独自の拡張機能を管理します。
レプリケーションを開始する前に、ソースと同じバージョンを使用して、すべてのレプリカに
拡張機能をインストールしてください。サーバーは正確なバージョンの一致を強制します。
バージョンが不一致だとレプリケーションが停止します。

レプリカが認識しないカスタム型に遭遇した場合、レプリケーションは DDL ステートメントで
停止します — `CREATE TABLE` または `ALTER TABLE` の実行時、関連する DML が
適用される前に停止します。正しい拡張機能バージョンをインストールし、再開してください：

```sql theme={null}
INSTALL EXTENSION my_extension;
START REPLICA SQL_THREAD;
```

`mysqldump` は、出力に完全に修飾されたカスタム型名を保持します。論理リストアは、
ダンプをインポートする前にターゲットサーバーに拡張機能がインストールされていれば
機能します。

<Warning>
  Clone プラグイン、XtraBackup、InnoDB Cluster / Group
  Replication での動作はまだテストされていません。本番環境で依存する前に、
  リストアパスをテストしてください。
</Warning>

***

## Docker での拡張機能の使用

Docker で VillageSQL を実行する際、`veb_dir` としてローカルディレクトリをマウントすると、コンテナを再構築せずにホストから `.veb` ファイルを追加できます。

**Docker Compose の例：**

```yaml theme={null}
services:
  villagesql:
    image: villagesql/server:stable
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
    ports:
      - "3306:3306"
    volumes:
      - ./extensions:/usr/lib/veb
    command: --veb_dir=/usr/lib/veb
```

ホストの `./extensions/` に `.veb` ファイルをコピーし、SQL からインストールします：

```sql theme={null}
INSTALL EXTENSION my_extension;
```

実行中のサーバーが使用しているディレクトリを確認するには：

```sql theme={null}
SHOW VARIABLES LIKE 'veb_dir';
```

***

## サポート

ここでカバーされていない問題が発生した場合は：

1. **エラーログを確認：** ほとんどの拡張機能エラーは詳細とともにログに記録されます
2. **拡張機能ドキュメントを確認：** 拡張機能固有のトラブルシューティングが存在する場合があります
3. **Discord で質問：** [VillageSQL Discord](https://discord.gg/KSr6whd3Fr) に参加してください
4. **問題を報告：** [GitHub Issues](https://github.com/villagesql/villagesql-server/issues) でバグを報告してください

***

## 次のステップ

<CardGroup cols={2}>
  <Card title="システムリファレンス" icon="book" href="/docs/ja/mysql-8.4/0.0.5/reference">
    システムテーブルとビューへのクエリ
  </Card>

  <Card title="拡張機能のアンインストール" icon="trash" href="/docs/ja/mysql-8.4/0.0.5/uninstall">
    拡張機能を安全に削除
  </Card>

  <Card title="拡張機能のアーキテクチャ" icon="sitemap" href="/docs/ja/mysql-8.4/0.0.5/architecture">
    内部構造の理解
  </Card>
</CardGroup>
