読譜活動 – ZetaSQL - SELECT

顔洗ってひげ剃ってコーヒー淹れて 5:10. 読んでくぞ。

  • まず FROM を解決するらしい。主要な入力である NameScope と主要な出力である ResolvedScan を覗いてみるべし。
  • NameScope は基本的には column (ResolvedColumn) を参照するものらしい。まあそうですね。ただ column の field (proto, struct) を参照できるのが特徴的といえる。Duck は field とかどうしてたっけな。
  • ResolvedColumn は globally unique な column_id を持っている。これで何を lookup できるのだろうか、というとテーブルとかなはずだが、あとで出てくることでしょう。
  • ResolvedScan は ResolvedColumn のリストである。
  • ResolveFromClauseAndCreateScan(). いやーコードはクリーンだしエラーメッセージは丁寧だしたいしたもんだわな(エラーメッセージの国際化はゼロだが)。むしろ初代 Dremel SQL がどのくらい雑だったのかに興味が出てくるが、そういうものはオープンソースではないのだった。Dremel はともかく世の中のオープンソースな SQL 実装を比べていくのはパーサーソムリエ的な楽しみがあるかもしれない。
  • FROM clause から現れる "scan" は何種類かあり、代表的なのは "array scan" と "table scan". あとはサブクエリとか table value function とか。
  • "array scan" はその名の通り array を FROM に指定できるらしい (BQ のリファレンス)。Array の扱い超難しいね・・・そしてここではまだ catalog が出てこない。Catalog どこいった。
  • ResolvePathExpressionAsTableScan() - catalog_->Find() しているね。しかしその周辺が複雑であることよ・・・。ところで ResolvedColumn::column_id は Resolver が (catalog の) Column を lookup するのに使っており、この関数の中で ID が割り振られている。つまり実際の Column の identity を保証するものではなく、FROM にテーブルが出てくるたびにその column に新しい ID が与えられる。(それは catalog のオブジェクトが担保する。)
  • コードのクリーンさを SQL という言語の魔窟さが打ち消しており、すごいね・・・。
  • まあ FROM でテーブルから ResolvedColumn や ResolvedScan が作られるところは見届けたので、次は select list の解決でも眺めていくかな。関心は column name の解決と、式。
  • ResolveSelectColumnFirstPass() - こういうのを読んでて思うこととして, select list は式を評価する仕事と評価結果に名前を付ける仕事を同時にやっており、しかし名前を付ける方は割と SQL が勝手にやっているということだよな。たとえば t.col1 とかやった場合の alias は col1 になることが多いが、こういう naming の挙動は標準化されているのだろうか。とてもそうとは思えないのだが・・・というのも式だけ書いた場合の alias とか GetAliasForExpression() が勝手につけてるんだけど、すごい恣意的じゃない?
  • 式を解決するぞ! ResolveExpr() ... は resolve_expr.cc で定義されており、これは 7000 行です。式の解決が 7000 行あるのは特に驚きはないが、これとは別に resolve_query.cc が 8000 行なところに SQL のヤバさがあると言えよう。
  • といったところで時間切れ。ラップトップをでかい画面につなぎたくなってきた。あとメモリ・・・。