Skip to content

Latest commit

 

History

History
201 lines (149 loc) · 7.92 KB

File metadata and controls

201 lines (149 loc) · 7.92 KB

Query AST Boundary Plan

目的

sql crate で得られる AST を、query crate が受け取って planner / executor 側へ安全に渡せる最小の境界を作る。

この段階では最適化や高度な名前解決を急がず、 まずは SQL -> AST -> query boundary -> Plan の流れを 責務分離を崩さずに通すことを目的にする。

現在地

2026-03-22 時点で、sql crate には最小 CRUD の AST と parser がある。 一方で query crate の Planner はまだ SQL 文字列を受ける仮置き形であり、 sql crate の AST を正式な入力として扱う境界は未整備である。

この状態では、parser で理解した構文情報が query 側で十分に再利用されず、 責務の分離も曖昧になりやすい。

この計画で作るもの

  • query crate が sql::Statement を受け取る入口
  • parser と planner の責務を分ける変換段階
  • 最小 CRUD を planner が扱うための共通の中間表現
  • 後続のトランザクション文を同じ入口に載せられる拡張余地
  • 将来 binder / optimizer / catalog 参照を挟める拡張余地

ここで守る境界

sql crate の責務

  • SQL 文字列を AST に変換する
  • 構文として正しいかどうかを判定する
  • 名前解決、型解決、テーブル存在確認はしない

query crate の責務

  • AST を受け取り、実行しやすい形へ変換する
  • 必要に応じて catalog を参照し、名前解決や簡単な検証を行う
  • 実行計画と実行手順を表現する

この段階でやらないこと

  • 本格的な optimizer
  • 複雑な結合順序最適化
  • rollback journal / WAL / 分離レベルを含む本格的なトランザクション実装
  • 方言差を吸収する高度な binder

ただし、後続の 03-transaction-control.mdBEGIN / COMMIT / ROLLBACK を同じ境界に載せられるよう、 文種の増加には耐えられる形を保つ。

なぜ AST 境界を先に作るか

  • parser の学習成果をそのまま planner へ渡せる
  • query crate が SQL 文字列を再解釈せずに済む
  • 将来 parser を差し替えても、AST 境界を維持すれば query 側への影響を抑えやすい
  • CRUD 全体を planner / executor へ接続すると、storage や catalog へ進む足場ができる

想定するデータフロー

flowchart LR
    A[SQL String] --> B[sql::Parser]
    B --> C[sql::Statement AST]
    C --> D[query Boundary]
    D --> E[Bound Statement / Logical Input]
    E --> F[query::Planner]
    F --> G[Plan]
    G --> H[query::Executor]
    H --> I[Storage / Catalog]
Loading

想定する層構造

flowchart TB
    subgraph SQL["sql crate"]
        P[Parser]
        AST[Statement AST]
    end

    subgraph QUERY["query crate"]
        QB[AST Boundary]
        BD[Binding / Validation]
        PL[Planner]
        EX[Executor]
    end

    subgraph META["support crates"]
        CAT[Catalog]
        ST[Storage]
        TY[Types]
    end

    P --> AST
    AST --> QB
    QB --> BD
    BD --> PL
    PL --> EX
    BD --> CAT
    EX --> ST
    BD --> TY
    PL --> TY
Loading

設計の考え方

1. 入口は SQL 文字列ではなく AST にする

query::Planner の主入力は SQL 文字列ではなく sql::Statement に寄せる。 これにより、構文解析と計画生成の責務が明確になる。

2. planner の前に境界層を置く

最初から planner にすべての責務を載せるのではなく、 AST を受け取る専用の境界層を置く。

この層は、次のような役割を持つ。

  • 文種ごとの入口を整理する
  • planner で扱いたい最小情報へ整形する
  • 将来 binder を独立させる余地を残す

3. 最小 CRUD を横断して同じ流れで扱う

SELECT だけを特別扱いせず、 INSERT / UPDATE / DELETE / CREATE TABLE も同じ入口から受ける。 この段階で文種ごとの分岐点を揃えておくと、 後で executor を足すときの見通しがよくなる。

後続で BEGIN / COMMIT / ROLLBACK を追加するときも、 この入口に transaction 文を足すだけで済む形を目指す。

4. 中間表現は「実行しやすさ」を優先する

AST は parser 目線の表現であり、 planner では必ずしもそのまま扱いやすいとは限らない。

そのため query 側では、文種、対象テーブル、投影列、条件式、更新代入、 列定義のような「実行計画へ落としやすい最小情報」に一度揃える。

5. ただし抽象化を増やしすぎない

学習段階では、中間表現や層を増やしすぎると理解コストが上がる。 最初は最小 CRUD が通るだけの薄い境界にし、 catalog や binder の複雑化は必要になってから段階的に足す。

最小スコープ

この計画で最初に通したい対象は次の通り。

  • SELECT の最小 projection / filter / scan
  • INSERT の単一行 VALUES
  • UPDATE の単一テーブル更新
  • DELETE の単一テーブル削除
  • CREATE TABLE の最小列定義

TODO リスト

  • query crate の入口を「SQL 文字列を受ける仮置き」から「AST を受ける正式入口」へ切り替える
  • AST を受け取る境界モジュールの責務を定義する
  • 文種ごとの受け口を SELECT / INSERT / UPDATE / DELETE / CREATE TABLE で揃える
  • 将来 BEGIN / COMMIT / ROLLBACK を追加しても入口が破綻しない文種ディスパッチにする
  • query 側で使う最小の中間表現を定義する
  • SELECT の AST から scan / filter / project へ落とす最小経路を作る
  • INSERT の AST から挿入対象テーブル・列・値を受け渡す最小経路を作る
  • UPDATE の AST から対象テーブル・代入一覧・条件式を受け渡す最小経路を作る
  • DELETE の AST から対象テーブル・条件式を受け渡す最小経路を作る
  • CREATE TABLE の AST から列定義一覧を受け渡す最小経路を作る
  • parser 側の責務に属するものと、query 側の責務に属するものを文書で固定する
  • catalog をまだ使わない範囲と、使い始める境界を明文化する
  • query crate のテストで「AST を入力にして期待する中間表現や Plan が得られる」ことを固定する
  • SQL 文字列ベースの古い planner 入口を縮小または撤去する
  • planner / executor / optimizer の役割を、現時点のスコープに合わせて再整理する

テスト方針

  • parser テストとは分けて、query crate 側で AST 入力のテストを作る
  • 文種ごとの正常系を最小 1 ケースずつ固定する
  • SELECT は projection / filter / scan の最小組み合わせを固定する
  • INSERT / UPDATE / DELETE / CREATE TABLE は対象テーブルと主要フィールドが正しく境界を越えるかを固定する
  • planner に入る前段で弾くべき不整合があれば、境界層のテストとして分離する

完了条件

次の状態になれば、この計画の第一段階は完了とみなす。

  • query crate が sql::Statement を正式入力として受け取れる
  • 最小 CRUD の各文種が、AST から query 側の中間表現または Plan へ変換できる
  • parser と planner の責務分離がコードと文書の両方で明確になっている
  • SQL 文字列を query 側で再解釈しなくても、最小経路が通る

後続方針

  • 必要になった時点で binder を独立した層として切り出す
  • catalog を参照した名前解決や型検証を段階的に追加する
  • トランザクション文の扱いは 03-transaction-control.md と接続する
  • SELECT の拡張計画と接続し、JOIN や派生表が増えても境界が破綻しない形へ育てる