From 8f84c0aceef9d839e600307d8e0bf812839125b9 Mon Sep 17 00:00:00 2001 From: Andrew Benton Date: Mon, 18 Dec 2023 22:09:12 -0800 Subject: [PATCH] feat(analyzer): Return zero values when encountering unexpected ast nodes This allows users to run generate on any parseable query, even when sqlc doesn't understand it. Closes #2377 --- internal/compiler/analyze.go | 13 -------- internal/compiler/compile.go | 12 +++---- internal/compiler/output_columns.go | 20 ++---------- internal/compiler/parse.go | 2 -- .../testdata/exec_create_table/mysql/db/db.go | 31 +++++++++++++++++++ .../exec_create_table/mysql/db/models.go | 7 +++++ .../mysql/db/mysql.query.sql.go | 19 ++++++++++++ .../exec_create_table/mysql/mysql.query.sql | 2 ++ .../exec_create_table/mysql/mysql.schema.sql | 0 .../exec_create_table/mysql/sqlc.yaml | 8 +++++ .../exec_create_table/postgresql/db/db.go | 31 +++++++++++++++++++ .../exec_create_table/postgresql/db/models.go | 7 +++++ .../postgresql/db/postgresql.query.sql.go | 19 ++++++++++++ .../postgresql/postgresql.query.sql | 2 ++ .../postgresql/postgresql.schema.sql | 0 .../exec_create_table/postgresql/sqlc.yaml | 9 ++++++ .../exec_create_table/sqlite/db/db.go | 31 +++++++++++++++++++ .../exec_create_table/sqlite/db/models.go | 7 +++++ .../sqlite/db/sqlite.query.sql.go | 19 ++++++++++++ .../exec_create_table/sqlite/sqlc.yaml | 8 +++++ .../exec_create_table/sqlite/sqlite.query.sql | 2 ++ .../sqlite/sqlite.schema.sql | 0 .../endtoend/testdata/vet_failures/query.sql | 6 ---- .../endtoend/testdata/vet_failures/sqlc.yaml | 2 +- 24 files changed, 210 insertions(+), 47 deletions(-) create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/db/db.go create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/db/models.go create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/mysql.schema.sql create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/db/db.go create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/db/models.go create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/postgresql.schema.sql create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/db/db.go create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/db/models.go create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/sqlite.schema.sql diff --git a/internal/compiler/analyze.go b/internal/compiler/analyze.go index 82a67fb6f2..38d66fce19 100644 --- a/internal/compiler/analyze.go +++ b/internal/compiler/analyze.go @@ -135,10 +135,6 @@ func (c *Compiler) _analyzeQuery(raw *ast.RawStmt, query string, failfast bool) var table *ast.TableName switch n := raw.Stmt.(type) { - case *ast.CallStmt: - case *ast.SelectStmt: - case *ast.DeleteStmt: - case *ast.DoStmt: case *ast.InsertStmt: if err := check(validate.InsertStmt(n)); err != nil { return nil, err @@ -148,15 +144,6 @@ func (c *Compiler) _analyzeQuery(raw *ast.RawStmt, query string, failfast bool) if err := check(err); err != nil { return nil, err } - case *ast.ListenStmt: - case *ast.NotifyStmt: - case *ast.TruncateStmt: - case *ast.UpdateStmt: - case *ast.RefreshMatViewStmt: - default: - if err := check(ErrUnsupportedStatementType); err != nil { - return nil, err - } } if err := check(validate.FuncCall(c.catalog, c.combo, raw)); err != nil { diff --git a/internal/compiler/compile.go b/internal/compiler/compile.go index 19b737257c..84fbb20a3c 100644 --- a/internal/compiler/compile.go +++ b/internal/compiler/compile.go @@ -79,9 +79,6 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) { } for _, stmt := range stmts { query, err := c.parseQuery(stmt.Raw, src, o) - if err == ErrUnsupportedStatementType { - continue - } if err != nil { var e *sqlerr.Error loc := stmt.Raw.Pos() @@ -95,6 +92,10 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) { } continue } + if query == nil { + continue + } + query.Metadata.Filename = filepath.Base(filename) queryName := query.Metadata.Name if queryName != "" { if _, exists := set[queryName]; exists { @@ -103,10 +104,7 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) { } set[queryName] = struct{}{} } - query.Metadata.Filename = filepath.Base(filename) - if query != nil { - q = append(q, query) - } + q = append(q, query) } } if len(merr.Errs()) > 0 { diff --git a/internal/compiler/output_columns.go b/internal/compiler/output_columns.go index 5b96a08567..dbdbe252b3 100644 --- a/internal/compiler/output_columns.go +++ b/internal/compiler/output_columns.go @@ -57,7 +57,7 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er return nil, err } - var targets *ast.List + targets := &ast.List{} switch n := node.(type) { case *ast.DeleteStmt: targets = n.ReturningList @@ -114,16 +114,8 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er if isUnion { return c.outputColumns(qc, n.Larg) } - case *ast.DoStmt: - targets = &ast.List{} - case *ast.CallStmt: - targets = &ast.List{} - case *ast.TruncateStmt, *ast.RefreshMatViewStmt, *ast.NotifyStmt, *ast.ListenStmt: - targets = &ast.List{} case *ast.UpdateStmt: targets = n.ReturningList - default: - return nil, fmt.Errorf("outputColumns: unsupported node type: %T", n) } var cols []*Column @@ -487,7 +479,7 @@ func (r *tableVisitor) Visit(n ast.Node) astutils.Visitor { // Return an error if a table is referenced twice // Return an error if an unknown column is referenced func (c *Compiler) sourceTables(qc *QueryCatalog, node ast.Node) ([]*Table, error) { - var list *ast.List + list := &ast.List{} switch n := node.(type) { case *ast.DeleteStmt: list = n.Relations @@ -514,14 +506,6 @@ func (c *Compiler) sourceTables(qc *QueryCatalog, node ast.Node) ([]*Table, erro astutils.Walk(&tv, n.FromClause) astutils.Walk(&tv, n.Relations) list = &tv.list - case *ast.DoStmt: - list = &ast.List{} - case *ast.CallStmt: - list = &ast.List{} - case *ast.NotifyStmt, *ast.ListenStmt: - list = &ast.List{} - default: - return nil, fmt.Errorf("sourceTables: unsupported node type: %T", n) } var tables []*Table diff --git a/internal/compiler/parse.go b/internal/compiler/parse.go index b47a72beef..8f47271446 100644 --- a/internal/compiler/parse.go +++ b/internal/compiler/parse.go @@ -15,8 +15,6 @@ import ( "github.com/sqlc-dev/sqlc/internal/sql/validate" ) -var ErrUnsupportedStatementType = errors.New("parseQuery: unsupported statement type") - func (c *Compiler) parseQuery(stmt ast.Node, src string, o opts.Parser) (*Query, error) { ctx := context.Background() diff --git a/internal/endtoend/testdata/exec_create_table/mysql/db/db.go b/internal/endtoend/testdata/exec_create_table/mysql/db/db.go new file mode 100644 index 0000000000..e06d75a08b --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/exec_create_table/mysql/db/models.go b/internal/endtoend/testdata/exec_create_table/mysql/db/models.go new file mode 100644 index 0000000000..477b93130d --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/db/models.go @@ -0,0 +1,7 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 + +package db + +import () diff --git a/internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go b/internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go new file mode 100644 index 0000000000..8dba113e56 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 +// source: mysql.query.sql + +package db + +import ( + "context" +) + +const createTable = `-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL) +` + +func (q *Queries) CreateTable(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, createTable) + return err +} diff --git a/internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql b/internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql new file mode 100644 index 0000000000..0a92ebb9cb --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql @@ -0,0 +1,2 @@ +-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL); diff --git a/internal/endtoend/testdata/exec_create_table/mysql/mysql.schema.sql b/internal/endtoend/testdata/exec_create_table/mysql/mysql.schema.sql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml b/internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml new file mode 100644 index 0000000000..bd888aabfc --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml @@ -0,0 +1,8 @@ +version: 2 +sql: +- queries: mysql.query.sql + schema: mysql.schema.sql + engine: mysql + gen: + go: + out: db diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/db/db.go b/internal/endtoend/testdata/exec_create_table/postgresql/db/db.go new file mode 100644 index 0000000000..e06d75a08b --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/db/models.go b/internal/endtoend/testdata/exec_create_table/postgresql/db/models.go new file mode 100644 index 0000000000..477b93130d --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/db/models.go @@ -0,0 +1,7 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 + +package db + +import () diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go b/internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go new file mode 100644 index 0000000000..24e23cefee --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 +// source: postgresql.query.sql + +package db + +import ( + "context" +) + +const createTable = `-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL) +` + +func (q *Queries) CreateTable(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, createTable) + return err +} diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql b/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql new file mode 100644 index 0000000000..0a92ebb9cb --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql @@ -0,0 +1,2 @@ +-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL); diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.schema.sql b/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.schema.sql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml b/internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml new file mode 100644 index 0000000000..6a89eb2179 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml @@ -0,0 +1,9 @@ +version: 2 +sql: +- queries: postgresql.query.sql + schema: postgresql.schema.sql + engine: postgresql + gen: + go: + out: db + diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/db/db.go b/internal/endtoend/testdata/exec_create_table/sqlite/db/db.go new file mode 100644 index 0000000000..e06d75a08b --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/db/models.go b/internal/endtoend/testdata/exec_create_table/sqlite/db/models.go new file mode 100644 index 0000000000..477b93130d --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/db/models.go @@ -0,0 +1,7 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 + +package db + +import () diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go b/internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go new file mode 100644 index 0000000000..ea8fcafec6 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.24.0 +// source: sqlite.query.sql + +package db + +import ( + "context" +) + +const createTable = `-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL) +` + +func (q *Queries) CreateTable(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, createTable) + return err +} diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml b/internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml new file mode 100644 index 0000000000..bf2e6024b6 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml @@ -0,0 +1,8 @@ +version: 2 +sql: +- queries: sqlite.query.sql + schema: sqlite.schema.sql + engine: sqlite + gen: + go: + out: db diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql b/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql new file mode 100644 index 0000000000..0a92ebb9cb --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql @@ -0,0 +1,2 @@ +-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL); diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.schema.sql b/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.schema.sql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/internal/endtoend/testdata/vet_failures/query.sql b/internal/endtoend/testdata/vet_failures/query.sql index 718f3395c0..75e38b2caf 100644 --- a/internal/endtoend/testdata/vet_failures/query.sql +++ b/internal/endtoend/testdata/vet_failures/query.sql @@ -1,9 +1,3 @@ -CREATE TABLE authors ( - id BIGSERIAL PRIMARY KEY, - name text NOT NULL, - bio text -); - -- name: GetAuthor :one SELECT * FROM authors WHERE id = $1 LIMIT 1; diff --git a/internal/endtoend/testdata/vet_failures/sqlc.yaml b/internal/endtoend/testdata/vet_failures/sqlc.yaml index 10d5246f8b..b1cff78c30 100644 --- a/internal/endtoend/testdata/vet_failures/sqlc.yaml +++ b/internal/endtoend/testdata/vet_failures/sqlc.yaml @@ -1,6 +1,6 @@ version: 2 sql: - - schema: "query.sql" + - schema: "schema.sql" queries: "query.sql" engine: "postgresql" gen: