|
| 1 | +# Database Engine Plugins |
| 2 | + |
| 3 | +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). |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +Engine plugins are external programs that implement the sqlc engine interface: |
| 8 | +- **Process plugins** (Go): Communicate via **Protocol Buffers** over stdin/stdout |
| 9 | +- **WASM plugins** (any language): Communicate via **JSON** over stdin/stdout |
| 10 | + |
| 11 | +## Compatibility Guarantee |
| 12 | + |
| 13 | +For Go process plugins, compatibility is guaranteed at **compile time**: |
| 14 | + |
| 15 | +```go |
| 16 | +import "github.com/sqlc-dev/sqlc/pkg/engine" |
| 17 | +``` |
| 18 | + |
| 19 | +When you import this package: |
| 20 | +- If your plugin compiles successfully → it's compatible with this version of sqlc |
| 21 | +- If types change incompatibly → your plugin won't compile until you update it |
| 22 | + |
| 23 | +The Protocol Buffer schema ensures binary compatibility. No version negotiation needed. |
| 24 | + |
| 25 | +## Configuration |
| 26 | + |
| 27 | +### sqlc.yaml |
| 28 | + |
| 29 | +```yaml |
| 30 | +version: "2" |
| 31 | + |
| 32 | +# Define engine plugins |
| 33 | +engines: |
| 34 | + - name: mydb |
| 35 | + process: |
| 36 | + cmd: sqlc-engine-mydb |
| 37 | + env: |
| 38 | + - MYDB_CONNECTION_STRING |
| 39 | + |
| 40 | +sql: |
| 41 | + - engine: mydb # Use the MyDB engine |
| 42 | + schema: "schema.sql" |
| 43 | + queries: "queries.sql" |
| 44 | + gen: |
| 45 | + go: |
| 46 | + package: db |
| 47 | + out: db |
| 48 | +``` |
| 49 | +
|
| 50 | +### Configuration Options |
| 51 | +
|
| 52 | +| Field | Description | |
| 53 | +|-------|-------------| |
| 54 | +| `name` | Unique name for the engine (used in `sql[].engine`) | |
| 55 | +| `process.cmd` | Command to run (must be in PATH or absolute path) | |
| 56 | +| `wasm.url` | URL to download WASM module (`file://` or `https://`) | |
| 57 | +| `wasm.sha256` | SHA256 checksum of the WASM module | |
| 58 | +| `env` | Environment variables to pass to the plugin | |
| 59 | + |
| 60 | +## Creating a Go Engine Plugin |
| 61 | + |
| 62 | +### 1. Import the SDK |
| 63 | + |
| 64 | +```go |
| 65 | +import "github.com/sqlc-dev/sqlc/pkg/engine" |
| 66 | +``` |
| 67 | + |
| 68 | +### 2. Implement the Handler |
| 69 | + |
| 70 | +```go |
| 71 | +package main |
| 72 | +
|
| 73 | +import ( |
| 74 | + "github.com/sqlc-dev/sqlc/pkg/engine" |
| 75 | +) |
| 76 | +
|
| 77 | +func main() { |
| 78 | + engine.Run(engine.Handler{ |
| 79 | + PluginName: "mydb", |
| 80 | + PluginVersion: "1.0.0", |
| 81 | + Parse: handleParse, |
| 82 | + GetCatalog: handleGetCatalog, |
| 83 | + IsReservedKeyword: handleIsReservedKeyword, |
| 84 | + GetCommentSyntax: handleGetCommentSyntax, |
| 85 | + GetDialect: handleGetDialect, |
| 86 | + }) |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | +### 3. Implement Methods |
| 91 | + |
| 92 | +#### Parse |
| 93 | + |
| 94 | +Parses SQL text into statements with AST. |
| 95 | + |
| 96 | +```go |
| 97 | +func handleParse(req *engine.ParseRequest) (*engine.ParseResponse, error) { |
| 98 | + sql := req.GetSql() |
| 99 | + // Parse SQL using your database's parser |
| 100 | + |
| 101 | + return &engine.ParseResponse{ |
| 102 | + Statements: []*engine.Statement{ |
| 103 | + { |
| 104 | + RawSql: sql, |
| 105 | + StmtLocation: 0, |
| 106 | + StmtLen: int32(len(sql)), |
| 107 | + AstJson: astJSON, // AST encoded as JSON bytes |
| 108 | + }, |
| 109 | + }, |
| 110 | + }, nil |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +#### GetCatalog |
| 115 | + |
| 116 | +Returns the initial catalog with built-in types and functions. |
| 117 | + |
| 118 | +```go |
| 119 | +func handleGetCatalog(req *engine.GetCatalogRequest) (*engine.GetCatalogResponse, error) { |
| 120 | + return &engine.GetCatalogResponse{ |
| 121 | + Catalog: &engine.Catalog{ |
| 122 | + DefaultSchema: "public", |
| 123 | + Name: "mydb", |
| 124 | + Schemas: []*engine.Schema{ |
| 125 | + { |
| 126 | + Name: "public", |
| 127 | + Functions: []*engine.Function{ |
| 128 | + {Name: "now", ReturnType: &engine.DataType{Name: "timestamp"}}, |
| 129 | + }, |
| 130 | + }, |
| 131 | + }, |
| 132 | + }, |
| 133 | + }, nil |
| 134 | +} |
| 135 | +``` |
| 136 | + |
| 137 | +#### IsReservedKeyword |
| 138 | + |
| 139 | +Checks if a string is a reserved keyword. |
| 140 | + |
| 141 | +```go |
| 142 | +func handleIsReservedKeyword(req *engine.IsReservedKeywordRequest) (*engine.IsReservedKeywordResponse, error) { |
| 143 | + reserved := map[string]bool{ |
| 144 | + "select": true, "from": true, "where": true, |
| 145 | + } |
| 146 | + return &engine.IsReservedKeywordResponse{ |
| 147 | + IsReserved: reserved[strings.ToLower(req.GetKeyword())], |
| 148 | + }, nil |
| 149 | +} |
| 150 | +``` |
| 151 | + |
| 152 | +#### GetCommentSyntax |
| 153 | + |
| 154 | +Returns supported SQL comment syntax. |
| 155 | + |
| 156 | +```go |
| 157 | +func handleGetCommentSyntax(req *engine.GetCommentSyntaxRequest) (*engine.GetCommentSyntaxResponse, error) { |
| 158 | + return &engine.GetCommentSyntaxResponse{ |
| 159 | + Dash: true, // -- comment |
| 160 | + SlashStar: true, // /* comment */ |
| 161 | + Hash: false, // # comment |
| 162 | + }, nil |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +#### GetDialect |
| 167 | + |
| 168 | +Returns SQL dialect information for formatting. |
| 169 | + |
| 170 | +```go |
| 171 | +func handleGetDialect(req *engine.GetDialectRequest) (*engine.GetDialectResponse, error) { |
| 172 | + return &engine.GetDialectResponse{ |
| 173 | + QuoteChar: "`", // Identifier quoting character |
| 174 | + ParamStyle: "dollar", // $1, $2, ... |
| 175 | + ParamPrefix: "$", // Parameter prefix |
| 176 | + CastSyntax: "cast_function", // CAST(x AS type) or "double_colon" for :: |
| 177 | + }, nil |
| 178 | +} |
| 179 | +``` |
| 180 | + |
| 181 | +### 4. Build and Install |
| 182 | + |
| 183 | +```bash |
| 184 | +go build -o sqlc-engine-mydb . |
| 185 | +mv sqlc-engine-mydb /usr/local/bin/ |
| 186 | +``` |
| 187 | + |
| 188 | +## Protocol |
| 189 | + |
| 190 | +### Process Plugins (Go) |
| 191 | + |
| 192 | +Process plugins use **Protocol Buffers** for serialization: |
| 193 | + |
| 194 | +``` |
| 195 | +sqlc → stdin (protobuf) → plugin → stdout (protobuf) → sqlc |
| 196 | +``` |
| 197 | + |
| 198 | +The proto schema is published at `buf.build/sqlc/sqlc` in `engine/engine.proto`. |
| 199 | + |
| 200 | +Methods are invoked as command-line arguments: |
| 201 | +```bash |
| 202 | +sqlc-engine-mydb parse # stdin: ParseRequest, stdout: ParseResponse |
| 203 | +sqlc-engine-mydb get_catalog # stdin: GetCatalogRequest, stdout: GetCatalogResponse |
| 204 | +``` |
| 205 | + |
| 206 | +### WASM Plugins |
| 207 | + |
| 208 | +WASM plugins use **JSON** for broader language compatibility: |
| 209 | + |
| 210 | +``` |
| 211 | +sqlc → stdin (JSON) → wasm module → stdout (JSON) → sqlc |
| 212 | +``` |
| 213 | + |
| 214 | +## Full Example |
| 215 | + |
| 216 | +See `examples/plugin-based-codegen/` for a complete engine plugin implementation. |
| 217 | + |
| 218 | +## Architecture |
| 219 | + |
| 220 | +``` |
| 221 | +┌─────────────────────────────────────────────────────────────────┐ |
| 222 | +│ sqlc generate │ |
| 223 | +│ │ |
| 224 | +│ 1. Read sqlc.yaml │ |
| 225 | +│ 2. Find engine: mydb → look up in engines[] │ |
| 226 | +│ 3. Run: sqlc-engine-mydb parse < schema.sql │ |
| 227 | +│ 4. Get AST via protobuf on stdout │ |
| 228 | +│ 5. Generate Go code │ |
| 229 | +└─────────────────────────────────────────────────────────────────┘ |
| 230 | +
|
| 231 | +Process Plugin Communication (Protobuf): |
| 232 | +
|
| 233 | + sqlc sqlc-engine-mydb |
| 234 | + ──── ──────────────── |
| 235 | + │ │ |
| 236 | + │──── spawn process ─────────────► │ |
| 237 | + │ args: ["parse"] │ |
| 238 | + │ │ |
| 239 | + │──── protobuf on stdin ─────────► │ |
| 240 | + │ ParseRequest{sql: "..."} │ |
| 241 | + │ │ |
| 242 | + │◄─── protobuf on stdout ───────── │ |
| 243 | + │ ParseResponse{statements} │ |
| 244 | + │ │ |
| 245 | +``` |
| 246 | + |
| 247 | +## See Also |
| 248 | + |
| 249 | +- [Codegen Plugins](plugins.md) - For custom code generators |
| 250 | +- [Configuration Reference](../reference/config.md) |
| 251 | +- Proto schema: `protos/engine/engine.proto` |
0 commit comments