Skip to content
Closed
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 examples/booktest/postgresql/query.sql.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ WHERE tags && ?::varchar[]
data class BooksByTagsRow (
val bookId: Int,
val title: String,
val name: String,
val name: String?,
val isbn: String,
val tags: List<String>
)
Expand Down
56 changes: 56 additions & 0 deletions internal/compiler/output_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package compiler
import (
"errors"
"fmt"
"github.com/lfittl/pg_query_go/nodes"

"github.com/kyleconroy/sqlc/internal/sql/ast"
"github.com/kyleconroy/sqlc/internal/sql/astutils"
Expand Down Expand Up @@ -199,9 +200,64 @@ func outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, error) {

}
}

// On certain join types (e.g. JOIN_LEFT, JOIN_FULL, JOIN_RIGHT)
// the referred joins may be null, thus we may have to adapt the appropriate
// join items to be nullable.
// See: https://github.com/kyleconroy/sqlc/issues/604
if rangeVarJoin := primaryRangeVarJoin(node); rangeVarJoin != nil {
for _, col := range cols {
col.NotNull = col.NotNull && col.Table.Name == *rangeVarJoin.Relname
}
}

return cols, nil
}

// Return the primary range var from a from clause, e.g. RangeVar of "foo" in:
// SELECT f.id, b.id FROM foo f LEFT JOIN bar b ON b.foo_id = f.id
func primaryRangeVarJoin(node ast.Node) *ast.RangeVar {
if n, ok := node.(*ast.SelectStmt); ok {
for _, fi := range n.FromClause.Items {
if j, ok := fi.(*ast.JoinExpr); ok {
return primaryRangeVar(j)
}
}
}

return nil
}

// Return the primary range var from a from clause, e.g. RangeVar of "foo" in:
// SELECT f.id, b.id FROM foo f LEFT JOIN bar b ON b.foo_id = f.id
func primaryRangeVar(j *ast.JoinExpr) *ast.RangeVar {
if rangeVar, ok := j.Larg.(*ast.RangeVar); ok && isNullableJoinType(j) {
return rangeVar
} else if !isNullableJoinType(j) {
// there may be a nullable join expr on larg
if je, ok := j.Larg.(*ast.JoinExpr); ok {
return primaryRangeVar(je)
}
return nil
}

l, _ := j.Larg.(*ast.JoinExpr)
return primaryRangeVar(l)
}

// Return true, if JoinExpr is a nullable join expression
func isNullableJoinType(j *ast.JoinExpr) bool {
nullableJoinTypes := []pg_query.JoinType{pg_query.JOIN_LEFT, pg_query.JOIN_FULL, pg_query.JOIN_RIGHT}

for _, nj := range nullableJoinTypes {
if uint(j.Jointype) == uint(nj) {
return true
}
}

return false
}

// Compute the output columns for a statement.
//
// Return an error if column references are ambiguous
Expand Down
29 changes: 29 additions & 0 deletions internal/endtoend/testdata/join_nullable/mysql/go/db.go

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

16 changes: 16 additions & 0 deletions internal/endtoend/testdata/join_nullable/mysql/go/models.go

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

45 changes: 45 additions & 0 deletions internal/endtoend/testdata/join_nullable/mysql/go/query.sql.go

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

8 changes: 8 additions & 0 deletions internal/endtoend/testdata/join_nullable/mysql/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE foo (id serial not null, bar_id int references bar(id));
CREATE TABLE bar (id serial not null);

-- name: NullableJoin :many
SELECT f.id, f.bar_id, b.id
FROM foo f
FULL OUTER JOIN bar b ON b.id = f.bar_id
WHERE f.id = $1;
12 changes: 12 additions & 0 deletions internal/endtoend/testdata/join_nullable/mysql/sqlc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "1",
"packages": [
{
"path": "go",
"engine": "postgresql",
"name": "querytest",
"schema": "query.sql",
"queries": "query.sql"
}
]
}
29 changes: 29 additions & 0 deletions internal/endtoend/testdata/join_nullable/postgresql/go/db.go

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

16 changes: 16 additions & 0 deletions internal/endtoend/testdata/join_nullable/postgresql/go/models.go

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

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

8 changes: 8 additions & 0 deletions internal/endtoend/testdata/join_nullable/postgresql/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE foo (id serial not null, bar_id int references bar(id));
CREATE TABLE bar (id serial not null);

-- name: NullableJoin :many
SELECT f.id, f.bar_id, b.id
FROM foo f
FULL OUTER JOIN bar b ON b.id = f.bar_id
WHERE f.id = $1;
12 changes: 12 additions & 0 deletions internal/endtoend/testdata/join_nullable/postgresql/sqlc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "1",
"packages": [
{
"path": "go",
"engine": "postgresql",
"name": "querytest",
"schema": "query.sql",
"queries": "query.sql"
}
]
}
29 changes: 29 additions & 0 deletions internal/endtoend/testdata/join_nullable02/mysql/go/db.go

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

22 changes: 22 additions & 0 deletions internal/endtoend/testdata/join_nullable02/mysql/go/models.go

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

Loading