ブログのしゅーくりーむ

技術的なメモとかライフログとか。

Cloud Spanner の DDL parser と DDL 変換ツールを作った

Cloud SpannerDDL parser の Go 実装と、 Spanner DDLMySQL DDL っぽいものに変換するツールを作りました。 本記事はこれらの紹介になります。

github.com

github.com

spar: Cloud Spanner DDL parser in Go

Spanner の DDLこんな感じ で、 SQL 方言に見えるもののカラムの型だの INTERLEAVE だの、仕様に対して独自の文法も結構な割合で持っているように見えます。 今回作った spar, DDL parser はこれらをパースして CREATE 文や ALTER 文などの構成要素をまとめて返してくれます。

リポジトリに同梱した DDL syntax checker のコードがシンプルな使用例としても有用です。 parser package の持つ Parse() に読みたい DDL の Reader を渡すとパースした結果を返してくれます。

package main

import (
    "io/ioutil"
    "log"
    "os"
    "strings"

    "github.com/syucream/spar/src/parser"
)

func main() {
    data, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        log.Fatal(err)
    }

    _, err = parser.Parse(strings.NewReader(string(data)))
    if err != nil {
        log.Fatal(err)
    }
}

パーサー部分は goyacc を使って生成しています。 また lexer 部分の一部は https://github.com/benbjohnson/sql-parser を参考にしています。

jackup: Jack up your DDL and translate between MySQL and Spanner

スパナときたら今度は別の工具も欲しくなってくると思われます。ということでジャッキを作りました。 jackup は標準入力か -f オプションで渡したパスのファイルの DDL を参照し、 spar を使ってパースした後、(現在は CREATE TABLE , CREATE INDEX しか読んでくれませんが) MySQL の同じような構造を持つ DDL を出力してくれます。 残念ながら一部の変換、特にカラムの長さに関する制限が Spanner のほうがゆるい部分があり、無理やり変換したり変換せず無視したりもしています。

このツールは Spanner を捨てて MySQL に以降したりなどクリティカルなユースケースに対応するつもりはなく、もう少しゆるく変換したらどうなりそうか確認したり、 MySQL 周りのエコシステム、例えば MySQL Workbench による ER 図生成に食わせたりしてみるために作ってます。 なお、このあたりの SQL 方言とその間の相互変換は、現状良いソリューションが無く今回自分は自前で実装したのですが、今後は Apache Calcite に淡い期待を寄せてみてもいいのかなと思っています。

Apache Calcite • Dynamic data management framework