-
Notifications
You must be signed in to change notification settings - Fork 988
Added support for the database engine plugin system for extending sqlc with new databases (in addition to PostgreSQL, Dolphin (MySQL), sqlite) #4247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Draft
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
b6aa62d
Added support for the database engine plugin system for extending sql...
asmyasnikov 5336821
Fix of endtoend tests
asmyasnikov 2b88994
added install plugin-based-codegen's
asmyasnikov b1d156d
remove tmp file
asmyasnikov 9f65d4f
removed go.{mod,sum}
asmyasnikov 74b621f
SQLCDEBUG=processplugins=1
asmyasnikov cede5d3
Fix
asmyasnikov 15b240d
Fix
asmyasnikov 0b3b165
Apply suggestions from code review
asmyasnikov 6c5b9a6
revert Combine
asmyasnikov 7609ebc
.gitignore + README
asmyasnikov a5131b5
WIP
asmyasnikov 2e9c21b
WIP
asmyasnikov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,3 +9,4 @@ __pycache__ | |
| .devenv* | ||
| devenv.local.nix | ||
|
|
||
| /bin/sqlc | ||
251 changes: 251 additions & 0 deletions
docs/howto/engine-plugins.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,251 @@ | ||
| # Database Engine Plugins | ||
|
|
||
| sqlc supports adding custom database backends through engine plugins. This allows you to use sqlc with databases that aren't natively supported (like MyDB, CockroachDB, or other SQL-compatible databases). | ||
|
|
||
| ## Overview | ||
|
|
||
| Engine plugins are external programs that implement the sqlc engine interface: | ||
| - **Process plugins** (Go): Communicate via **Protocol Buffers** over stdin/stdout | ||
| - **WASM plugins** (any language): Communicate via **JSON** over stdin/stdout | ||
|
|
||
| ## Compatibility Guarantee | ||
|
|
||
| For Go process plugins, compatibility is guaranteed at **compile time**: | ||
|
|
||
| ```go | ||
| import "github.com/sqlc-dev/sqlc/pkg/engine" | ||
| ``` | ||
|
|
||
| When you import this package: | ||
| - If your plugin compiles successfully → it's compatible with this version of sqlc | ||
| - If types change incompatibly → your plugin won't compile until you update it | ||
|
|
||
| The Protocol Buffer schema ensures binary compatibility. No version negotiation needed. | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### sqlc.yaml | ||
|
|
||
| ```yaml | ||
| version: "2" | ||
|
|
||
| # Define engine plugins | ||
| engines: | ||
| - name: mydb | ||
| process: | ||
| cmd: sqlc-engine-mydb | ||
| env: | ||
| - MYDB_CONNECTION_STRING | ||
|
|
||
| sql: | ||
| - engine: mydb # Use the MyDB engine | ||
| schema: "schema.sql" | ||
| queries: "queries.sql" | ||
| gen: | ||
| go: | ||
| package: db | ||
| out: db | ||
| ``` | ||
|
|
||
| ### Configuration Options | ||
|
|
||
| | Field | Description | | ||
| |-------|-------------| | ||
| | `name` | Unique name for the engine (used in `sql[].engine`) | | ||
| | `process.cmd` | Command to run (must be in PATH or absolute path) | | ||
| | `wasm.url` | URL to download WASM module (`file://` or `https://`) | | ||
| | `wasm.sha256` | SHA256 checksum of the WASM module | | ||
| | `env` | Environment variables to pass to the plugin | | ||
|
|
||
| ## Creating a Go Engine Plugin | ||
|
|
||
| ### 1. Import the SDK | ||
|
|
||
| ```go | ||
| import "github.com/sqlc-dev/sqlc/pkg/engine" | ||
| ``` | ||
|
|
||
| ### 2. Implement the Handler | ||
|
|
||
| ```go | ||
| package main | ||
|
|
||
| import ( | ||
| "github.com/sqlc-dev/sqlc/pkg/engine" | ||
| ) | ||
|
|
||
| func main() { | ||
| engine.Run(engine.Handler{ | ||
| PluginName: "mydb", | ||
| PluginVersion: "1.0.0", | ||
| Parse: handleParse, | ||
| GetCatalog: handleGetCatalog, | ||
| IsReservedKeyword: handleIsReservedKeyword, | ||
| GetCommentSyntax: handleGetCommentSyntax, | ||
| GetDialect: handleGetDialect, | ||
| }) | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Implement Methods | ||
|
|
||
| #### Parse | ||
|
|
||
| Parses SQL text into statements with AST. | ||
|
|
||
| ```go | ||
| func handleParse(req *engine.ParseRequest) (*engine.ParseResponse, error) { | ||
| sql := req.GetSql() | ||
| // Parse SQL using your database's parser | ||
|
|
||
| return &engine.ParseResponse{ | ||
| Statements: []*engine.Statement{ | ||
| { | ||
| RawSql: sql, | ||
| StmtLocation: 0, | ||
| StmtLen: int32(len(sql)), | ||
| AstJson: astJSON, // AST encoded as JSON bytes | ||
| }, | ||
| }, | ||
| }, nil | ||
| } | ||
| ``` | ||
|
|
||
| #### GetCatalog | ||
|
|
||
| Returns the initial catalog with built-in types and functions. | ||
|
|
||
| ```go | ||
| func handleGetCatalog(req *engine.GetCatalogRequest) (*engine.GetCatalogResponse, error) { | ||
| return &engine.GetCatalogResponse{ | ||
| Catalog: &engine.Catalog{ | ||
| DefaultSchema: "public", | ||
| Name: "mydb", | ||
| Schemas: []*engine.Schema{ | ||
| { | ||
| Name: "public", | ||
| Functions: []*engine.Function{ | ||
| {Name: "now", ReturnType: &engine.DataType{Name: "timestamp"}}, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, nil | ||
| } | ||
| ``` | ||
|
|
||
| #### IsReservedKeyword | ||
|
|
||
| Checks if a string is a reserved keyword. | ||
|
|
||
| ```go | ||
| func handleIsReservedKeyword(req *engine.IsReservedKeywordRequest) (*engine.IsReservedKeywordResponse, error) { | ||
| reserved := map[string]bool{ | ||
| "select": true, "from": true, "where": true, | ||
| } | ||
| return &engine.IsReservedKeywordResponse{ | ||
| IsReserved: reserved[strings.ToLower(req.GetKeyword())], | ||
| }, nil | ||
| } | ||
| ``` | ||
|
|
||
| #### GetCommentSyntax | ||
|
|
||
| Returns supported SQL comment syntax. | ||
|
|
||
| ```go | ||
| func handleGetCommentSyntax(req *engine.GetCommentSyntaxRequest) (*engine.GetCommentSyntaxResponse, error) { | ||
| return &engine.GetCommentSyntaxResponse{ | ||
| Dash: true, // -- comment | ||
| SlashStar: true, // /* comment */ | ||
| Hash: false, // # comment | ||
| }, nil | ||
| } | ||
| ``` | ||
|
|
||
| #### GetDialect | ||
|
|
||
| Returns SQL dialect information for formatting. | ||
|
|
||
| ```go | ||
| func handleGetDialect(req *engine.GetDialectRequest) (*engine.GetDialectResponse, error) { | ||
| return &engine.GetDialectResponse{ | ||
| QuoteChar: "`", // Identifier quoting character | ||
| ParamStyle: "dollar", // 1,ドル 2,ドル ... | ||
| ParamPrefix: "$", // Parameter prefix | ||
| CastSyntax: "cast_function", // CAST(x AS type) or "double_colon" for :: | ||
| }, nil | ||
| } | ||
| ``` | ||
|
|
||
| ### 4. Build and Install | ||
|
|
||
| ```bash | ||
| go build -o sqlc-engine-mydb . | ||
| mv sqlc-engine-mydb /usr/local/bin/ | ||
| ``` | ||
|
|
||
| ## Protocol | ||
|
|
||
| ### Process Plugins (Go) | ||
|
|
||
| Process plugins use **Protocol Buffers** for serialization: | ||
|
|
||
| ``` | ||
| sqlc → stdin (protobuf) → plugin → stdout (protobuf) → sqlc | ||
| ``` | ||
|
|
||
| The proto schema is published at `buf.build/sqlc/sqlc` in `engine/engine.proto`. | ||
|
|
||
| Methods are invoked as command-line arguments: | ||
| ```bash | ||
| sqlc-engine-mydb parse # stdin: ParseRequest, stdout: ParseResponse | ||
| sqlc-engine-mydb get_catalog # stdin: GetCatalogRequest, stdout: GetCatalogResponse | ||
| ``` | ||
|
|
||
| ### WASM Plugins | ||
|
|
||
| WASM plugins use **JSON** for broader language compatibility: | ||
|
|
||
| ``` | ||
| sqlc → stdin (JSON) → wasm module → stdout (JSON) → sqlc | ||
| ``` | ||
|
|
||
| ## Full Example | ||
|
|
||
| See `examples/plugin-based-codegen/` for a complete engine plugin implementation. | ||
|
|
||
| ## Architecture | ||
|
|
||
| ``` | ||
| ┌─────────────────────────────────────────────────────────────────┐ | ||
| │ sqlc generate │ | ||
| │ │ | ||
| │ 1. Read sqlc.yaml │ | ||
| │ 2. Find engine: mydb → look up in engines[] │ | ||
| │ 3. Run: sqlc-engine-mydb parse < schema.sql │ | ||
| │ 4. Get AST via protobuf on stdout │ | ||
| │ 5. Generate Go code │ | ||
| └─────────────────────────────────────────────────────────────────┘ | ||
|
|
||
| Process Plugin Communication (Protobuf): | ||
|
|
||
| sqlc sqlc-engine-mydb | ||
| ──── ──────────────── | ||
| │ │ | ||
| │──── spawn process ─────────────► │ | ||
| │ args: ["parse"] │ | ||
| │ │ | ||
| │──── protobuf on stdin ─────────► │ | ||
| │ ParseRequest{sql: "..."} │ | ||
| │ │ | ||
| │◄─── protobuf on stdout ───────── │ | ||
| │ ParseResponse{statements} │ | ||
| │ │ | ||
| ``` | ||
|
|
||
| ## See Also | ||
|
|
||
| - [Codegen Plugins](plugins.md) - For custom code generators | ||
| - [Configuration Reference](../reference/config.md) | ||
| - Proto schema: `protos/engine/engine.proto` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.