タイトルの通りです。
前提
MySQLのリファレンスマニュアルの構文のページにはEBNFが書いてあります。
例としてCREATE TABLE
文のページを用意しました。ページの上のほうにEBNFによって定義された文法が書かれています。
dev.mysql.com
EBNFに定義されていない書きかた
前のセクションでCREATE TABLE
文のリファレンスマニュアルを参照しました。このセクションではこのCREATE TABLE
文の文法の話をします。ですのでこれ以降はリファレンスマニュアルのEBNFを用意いただき一緒に読んでもらうと楽しめると思います。
次のSQLはMySQL8.0.33で正常にパースできます。
CREATE TABLE user ( id BIGINT ) DEFAULT CHARSET = utf8mb4;
なので文法としては正しいということが分かります。しかしEBNFだけを見るとDEFAULT CHARSET = utf8mb4
は当てはまる文が存在しません。
デフォルト文字セットを定義できるのは[DEFAULT] CHARACTER SET [=] charset_name
の形式に合う文のみです。SQLとEBNFを見比べるとCHARSETの部分が異なることが分かります。
ということで例にあげたSQLは何故かパースできるけどリファレンスマニュアルにあるEBNF上では正しくない文ということになります。
Yaccでの定義を見てみる
前セクションでEBNFで定義されていないけどなぜかパースできるSQLを紹介しました。
では実際にMySQLはどのような定義のもとで構文解析しているのか深堀りしてみましょう。
今回注目するのはリファレンスマニュアルのEBNFには存在しない定義であるDEFAULT CHARSET = utf8mb4
の部分にします。
MySQLはパーサジェネレータとしてBisonを用いています。なのでyaccファイルを見ると構文の定義が分かりそうです。読んでみましょう。
CREATE TABLE
文はこの場所から定義が始まっています。
https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L3395
今回注目しているのはリファレンスマニュアルにtable_options
として定義されている場所なのでそれらしい文字を更に追いかけます。
そんな調子で深堀りをしていくと今回注目しているDEFAULT CHARSET
を指定する箇所は以下の場所であることが分かります。
default_charset: opt_default character_set opt_equal charset_name { $$ = $4; } ;
コードは以下URLから引用。
https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L6903
どうやらcharacter_set
に何故かパースできる部分の答えがありそうです。
character_set: CHAR_SYM SET_SYM | CHARSET ;
コードは以下URLから引用。
https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L7600C1-L7603C10
このコードを見るとcharacter_set
はCHARACTER SET
かCHARSET
と書くことができると定義されています。
ということで CHARSET
はCHARACTER SET
と同じように定義されているので正常にパースされたということです。別名になっているとも言えるでしょう。
リファレンスマニュアルのEBNFには定義されていないけど。
実は定義されている
ということで前セクションでEBNFとして定義されていないけど何故かパースできる箇所についてパーサの定義を調べることで結論を探しました。
結論としてはEBNFとしては定義されていないCHARSET
はCHARACTER SET
と同じように振る舞うということが分かりました。
ここでもう一度リファレンスマニュアルを読むと以下のような記載が見つかります。
CHARSET is a synonym for CHARACTER SET.
https://dev.mysql.com/doc/refman/8.0/en/create-table.html#create-table-options
はい。今回yaccの定義を追い掛けて見つけることができた結論が書いてあります。
ここでタイトル回収です。MySQLのリファレンスマニュアルにあるEBNFは全てを表現していません。
なのでリファレンスマニュアルをしっかり最後まで読み込みましょう。EBNFに定義されていない文法もあります。
まとめ
MySQLのリファレンスマニュアルのEBNFは許容する全ての文法を表現していない可能性があります。
なので参照するときはリファレンスマニュアルの下のほうを最後まで読みましょう。
全てを表現していないEBNFを冒頭に載せるの、リファレンスマニュアルとしてどうなの?とはちょっと思う。