sql5 4.0.2

SQLite compatible database with CJK FTS5 full-text search and vector similarity
# sql5 v1.16 版本說明(已被 v1.17 取代)

## 版本資訊
- **版本**:1.16
- **日期**:2026-05-04
- **名稱**:TRIGGERs 支援(部分)

## SQLite Trigger 語法

```sql
-- 建立 trigger
CREATE TRIGGER [IF NOT EXISTS] trigger_name
    [BEFORE|AFTER|INSTEAD OF] [DELETE|INSERT|UPDATE [OF column_name, ...]]
    ON table_name
    [FOR EACH ROW]
    [WHEN condition]
BEGIN
    trigger_body;  -- 單一 SQL 語句(不支援多語句 Transaction)
END;

-- 刪除 trigger
DROP TRIGGER [IF EXISTS] trigger_name;
```

### 時機(Timing)
- `BEFORE` — 操作發生前觸發
- `AFTER` — 操作完成後觸發
- `INSTEAD OF` — 取代原本操作(通常用於視圖)

### 事件(Event)
- `INSERT`
- `DELETE`
- `UPDATE [OF col1, col2]` — 可限定特定欄位

### FOR EACH ROW
- 所有 trigger 都是 ROW-level(SQLite 不支援 STATEMENT-level)

### WHEN 子句
- 每行滿足條件才執行 trigger body

## 實作規劃

### 1. AST / Parser

- `Statement::CreateTrigger(CreateTriggerStmt)`
- `Statement::DropTrigger(DropTriggerStmt)`
- 解析 `CREATE TRIGGER` 語法到 AST(參考 `CreateViewStmt` 結構)

```rust
// 新增 AST 節點
#[derive(Debug, Clone)]
pub struct CreateTriggerStmt {
    pub name: String,
    pub table: String,
    pub timing: TriggerTiming,   // Before, After, InsteadOf
    pub event: TriggerEvent,      // Delete, Insert, Update(Option<Vec<String>>)
    pub for_each_row: bool,
    pub when: Option<Expr>,
    pub body: String,  // trigger body(內部 SQL 語句字串)
}

#[derive(Debug, Clone, PartialEq)]
pub enum TriggerTiming { Before, After, InsteadOf }

#[derive(Debug, Clone, PartialEq)]
pub enum TriggerEvent { Delete, Insert, Update(Vec<String>) }

#[derive(Debug, Clone)]
pub struct DropTriggerStmt {
    pub name: String,
}
```

### 2. Catalog

- `TableMeta` 或單獨 `TriggerMeta` 中儲存 trigger 定義
- Catalog 提供 `create_trigger()`, `drop_trigger()`, `get_triggers(table)` 等 API
- Trigger 需要持久化(重啟後仍有效)

### 3. Planner

- `plan_create_trigger()`: 驗證 table 存在,寫入 catalog
- `plan_drop_trigger()`: 從 catalog 刪除
- **觸發時機**  - INSERT/UPDATE/DELETE 執行時,根據該表的 triggers 列表
  - BEFORE trigger 在 mutation 前執行,AFTER 在之後
  - INSTEAD OF trigger 用於視圖(需要單獨處理)

### 4. Executor

修改 `exec_insert` / `exec_update` / `exec_delete`:
```rust
// 概念:每行資料變化前/後遍歷並執行該表的 triggers
fn fire_triggers(&mut self, table: &str, event: TriggerEvent, row: &Row, old_row: Option<&Row>) {
    let triggers = self.catalog.get_triggers(table, &event);
    for trigger in triggers {
        if let Some(when) = &trigger.when {
            if !eval_expr(when, row, &self.col_names).map(is_truthy).unwrap_or(false) {
                continue;
            }
        }
        // parse and execute trigger.body
    }
}
```

### 5. 限制(Phase 1)
- Trigger body 只支援單一 SQL 語句(不含 BEGIN...END 封裝)
- 暫不支援 `INSTEAD OF` 視圖 trigger
- 暫不支援巢狀 trigger(trigger 內再 trigger)
- Trigger 變數 `NEW.col` / `OLD.col` 需要特殊處理

## 架構變化

```
src/
  parser/
    ast.rs     — +CreateTriggerStmt, DropTriggerStmt
    parser.rs  — +parse_create_trigger(), parse_drop_trigger()
  catalog/
    catalog.rs — +trigger CRUD,持久化
  planner/
    planner.rs — +plan_create_trigger, plan_drop_trigger
    executor.rs — exec_insert/update/delete + fire_triggers()
```

## 測試計畫
- [ ] `CREATE TRIGGER` 基本解析
- [ ] `DROP TRIGGER`
- [ ] BEFORE INSERT trigger 驗證
- [ ] AFTER INSERT/UPDATE/DELETE trigger 驗證
- [ ] WHEN 子句
- [ ] 單一欄位 UPDATE trigger(`UPDATE OF col`- [ ] Trigger 持久化(重啟後仍在)

## 對應 SQLite 相容性

| SQLite 功能 | sql5 v1.16 狀態 |
|------------|---------------|
| TRIGGERs | 🔧 實作中 (v1.16) |
| ATTACH | ❌ 待支援 |
| VACUUM | ❌ 待支援 |