Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
SpannerのSQL解析ライブラリ "memefish" の紹介/gcpug-memefis...
Search
TSUYUSATO Kitsune
February 06, 2020
Programming
3
1.3k
SpannerのSQL解析ライブラリ "memefish" の紹介/gcpug-memefish-introduction
GCPUG Tokyo Handy Spanner Day February 2020 (2020/02/06)での発表資料
TSUYUSATO Kitsune
February 06, 2020
Tweet
Share
More Decks by TSUYUSATO Kitsune
See All by TSUYUSATO Kitsune
YAPC::Japan::Online 2022で発表して WEB+DB PRESSに記事を寄稿した話
makenowjust
0
17
Regular Expressions, REXML, Automata Learning
makenowjust
0
270
オートマトン学習しろ / Do automata learning
makenowjust
3
190
#kaigieffect LT 2024 - rexml-css_selector: A REXML extension for supporting CSS selector
makenowjust
1
330
RubyKaigi 2024 - Make Your Own Regex Engine!
makenowjust
1
1.4k
正規表現改善報告する回 / Regexp memoization progress report
makenowjust
2
560
Make Regexp#match much faster
makenowjust
1
2.6k
ReDoS 検出の最先端 recheck の紹介 / State of the Art of ReDoS Detection
makenowjust
9
3.5k
ReDoS 検出プログラム recheck の開発 / recheck: ReDoS check program
makenowjust
0
130
Other Decks in Programming
See All in Programming
CSC305 Lecture 26
javiergs
PRO
0
140
HTTP compression in PHP and Symfony apps
dunglas
2
1.7k
Monixと常駐プログラムの勘どころ / Scalaわいわい勉強会 #4
stoneream
0
280
Mermaid x AST x 生成AI = コードとドキュメントの完全同期への道
shibuyamizuho
0
160
Symfony Mapper Component
soyuka
2
730
今年のアップデートで振り返るCDKセキュリティのシフトレフト/2024-cdk-security-shift-left
tomoki10
0
200
Webエンジニア主体のモバイルチームの 生産性を高く保つためにやったこと
igreenwood
0
340
PSR-15 はあなたのための ものではない? - phpcon2024
myamagishi
0
130
KubeCon + CloudNativeCon NA 2024 Overviewat Kubernetes Meetup Tokyo #68 / amsy810_k8sjp68
masayaaoyama
0
250
これが俺の”自分戦略” プロセスを楽しんでいこう! - Developers CAREER Boost 2024
niftycorp
PRO
0
190
MCP with Cloudflare Workers
yusukebe
2
220
ブラウザ単体でmp4書き出すまで - muddy-web - 2024-12
yue4u
3
470
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
181
21k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
Rails Girls Zürich Keynote
gr2m
94
13k
Agile that works and the tools we love
rasmusluckow
328
21k
Visualization
eitanlees
146
15k
Why Our Code Smells
bkeepers
PRO
335
57k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.1k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
YesSQL, Process and Tooling at Scale
rocio
169
14k
Automating Front-end Workflow
addyosmani
1366
200k
Transcript
SpannerのSQL解析ライブラリ "memefish" の紹介 @MakeNowJust at GCPUG Tokyo Handy Spanner Day
February 2020 (2020/02/06) SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 1
⾃⼰紹介 HN: MakeNowJust 学⽣ 去年の夏にメルカリのインターンに参加していた 今回紹介するものも、インターンで開発したもの SpannerのSQL解析ライブラリ "memefish" の紹介 by
@MakeNowJust 2
SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 3
紹介するもの SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 4
méméfish méméfish méméfish https://makenowjust.github.io/memefish SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 5
memefish Spannerで使えるSQLを解析するためのGo⾔語のライブラリ (OSS) https://github.com/MakeNowJust/memefishで公開されている 主な機能 1. SQLのパース 2. 構⽂⽊からのSQLの⽣成 3.
SQLの意味解析・型チェック SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 6
memefishを使っているプロジェクト gcpug/handy-spanner mercari/yo SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 7
パッケージ構成 github.com/MakeNowJust/memefish/pkg 以下の重要なパッケージ token : パースに使うトークンやファイルの構造体を定義したパッケージ ast : パース結果のAST (抽象構⽂⽊)を定義したパッケージ
parser : パーサーの実装があるパッケージ analyzer : 型チェッカーのあるパッケージ go/token, go/ast, go/parser などのパッケージを参考にしている SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 8
主な機能 1. SQLのパース 2. 構⽂⽊からのSQLの⽣成 3. SQLの意味解析・型チェック 今⽇の主題 これらの機能がどのようなものなのか memefishでそれらの機能をどうやって使うのか
を説明します (前提知識: Go⾔語を知ってること) SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 9
1. SQLのパース・2. 構⽂⽊からのSQLの⽣成 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 10
パースとは 与えられた⽂字列をSQLとして解釈して、対応する抽象構⽂⽊を組み⽴てること。 例: パースしたい⽂字列 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 11
パース: Lexer そのまま抽象構⽂⽊を組み⽴てるのは難しいので、 まず意味のある最⼩の単位(トークン)に⽂字列を分割する。 トークンには、その部分の役割(キーワードか?識別⼦か?⽂字列リテラルか?など)も 記録されている。 SpannerのSQL解析ライブラリ "memefish" の紹介 by
@MakeNowJust 12
パース: Lexer この処理を⾏うオブジェクトを Lexer と呼ぶ。 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust
13
パース: Parser Lexer によって分割されたトークンの列から抽象構⽂⽊を組み⽴てていく。 抽象構⽂⽊: SQLの各要素に対応する構造体 (⽊構造) この処理を⾏うオブジェクトを Parser と呼ぶ。
SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 14
使い⽅: import ⽂ まずは import 。 ast, token, parser を使う。
import ( "fmt" "log" "github.com/MakenowJust/memefish/pkg/ast" "github.com/MakenowJust/memefish/pkg/parser" "github.com/MakenowJust/memefish/pkg/token" ) SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 15
使い⽅: Parser の組み⽴て Parser は構造体なので必要なフィールドを埋めていく。 必要なフィールドは Lexer だけ。 ( Parser
が Lexer を使うので) また、パースしたい⽂字列は File という構造体に包む。 file := &token.File{ Buffer: "SELECT * FROM Singers WHERE FirstName = \"Foo\"", } p := &parser.Parser{ Lexer: &parser.Lexer{File: file}, } SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 16
使い⽅: ParseQuery の呼び出し 実際のパースは ParseQuery メソッドの呼び出しで⾏なわれる。 ParseQuery の返り値は抽象構⽂⽊とパース時のエラー。 stmt, err
:= p.ParseQuery() if err != nil { log.Fatal(err) } あとは、この stmt を使ってやりたいことをする。 stmt.Query.(*ast.Select).From.Source.(*ast.TableName).Table.Name == "Singers" // => true SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 17
使い⽅: まとめ パースしたい⽂字列を構造体 File に包む ↑を使って Lexer 、 Parser を作る
ParseQuery を呼び出してパースを実⾏する (DMLのパースなら ParseDML 、DDLのパースなら ParseDDL が使える) 結果の抽象構⽂⽊を使ってごにょごにょする SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 18
SQLの⽣成 抽象構⽂⽊の型 ast.Node の定義 type Node interface { Pos() token.Pos
End() token.Pos // Convert AST node into SQL source string (a.k.a. Unparse). SQL() string } この SQL() メソッドで、抽象構⽂⽊からSQLの⽂字列を⽣成できる。 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 19
例: SQLの⽣成 さきほどまでのパースの例の続き // Singers の部分を Albums に差し替える stmt.Query.(*ast.Select).From.Source.(*ast.TableName).Table.Name =
"Albums" fmt.Println(stmt.SQL()) // Output: // SELECT * FROM Albums WHERE FirstName = "Foo" SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 20
3. SQLの意味解析・型チェック SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 21
意味解析・型チェック SQL中の 識別⼦がテーブル・カラム・変数名のどれなのか? 具体的には何を指しているのか? 式の結果がどのような型になるか? を求める機能。 (パースなどと⽐べるとやや不安定です……) SpannerのSQL解析ライブラリ "memefish" の紹介
by @MakeNowJust 22
意味解析・型チェック 意味解析の途中で、 存在しないテーブル・カラムを参照している おかしな操作をしている 例: ⽂字列と数値を⾜し合わせようとしている 例: WHERE の式が BOOL
値を返していない などのエラーが分かる。 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 23
意味解析・型チェック: 疑問 Q. 実際にSpanner送って実⾏計画を⾒るなりすれば、それらのエラーは分かるのでは? memefishで意味解析をする場合、 1. ローカルで全て完結する (通信を伴わない) 2. 型情報や参照の情報をプログラムから利⽤できる
といったメリットがある。特に2番が重要。 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 24
意味解析・型チェック: 使⽤イメージ 例えば、意味解析ではクエリの結果の各カラムがどのような名前・型なのかを取得できる。 これを利⽤すると、クエリからその結果に⼀致する構造体を⾃動⽣成する、 といったことができる。 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust
25
意味解析・型チェック: 使⽤イメージ 例: SELECT CONCAT(FirstName, " ", LastName) AS Name,
BirthDate FROM Singers から type Result struct { Name string BirthDate time.Time } を⾃動⽣成 SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 26
→次のスライドから、これを作っていきます SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 27
使い⽅: import ⽂ 意味解析は抽象構⽂⽊に対して⾏うので、 parser, token のインポートも必要 import ( "fmt"
"log" "github.com/MakeNowJust/memefish/pkg/analyzer" "github.com/MakeNowJust/memefish/pkg/parser" "github.com/MakeNowJust/memefish/pkg/token" ) SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 28
使い⽅: パース まずはパースをする。(さっきと同じ) file := &token.File{ Buffer: "SELECT CONCAT(FirstName, \"
\", LastName) AS Name, BirthDate FROM Singers", } p := &parser.Parser{ Lexer: &parser.Lexer{File: file}, } stmt, err := p.ParseQuery() if err != nil { log.Fatal(err) } SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 29
使い⽅: Catalog の組み⽴て テーブルのスキーマ定義をまとめたものを Catalog と呼ぶ。 catalog := &analyzer.Catalog{ Tables:
map[string]*analyzer.TableSchema{ "SINGERS": { Name: "Singers", Columns: []*analyzer.ColumnSchema{ {Name: "FirstName", Type: analyzer.StringType}, {Name: "LastName", Type: analyzer.StringType}, {Name: "BirthDate", Type: analyzer.DateType}, }, }, }, } SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 30
使い⽅: Analyzer の組み⽴て Catalog と File を渡す必要がある。 File はエラー位置を実際のソースコードに対応させるために必要。 a
:= &analyzer.Analyzer{ File: file, Catalog: catalog, } SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 31
使い⽅: 意味解析の実⾏ AnalyzeQueryStatement に解析したい抽象構⽂⽊を渡すことで意味解析を実⾏できる。 返り値はエラーのみで、意味解析の結果は Analyzer ⾃⾝に保存される。 err = a.AnalyzeQueryStatement(stmt)
if err != nil { log.Fatal(err) } SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 32
使い⽅: 意味解析の結果を使う 例えば、 a.NameList には結果の各カラムの情報が保存されている。 これを使って、SQLの結果に対応する構造体の定義を出⼒する。 columns := a.NameLists[stmt.Query] fmt.Printf("type
Result struct {\n"); for _, column := range columns { fmt.Printf("\t%-9s %s\n", column.Text, mapSQLType(column.Type)) } fmt.Printf("}\n"); ( mapSQLType はSQLの型をGo⾔語の型に対応させる関数。省略) SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 33
使い⽅: まとめ 解析したいSQLをパースする スキーマをまとめた Catalog を組み⽴てる Catalog と File から
Analyzer を組み⽴てる AnalyzeQueryStatement に解析したい抽象構⽂⽊を渡す 意味解析の結果は Analyzer ⾃⾝に保存されている 他には Types フィールドに各式の型が保存されていたりする。 今回の例の全体は次のGo Playgroundから確認できます。 https://play.golang.org/p/PN5JuJKB-Mo SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 34
今回のまとめ SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 35
今回のまとめ memefishはSpannerのSQLをパース・意味解析できるGo⾔語のライブラリ SQL⽂をプログラムで扱うことができる ⾊々と⾯⽩いことに使えると思うので、記憶に⽚隅にでも留めてもらえたら その他、希望など memefishはOSSなので、バグ報告・修正などはいつでもウェルカムです memefishを使って何か作ったよ、みたいな報告もありがたいです ただ、 analyzer 周りはやや開発途中な部分があるので、
後⽅互換性の無い変更などあるかもしれません (悪しからず) SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 36
Q&A? SpannerのSQL解析ライブラリ "memefish" の紹介 by @MakeNowJust 37