# 機能設計書 10-CREATE TABLE処理

## 概要

本ドキュメントは、SQLiteにおけるCREATE TABLE文によるテーブル作成処理について、その設計と実装の詳細を記述する。テーブルスキーマの定義、制約の設定、インデックスの自動生成について解説する。

### 本機能の処理概要

**業務上の目的・背景**：CREATE TABLE文はデータベーススキーマを定義するための基本的なDDL操作である。カラム定義、データ型、制約条件、インデックスなど、テーブルの構造を決定する全ての要素を指定できる。

**機能の利用シーン**：
- 新規テーブルの作成
- 一時テーブルの作成（TEMPORARY）
- 存在確認付きテーブル作成（IF NOT EXISTS）
- 他テーブルを基にしたテーブル作成（CREATE TABLE ... AS SELECT）
- WASMデモでのテーブル作成

**主要な処理内容**：
1. CREATE TABLE文のパースとテーブル名の検証
2. カラム定義の解析（名前、型、制約）
3. テーブルレベル制約の処理（PRIMARY KEY、UNIQUE、FOREIGN KEY、CHECK）
4. sqlite_schemaへのスキーマ情報登録
5. テーブル用B-Treeの作成
6. 暗黙のインデックス作成（PRIMARY KEY、UNIQUE制約）
7. 外部キー関係の登録

**関連システム・外部連携**：
- パーサー（parse.y、tokenize.c）
- スキーマキャッシュ（sqlite_schema）
- B-Treeストレージエンジン（btree.c）
- インデックス管理（build.c）

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | 基本デモ（UIスレッド版） | 主画面 | db.exec("CREATE TABLE IF NOT EXISTS t(a,b)")でテーブル作成 |
| 8 | SQLite3 Fiddle | 主画面 | テーブル作成DDLの実行 |

## 機能種別

DDL処理（データ定義言語）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| テーブル名 | Token* | Yes | 作成するテーブル名 | 一意性チェック |
| カラム定義 | Column[] | Yes（AS SELECT以外） | カラムのリスト | 1つ以上必須 |
| テーブル制約 | Constraint[] | No | PRIMARY KEY、UNIQUE等 | 省略可 |
| TEMPORARY | int | No | 一時テーブルフラグ | true/false |
| IF NOT EXISTS | int | No | 存在時スキップフラグ | true/false |
| WITHOUT ROWID | int | No | ROWID省略フラグ | true/false |
| STRICT | int | No | 厳密型チェックフラグ | true/false |
| AS SELECT | Select* | Cond | SELECT結果でテーブル作成 | カラム定義と排他 |

### 入力データソース

- SQL文で指定されたスキーマ定義

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | SQLITE_OK（成功）、またはエラーコード |

### 出力先

- sqlite_schemaテーブル（スキーマ情報）
- B-Treeファイル（テーブルデータ用）
- 内部スキーマキャッシュ

## 処理フロー

### 処理シーケンス

```
1. CREATE TABLE文のパース
   └─ テーブル名、カラム定義、制約の解析

2. 名前の検証
   ├─ 予約語との衝突チェック
   ├─ 既存テーブル名との重複チェック
   └─ IF NOT EXISTSの評価

3. Table構造体の構築
   └─ sqlite3StartTable()でTable構造体を初期化

4. カラム定義の処理
   ├─ sqlite3AddColumn()で各カラムを追加
   ├─ 型アフィニティの決定
   └─ カラムレベル制約の処理

5. テーブルレベル制約の処理
   ├─ PRIMARY KEY（単一/複合）
   ├─ UNIQUE制約
   ├─ FOREIGN KEY制約
   └─ CHECK制約

6. B-Treeの作成
   └─ テーブル用のルートページ割り当て

7. sqlite_schemaへの登録
   └─ スキーマ情報の永続化

8. インデックスの作成
   ├─ PRIMARY KEY用インデックス（WITHOUT ROWID以外）
   └─ UNIQUE制約用インデックス

9. スキーマキャッシュの更新
   └─ 内部データ構造の更新
```

### フローチャート

