# 機能設計書 33-仮想テーブル

## 概要

本ドキュメントは、SQLiteにおける仮想テーブル（Virtual Table）機能の設計仕様を定義する。仮想テーブルはSQLiteの拡張機能として、外部データソースやカスタムデータ構造をテーブルとしてアクセス可能にするインターフェースを提供する。

### 本機能の処理概要

仮想テーブルは、SQLインターフェースを通じて非SQLiteデータ（CSV、JSON、外部API等）にアクセスするための仮想化レイヤーを提供する機能である。

**業務上の目的・背景**：現代のアプリケーションでは、データベースだけでなく様々なデータソース（ファイル、Web API、システム情報等）を統合的に扱う必要がある。仮想テーブルにより、これらの異種データソースをSQL文で統一的にクエリでき、JOINやサブクエリによる統合分析が可能になる。これによりデータ統合の開発コストを大幅に削減できる。

**機能の利用シーン**：
- CSVファイルやJSONファイルをテーブルとして直接クエリ
- FTS（全文検索）機能の実装基盤
- R-Tree空間インデックスの実装基盤
- 外部REST APIの結果をテーブルとして公開
- システム情報（プロセス、ファイルシステム等）のSQL経由アクセス

**主要な処理内容**：
1. sqlite3_create_module()でモジュール（xCreate、xConnect、xBestIndex等のメソッド群）を登録
2. CREATE VIRTUAL TABLE文で仮想テーブルを定義
3. SQL実行時、クエリプランナーがxBestIndexを呼び出して最適なアクセス方法を決定
4. 実行時、xFilter/xNext/xColumnでデータを取得
5. INSERT/UPDATE/DELETE時はxUpdate呼び出し

**関連システム・外部連携**：
- クエリプランナー：xBestIndexによるコスト見積もり
- VDBEバイトコードインタープリター：仮想テーブルオペコードの実行
- 拡張モジュールローダー：外部モジュールの動的ロード

**権限による制御**：
- sqlite3_set_authorizer()による仮想テーブル操作の認可チェック
- SQLITE_CREATE_VTABLE/SQLITE_DROP_VTABLEアクションコード

## 関連画面

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

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | SQLite3 Fiddle | 参照画面 | 仮想テーブルの作成・クエリ |

## 機能種別

データ抽象化 / 拡張インターフェース / クエリ最適化連携

## 入力仕様

### 入力パラメータ（モジュール登録）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| db | sqlite3* | Yes | データベース接続ハンドル | NULLでないこと |
| zName | const char* | Yes | モジュール名 | 空文字列でないこと |
| pModule | sqlite3_module* | Yes | モジュールメソッドテーブル | NULLでないこと |
| pAux | void* | No | ユーザーデータ | - |
| xDestroy | void(*)(void*) | No | クリーンアップ関数 | - |

### sqlite3_module構造体

| メソッド | 必須 | 説明 |
|---------|------|------|
| xCreate | Yes | CREATE VIRTUAL TABLE時に呼び出し |
| xConnect | Yes | 既存の仮想テーブルへの接続 |
| xBestIndex | Yes | クエリプラン最適化 |
| xDisconnect | Yes | 接続解除 |
| xDestroy | Yes | テーブル削除 |
| xOpen | Yes | カーソルオープン |
| xClose | Yes | カーソルクローズ |
| xFilter | Yes | クエリ開始、結果セット初期化 |
| xNext | Yes | 次の行へ移動 |
| xEof | Yes | 結果セット終端判定 |
| xColumn | Yes | カラム値取得 |
| xRowid | Yes | rowid取得 |
| xUpdate | No | INSERT/UPDATE/DELETE |
| xBegin | No | トランザクション開始 |
| xSync | No | 同期 |
| xCommit | No | コミット |
| xRollback | No | ロールバック |
| xFindFunction | No | カスタム関数検索 |
| xRename | No | テーブル名変更 |
| xSavepoint | No | セーブポイント |
| xRelease | No | セーブポイント解放 |
| xRollbackTo | No | セーブポイントへロールバック |

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| SQLITE_OK | int | 成功 |
| SQLITE_ERROR | int | 一般エラー |
| SQLITE_NOMEM | int | メモリ不足 |
| 仮想テーブル行データ | - | xColumn/xRowidの返却値 |
| sqlite3_index_info | struct | xBestIndexの入出力 |

### 出力先

- VDBEオペコード：仮想テーブル操作コード
- カーソル：スキャン状態の管理
- sqlite3_context：xColumn値の返却

## 処理フロー

### 処理シーケンス

