# 機能設計書 40-データベースリカバリ

## 概要

本ドキュメントは、SQLiteにおけるデータベースリカバリ（Database Recovery）機能の設計仕様を定義する。破損したデータベースからできる限り多くのデータを救出する拡張機能である。

### 本機能の処理概要

データベースリカバリは、破損したSQLiteデータベースファイルを低レベルで解析し、可能な限りのスキーマとデータを新しい正常なデータベースに復元する機能である。

**業務上の目的・背景**：ディスク障害、突然の電源断、ソフトウェアバグ等により、SQLiteデータベースが破損する場合がある。通常のSQLite APIでは破損したデータベースを開けないことがあるが、リカバリ機能により、破損していない部分からデータを救出できる可能性がある。

**機能の利用シーン**：
- ディスク障害後のデータ復旧
- 不完全なバックアップからのデータ救出
- アプリケーションバグによる破損からの復旧
- フォレンジック調査（削除されたデータの復元）

**主要な処理内容**：
1. sqlite3_recover_init()でリカバリハンドルを作成
2. sqlite3_recover_config()でオプション設定
3. sqlite3_recover_step()を繰り返し呼び出してリカバリを進行
4. sqlite_schemaからテーブル定義を復元
5. 各ページを走査してレコードを抽出
6. lost_and_foundテーブルに孤立データを保存
7. sqlite3_recover_finish()で完了

**関連システム・外部連携**：
- sqlite_dbdata仮想テーブル：低レベルページ解析
- sqlite_dbptr仮想テーブル：ポインタマップ解析
- 出力データベース：復元結果の格納先

**権限による制御**：
- 入力データベースへの読み取りアクセスが必要
- 出力データベース（またはSQLコールバック）への書き込みアクセスが必要

## 関連画面

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

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

データ復旧 / 低レベル解析 / フォレンジック

## 入力仕様

### 入力パラメータ（リカバリ初期化）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| db | sqlite3* | Yes | 入力データベース接続 | NULLでないこと |
| zDb | const char* | Yes | データベース名（"main"等） | 有効なDB名 |
| zUri | const char* | Yes | 出力データベースURI | NULLでないこと |

### 設定オプション

| オプション | 型 | 説明 | デフォルト |
|-----------|-----|------|-----------|
| SQLITE_RECOVER_LOST_AND_FOUND | const char* | 孤立データ格納テーブル名 | NULL（無効） |
| SQLITE_RECOVER_FREELIST_CORRUPT | int | フリーリスト破損フラグ | 0 |
| SQLITE_RECOVER_ROWIDS | int | rowid復元フラグ | 1 |
| SQLITE_RECOVER_SLOWINDEXES | int | インデックス遅延作成フラグ | 0 |

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| SQLITE_OK | int | ステップ成功 |
| SQLITE_DONE | int | リカバリ完了 |
| SQLITE_ERROR | int | エラー発生 |
| 出力データベース | sqlite3* | 復元されたデータベース |

### 出力構造

```sql
-- 復元されたテーブル
CREATE TABLE original_table(...);  -- スキーマから復元

-- 孤立データ（lost_and_found設定時）
CREATE TABLE lost_and_found(
  rootpgno INTEGER,    -- 元のルートページ
  pgno INTEGER,        -- 発見されたページ
  nfield INTEGER,      -- フィールド数
  id INTEGER,          -- rowid（可能な場合）
  c0, c1, c2, ...      -- 各フィールドの値
);
```

## 処理フロー

### 処理シーケンス

```
1. 初期化フェーズ
   ├─ sqlite3_recover_init()でハンドル作成
   ├─ sqlite3_dbdata/sqlite3_dbptr仮想テーブルを登録
   └─ オプション設定

2. スキーマリカバリフェーズ（RECOVER_STATE_WRITING）
   ├─ sqlite_schemaテーブルからCREATE文を抽出
   ├─ 各テーブル定義を出力DBで実行
   └─ RecoverTable構造体リストを構築

3. データリカバリフェーズ（RECOVER_STATE_WRITING続き）
   ├─ 各RecoverTableに対してページを走査
   ├─ sqlite_dbdataでレコードを抽出
   └─ 出力DBにINSERT

4. Lost-and-Foundフェーズ（RECOVER_STATE_LOSTANDFOUND1〜3）
   ├─ 使用済みページのビットマップを構築
   ├─ ルートページの特定
   └─ 孤立データをlost_and_foundテーブルに保存

5. 完了フェーズ
   └─ sqlite3_recover_finish()でリソース解放
```

