sqlcのコードリーディング
#sqlc #Go #WASM #メモ #コードリーディング
sqlcの内部実装が気になったのでコードを読んでみる
v1.26.0時点の内容を元に、気になる部分について調べる
WASMプラグインの実行周り
WASMプラグインについてのドキュメントはこちら - docs/guides/plugins.md
WASMプラグインのダウンロード
1. sqlc.yamlで指定されたURLへHTTPリクエストを送り、ダウンロードする (internal/ext/wasm/wasm.go#L87-L97)
1. internal/cmd/generate.go#L355-L360 - wasm.Runnerが作られているのはここ
2. internal/cmd/generate.go#L195 - plug変数の実体はここで作られている
2. sqlc.yamlで指定されたプラグインのチェックサムと実際のチェックサムが一致していることを検証する (internal/ext/wasm/wasm.go#L126-L133)
3. チェックサムが一致したら、ダウンロードしてきたWASMプラグインをローカルに保存する (internal/ext/wasm/wasm.go#L135-L143)
ファイル名は、下記ディレクトリ配下に${チェックサム}/plugin.wasmという名前で保存される
WASMプラグインの保存先は以下のいずれか (internal/cache/cache.go#L25-L35)
1. SQLCCACHE配下の/pluginsディレクトリ
2. ${os.UserCacheDir()}/sqlc/plugins (デフォルト)
WASMプラグインの実行
1. wasm.Runner.Invoke() - ここでWASMプラグインが実行されている (internal/ext/wasm/wasm.go#L188)
2. ダウンロードされたWASMプラグインのコンパイルとwazeroランタイムの作成を行う (internal/ext/wasm/wasm.go#L145-L164)
wazeroというのは、Go向けのWebAssemblyランタイムとのこと
WASIも利用されている (internal/ext/wasm/wasm.go#L153)
3. wazeroを使ってWASMを実行する (internal/ext/wasm/wasm.go#L206-L242)
WASMプラグインが標準出力に出力した結果をデコードする (internal/ext/wasm/wasm.go#L217, internal/ext/wasm/wasm.go#L240)
スキーマの解析
1. (*Compiler).ParseCatalogのあたりが怪しそう (internal/cmd/generate.go#L308)
引数としてsqlc.yamlのsql.schemaを受け取っているっぽい
*Compilerを作成する際に、RDBMSに応じてParserを作っている (internal/compiler/engine.go#L42-L63)
2. (*Compiler).ParseCatalogの実体は(*Compiler).parseCatalogにある (internal/compiler/engine.go#L71-L73)
3. (*Compiler).parseCatalogはsqlc.yamlのsql.schemaで指定された.sqlファイルを解析して、Catalogを更新している (internal/compiler/compile.go#L29-L53)
この際に、migrations.RemoveRollbackStatementsによって各種マイグレーションツール(dbmate, sql-migrateなど)におけるdown用のSQLを削除している (internal/migrations/migrations.go#L14-L33)
スキーマの定義ファイルを読み込む処理はsqlpath.Globで記述されている (internal/sql/sqlpath/read.go#L19)
スキーマファイルの一覧は基本的にos.ReadDirで読み込まれている
os.ReadDirはファイル名順でファイル名の一覧を返す
各種マイグレーションツールのマイグレーションファイルは、ファイル名の頭にタイムスタンプがつくから、これにより意図した順番で.sqlファイルの一覧が取得できる
4. (*Catalog).Updateの実体はここ (internal/sql/catalog/catalog.go#L45)
この.Update()メソッドは、各.sqlファイルごとに都度呼び出される
Catalogは現在のスキーマ定義に関するスナップショットを管理していて、.Update'(によりスナップショットが更新される
この.Update()の内部ではParserが返却した各ノードを愚直に一つずつ検査し、*Catalogに定義された各種ノード種別に対応するメソッドを呼んでスナップショットを更新している