snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
This commit is contained in:
153
internal/goldeneye/mssql/mssql.go
Normal file
153
internal/goldeneye/mssql/mssql.go
Normal file
@@ -0,0 +1,153 @@
|
||||
// Package mssql generates the SQL Server dialect seed under
|
||||
// internal/engine/mssql/dialect from a live server, and verifies the SQL
|
||||
// Server analyze cases under internal/endtoend/testdata against the same
|
||||
// server.
|
||||
//
|
||||
// SQL Server keeps no catalog of its built-in functions or operators — the
|
||||
// intrinsic functions such as GETDATE and LEN are not objects — so
|
||||
// types.jsonl and functions.jsonl are written by hand and are not this
|
||||
// package's business. What it does describe is its catalog: relations.jsonl
|
||||
// is every view of the sys and INFORMATION_SCHEMA schemas, with each view's
|
||||
// columns as the server itself describes a SELECT * from it.
|
||||
//
|
||||
// The package also verifies the SQL Server analyze cases under
|
||||
// internal/endtoend/testdata against the same server: each case's schema
|
||||
// and fixture are loaded into a database of their own and its queries
|
||||
// described there, without being run. Result columns come from
|
||||
// sys.dm_exec_describe_first_result_set, which says what each column is
|
||||
// called, what type it has, whether it can be NULL and which table column
|
||||
// it is read from; parameters from sp_describe_undeclared_parameters, which
|
||||
// says what type the server would give each, and from the estimated
|
||||
// showplan, which says which column each is compared with or assigned to.
|
||||
// The answer is printed in the JSON shape sqlc analyze prints and compared
|
||||
// with the case's committed stdout.json byte for byte.
|
||||
//
|
||||
// The server is named by MSSQL_SERVER_URI, in any form the go-mssqldb
|
||||
// driver accepts, such as
|
||||
// sqlserver://sa:password@127.0.0.1:1433?encrypt=disable, and has to be
|
||||
// the major release in Major, since each release adds to the catalog views.
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
_ "github.com/microsoft/go-mssqldb"
|
||||
"github.com/microsoft/go-mssqldb/msdsn"
|
||||
|
||||
"github.com/sqlc-dev/sqlc/internal/goldeneye/dialect"
|
||||
)
|
||||
|
||||
// Engine is the name sqlc knows the dialect by, and the name of the analyze
|
||||
// case directories under internal/endtoend/testdata.
|
||||
const Engine = "mssql"
|
||||
|
||||
// Major is the SQL Server major release the dialect is generated from, as
|
||||
// SERVERPROPERTY('ProductMajorVersion') reports it: 17 is SQL Server 2025.
|
||||
// Bumping it is a deliberate change: every release adds views and columns
|
||||
// to the catalog, so regenerate and review the dialect after changing it.
|
||||
const Major = 17
|
||||
|
||||
// Locate returns the server to generate from, named by MSSQL_SERVER_URI.
|
||||
func Locate() (string, error) {
|
||||
dsn := os.Getenv("MSSQL_SERVER_URI")
|
||||
if dsn == "" {
|
||||
return "", errors.New("MSSQL_SERVER_URI is not set")
|
||||
}
|
||||
if _, err := msdsn.Parse(dsn); err != nil {
|
||||
return "", fmt.Errorf("MSSQL_SERVER_URI: %w", err)
|
||||
}
|
||||
return dsn, nil
|
||||
}
|
||||
|
||||
// open connects to the server and holds one session, since a case's
|
||||
// database is the session's current database and the showplan is a
|
||||
// session setting.
|
||||
func open(ctx context.Context, dsn string) (*sql.Conn, error) {
|
||||
db, err := sql.Open("sqlserver", dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := db.Conn(ctx)
|
||||
if err != nil {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Version reports the release a server is.
|
||||
func Version(ctx context.Context, dsn string) (string, error) {
|
||||
conn, err := open(ctx, dsn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer conn.Close()
|
||||
var v string
|
||||
if err := conn.QueryRowContext(ctx, "SELECT @@VERSION").Scan(&v); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// The first line names the product and build; the rest is the copyright
|
||||
// and the platform.
|
||||
v, _, _ = strings.Cut(v, "\n")
|
||||
return strings.TrimSpace(v), nil
|
||||
}
|
||||
|
||||
// checkVersion refuses a server of another major release than the dialect
|
||||
// is generated from, whose catalog would differ from the committed one
|
||||
// without anything being wrong.
|
||||
func checkVersion(ctx context.Context, conn *sql.Conn) error {
|
||||
var v string
|
||||
if err := conn.QueryRowContext(ctx, "SELECT CAST(SERVERPROPERTY('ProductMajorVersion') AS nvarchar(10))").Scan(&v); err != nil {
|
||||
return err
|
||||
}
|
||||
major, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ProductMajorVersion %q: %w", v, err)
|
||||
}
|
||||
if major != Major {
|
||||
return fmt.Errorf("the dialect is generated from SQL Server major release %d, but the server is release %d", Major, major)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate reads the dialect from the server: relations.jsonl, the views of
|
||||
// sys and INFORMATION_SCHEMA. They are read from a database of their own,
|
||||
// since the views a query sees are the ones a user database has, and
|
||||
// master lists internal views of its own that no query can name.
|
||||
func Generate(ctx context.Context, dsn string) (dialect.Files, error) {
|
||||
conn, err := open(ctx, dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
if err := checkVersion(ctx, conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db := quote("goldeneye_dialect")
|
||||
for _, stmt := range []string{
|
||||
"USE master",
|
||||
"DROP DATABASE IF EXISTS " + db,
|
||||
"CREATE DATABASE " + db,
|
||||
"USE " + db,
|
||||
} {
|
||||
if _, err := conn.ExecContext(ctx, stmt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
defer conn.ExecContext(context.WithoutCancel(ctx), "USE master; DROP DATABASE IF EXISTS "+db)
|
||||
relations, err := readRelations(ctx, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blob, err := dialect.JSONL(relations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dialect.Files{dialect.RelationsFile: blob}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user