# 機能設計書 34-拡張モジュールローダー

## 概要

本ドキュメントは、SQLiteにおける拡張モジュールローダー（Extension Loading）機能の設計仕様を定義する。動的共有ライブラリとして実装されたSQLite拡張を実行時にロードする機能である。

### 本機能の処理概要

拡張モジュールローダーは、共有ライブラリ（.so/.dll/.dylib）形式のSQLite拡張を動的にロードし、データベース接続に新しい機能（関数、照合順序、仮想テーブル等）を追加する機能である。

**業務上の目的・背景**：SQLiteはシンプルで軽量なデータベースエンジンであるが、特定の用途に応じて機能を拡張したい場合がある。拡張モジュールローダーにより、SQLiteを再コンパイルすることなく、実行時に必要な機能を追加できる。これによりアプリケーションの柔軟性が向上し、プラグイン型のアーキテクチャを実現できる。

**機能の利用シーン**：
- カスタムSQL関数の追加（暗号化、圧縮等）
- サードパーティ仮想テーブルモジュールの動的ロード
- アプリケーション固有の照合順序の追加
- テスト環境でのモック機能の注入

**主要な処理内容**：
1. sqlite3_enable_load_extension()で拡張ロードを有効化（セキュリティ対策として初期値は無効）
2. sqlite3_load_extension()またはload_extension() SQL関数で共有ライブラリをロード
3. ライブラリ内のエントリーポイント関数（通常はsqlite3_extension_init）を呼び出し
4. エントリーポイント関数内でsqlite3_create_function()等のAPIを使用して機能を登録
5. sqlite3_auto_extension()で自動ロード拡張を登録可能

**関連システム・外部連携**：
- OS動的リンカー：dlopen/LoadLibrary等
- VFS層：プラットフォーム依存の動的ロード処理を抽象化
- 仮想テーブル：拡張で新しいモジュールを登録

**権限による制御**：
- 拡張ロードはデフォルトで無効（セキュリティ上の理由）
- SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSIONで有効化必要
- 拡張内の関数呼び出しはsqlite3_set_authorizer()で制御可能

## 関連画面

本機能はSQLite内部機能のため、直接的な画面関連はない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | SQLite3 Fiddle | 参照画面 | load_extension()関数の使用（環境による） |

## 機能種別

動的ロード / プラグイン機構 / 拡張性基盤

## 入力仕様

### 入力パラメータ（sqlite3_load_extension）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| db | sqlite3* | Yes | データベース接続ハンドル | NULLでないこと |
| zFile | const char* | Yes | 共有ライブラリのパス | 空文字列でないこと |
| zProc | const char* | No | エントリーポイント関数名（NULLで自動検出） | - |
| pzErrMsg | char** | No | エラーメッセージ出力先 | - |

### 入力パラメータ（sqlite3_auto_extension）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| xEntryPoint | void(*)(void) | Yes | 自動実行する初期化関数 | NULLでないこと |

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| SQLITE_OK | int | 成功 |
| SQLITE_ERROR | int | ロード失敗 |
| SQLITE_OK_LOAD_PERMANENTLY | int | 永続的にロード（アンロード不可） |

### 出力先

- 登録された関数/照合順序/モジュール
- エラーメッセージ（pzErrMsg）
- db->aExtension[]配列（ロード済みハンドル管理）

## 処理フロー

### 処理シーケンス

```
1. 拡張ロード有効化確認
   └─ db->flags & SQLITE_LoadExtensionのチェック

2. 共有ライブラリのオープン
   ├─ sqlite3OsDlOpen()で動的ロード
   ├─ 失敗時、拡張子（.so/.dll/.dylib）を付加してリトライ
   └─ パス長チェック（SQLITE_MAX_PATHLEN）

3. エントリーポイント検索
   ├─ 指定された関数名を検索
   ├─ 未指定時は"sqlite3_extension_init"を検索
   └─ 見つからない場合、ファイル名から自動生成
       例: libExample5.so → sqlite3_example_init

4. エントリーポイント呼び出し
   ├─ xInit(db, &zErrmsg, &sqlite3Apis)
   └─ sqlite3Apis経由でSQLite APIにアクセス

5. ハンドル管理
   ├─ db->aExtension[]にハンドルを追加
   └─ 接続クローズ時に自動アンロード
```

### フローチャート

