Skip to content

Commit

Permalink
fix: check column references in ORDER BY (sqlc-dev#1411)
Browse files Browse the repository at this point in the history
  • Loading branch information
akutschera committed Oct 27, 2022
1 parent 1a28c29 commit 9c8c4b3
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 2 deletions.
37 changes: 35 additions & 2 deletions internal/compiler/output_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,41 @@ func outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, error) {

if n.GroupClause != nil {
for _, item := range n.GroupClause.Items {
ref, ok := item.(*ast.ColumnRef)
if err := findColumnForNode(item, tables, n); err != nil {
return nil, err
}
}
}
if n.SortClause != nil {
for _, item := range n.SortClause.Items {
sb, ok := item.(*ast.SortBy)
if !ok {
continue
}

if err := findColumnForRef(ref, tables, n); err != nil {
if err := findColumnForNode(sb.Node, tables, n); err != nil {
return nil, err
}
}
}
if n.WindowClause != nil {
for _, item := range n.WindowClause.Items {
sb, ok := item.(*ast.List)
if !ok {
continue
}
for _, single := range sb.Items {
caseExpr, ok := single.(*ast.CaseExpr)
if !ok {
continue
}

if err := findColumnForNode(caseExpr.Xpr, tables, n); err != nil {
return nil, err
}
}
}
}

// For UNION queries, targets is empty and we need to look for the
// columns in Largs.
Expand Down Expand Up @@ -516,6 +541,14 @@ func outputColumnRefs(res *ast.ResTarget, tables []*Table, node *ast.ColumnRef)
return cols, nil
}

func findColumnForNode(item ast.Node, tables []*Table, n *ast.SelectStmt) error {
ref, ok := item.(*ast.ColumnRef)
if !ok {
return nil
}
return findColumnForRef(ref, tables, n)
}

func findColumnForRef(ref *ast.ColumnRef, tables []*Table, selectStatement *ast.SelectStmt) error {
parts := stringSlice(ref.Fields)
var alias, name string
Expand Down
104 changes: 104 additions & 0 deletions internal/compiler/parse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package compiler

import (
"fmt"
"strings"
"testing"

"github.com/kyleconroy/sqlc/internal/config"
"github.com/kyleconroy/sqlc/internal/engine/dolphin"
"github.com/kyleconroy/sqlc/internal/engine/postgresql"
"github.com/kyleconroy/sqlc/internal/engine/sqlite"
"github.com/kyleconroy/sqlc/internal/opts"
)

func Test_ParseQueryErrors(t *testing.T) {
for _, tc := range []struct {
name string
engine config.Engine
createStmt string
selectStmt string
parser Parser
wantErr error
}{
{
name: "unreferenced order column postgresql",
engine: config.EnginePostgreSQL,
createStmt: `CREATE TABLE authors (id INT);`,
selectStmt: `SELECT id FROM authors ORDER BY foo;`,
parser: postgresql.NewParser(),
wantErr: fmt.Errorf(`column reference "foo" not found`),
},
{
name: "unreferenced order column mysql",
engine: config.EngineMySQL,
createStmt: `CREATE TABLE authors (id INT);`,
selectStmt: `SELECT id FROM authors ORDER BY foo;`,
parser: dolphin.NewParser(),
wantErr: fmt.Errorf(`column reference "foo" not found`),
},
{
name: "unreferenced order column sqlite",
engine: config.EngineSQLite,
createStmt: `CREATE TABLE authors (id INT);`,
selectStmt: `SELECT id FROM authors ORDER BY foo;`,
parser: sqlite.NewParser(),
wantErr: fmt.Errorf(`column reference "foo" not found`),
},
{
name: "unreferenced group column postgresql",
engine: config.EnginePostgreSQL,
createStmt: `CREATE TABLE authors ( id INT );`,
selectStmt: `SELECT id FROM authors GROUP BY foo;`,
parser: postgresql.NewParser(),
wantErr: fmt.Errorf(`column reference "foo" not found`),
},
{
name: "unreferenced group column mysql",
engine: config.EngineMySQL,
createStmt: `CREATE TABLE authors (id INT);`,
selectStmt: `SELECT id FROM authors GROUP BY foo;`,
parser: dolphin.NewParser(),
wantErr: fmt.Errorf(`column reference "foo" not found`),
},
{
name: "unreferenced group column sqlite",
engine: config.EngineSQLite,
createStmt: `CREATE TABLE authors (id INT);`,
selectStmt: `SELECT id FROM authors GROUP BY foo;`,
parser: sqlite.NewParser(),
wantErr: fmt.Errorf(`column reference "foo" not found`),
},
} {
t.Run(tc.name, func(t *testing.T) {
conf := config.SQL{
Engine: tc.engine,
}
combo := config.CombinedSettings{}
comp := NewCompiler(conf, combo)
stmts, err := tc.parser.Parse(strings.NewReader(tc.createStmt))
if err != nil {
t.Fatalf("cannot parse test catalog: %v", err)
}
err = comp.catalog.Update(stmts[0], comp)
if err != nil {
t.Fatalf("cannot update test catalog: %v", err)
}
stmts, err = tc.parser.Parse(strings.NewReader(tc.selectStmt))
if err != nil {
t.Errorf("Parse failed: %v", err)
}
if len(stmts) != 1 {
t.Errorf("expected one statement, got %d", len(stmts))
}

_, err = comp.parseQuery(stmts[0].Raw, tc.selectStmt, opts.Parser{})
if err == nil {
t.Fatalf("expected parseQuery to return an error, got nil")
}
if err.Error() != tc.wantErr.Error() {
t.Errorf("error message: want %s, got %s", tc.wantErr, err.Error())
}
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Example queries for sqlc
CREATE TABLE authors (
id INT
);

-- name: ListAuthors :many
SELECT id FROM authors
ORDER BY adfadsf;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 1
packages:
- path: "go"
name: "querytest"
engine: "postgresql"
schema: "query.sql"
queries: "query.sql"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# package querytest
query.sql:8:10: column reference "adfadsf" not found

0 comments on commit 9c8c4b3

Please sign in to comment.