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
15
Regular Expressions, REXML, Automata Learning
makenowjust
0
260
オートマトン学習しろ / Do automata learning
makenowjust
3
170
#kaigieffect LT 2024 - rexml-css_selector: A REXML extension for supporting CSS selector
makenowjust
1
320
RubyKaigi 2024 - Make Your Own Regex Engine!
makenowjust
1
1.4k
正規表現改善報告する回 / Regexp memoization progress report
makenowjust
2
540
Make Regexp#match much faster
makenowjust
1
2.6k
ReDoS 検出の最先端 recheck の紹介 / State of the Art of ReDoS Detection
makenowjust
9
3.4k
ReDoS 検出プログラム recheck の開発 / recheck: ReDoS check program
makenowjust
0
120
Other Decks in Programming
See All in Programming
Jakarta Concurrencyによる並行処理プログラミングの始め方 (JJUG CCC 2024 Fall)
tnagao7
1
290
アジャイルを支えるテストアーキテクチャ設計/Test Architecting for Agile
goyoki
9
3.3k
色々なIaCツールを実際に触って比較してみる
iriikeita
0
330
CSC509 Lecture 12
javiergs
PRO
0
160
ふかぼれ!CSSセレクターモジュール / Fukabore! CSS Selectors Module
petamoriken
0
150
C++でシェーダを書く
fadis
6
4.1k
AI時代におけるSRE、 あるいはエンジニアの生存戦略
pyama86
6
1.1k
[Do iOS '24] Ship your app on a Friday...and enjoy your weekend!
polpielladev
0
100
Less waste, more joy, and a lot more green: How Quarkus makes Java better
hollycummins
0
100
Jakarta EE meets AI
ivargrimstad
0
610
Enabling DevOps and Team Topologies Through Architecture: Architecting for Fast Flow
cer
PRO
0
330
OSSで起業してもうすぐ10年 / Open Source Conference 2024 Shimane
furukawayasuto
0
100
Featured
See All Featured
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
Side Projects
sachag
452
42k
Docker and Python
trallard
40
3.1k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
93
16k
Gamification - CAS2011
davidbonilla
80
5k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.2k
Building an army of robots
kneath
302
43k
Agile that works and the tools we love
rasmusluckow
327
21k
Being A Developer After 40
akosma
86
590k
[RailsConf 2023] Rails as a piece of cake
palkan
52
4.9k
Designing the Hi-DPI Web
ddemaree
280
34k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
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