読譜活動 – ZetaSQL - Resolver
昨晩遅かったので朝は走るだけ、と思ったら雨。コード読むかな。
- execute_query 全体的に大げさなコードでいまいちである。
- execute_query_tool.cc : ExecuteQuery() - が本題だと思われる。
- まず ParseExpession で ASTNode を作ります
- ... と思ったが AnalyzeStatement() で ResolvedNode を作ります、だな。なおこれを呼ぶには Catalog と type factory が必要。AnalyzeStatement() は free function で、謎のコンテクストとかは必要ない。クリーンでえらいね。AnalyzerOptions には arena (!) やら string id pool (interned string?) やら、それなりに context 的なオブジェクトも突っ込まれているらしいが。
- で内部では結局 ParseExpression なり ParseStatement なりを呼んで、その AST を analyze するらしい。Parser はあとで詳しく見るとして、この AST の段階では catalog とかいらない。つまり型の解決とかは analyze の仕事らしい。ZetaSQL, SQL を statically typed ぽく扱っている節があるのでそれをどうやってるのがが気になるところ。
- で、Analaysis は Resolver クラスがエントリポイントです。resolver.h は 4000 行くらいあって一瞬ギョっとするが、Android で鍛えた我々は 1 万行以下のファイルではビビらないのである。というかこのての parser とか analyzer とか、だいたいデカくなりがち。型単位で再帰的に解決したりするので。これを visitor とかで小さいクラスに分ければ読みやすくなるというものでもない。なお .cc ファイルは resolver_*.cc に分割されている。これ duck も似たような構成だったな。
- 複雑さという意味で Resolver の private fields (状態) を眺めると、全然ない。つまりクラスにはなっているが概ね side-effect-free ぽく書かれていることが期待できる。
- ResolveStatement の signature はこんなかんじ。(この改行をなんとか殺さねばならぬ・・・)
// Resolve a parsed ASTStatement to a ResolvedStatement.
// This fails if the statement is not of a type accepted by
// LanguageOptions.SupportsStatementKind().
// <sql> contains the text at which the ASTStatement points.
absl::Status ResolveStatement(
absl::string_view sql, const ASTStatement* statement,
std::unique_ptr<const ResolvedStatement>* output);
- つまり ASTStatement を ResolvedStatement に map している。他もまあ似たような構成になっていることが予想される。常識的な作りでよい。なお Duck もこんなんだったな。彼らの "resolve" は割と雑だったが、Zeta はどうでしょうか。
- ところで Zeta には LanguageOptions というのがあって、これで言語機能をかなり細かく制御できる。statement の種類を絞ったりとか。これが世界(社内)を統べる SQL の力だが、同時に実装は複雑になるね。
といったところで時間ぎれ。execute_query がいまいちだったので心配していたが、ライブラリ本体はなかなかクリーンぽくて安心。
次回以降への疑問:
- Query の解決。
- Parser の実装はどうなってるのか。
- Catalog はどうやって作るのか。Catalog への副作用は発行できるのか。つまりDDL はどうハンドルされるのか。