2015-11-30

S式SQL その2

ちょっと書き始めたらいきなり壁にぶち当たったのでSQL恐ろしい子という感じである。

SQLにはqualified identifierというものがある。何かといえば「.」で繋げられたあれである。例えば以下のSQLをS式にするとする:
select f.bar from foo f;
特に何も考えなければ以下のようになるだろう。
(select (f.bar) (from (as foo f)))
asをつけるかどうかは決めてない(SQL的には要らない子でもS式的にはあった方がいいような)。大抵の場合はこれで問題ないんだけど、SQLにはdelimited identifierというものがある。例えばこんなにも合法なSQL:
select f."bar" from foo f;
SchemeにはR7RSから「||」が入ったんだからdelimited identifierもそれでいいじゃん?と思わなくもない。S式からSQL文字列にした際にどうするとか考えなければだけど。

ここまではまだ序の口で、少なくともSQL2003からはユニコードが使えて、以下のようなのも合法:
select f.U&"\0062ar" from foo f;
大分怪しくなってきた。さらにエスケープ文字の変更も可能なので、以下のも合法:
select f.U&"$0062ar" uescape '$' from foo f;
誰が書くんだこんなのというレベルだが、テーブルやカラム名にASCII以外を使っているとありえるのかもしれない。さらに、U&"$0062ar" uescape '$'はunicode delimited identifierというトークンなので、単なる識別子として処理される。つまり、末尾である必要がなく、以下も合法:
select U&"$0066" uescape '$'.U&"$0062ar" uescape '$' from foo f;
涙出そう。ここまで行くと全てを捨ててシンボルでというわけにはいかないので、SQLの読み込みで作られるqualified identifierはリストにすることにした。こんな感じ:
(select ((@ (unicode (! "$0066") uescape "$") (unicode (! "$0062ar") uescape "$"))) 
 (from (as foo f)))
果てしなく冗長な気がする。連結を表すのに「@」を使うか悩み中。「.」が使えるといいんだけど、「|」でエスケープしたくない。ただ、「@」は別のところで使いたい場面が出てきそうな上に、今一連結(もしくは参照)というイメージが湧かない。「->」はSQLのキーワードの一つなのでできれば使いたくない。「=>」だと紛らわしいかなぁ?

パーサー自体はゴリゴリとBNFを書いていくだけなので作業量は多いけどそこまで大変ではない(大変だけど)。必要な部分だけ書いて後は必要に応じてということができそう。やはり問題になるのはこういう細かい表記の部分だろう。一度使い始めると変更できない(したくない)部分になるので可能な限り違和感のないものにしたいところである。

追記:qualified indentifierをスロットアクセスと考えれば「~」を使うのはありかもしれないなぁ。後は連結に何を割り当てるか考えないとなぁ。

4 comments:

Shiro Kawai said...

Unicodeのそのへんはlexerのレイヤの話ではなかったでしたっけ。foo."bar" と foo.bar と foo.U&"\0062ar" と foo.U&"$0062ar" uescape '$' って区別されませんよね?

kei said...

そうなんですけど、SQL->S式->SQLと変換した際に元のSQLに近い形にしたいと思うと残さざるを得ないんですよね(他にいい手が思い付かない)。どちらかと言えば僕個人のニーズではありますけど。後、UESCAPEを字句解析でやるとかなり先読みする必要+UESCAPEを特別視しないといけないから気持ち悪いというのもあります。

Shiro Kawai said...

そういう需要か…とするとコメントとかも残したくなって通常のパージングの手前に1レイヤ作る感じになりますね。pre-lexer (元の表現情報をできるだけ保存) -> lexer (意味に影響を与えない範囲で正規化) -> parser (構文解析)。SQLの意味レベルでの操作をするparser出力のフォーマットと、表現レベルでいじりたいpre-lexer出力のフォーマットは別仕様として考えた方が扱いやすいと思います。

kei said...

Lexerは既にオプションでコメントを残すようにはしてますね。上に乗せてるパーサは今のところコメントをlexerからは受け取らないので意味を成してはいないのですが。(正規化しないのでpre-lexerですね。tokenizerに近いかな)

変換後のS式を弄って可能な限り元の情報を残した形でSQLに戻すというのが最終系の予定ではいます。

Post a Comment