Skip to content

Commit 9d8dbd5

Browse files
committed
feat(sqlserver): add Microsoft SQL Server support
Add MSSQL/SQL Server engine support using the sqlc-dev/teesql parser. This implementation uses database-only mode (analyzer.database: only) which analyzes queries against a live SQL Server database using sp_describe_first_result_set for column metadata. Features: - T-SQL parser integration using teesql - Database analyzer using go-mssqldb driver - MSSQL catalog with dbo default schema - Example configuration in examples/authors/sqlserver The SQL Server engine requires a database connection and does not support static catalog analysis. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent ba513e7 commit 9d8dbd5

File tree

12 files changed

+1774
-0
lines changed

12 files changed

+1774
-0
lines changed

docker-compose.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,13 @@ services:
1919
POSTGRES_DB: postgres
2020
POSTGRES_PASSWORD: mysecretpassword
2121
POSTGRES_USER: postgres
22+
23+
mssql:
24+
image: "mcr.microsoft.com/mssql/server:2022-latest"
25+
ports:
26+
- "1433:1433"
27+
restart: always
28+
environment:
29+
ACCEPT_EULA: "Y"
30+
MSSQL_SA_PASSWORD: "MySecretPassword1!"
31+
MSSQL_PID: "Developer"

examples/authors/sqlc.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ sql:
4343
go:
4444
package: authors
4545
out: sqlite
46+
- name: sqlserver
47+
schema: sqlserver/schema.sql
48+
queries: sqlserver/query.sql
49+
engine: sqlserver
50+
database:
51+
uri: "sqlserver://sa:MySecretPassword1!@localhost:1433?database=master"
52+
gen:
53+
go:
54+
package: authors
55+
out: sqlserver
4656
rules:
4757
- name: postgresql-query-too-costly
4858
message: "Too costly"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-- name: GetAuthor :one
2+
SELECT * FROM authors
3+
WHERE id = @p1;
4+
5+
-- name: ListAuthors :many
6+
SELECT * FROM authors
7+
ORDER BY name;
8+
9+
-- name: CreateAuthor :exec
10+
INSERT INTO authors (name, bio) VALUES (@p1, @p2);
11+
12+
-- name: DeleteAuthor :exec
13+
DELETE FROM authors
14+
WHERE id = @p1;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE authors (
2+
id BIGINT IDENTITY(1,1) PRIMARY KEY,
3+
name NVARCHAR(255) NOT NULL,
4+
bio NVARCHAR(MAX)
5+
);