```
1. モジュール登録フェーズ
   └─ sqlite3_create_module_v2()でモジュールをハッシュに登録

2. テーブル作成フェーズ
   ├─ CREATE VIRTUAL TABLE...USING module_name(args)
   ├─ 対応するモジュールをハッシュから検索
   ├─ xCreate()を呼び出し
   └─ sqlite3_declare_vtab()でスキーマを宣言

3. クエリコンパイルフェーズ
   ├─ FROM句で仮想テーブルを参照
   ├─ xBestIndex()を呼び出して最適プラン選択
   └─ VDBEコード生成（OP_VOpen、OP_VFilter等）

4. クエリ実行フェーズ
   ├─ OP_VOpen: xOpen()でカーソル作成
   ├─ OP_VFilter: xFilter()でスキャン開始
   ├─ OP_VColumn: xColumn()で値取得
   ├─ OP_VNext: xNext()で次行へ
   └─ OP_VClose: xClose()でカーソル破棄

5. 更新実行フェーズ（DML時）
   └─ OP_VUpdate: xUpdate()で挿入/更新/削除
```

### フローチャート

```mermaid
flowchart TD
    A[sqlite3_create_module] --> B[モジュールハッシュに登録]
    B --> C[CREATE VIRTUAL TABLE]
    C --> D[モジュール検索]
    D --> E{モジュール存在?}
    E -->|No| F[エラー: no such module]
    E -->|Yes| G[xCreate呼び出し]
    G --> H[sqlite3_declare_vtab]
    H --> I[スキーマ登録完了]

    J[SELECT FROM vtab] --> K[xBestIndex呼び出し]
    K --> L[コスト計算・制約処理]
    L --> M[VDBEコード生成]
    M --> N[xOpen]
    N --> O[xFilter]
    O --> P{xEof?}
    P -->|Yes| Q[結果終了]
    P -->|No| R[xColumn]
    R --> S[xNext]
    S --> P
    Q --> T[xClose]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-1 | モジュール先行登録 | CREATE VIRTUAL TABLEの前にモジュールが登録されている必要がある | 常時 |
| BR-33-2 | スキーマ宣言必須 | xCreate/xConnect内でsqlite3_declare_vtab()を呼び出す必要がある | xCreate/xConnect時 |
| BR-33-3 | xBestIndex制約 | xBestIndexは副作用を持ってはならない | xBestIndex呼び出し時 |
| BR-33-4 | カーソル独立性 | 各カーソルは独立した状態を持つ | マルチスレッド/複数カーソル時 |

### 計算ロジック

**xBestIndexのコスト計算**：
- estimatedCost: 推定I/Oコスト（低いほど優先）
- estimatedRows: 推定行数
- idxNum/idxStr: モジュール固有のインデックス識別子

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| CREATE VIRTUAL TABLE | sqlite_schema | INSERT | 仮想テーブル定義を登録 |
| DROP | sqlite_schema | DELETE | 仮想テーブル定義を削除 |
| xUpdate | 外部データソース | INSERT/UPDATE/DELETE | モジュール依存 |

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

#### sqlite_schema

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | type | 'table' | 仮想テーブル作成時 |
| INSERT | name | テーブル名 | 仮想テーブル作成時 |
| INSERT | sql | CREATE文 | 仮想テーブル作成時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SQLITE_ERROR | モジュール未登録 | 指定モジュールが登録されていない | モジュールを事前登録 |
| SQLITE_MISUSE | API誤用 | xCreate内でのDML実行等 | API利用方法の修正 |
| SQLITE_CONSTRAINT | 制約違反 | xUpdateで返されたエラー | モジュール実装による |
| SQLITE_READONLY | 読み取り専用 | xUpdateが未実装の仮想テーブルへの更新 | 更新可能なモジュールを使用 |

### リトライ仕様

仮想テーブルのエラーはモジュール実装に依存する。一般的には自動リトライは行わない。

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

- xBegin/xSync/xCommit/xRollbackが実装されている場合、トランザクション管理に参加
- 未実装の場合、仮想テーブル操作はトランザクション外で即座に反映
- xSavepoint/xRelease/xRollbackToでセーブポイントをサポート可能

## パフォーマンス要件

- xBestIndexは複数回呼び出される可能性があるため、軽量に実装する必要がある
- xBestIndexの戻り値（idxNum、idxStr、aConstraintUsage）によりインデックス使用を最適化
- estimatedCostの正確な設定がクエリプランナーの効率に影響

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

- 仮想テーブルモジュールはC言語で実装されるため、メモリ安全性に注意が必要
- 外部データソースへのアクセスにはモジュール内で適切な認証/認可を実装
- sqlite3_vtab_config()でリスクレベルを設定可能（SQLITE_VTAB_INNOCUOUS等）

## 備考

- SQLITE_OMIT_VIRTUALTABLE でコンパイルした場合、本機能は無効
- eponymous仮想テーブル（CREATE TABLE不要で同名でアクセス可能）をサポート
- シャドウテーブル（モジュールが内部で使用するテーブル）の保護機能あり

---

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

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

### 推奨読解順序

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

仮想テーブルの中核となるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sqlite3.h | `src/sqlite3.h` | sqlite3_module構造体（メソッドテーブル）の定義 |
| 1-2 | sqlite3.h | `src/sqlite3.h` | sqlite3_vtab、sqlite3_vtab_cursor構造体の定義 |
| 1-3 | sqliteInt.h | `src/sqliteInt.h` | VTable、Module構造体の内部定義 |

**読解のコツ**: sqlite3_module構造体は公開API、VTable/Module構造体は内部実装。sqlite3_vtabは仮想テーブルインスタンス、sqlite3_vtab_cursorはカーソル状態を管理。

#### Step 2: モジュール登録を理解する

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

**主要処理フロー**:
1. **1101-1166行目**: sqlite3_create_module_v2()の実装
2. **1111-1130行目**: Module構造体の作成とメンバー設定
3. **1132-1144行目**: モジュールハッシュへの登録

#### Step 3: テーブル作成処理を理解する

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

**主要処理フロー**:
- **614-740行目**: vtabCallConstructor()でxCreate/xConnectを呼び出し
- **648-651行目**: sqlite3_vtab構造体のアロケート
- **687-710行目**: xCreate/xConnectコールバック実行
- **714-730行目**: エラー処理とクリーンアップ

#### Step 4: クエリプラン最適化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | vtab.c | `src/vtab.c` | sqlite3VtabBestIndex()関数 |
| 4-2 | where.c | `src/where.c` | whereLoopAddVirtual()関数 |

**主要処理フロー**:
- **891-948行目**: sqlite3VtabBestIndex()でxBestIndex呼び出し
- **910-930行目**: sqlite3_index_info構造体の設定
- **936行目**: pModule->xBestIndex呼び出し

#### Step 5: クエリ実行処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | vdbe.c | `src/vdbe.c` | OP_VOpen、OP_VFilter、OP_VColumn、OP_VNext実装 |

**主要処理フロー**:
- OP_VOpen: xOpen()呼び出しでカーソル作成
- OP_VFilter: xFilter()呼び出しでスキャン開始
- OP_VColumn: xColumn()呼び出しで値取得
- OP_VNext: xNext()呼び出しで次行へ移動

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

```
sqlite3_create_module_v2()
    │
    └─ Module構造体をaModuleハッシュに登録

