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 側で十分に再利用されず、
責務の分離も曖昧になりやすい。
querycrate がsql::Statementを受け取る入口- parser と planner の責務を分ける変換段階
- 最小 CRUD を planner が扱うための共通の中間表現
- 後続のトランザクション文を同じ入口に載せられる拡張余地
- 将来 binder / optimizer / catalog 参照を挟める拡張余地
- SQL 文字列を AST に変換する
- 構文として正しいかどうかを判定する
- 名前解決、型解決、テーブル存在確認はしない
- AST を受け取り、実行しやすい形へ変換する
- 必要に応じて catalog を参照し、名前解決や簡単な検証を行う
- 実行計画と実行手順を表現する
- 本格的な optimizer
- 複雑な結合順序最適化
- rollback journal / WAL / 分離レベルを含む本格的なトランザクション実装
- 方言差を吸収する高度な binder
ただし、後続の
03-transaction-control.md
で BEGIN / COMMIT / ROLLBACK を同じ境界に載せられるよう、
文種の増加には耐えられる形を保つ。
- parser の学習成果をそのまま planner へ渡せる
querycrate が 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]
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
query::Planner の主入力は SQL 文字列ではなく sql::Statement に寄せる。
これにより、構文解析と計画生成の責務が明確になる。
最初から planner にすべての責務を載せるのではなく、 AST を受け取る専用の境界層を置く。
この層は、次のような役割を持つ。
- 文種ごとの入口を整理する
- planner で扱いたい最小情報へ整形する
- 将来 binder を独立させる余地を残す
SELECT だけを特別扱いせず、
INSERT / UPDATE / DELETE / CREATE TABLE も同じ入口から受ける。
この段階で文種ごとの分岐点を揃えておくと、
後で executor を足すときの見通しがよくなる。
後続で BEGIN / COMMIT / ROLLBACK を追加するときも、
この入口に transaction 文を足すだけで済む形を目指す。
AST は parser 目線の表現であり、 planner では必ずしもそのまま扱いやすいとは限らない。
そのため query 側では、文種、対象テーブル、投影列、条件式、更新代入、
列定義のような「実行計画へ落としやすい最小情報」に一度揃える。
学習段階では、中間表現や層を増やしすぎると理解コストが上がる。 最初は最小 CRUD が通るだけの薄い境界にし、 catalog や binder の複雑化は必要になってから段階的に足す。
この計画で最初に通したい対象は次の通り。
SELECTの最小 projection / filter / scanINSERTの単一行VALUESUPDATEの単一テーブル更新DELETEの単一テーブル削除CREATE TABLEの最小列定義
-
querycrate の入口を「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 をまだ使わない範囲と、使い始める境界を明文化する
-
querycrate のテストで「AST を入力にして期待する中間表現や Plan が得られる」ことを固定する - SQL 文字列ベースの古い planner 入口を縮小または撤去する
- planner / executor / optimizer の役割を、現時点のスコープに合わせて再整理する
- parser テストとは分けて、
querycrate 側で AST 入力のテストを作る - 文種ごとの正常系を最小 1 ケースずつ固定する
SELECTは projection / filter / scan の最小組み合わせを固定するINSERT / UPDATE / DELETE / CREATE TABLEは対象テーブルと主要フィールドが正しく境界を越えるかを固定する- planner に入る前段で弾くべき不整合があれば、境界層のテストとして分離する
次の状態になれば、この計画の第一段階は完了とみなす。
querycrate がsql::Statementを正式入力として受け取れる- 最小 CRUD の各文種が、AST から
query側の中間表現または Plan へ変換できる - parser と planner の責務分離がコードと文書の両方で明確になっている
- SQL 文字列を
query側で再解釈しなくても、最小経路が通る
- 必要になった時点で binder を独立した層として切り出す
- catalog を参照した名前解決や型検証を段階的に追加する
- トランザクション文の扱いは
03-transaction-control.mdと接続する SELECTの拡張計画と接続し、JOIN や派生表が増えても境界が破綻しない形へ育てる