go.mod

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ require (
3434
require (
3535
cel.dev/expr v0.24.0 // indirect
3636
filippo.io/edwards25519 v1.1.0 // indirect
37+
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
38+
github.com/golang-sql/sqlexp v0.1.0 // indirect
39+
github.com/google/uuid v1.6.0 // indirect
3740
github.com/inconshreveable/mousetrap v1.1.0 // indirect
3841
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
3942
github.com/jackc/pgconn v1.14.3 // indirect
@@ -43,11 +46,14 @@ require (
4346
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
4447
github.com/jackc/pgtype v1.14.0 // indirect
4548
github.com/jackc/puddle/v2 v2.2.2 // indirect
49+
github.com/microsoft/go-mssqldb v1.9.5 // indirect
4650
github.com/ncruces/julianday v1.0.0 // indirect
4751
github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb // indirect
4852
github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 // indirect
4953
github.com/pingcap/log v1.1.0 // indirect
5054
github.com/rogpeppe/go-internal v1.10.0 // indirect
55+
github.com/shopspring/decimal v1.4.0 // indirect
56+
github.com/sqlc-dev/teesql v0.0.0-20251223200649-2af7220b5d6d // indirect
5157
github.com/stoewer/go-strcase v1.2.0 // indirect
5258
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect
5359
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect

go.sum

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
2929
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
3030
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
3131
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
32+
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
33+
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
34+
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
35+
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
3236
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
3337
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
3438
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
@@ -117,6 +121,8 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
117121
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
118122
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
119123
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
124+
github.com/microsoft/go-mssqldb v1.9.5 h1:orwya0X/5bsL1o+KasupTkk2eNTNFkTQG0BEe/HxCn0=
125+
github.com/microsoft/go-mssqldb v1.9.5/go.mod h1:VCP2a0KEZZtGLRHd1PsLavLFYy/3xX2yJUPycv3Sr2Q=
120126
github.com/ncruces/go-sqlite3 v0.30.3 h1:X/CgWW9GzmIAkEPrifhKqf0cC15DuOVxAJaHFTTAURQ=
121127
github.com/ncruces/go-sqlite3 v0.30.3/go.mod h1:AxKu9sRxkludimFocbktlY6LiYSkxiI5gTA8r+os/Nw=
122128
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
@@ -150,6 +156,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
150156
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
151157
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
152158
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
159+
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
160+
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
153161
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
154162
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
155163
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
@@ -159,6 +167,8 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
159167
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
160168
github.com/sqlc-dev/mysql v0.0.0-20251129233104-d81e1cac6db2 h1:kmCAKKtOgK6EXXQX9oPdEASIhgor7TCpWxD8NtcqVcU=
161169
github.com/sqlc-dev/mysql v0.0.0-20251129233104-d81e1cac6db2/go.mod h1:TrDMWzjNTKvJeK2GC8uspG+PWyPLiY9QKvwdWpAdlZE=
170+
github.com/sqlc-dev/teesql v0.0.0-20251223200649-2af7220b5d6d h1:Zh8xFDF6f5X6TQFhRKOfxkxdAS7rgWgXGSVlbNwOJMI=
171+
github.com/sqlc-dev/teesql v0.0.0-20251223200649-2af7220b5d6d/go.mod h1:uvS3GUOPfpdzH2atGyavoVrbIuJkwrokFRyU/G1AaK4=
162172
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
163173
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
164174
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -171,6 +181,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
171181
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
172182
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
173183
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
184+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
174185
github.com/tetratelabs/wazero v1.10.1 h1:2DugeJf6VVk58KTPszlNfeeN8AhhpwcZqkJj2wwFuH8=
175186
github.com/tetratelabs/wazero v1.10.1/go.mod h1:DRm5twOQ5Gr1AoEdSi0CLjDQF1J9ZAuyqFIjl1KKfQU=
176187
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfPe7z7go8Dvv1AJQDI3eQ/5xith3q2mFlo=

internal/compiler/engine.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"github.com/sqlc-dev/sqlc/internal/config"
99
"github.com/sqlc-dev/sqlc/internal/dbmanager"
1010
"github.com/sqlc-dev/sqlc/internal/engine/dolphin"
11+
"github.com/sqlc-dev/sqlc/internal/engine/mssql"
12+
mssqlanalyze "github.com/sqlc-dev/sqlc/internal/engine/mssql/analyzer"
1113
"github.com/sqlc-dev/sqlc/internal/engine/postgresql"
1214
pganalyze "github.com/sqlc-dev/sqlc/internal/engine/postgresql/analyzer"
1315
"github.com/sqlc-dev/sqlc/internal/engine/sqlite"
@@ -111,6 +113,25 @@ func NewCompiler(conf config.SQL, combo config.CombinedSettings, parserOpts opts
111113
)
112114
}
113115
}
116+
case config.EngineMSSQL:
117+
parser := mssql.NewParser()
118+
c.parser = parser
119+
c.catalog = mssql.NewCatalog()
120+
c.selector = newDefaultSelector()
121+
122+
// MSSQL only supports database-only mode
123+
if conf.Database == nil {
124+
return nil, fmt.Errorf("sqlserver engine requires database configuration")
125+
}
126+
if conf.Database.URI == "" && !conf.Database.Managed {
127+
return nil, fmt.Errorf("sqlserver engine requires database.uri or database.managed")
128+
}
129+
c.databaseOnlyMode = true
130+
// Create the MSSQL analyzer (implements Analyzer interface)
131+
mssqlAnalyzer := mssqlanalyze.New(*conf.Database)
132+
c.analyzer = analyzer.Cached(mssqlAnalyzer, combo.Global, *conf.Database)
133+
// Create the expander using the analyzer as the column getter
134+
c.expander = expander.New(c.analyzer, parser, parser)
114135
default:
115136
return nil, fmt.Errorf("unknown engine: %s", conf.Engine)
116137
}

internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const (
5454
EngineMySQL Engine = "mysql"
5555
EnginePostgreSQL Engine = "postgresql"
5656
EngineSQLite Engine = "sqlite"
57+
EngineMSSQL Engine = "sqlserver"
5758
)
5859

5960
type Config struct {

0 commit comments

Comments
 (0)