```mermaid
flowchart TD
    A[sqlite3_load_extension] --> B{LoadExtension有効?}
    B -->|No| C[エラー: not authorized]
    B -->|Yes| D[パス長チェック]
    D -->|超過| E[エラー: unable to open]
    D -->|OK| F[sqlite3OsDlOpen]
    F --> G{オープン成功?}
    G -->|No| H[拡張子付加してリトライ]
    H --> I{リトライ成功?}
    I -->|No| J[エラー: unable to open shared library]
    I -->|Yes| K[エントリーポイント検索]
    G -->|Yes| K
    K --> L{関数名指定?}
    L -->|Yes| M[指定名で検索]
    L -->|No| N["sqlite3_extension_init"で検索]
    M --> O{見つかった?}
    N --> O
    O -->|No| P[ファイル名から自動生成]
    P --> Q{見つかった?}
    Q -->|No| R[エラー: no entry point]
    O -->|Yes| S[xInit呼び出し]
    Q -->|Yes| S
    S --> T{戻り値}
    T -->|SQLITE_OK| U[ハンドルをaExtension[]に追加]
    T -->|SQLITE_OK_LOAD_PERMANENTLY| V[成功（アンロードなし）]
    T -->|その他| W[エラー: initialization failed]
    U --> X[成功]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-34-1 | デフォルト無効 | 拡張ロードはセキュリティ上の理由でデフォルト無効 | 常時 |
| BR-34-2 | 明示的有効化 | sqlite3_enable_load_extension()またはSQLITE_DBCONFIG_ENABLE_LOAD_EXTENSIONで有効化 | ロード前 |
| BR-34-3 | パス長制限 | ファイルパスはSQLITE_MAX_PATHLEN以下 | ファイル指定時 |
| BR-34-4 | 自動アンロード | 接続クローズ時にロード済み拡張を自動アンロード | 接続終了時 |
| BR-34-5 | 永続ロード | SQLITE_OK_LOAD_PERMANENTLYを返すとアンロードされない | 拡張実装時 |

### 計算ロジック

**エントリーポイント名自動生成**：
1. ファイル名からディレクトリ部分を除去
2. 先頭の"lib"を除去
3. 拡張子（.以降）を除去
4. "sqlite3_" + 小文字化した名前 + "_init"

例: `/usr/lib/libExample5.so` → `sqlite3_example_init`

## データベース操作仕様

### 操作別データベース影響一覧

本機能自体はデータベースへの直接操作は行わない。ロードされた拡張により機能が追加される。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

### テーブル別操作詳細

なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SQLITE_ERROR | 権限エラー | 拡張ロードが無効 | sqlite3_enable_load_extension()で有効化 |
| SQLITE_ERROR | ファイルエラー | 共有ライブラリが存在しないまたはオープン失敗 | パスを確認 |
| SQLITE_ERROR | エントリーポイント未検出 | 指定/自動検出した関数が存在しない | エントリーポイント名を確認 |
| SQLITE_ERROR | 初期化失敗 | エントリーポイント関数がエラーを返却 | 拡張実装を確認 |
| SQLITE_NOMEM | メモリ不足 | メモリ確保失敗 | システムリソースを確認 |

### リトライ仕様

- ライブラリオープン失敗時、プラットフォーム固有の拡張子（.so/.dll/.dylib）を付加してリトライ
- エントリーポイント未検出時、ファイル名から自動生成した名前でリトライ

## トランザクション仕様

拡張ロードはトランザクションと独立して動作する。ロード中にトランザクションが中断されても、既にロードされた拡張は有効なまま。

## パフォーマンス要件

- 拡張ロードは接続ごとに1回のみ必要（sqlite3_auto_extension()使用時を除く）
- 動的リンクのオーバーヘッドはOS依存
- ロード後の関数呼び出しは静的リンクとほぼ同等

## セキュリティ考慮事項

- **デフォルト無効**: 悪意のある拡張のロードを防止するため、初期状態では拡張ロードは無効
- **明示的有効化**: アプリケーション開発者が意図的に有効化する必要がある
- **load_extension() SQL関数**: デフォルトでは無効化されており、SQLITE_LoadExtFuncフラグでの有効化が必要
- **空ファイル名のブロック**: 空文字列のファイル名は実行プログラム自体のロードを防止するためブロック
- **パス長制限**: 過度に長いパスによるバッファオーバーフローを防止

## 備考

- SQLITE_OMIT_LOAD_EXTENSIONでコンパイルした場合、本機能は無効
- sqlite3_auto_extension()で登録した拡張は全ての新規接続で自動的にロード
- sqlite3_cancel_auto_extension()で自動ロード登録を解除可能
- sqlite3_reset_auto_extension()で全ての自動ロード登録をクリア

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

拡張ロードで使用するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | loadext.c | `src/loadext.c` | sqlite3Apis静的構造体（APIテーブル） |
| 1-2 | sqliteInt.h | `src/sqliteInt.h` | db->aExtension[]（ロード済みハンドル配列） |
| 1-3 | loadext.c | `src/loadext.c` | sqlite3AutoExtList構造体（自動ロード管理） |

**読解のコツ**: sqlite3Apis（133-534行目）はSQLiteの全公開APIへのポインタテーブル。拡張はこのテーブル経由でSQLite APIにアクセスする。db->aExtensionはロード済みの共有ライブラリハンドルを管理。

#### Step 2: 有効化処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | loadext.c | `src/loadext.c` | sqlite3_enable_load_extension()関数 |

**主要処理フロー**:
- **757-769行目**: sqlite3_enable_load_extension()の実装
- **762-766行目**: SQLITE_LoadExtensionフラグの設定/解除

#### Step 3: 拡張ロード処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | loadext.c | `src/loadext.c` | sqlite3LoadExtension()関数 |

**主要処理フロー**:
- **556-725行目**: sqlite3LoadExtension()のメイン実装
- **587-599行目**: LoadExtension有効性チェック
- **617-627行目**: 共有ライブラリのオープン（拡張子リトライ含む）
- **648-671行目**: エントリーポイント名の自動生成
- **688行目**: エントリーポイント関数の呼び出し
- **699-711行目**: ハンドルのdb->aExtension[]への追加

#### Step 4: 自動ロード機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | loadext.c | `src/loadext.c` | sqlite3_auto_extension()、sqlite3AutoLoadExtensions()関数 |

**主要処理フロー**:
- **806-845行目**: sqlite3_auto_extension()で自動ロード登録
- **826-840行目**: wsdAutoext.aExt[]への関数ポインタ追加
- **906-943行目**: sqlite3AutoLoadExtensions()で全自動拡張を実行
- **917-941行目**: 各拡張のxInit呼び出しループ

#### Step 5: クリーンアップ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | loadext.c | `src/loadext.c` | sqlite3CloseExtensions()関数 |

**主要処理フロー**:
- **744-751行目**: 接続クローズ時の拡張アンロード
- **747-749行目**: 各ハンドルに対してsqlite3OsDlClose()呼び出し

### プログラム呼び出し階層図

```
sqlite3_enable_load_extension()
    │
    └─ db->flags |= SQLITE_LoadExtension  フラグ設定