CREATE VIRTUAL TABLE
    │
    └─ sqlite3VtabCallCreate()
           │
           └─ vtabCallConstructor()
                  │
                  └─ pModule->xCreate()  ────▶ ユーザーコールバック

SELECT FROM virtual_table
    │
    ├─ sqlite3VtabBestIndex()
    │      │
    │      └─ pModule->xBestIndex()  ────▶ コスト計算
    │
    └─ sqlite3VdbeExec()
           │
           ├─ OP_VOpen: pModule->xOpen()
           ├─ OP_VFilter: pModule->xFilter()
           ├─ OP_VColumn: pModule->xColumn()
           ├─ OP_VNext: pModule->xNext()
           └─ OP_VClose: pModule->xClose()
```

### データフロー図

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

sqlite3_module* ──────────▶ sqlite3_create_module_v2() ──▶ Moduleハッシュ
モジュールメソッドテーブル   モジュール登録

CREATE VIRTUAL TABLE ─────▶ vtabCallConstructor() ────────▶ VTable構造体
SQL文                       │                               sqlite_schema行
                           └─ xCreate()
                           └─ sqlite3_declare_vtab()

sqlite3_index_info ───────▶ sqlite3VtabBestIndex() ───────▶ idxNum/idxStr
WHERE句制約                  │                               estimatedCost
                           └─ xBestIndex()

VDBEプログラム ────────────▶ sqlite3VdbeExec() ────────────▶ 結果セット
                           │
                           ├─ xOpen() ────────▶ sqlite3_vtab_cursor
                           ├─ xFilter() ──────▶ スキャン開始
                           ├─ xColumn() ──────▶ カラム値
                           └─ xNext() ────────▶ 次行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| vtab.c | `src/vtab.c` | ソース | 仮想テーブルのメイン実装 |
| sqlite3.h | `src/sqlite3.h` | ヘッダー | 公開API（sqlite3_module等）定義 |
| sqliteInt.h | `src/sqliteInt.h` | ヘッダー | 内部構造体（VTable、Module）定義 |
| build.c | `src/build.c` | ソース | CREATE VIRTUAL TABLEの構文解析 |
| where.c | `src/where.c` | ソース | xBestIndex呼び出しとクエリプラン最適化 |
| vdbe.c | `src/vdbe.c` | ソース | VDBEオペコード（OP_VOpen等）実装 |
| select.c | `src/select.c` | ソース | 仮想テーブルからのSELECT処理 |
| insert.c | `src/insert.c` | ソース | 仮想テーブルへのINSERT処理 |
| update.c | `src/update.c` | ソース | 仮想テーブルのUPDATE処理 |
| delete.c | `src/delete.c` | ソース | 仮想テーブルからのDELETE処理 |
