# 機能設計書 8-UPDATE文処理

## 概要

本ドキュメントは、SQLiteにおけるUPDATE文によるデータ更新処理について、その設計と実装の詳細を記述する。既存レコードの値変更、制約チェック、インデックス更新の一連の処理について解説する。

### 本機能の処理概要

**業務上の目的・背景**：UPDATE文は既存のデータを変更するための基本的なDML操作である。単一行の更新から、複数行の一括更新、JOIN句を使用した複雑な更新まで、様々なデータ変更要件に対応する必要がある。

**機能の利用シーン**：
- 既存データの値変更
- 複数行の一括更新
- 条件に基づく選択的更新
- JOIN句を使用した他テーブル参照更新（UPDATE ... FROM）
- RETURNING句を使用した更新後の値取得
- WASMデモでのデータ更新処理

**主要な処理内容**：
1. UPDATE文のパースとターゲットテーブルの特定
2. SET句の解析と更新カラムの特定
3. WHERE句による対象行の絞り込み
4. FROM句（UPDATE FROM構文）の処理
5. 新しい値の計算と型変換
6. 制約チェック（NOT NULL、UNIQUE、FOREIGN KEY等）
7. インデックスエントリの更新
8. トリガーの実行
9. RETURNING句の処理

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

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | SQLite3 Fiddle | 主画面 | データ更新SQLの実行 |

## 機能種別

データ更新処理（CRUD操作のUpdate）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| テーブル名 | SrcList* | Yes | 更新対象テーブル | 存在するテーブル |
| SET句 | ExprList* | Yes | 更新するカラムと値のリスト | 1つ以上必須 |
| WHERE句 | Expr* | No | 更新対象行の条件 | 省略時は全行更新 |
| FROM句 | SrcList* | No | 参照テーブル（UPDATE FROM） | 省略可 |
| ORDER BY | ExprList* | No | 更新順序 | LIMIT指定時のみ |
| LIMIT | Expr* | No | 更新件数制限 | 省略可 |
| ON CONFLICT | int | No | 競合時の動作 | ABORT/ROLLBACK/FAIL/IGNORE/REPLACE |
| RETURNING | ExprList* | No | 返却するカラム | 省略可 |

### 入力データソース

- 更新対象テーブルの既存データ
- SET句で指定された新しい値
- FROM句で参照する他テーブルのデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 影響行数 | int | 更新された行数 |
| RETURNING結果 | sqlite3_stmt* | RETURNING句指定時の結果セット |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. UPDATE文のパース
   └─ ターゲットテーブルとSET句の解析

2. FROM句処理（UPDATE FROM構文の場合）
   └─ updateFromSelect()で一時テーブルに結果を格納

3. WHERE句の最適化
   └─ 更新対象行の効率的な特定

4. 更新対象行のスキャン
   └─ インデックスまたはフルスキャン

5. 各行の処理
   ├─ 新しい値の計算
   ├─ デフォルト値の適用（カラム未指定時）
   └─ 型変換とアフィニティ

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

7. インデックス更新
   ├─ 変更されたカラムを含むインデックスのエントリ更新
   └─ 部分インデックスの条件評価

8. トリガー実行
   └─ BEFORE UPDATE、AFTER UPDATEトリガー

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

### フローチャート