sqlite3_load_extension()
    │
    ├─ sqlite3_mutex_enter()  スレッド安全性
    │
    └─ sqlite3LoadExtension()
           │
           ├─ sqlite3OsDlOpen()  ────▶ OS動的ロードAPI
           │
           ├─ sqlite3OsDlSym()   ────▶ シンボル検索
           │
           └─ xInit(db, &zErrmsg, &sqlite3Apis)  ────▶ 拡張初期化

sqlite3_auto_extension()
    │
    └─ wsdAutoext.aExt[]に関数ポインタ追加

sqlite3_open_v2()
    │
    └─ sqlite3AutoLoadExtensions()
           │
           └─ 各xInit()を順次呼び出し

sqlite3_close()
    │
    └─ sqlite3CloseExtensions()
           │
           └─ sqlite3OsDlClose()  ────▶ ライブラリアンロード
```

### データフロー図

```
[入力]                      [処理]                           [出力]

拡張パス ─────────────────▶ sqlite3LoadExtension() ────────▶ 機能追加
zFile                       │                               (関数/モジュール等)
                           ├─ sqlite3OsDlOpen()
                           │   動的ロード
                           │
                           ├─ sqlite3OsDlSym()
                           │   シンボル検索
                           │
                           └─ xInit()
                               拡張初期化

sqlite3Apis ──────────────▶ xInit() ──────────────────────▶ API呼び出し
APIテーブル                  拡張初期化関数                   (sqlite3_create_function等)

自動拡張登録 ─────────────▶ sqlite3AutoLoadExtensions() ──▶ 全接続で機能追加
sqlite3_auto_extension      新規接続時

db->aExtension[] ──────────▶ sqlite3CloseExtensions() ────▶ ライブラリ解放
ハンドル配列                 接続クローズ時
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| loadext.c | `src/loadext.c` | ソース | 拡張ローダーのメイン実装 |
| sqlite3ext.h | `src/sqlite3ext.h` | ヘッダー | 拡張開発用マクロ定義 |
| sqlite3.h | `src/sqlite3.h` | ヘッダー | 公開API定義 |
| sqliteInt.h | `src/sqliteInt.h` | ヘッダー | 内部構造体定義 |
| os_unix.c | `src/os_unix.c` | ソース | Unix用動的ロード（dlopen/dlsym） |
| os_win.c | `src/os_win.c` | ソース | Windows用動的ロード（LoadLibrary） |
| main.c | `src/main.c` | ソース | sqlite3_open時の自動拡張呼び出し |
