# 機能設計書 7-INSERT文処理

## 概要

本ドキュメントは、SQLiteにおけるINSERT文によるデータ挿入処理について、その設計と実装の詳細を記述する。テーブルへの新規レコード追加、制約チェック、インデックス更新の一連の処理について解説する。

### 本機能の処理概要

**業務上の目的・背景**：INSERT文はデータベースに新しいレコードを追加するための基本的なDML操作である。単一行の挿入から、SELECT結果の一括挿入、競合時の処理（ON CONFLICT）まで、様々なデータ投入要件に対応する必要がある。

**機能の利用シーン**：
- 新規データのテーブルへの追加
- バルクデータの一括挿入（INSERT INTO ... SELECT）
- デフォルト値を使用した挿入（INSERT INTO ... DEFAULT VALUES）
- 競合時の処理指定（INSERT OR REPLACE、INSERT OR IGNORE等）
- RETURNING句を使用した挿入後の値取得
- WASMデモでのデータ挿入処理

**主要な処理内容**：
1. INSERT文のパースとターゲットテーブルの特定
2. カラムリストの解析とマッピング
3. 値リストまたはSELECT文の処理
4. データ型変換とアフィニティ処理
5. 制約チェック（NOT NULL、UNIQUE、FOREIGN KEY等）
6. インデックスエントリの追加
7. トリガーの実行
8. RETURNING句の処理

**関連システム・外部連携**：
- パーサー（parse.y、tokenize.c）
- VDBEコードジェネレータ
- B-Treeストレージエンジン（btree.c）
- 外部キー制約処理（fkey.c）
- トリガー処理（trigger.c）

**権限による制御**：sqlite3_set_authorizer()で設定されたauthorizerコールバックによるINSERT操作の許可/拒否が適用される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | 基本デモ（UIスレッド版） | 主画面 | db.exec()でのINSERT文実行 |
| 4 | 基本デモ（Worker版） | 主画面 | Worker内でのデータ挿入処理 |
| 5 | JS Storage デモ | 補助画面 | 永続化DBへのデータ挿入 |
| 8 | SQLite3 Fiddle | 主画面 | データ挿入SQLの実行 |
| 12 | Tester1（メインスレッド版） | 主画面 | 各種INSERT文の単体・回帰テスト |
| 18 | SQLTester | 主画面 | テストスクリプト内INSERT文実行 |

## 機能種別

データ挿入処理（CRUD操作のCreate）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| テーブル名 | SrcList* | Yes | 挿入先テーブル | 存在するテーブル |
| カラムリスト | IdList* | No | 挿入先カラム | 省略時は全カラム |
| VALUES句 | Select* | Cond | 挿入する値リスト | DEFAULT VALUESまたはSELECTと排他 |
| SELECT句 | Select* | Cond | 挿入するデータのソース | VALUESと排他 |
| ON CONFLICT | int | No | 競合時の動作 | ABORT/ROLLBACK/FAIL/IGNORE/REPLACE |
| RETURNING | ExprList* | No | 返却するカラム | 省略可 |

### 入力データソース

- VALUES句で指定されたリテラル値
- SELECT文の実行結果
- デフォルト値定義

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 影響行数 | int | 挿入された行数 |
| last_insert_rowid | sqlite3_int64 | 最後に挿入された行のROWID |
| RETURNING結果 | sqlite3_stmt* | RETURNING句指定時の結果セット |

### 出力先

- データベーステーブル
- インデックス
- RETURNING句指定時はアプリケーションへ

## 処理フロー

### 処理シーケンス