```mermaid
flowchart TD
    A[UPDATE文入力] --> B[テーブル・SET句解析]
    B --> C{FROM句あり?}
    C -->|Yes| D[updateFromSelect]
    C -->|No| E[WHERE句最適化]
    D --> E
    E --> F[対象行スキャン]
    F --> G[新しい値の計算]
    G --> H[型変換・アフィニティ]
    H --> I[制約チェック]
    I --> J{違反?}
    J -->|Yes| K[ON CONFLICT処理]
    J -->|No| L[行更新]
    K --> M{競合処理}
    M -->|IGNORE| N[スキップ]
    M -->|ABORT/FAIL| O[エラー返却]
    L --> P[インデックス更新]
    P --> Q[トリガー実行]
    Q --> R{次の行?}
    R -->|Yes| F
    R -->|No| S{RETURNING?}
    S -->|Yes| T[結果返却]
    S -->|No| U[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 全行更新警告 | WHERE句なしは全行が更新対象 | WHERE省略時 |
| BR-002 | ROWID更新 | ROWID/INTEGER PRIMARY KEYの更新は行の移動を伴う場合あり | ROWID更新時 |
| BR-003 | 部分インデックス | 部分インデックスの条件に影響するカラム更新時は再評価 | 部分インデックス存在時 |
| BR-004 | 生成列 | STORED生成列は参照カラム変更時に自動再計算 | 生成列存在時 |
| BR-005 | トリガー内参照 | OLD.column、NEW.columnで変更前後の値を参照可能 | トリガー内 |
| BR-006 | カスケード更新 | 外部キーでON UPDATE CASCADE設定時は参照先も更新 | FOREIGN KEY有効時 |

### 計算ロジック

**変更カラムの特定**：
- aXRef配列でカラムごとの変更有無を管理
- indexColumnIsBeingUpdated()でインデックスへの影響を判定

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| UPDATE | 指定テーブル | UPDATE | 既存レコードの値変更 |
| UPDATE | インデックス | DELETE+INSERT | インデックスエントリの更新 |
| UPDATE | 参照テーブル | UPDATE | CASCADEによる連鎖更新 |

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

#### 指定テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | SET句で指定されたカラム | 新しい値 | WHERE条件に一致する行 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SQLITE_CONSTRAINT | 制約違反 | NOT NULL、UNIQUE等の違反 | データ修正またはON CONFLICT |
| SQLITE_CONSTRAINT_FOREIGNKEY | 外部キー違反 | 参照整合性違反 | 参照先のデータを確認 |
| SQLITE_MISMATCH | 型不一致 | STRICTテーブルでの型エラー | 正しい型で更新 |
| SQLITE_READONLY | 読み取り専用 | 読み取り専用接続での更新 | 書き込み可能接続を使用 |
| SQLITE_BUSY | ロック競合 | 他接続が行をロック中 | リトライまたはタイムアウト設定 |

### リトライ仕様

- SQLITE_BUSYは設定されたビジーハンドラに従ってリトライ
- 制約違反はデータ修正後に再試行

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

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

## パフォーマンス要件

- インデックス使用時の行特定はO(log n)
- フルスキャン時はO(n)
- 更新するインデックス数に応じてオーバーヘッド増加
- LIMIT句で更新件数を制限可能

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

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

## 備考

- UPDATE FROM構文（UPDATE ... FROM ...）はSQLite 3.33.0以降でサポート
- 複数テーブルの結合結果に基づく更新が可能
- RETURNING句でUPDATE後の値を即座に取得可能

---

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

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

### 推奨読解順序

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

まず、UPDATE処理で使用される構造体と変数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sqliteInt.h | `src/sqliteInt.h` | Table構造体、Expr構造体、ExprList構造体 |
| 1-2 | update.c | `src/update.c` | 処理で使用するローカル変数 |

**読解のコツ**: aXRef配列はカラムごとの更新有無を管理。-1は更新なし、0以上はpChanges内の位置を示す。

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

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

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

**主要処理フロー**:
1. **277-284行目**: sqlite3Update()の関数シグネチャとパラメータ
2. **285-300行目**: ローカル変数の宣言
3. pTabList（テーブルリスト）、pChanges（SET句）、pWhere（WHERE句）

#### Step 3: FROM句処理を理解する

UPDATE FROM構文の処理を把握する。

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

**主要処理フロー**:
- **187-274行目**: updateFromSelect()の実装
- 一時テーブル（エフェメラルテーブル）に結果を格納

#### Step 4: インデックス更新判定を理解する

更新がインデックスに影響するかの判定を把握する。

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

**主要処理フロー**:
- **97-113行目**: indexColumnIsBeingUpdated()の実装
- **127-135行目**: indexWhereClauseMightChange()の実装

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

```
sqlite3Update()                    [update.c:285]
    │
    ├─ sqlite3SrcListLookup()      テーブル検索
    │
    ├─ updateFromSelect()          [update.c:187]
    │      └─ FROM句の処理（エフェメラルテーブル作成）
    │
    ├─ sqlite3WhereBegin()         [where.c]
    │      └─ WHERE句最適化・対象行スキャン
    │
    ├─ 新しい値の計算
    │      ├─ sqlite3ExprCode()    式のコード生成
    │      └─ sqlite3ColumnDefault() デフォルト値取得
    │
    ├─ 制約チェック
    │      ├─ NOT NULL チェック
    │      ├─ UNIQUE チェック
    │      └─ FOREIGN KEY チェック [fkey.c]
    │
    └─ VDBEコード生成
           ├─ OP_Delete + OP_Insert（ROWIDテーブル）
           └─ インデックス更新
```

### データフロー図

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

UPDATE文          ───▶ パース・検証            ───▶ テーブル更新
    │                      │
    ▼                      ▼
SET句の値         ───▶ WHERE条件評価           ───▶ 対象行特定
    │                      │
FROM句データ      ───▶ 新しい値の計算          ───▶ 行データ更新
                           │
                           ▼
                     インデックス更新
                           │
                           ▼
                     トリガー実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| update.c | `src/update.c` | ソース | UPDATE文処理のメイン実装 |
| where.c | `src/where.c` | ソース | WHERE句最適化 |
| expr.c | `src/expr.c` | ソース | 式の評価・コード生成 |
| fkey.c | `src/fkey.c` | ソース | 外部キー制約処理 |
| trigger.c | `src/trigger.c` | ソース | トリガー処理 |
| vdbe.c | `src/vdbe.c` | ソース | VDBE実行 |
| sqliteInt.h | `src/sqliteInt.h` | ヘッダー | 構造体定義 |