```mermaid
flowchart TD
    A[CREATE TABLE文入力] --> B[テーブル名検証]
    B --> C{既存テーブル?}
    C -->|Yes| D{IF NOT EXISTS?}
    D -->|Yes| E[スキップ]
    D -->|No| F[エラー返却]
    C -->|No| G[Table構造体作成]
    G --> H[カラム定義処理]
    H --> I[テーブル制約処理]
    I --> J{WITHOUT ROWID?}
    J -->|Yes| K[PRIMARY KEY必須チェック]
    J -->|No| L[B-Tree作成]
    K --> L
    L --> M[sqlite_schema登録]
    M --> N[インデックス作成]
    N --> O[スキーマキャッシュ更新]
    O --> P[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | テーブル名一意性 | 同一データベース内でテーブル名は一意 | 常時 |
| BR-002 | sqlite_プレフィックス禁止 | sqlite_で始まるテーブル名は作成不可 | 常時 |
| BR-003 | WITHOUT ROWID制約 | WITHOUT ROWIDテーブルはPRIMARY KEY必須 | WITHOUT ROWID指定時 |
| BR-004 | STRICT制約 | STRICTテーブルはカラムに型指定必須（ANY可） | STRICT指定時 |
| BR-005 | 型アフィニティ | 型名から自動的にアフィニティを決定 | 常時 |
| BR-006 | AUTOINCREMENT制約 | INTEGER PRIMARY KEYでのみ使用可能 | AUTOINCREMENT指定時 |
| BR-007 | 生成列 | GENERATED ALWAYS AS (expr)で計算列を定義 | 生成列指定時 |

### 計算ロジック

**型アフィニティの決定**：
1. "INT"を含む → INTEGER
2. "CHAR"、"CLOB"、"TEXT"を含む → TEXT
3. "BLOB"または型名なし → BLOB
4. "REAL"、"FLOA"、"DOUB"を含む → REAL
5. それ以外 → NUMERIC

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| CREATE TABLE | sqlite_schema | INSERT | スキーマ情報の登録 |
| CREATE TABLE | 新規テーブル | CREATE | B-Treeルートページの割り当て |
| CREATE TABLE | 自動インデックス | CREATE | PRIMARY KEY/UNIQUE用 |

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

#### sqlite_schema

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | type | 'table' | テーブル種別 |
| INSERT | name | テーブル名 | |
| INSERT | tbl_name | テーブル名 | |
| INSERT | rootpage | B-Treeルートページ番号 | |
| INSERT | sql | CREATE TABLE文 | 元のSQL文を保存 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SQLITE_ERROR | テーブル重複 | 同名テーブルが既に存在 | IF NOT EXISTSを使用 |
| SQLITE_ERROR | 予約語使用 | sqlite_プレフィックスの使用 | 別の名前を使用 |
| SQLITE_ERROR | PRIMARY KEY重複 | 複数のPRIMARY KEY定義 | 1つのPRIMARY KEYに統合 |
| SQLITE_ERROR | WITHOUT ROWID制約違反 | PRIMARY KEYなしでWITHOUT ROWID | PRIMARY KEYを追加 |
| SQLITE_NOMEM | メモリ不足 | スキーマ構築時のメモリ確保失敗 | メモリを解放して再試行 |

### リトライ仕様

- DDL操作は通常リトライ不要
- メモリ不足の場合は環境改善後に再試行

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

- CREATE TABLE文は暗黙のトランザクション内で実行
- DDL操作は自動コミット（autocommitモード時）
- 明示的トランザクション内でもDDL実行可能

## パフォーマンス要件

- テーブル作成は通常数十ミリ秒以内
- 大量のカラム/制約がある場合は時間増加
- スキーマキャッシュの更新コストあり

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

- authorizerコールバックによるCREATE TABLE許可制御
- sqlite_プレフィックステーブルの作成制限
- 一時テーブルの適切な権限管理

## 備考

- CREATE TABLE ... AS SELECTはSELECT結果の構造でテーブルを作成
- 仮想テーブル（VIRTUAL TABLE）は別の処理フロー（vtab.c）
- ALTERテーブルによるスキーマ変更は別機能（alter.c）

---

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

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

### 推奨読解順序

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

まず、テーブルスキーマを表す構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sqliteInt.h | `src/sqliteInt.h` | Table構造体、Column構造体、Index構造体 |
| 1-2 | build.c | `src/build.c` | TableLock構造体 |

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

#### Step 2: 補助関数を理解する

テーブル作成で使用される補助関数を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | build.c | `src/build.c` | sqlite3TableLock()、sqlite3FinishCoding() |

**主要処理フロー**:
1. **49-96行目**: lockTable()とsqlite3TableLock()でテーブルロック管理
2. **141-278行目**: sqlite3FinishCoding()でVDBEプログラムの完成

#### Step 3: テーブル作成の開始を理解する

CREATE TABLE処理の起点を把握する。

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

**主要処理フロー**:
- Table構造体の初期化
- テーブル名の検証
- 一時テーブルフラグの設定

#### Step 4: カラム追加を理解する

カラム定義の処理を把握する。

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

**主要処理フロー**:
- Column構造体の初期化
- 型アフィニティの決定
- デフォルト値の設定

#### Step 5: テーブル作成の完了を理解する

テーブル定義の確定処理を把握する。

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

**主要処理フロー**:
- 制約の検証
- B-Tree作成のVDBEコード生成
- sqlite_schemaへの登録コード生成

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

```
パーサー（parse.y）
    │
    ├─ sqlite3StartTable()         [build.c]
    │      └─ Table構造体の初期化
    │
    ├─ sqlite3AddColumn()          [build.c]（複数回）
    │      └─ カラム定義の追加
    │
    ├─ sqlite3AddPrimaryKey()      [build.c]
    │      └─ PRIMARY KEY制約の追加
    │
    ├─ sqlite3CreateForeignKey()   [build.c]
    │      └─ FOREIGN KEY制約の追加
    │
    └─ sqlite3EndTable()           [build.c]
           │
           ├─ 制約の検証
           │
           ├─ B-Tree作成
           │      └─ sqlite3BtreeCreateTable() [btree.c]
           │
           ├─ sqlite_schema登録
           │      └─ INSERT INTO sqlite_schema
           │
           └─ インデックス作成
                  └─ sqlite3CreateIndex()
```

### データフロー図

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

CREATE TABLE文    ───▶ パース                    ───▶ Table構造体
    │                      │
    ▼                      ▼
カラム定義        ───▶ sqlite3AddColumn()        ───▶ Column配列
    │                      │
    ▼                      ▼
制約定義          ───▶ 制約処理                   ───▶ Index/FKey
    │                      │
    ▼                      ▼
テーブル名        ───▶ sqlite3EndTable()         ───▶ sqlite_schema登録
                           │
                           ▼
                     B-Tree作成
                           │
                           ▼
                     スキーマキャッシュ更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| build.c | `src/build.c` | ソース | CREATE TABLE処理のメイン実装 |
| parse.y | `src/parse.y` | 文法定義 | CREATE TABLE文法 |
| btree.c | `src/btree.c` | ソース | B-Tree作成 |
| fkey.c | `src/fkey.c` | ソース | 外部キー制約登録 |
| prepare.c | `src/prepare.c` | ソース | スキーマ読み込み |
| sqliteInt.h | `src/sqliteInt.h` | ヘッダー | Table/Column構造体定義 |