### フローチャート

```mermaid
flowchart TD
    A[sqlite3_recover_init] --> B[sqlite3_recover_config]
    B --> C[sqlite3_recover_step]
    C --> D{状態}
    D -->|INIT| E[初期化]
    E --> F[sqlite_dbdata/dbptr登録]
    F --> C
    D -->|WRITING| G[スキーマ復元]
    G --> H[データ復元]
    H --> C
    D -->|LOSTANDFOUND1| I[使用ページビットマップ構築]
    I --> C
    D -->|LOSTANDFOUND2| J[ルートページ特定]
    J --> C
    D -->|LOSTANDFOUND3| K[孤立データ保存]
    K --> C
    D -->|DONE| L[sqlite3_recover_finish]
    C -->|SQLITE_DONE| L
    C -->|SQLITE_ERROR| M[エラー処理]
    M --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-40-1 | ベストエフォート | 可能な限りのデータを復元するが、完全な復元は保証しない | 常時 |
| BR-40-2 | rowid復元 | INTEGER PRIMARY KEYのrowidはデフォルトで復元 | ROWIDS=1時 |
| BR-40-3 | インデックス後作成 | SLOWINDEXESで全データ復元後にインデックス作成 | SLOWINDEXES=1時 |
| BR-40-4 | 孤立データ保存 | LOST_AND_FOUND設定時、関連テーブル不明のデータを保存 | 設定時 |

### 計算ロジック

**ページ使用状況判定**：
- sqlite_dbptrでポインタ関係を解析
- フリーリストページを除外（FREELIST_CORRUPT=0時）
- 使用中でないページを孤立ページとして扱う

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| READ | 入力DB（破損） | SELECT via sqlite_dbdata | 低レベルページ解析 |
| WRITE | 出力DB | CREATE TABLE | スキーマ復元 |
| WRITE | 出力DB | INSERT | データ復元 |
| WRITE | lost_and_found | INSERT | 孤立データ保存 |

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

#### sqlite_dbdata（仮想テーブル）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | pgno | ページ番号 | 入力DB |
| SELECT | cell | セル番号 | ページ内 |
| SELECT | field | フィールド番号 | レコード内 |
| SELECT | value | フィールド値 | 任意の型 |

#### lost_and_found

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | rootpgno | 推定ルートページ | 不明時は0 |
| INSERT | pgno | 発見ページ番号 | - |
| INSERT | nfield | フィールド数 | - |
| INSERT | id | rowid | 復元可能時 |
| INSERT | c0, c1, ... | 各フィールド値 | 動的カラム数 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SQLITE_ERROR | 設定エラー | INIT状態以外でconfig呼び出し | 初期化直後に設定 |
| SQLITE_NOMEM | メモリ不足 | 大量データ処理時 | メモリ増設 |
| SQLITE_CORRUPT | 破損検出 | 入力DBの深刻な破損 | 継続して可能な限り復元 |
| SQLITE_IOERR | I/Oエラー | ディスク読み取りエラー | ディスク状態確認 |

### リトライ仕様

リカバリ処理は基本的にリトライ不可。エラー発生時はsqlite3_recover_errcode()とsqlite3_recover_errmsg()でエラー情報を取得し、sqlite3_recover_finish()でクリーンアップ。

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

- リカバリ処理は入力DBをread-onlyで開く
- 出力DBへの書き込みは内部的にトランザクション管理
- sqlite3_recover_step()の各呼び出しは部分的な進捗

## パフォーマンス要件

- 各sqlite3_recover_step()は増分処理（一度に全処理しない）
- 大きなDBでは多数のstep()呼び出しが必要
- sqlite_dbdata仮想テーブルによる低レベルアクセスで効率化

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

- 破損DBには悪意のあるデータが含まれる可能性がある
- 出力DBのサニタイズを検討
- リカバリ結果の検証を推奨

## 備考

- SQLite 3.40.0以降で利用可能
- .recoverコマンド（SQLiteシェル）でも使用可能
- sqlite_dbdata/sqlite_dbptrは独立した仮想テーブルとして登録可能
- WITHOUT ROWIDテーブルもサポート

---

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

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

### 推奨読解順序

#### Step 1: 主要構造体を理解する

リカバリ機能の中核となるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sqlite3recover.c | `ext/recover/sqlite3recover.c` | 46-93行目のRecoverTable/RecoverColumn構造体 |
| 1-2 | sqlite3recover.c | `ext/recover/sqlite3recover.c` | 205-243行目のsqlite3_recover構造体 |
| 1-3 | sqlite3recover.c | `ext/recover/sqlite3recover.c` | 267-274行目のRECOVER_STATE定数 |

**読解のコツ**: RecoverTableはスキーマから復元されたテーブル定義を保持。sqlite3_recoverは全体の状態を管理。RECOVER_STATE_*で処理フェーズを追跡。

#### Step 2: 仮想テーブルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dbdata.c | `ext/recover/dbdata.c` | sqlite_dbdata/sqlite_dbptr仮想テーブル |

**主要処理フロー**:
- sqlite_dbdata: 各ページ内のセル・フィールドを返す
- sqlite_dbptr: ページ間のポインタ関係を返す

#### Step 3: 状態遷移を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sqlite3recover.c | `ext/recover/sqlite3recover.c` | 246-274行目の状態定義コメント |

**主要処理フロー**:
- RECOVER_STATE_INIT: 初期化
- RECOVER_STATE_WRITING: スキーマ/データ復元
- RECOVER_STATE_LOSTANDFOUND1〜3: 孤立データ処理
- RECOVER_STATE_SCHEMA2: 追加スキーマ処理
- RECOVER_STATE_DONE: 完了

#### Step 4: Lost-and-Found処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | sqlite3recover.c | `ext/recover/sqlite3recover.c` | RecoverStateLAF構造体（186-200行目） |

**主要処理フロー**:
- pUsed: 使用済みページビットマップ
- pMapInsert: ルートページマッピング
- pInsert: lost_and_foundへの挿入

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

```
sqlite3_recover_init()
    │
    ├─ sqlite3_recover構造体を作成
    ├─ 入力DB接続を保存
    └─ 出力URI/コールバックを保存