```
1. INSERT文のパース
   └─ ターゲットテーブルとカラムリストの特定

2. テーブルオープン
   └─ sqlite3OpenTable()でテーブルとインデックスをオープン

3. 値の準備
   ├─ VALUES句：値のコード生成
   ├─ SELECT句：サブクエリの実行
   └─ DEFAULT VALUES：デフォルト値の取得

4. 型変換とアフィニティ
   └─ sqlite3TableAffinity()でカラムアフィニティを適用

5. 制約チェック
   ├─ NOT NULL制約
   ├─ CHECK制約
   ├─ UNIQUE制約
   └─ FOREIGN KEY制約

6. 競合処理
   ├─ ABORT：トランザクションをロールバック
   ├─ ROLLBACK：全てをロールバック
   ├─ FAIL：エラーで中断（途中まで保持）
   ├─ IGNORE：行をスキップ
   └─ REPLACE：既存行を削除して挿入

7. データ挿入
   ├─ B-Tree操作（テーブル）
   └─ インデックスエントリの追加

8. トリガー実行
   └─ AFTER INSERTトリガー

9. RETURNING処理
   └─ 指定カラムの値を返却
```

### フローチャート

```mermaid
flowchart TD
    A[INSERT文入力] --> B[テーブル・カラム解析]
    B --> C{データソース}
    C -->|VALUES| D[値リスト処理]
    C -->|SELECT| E[サブクエリ実行]
    C -->|DEFAULT| F[デフォルト値取得]
    D --> G[型変換・アフィニティ]
    E --> G
    F --> G
    G --> H[制約チェック]
    H --> I{違反?}
    I -->|Yes| J[ON CONFLICT処理]
    I -->|No| K[B-Tree挿入]
    J --> L{競合処理}
    L -->|REPLACE| M[既存行削除]
    L -->|IGNORE| N[スキップ]
    L -->|ABORT/FAIL| O[エラー返却]
    M --> K
    K --> P[インデックス更新]
    P --> Q[トリガー実行]
    Q --> R{RETURNING?}
    R -->|Yes| S[結果返却]
    R -->|No| T[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | ROWID自動生成 | INTEGER PRIMARY KEYにNULL挿入時は自動生成 | ROWID型テーブル |
| BR-002 | デフォルト値適用 | 省略されたカラムにはデフォルト値を使用 | デフォルト定義時 |
| BR-003 | 型アフィニティ | カラムのアフィニティに従って型変換 | 常時 |
| BR-004 | STRICT制約 | STRICTテーブルでは厳密な型チェック | STRICT宣言時 |
| BR-005 | AUTO_INCREMENT | autoincrement属性では最大+1を保証 | autoincrement指定時 |
| BR-006 | 外部キー参照 | 参照先に存在する値のみ挿入可能 | FOREIGN KEY有効時 |

### 計算ロジック

**ROWID生成**：
- 通常：最大ROWID + 1
- AUTOINCREMENT：過去最大を超える値を保証

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| INSERT | 指定テーブル | INSERT | 新規レコード追加 |
| INSERT | インデックス | INSERT | インデックスエントリ追加 |
| INSERT | sqlite_sequence | UPDATE | autoincrement使用時 |

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

#### 指定テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | 全指定カラム | VALUES/SELECT/DEFAULT | ROWID自動生成可 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SQLITE_CONSTRAINT | 制約違反 | NOT NULL、UNIQUE等の違反 | データ修正またはON CONFLICT |
| SQLITE_CONSTRAINT_FOREIGNKEY | 外部キー違反 | 参照先に存在しない | 参照先にデータを追加 |
| SQLITE_MISMATCH | 型不一致 | STRICTテーブルでの型エラー | 正しい型で再挿入 |
| SQLITE_READONLY | 読み取り専用 | 読み取り専用接続での挿入 | 書き込み可能接続を使用 |
| SQLITE_FULL | ディスク満杯 | ストレージ容量不足 | ディスク領域を確保 |

### リトライ仕様

- 制約違反はデータ修正後に再試行
- ディスク満杯は領域確保後に再試行

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

- INSERT文は暗黙のトランザクション内で実行
- 明示的トランザクション内では複数INSERTを一括コミット可能
- ON CONFLICT ABORTは現在のステートメントのみロールバック
- ON CONFLICT ROLLBACKはトランザクション全体をロールバック

## パフォーマンス要件

- 単一行挿入は通常数ミリ秒以内
- バルク挿入時はトランザクションでまとめると高速
- インデックス数に応じてオーバーヘッド増加
- WITHOUT ROWIDテーブルはCLUSTERED索引のため挿入位置依存

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

- authorizerコールバックによるINSERT許可制御
- プリペアドステートメントによるSQLインジェクション防止
- トリガー内でのセキュリティ考慮

## 備考

- REPLACE文はINSERT OR REPLACEの省略形
- INSERT文でのUPSERT（ON CONFLICT DO UPDATE）もサポート
- 生成列（GENERATED COLUMNS）は自動計算

---

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

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

### 推奨読解順序

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

まず、INSERT処理で使用される構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sqliteInt.h | `src/sqliteInt.h` | Table構造体、Index構造体、Column構造体 |
| 1-2 | insert.c | `src/insert.c` | 各種定数定義 |

**読解のコツ**: Table構造体はテーブルのスキーマ情報を保持。aCol配列でカラム情報、pIndex連結リストでインデックス情報を管理。

#### Step 2: エントリーポイントを理解する

INSERT処理の起点を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | insert.c | `src/insert.c` | sqlite3Insert()関数（実際の関数名はパーサーから呼ばれる） |

**主要処理フロー**:
1. **26-53行目**: sqlite3OpenTable()でテーブルをオープン
2. テーブルロック取得、カーソルオープン

#### Step 3: テーブルアクセス処理を理解する

テーブルオープンとアフィニティ処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | insert.c | `src/insert.c` | sqlite3OpenTable()の実装 |
| 3-2 | insert.c | `src/insert.c` | sqlite3TableAffinity()の実装 |

**主要処理フロー**:
- **26-53行目**: sqlite3OpenTable()でテーブルカーソルをオープン
- **179-224行目**: sqlite3TableAffinity()でアフィニティ適用

#### Step 4: アフィニティ処理を理解する

型変換とSTRICTテーブル処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | insert.c | `src/insert.c` | 通常テーブルのアフィニティ |
| 4-2 | insert.c | `src/insert.c` | STRICTテーブルのOP_TypeCheck |

**主要処理フロー**:
- **179-203行目**: STRICTテーブルのTypeCheck生成
- **204-224行目**: 通常テーブルのAffinity適用

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

```
sqlite3Insert()                    [parse.y経由で呼び出し]
    │
    ├─ sqlite3SrcListLookup()      テーブル検索
    │
    ├─ sqlite3OpenTable()          [insert.c:26]
    │      └─ テーブル・インデックスをオープン
    │
    ├─ sqlite3TableAffinity()      [insert.c:179]
    │      └─ 型アフィニティ適用
    │
    ├─ 制約チェック
    │      ├─ NOT NULL チェック
    │      ├─ UNIQUE チェック
    │      └─ FOREIGN KEY チェック [fkey.c]
    │
    └─ VDBEコード生成
           ├─ OP_Insert
           └─ OP_IdxInsert（インデックス用）
```

### データフロー図

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

INSERT文          ───▶ パース・検証            ───▶ テーブル更新
    │                      │
    ▼                      ▼
VALUES/SELECT     ───▶ 型変換・アフィニティ    ───▶ B-Tree挿入
                           │
                           ▼
                     制約チェック
                           │
                           ▼
                     インデックス更新
                           │
                           ▼
                     トリガー実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| insert.c | `src/insert.c` | ソース | INSERT文処理のメイン実装 |
| build.c | `src/build.c` | ソース | テーブル構造関連 |
| btree.c | `src/btree.c` | ソース | B-Tree操作 |
| fkey.c | `src/fkey.c` | ソース | 外部キー制約処理 |
| trigger.c | `src/trigger.c` | ソース | トリガー処理 |
| vdbe.c | `src/vdbe.c` | ソース | VDBE実行（OP_Insert等） |
| sqliteInt.h | `src/sqliteInt.h` | ヘッダー | 構造体定義 |
