Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ go 1.26.0
toolchain go1.26.5

require (
github.com/antlr4-go/antlr/v4 v4.13.1
github.com/cubicdaiya/gonp v1.0.4
github.com/davecgh/go-spew v1.1.1
github.com/fatih/structtag v1.2.0
Expand All @@ -22,6 +21,7 @@ require (
github.com/spf13/pflag v1.0.10
github.com/sqlc-dev/doubleclick v1.0.0
github.com/sqlc-dev/marino v0.1.0
github.com/sqlc-dev/meyer v0.1.1
github.com/sqlc-dev/zetajones v0.1.0
github.com/tetratelabs/wazero v1.12.0
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07
Expand All @@ -36,6 +36,7 @@ require (
require (
cel.dev/expr v0.25.2 // indirect
filippo.io/edwards25519 v1.2.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ github.com/sqlc-dev/doubleclick v1.0.0 h1:2/OApfQ2eLgcfa/Fqs8WSMA6atH0G8j9hHbQIg
github.com/sqlc-dev/doubleclick v1.0.0/go.mod h1:ODHRroSrk/rr5neRHlWMSRijqOak8YmNaO3VAZCNl5Y=
github.com/sqlc-dev/marino v0.1.0 h1:8Fn13vFhx7OUcmDFfRZdf3zARAbNl04Lcy74211ZpIw=
github.com/sqlc-dev/marino v0.1.0/go.mod h1:mQxC2dgDE0DWHMb2B5jZNk7KToJuS6wnxnffBfYnq08=
github.com/sqlc-dev/meyer v0.1.1 h1:BAeZcfgLyTnk9f90DyGEKXPrHxtgvVD/DTM6awq2kUY=
github.com/sqlc-dev/meyer v0.1.1/go.mod h1:pS4USCRf/SLjWtaMcnTo4YrEEFKBj8CyyqlxcVUJQH8=
github.com/sqlc-dev/zetajones v0.1.0 h1:VeG0atx6lNABr9V2bSI5vL9DvOKTHX0XjMqWUE/rv40=
github.com/sqlc-dev/zetajones v0.1.0/go.mod h1:dU1DxwqC6Cahbpnw16KpH1J2waWRDMdwyDSvovMZR4I=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
40 changes: 38 additions & 2 deletions internal/compiler/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ func (c *Compiler) parseCatalog(schemas []string) error {
// but don't update the catalog - the database will be the source of truth
stmts, err := c.parser.Parse(strings.NewReader(contents))
if err != nil {
merr.Add(filename, contents, 0, err)
// A schema file and a query file are often the same file, so a
// query's sqlc syntax can fail here. Look for an explanation
// before reporting the syntax error it caused.
if reported := addSyntaxErrors(merr, filename, contents, preprocess.File(c.conf.Engine, contents)); !reported {
merr.Add(filename, contents, 0, err)
}
continue
}

Expand Down Expand Up @@ -111,7 +116,9 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {

stmts, err := c.parser.Parse(strings.NewReader(pp.Text))
if err != nil {
merr.Add(filename, src, 0, err)
if reported := addSyntaxErrors(merr, filename, src, pp); !reported {
merr.Add(filename, src, 0, err)
}
continue
}
for _, stmt := range stmts {
Expand Down Expand Up @@ -162,3 +169,32 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {
Queries: q,
}, nil
}

// addSyntaxErrors reports every sqlc syntax error the preprocessor recorded
// for a file, in source order, and says whether there were any. Locations come
// back in the rewritten text's coordinates, so they are mapped through Origin
// to point at what the user wrote.
//
// A statement whose sqlc syntax did not validate is copied through for the
// engine to parse, which assumes the engine can parse it. SQLite cannot: it
// has no schema-qualified function call, so a bad sqlc.arg() is a syntax error
// there rather than a call the preprocessor's message can be attached to.
// These messages name the cause, so they are reported in place of the failure
// they produced; anything else wrong with the file surfaces on the next run.
func addSyntaxErrors(merr *multierr.Error, filename, src string, pp *preprocess.Result) bool {
var found bool
for _, stmt := range pp.Statements() {
if stmt.Err == nil {
continue
}
found = true
loc := pp.Origin(stmt.Start)
var e *sqlerr.Error
if errors.As(stmt.Err, &e) && e.Location != 0 {
loc = pp.Origin(e.Location)
e.Location = loc
}
merr.Add(filename, src, loc, stmt.Err)
}
return found
}
31 changes: 27 additions & 4 deletions internal/compiler/output_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"

"github.com/sqlc-dev/sqlc/internal/config"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/astutils"
"github.com/sqlc-dev/sqlc/internal/sql/catalog"
Expand Down Expand Up @@ -69,7 +70,7 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er

if n.GroupClause != nil {
for _, item := range n.GroupClause.Items {
if err := findColumnForNode(item, tables, targets); err != nil {
if err := c.findColumnForNode(item, tables, targets); err != nil {
return nil, err
}
}
Expand All @@ -85,7 +86,7 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er
if !ok {
continue
}
if err := findColumnForNode(sb.Node, tables, targets); err != nil {
if err := c.findColumnForNode(sb.Node, tables, targets); err != nil {
return nil, fmt.Errorf("%v: if you want to skip this validation, set 'strict_order_by' to false", err)
}
}
Expand All @@ -101,7 +102,7 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er
if !ok {
continue
}
if err := findColumnForNode(caseExpr.Xpr, tables, targets); err != nil {
if err := c.findColumnForNode(caseExpr.Xpr, tables, targets); err != nil {
return nil, fmt.Errorf("%v: if you want to skip this validation, set 'strict_order_by' to false", err)
}
}
Expand Down Expand Up @@ -713,14 +714,36 @@ func outputColumnRefs(res *ast.ResTarget, tables []*Table, node *ast.ColumnRef)
return cols, nil
}

func findColumnForNode(item ast.Node, tables []*Table, targetList *ast.List) error {
func (c *Compiler) findColumnForNode(item ast.Node, tables []*Table, targetList *ast.List) error {
ref, ok := item.(*ast.ColumnRef)
if !ok {
return nil
}
if c.isImplicitColumnRef(ref) {
return nil
}
return findColumnForRef(ref, tables, targetList)
}

// isImplicitColumnRef reports whether ref names a column that every table in
// the dialect has without declaring it, and which therefore never appears in
// a catalog built from the schema. SQLite gives each ordinary table a rowid,
// reachable under three spellings.
func (c *Compiler) isImplicitColumnRef(ref *ast.ColumnRef) bool {
if c.conf.Engine != config.EngineSQLite {
return false
}
parts := stringSlice(ref.Fields)
if len(parts) == 0 {
return false
}
switch parts[len(parts)-1] {
case "rowid", "_rowid_", "oid":
return true
}
return false
}

func findColumnForRef(ref *ast.ColumnRef, tables []*Table, targetList *ast.List) error {
parts := stringSlice(ref.Fields)
var alias, name string
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

123 changes: 0 additions & 123 deletions internal/engine/sqlite/analyzer/analyze_test.go

This file was deleted.

4 changes: 0 additions & 4 deletions internal/engine/sqlite/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,3 @@ func NewCatalog() *catalog.Catalog {
Extensions: map[string]struct{}{},
}
}

func newTestCatalog() *catalog.Catalog {
return catalog.New("main")
}
Loading
Loading