sqlite3_recover_config()
    │
    └─ オプション設定（LOST_AND_FOUND等）

sqlite3_recover_step()
    │
    ├─ [INIT]
    │      └─ sqlite3_dbdata_init()  仮想テーブル登録
    │
    ├─ [WRITING]
    │      ├─ recoverWriteSchema()  スキーマ復元
    │      └─ recoverWriteData()    データ復元
    │
    ├─ [LOSTANDFOUND1]
    │      └─ recoverLostAndFound1()  ビットマップ構築
    │
    ├─ [LOSTANDFOUND2]
    │      └─ recoverLostAndFound2()  ルート特定
    │
    └─ [LOSTANDFOUND3]
           └─ recoverLostAndFound3()  孤立データ保存

sqlite3_recover_finish()
    │
    └─ リソース解放
```

### データフロー図

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

破損DB ────────────────────▶ sqlite_dbdata ─────────────────▶ ページ/セル/値
                           低レベル解析

sqlite_schema ─────────────▶ recoverWriteSchema() ──────────▶ CREATE TABLE
スキーマ                     スキーマ復元                     出力DB

sqlite_dbdata ─────────────▶ recoverWriteData() ────────────▶ INSERT INTO
ページデータ                 データ復元                       出力DB

未使用ページ ──────────────▶ recoverLostAndFound*() ────────▶ lost_and_found
                           孤立データ処理                    テーブル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sqlite3recover.c | `ext/recover/sqlite3recover.c` | ソース | リカバリメイン実装 |
| sqlite3recover.h | `ext/recover/sqlite3recover.h` | ヘッダー | 公開API定義 |
| dbdata.c | `ext/recover/dbdata.c` | ソース | sqlite_dbdata/dbptr仮想テーブル |
| test_recover.c | `ext/recover/test_recover.c` | ソース | テスト用実装 |
