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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Improve nullability evaluation
This now supports evaluating nullability if subqueries, function-defined
tables or sqlc.embed macros are involved.
If nullable embeds are generated, this now errors out instead of
emitting code which breaks at runtime.

Generating correct type definitions for that case would be easy, but
scanning data into embed pointers is hard as it would require "peeking"
at row nullability to decide if the type should be allocated and scanned
into. Otherwise the null columns need to be directed into some kind
of sink. Because this is nontrivial to do this is not part of this PR.
  • Loading branch information
lorenz committed Oct 15, 2023
commit 698c4718565e71600d273c50b65cafa8d9c18f62
6 changes: 5 additions & 1 deletion internal/codegen/golang/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,11 @@ func columnsToStruct(req *plugin.CodeGenRequest, options *opts, name string, col
if c.embed == nil {
f.Type = goType(req, options, c.Column)
} else {
f.Type = c.embed.modelType
if c.NotNull {
f.Type = c.embed.modelType
} else {
return nil, fmt.Errorf("embedded macro for %q is nullable, this is currently unsupported", c.embed.modelName)
}
f.EmbedFields = c.embed.fields
}

Expand Down
27 changes: 24 additions & 3 deletions internal/compiler/output_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er
cols = append(cols, &Column{
Name: embed.Table.Name,
EmbedTable: embed.Table,
// In general, embeds should not be nullable.
// If joins require them to be, this will be overriden
// later on.
NotNull: true,
})
continue
}
Expand Down Expand Up @@ -399,7 +403,7 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er

if n, ok := node.(*ast.SelectStmt); ok {
for _, col := range cols {
if !col.NotNull || col.Table == nil || col.skipTableRequiredCheck {
if !col.NotNull || col.skipTableRequiredCheck {
continue
}
for _, f := range n.FromClause.Items {
Expand All @@ -423,10 +427,27 @@ const (
func isTableRequired(n ast.Node, col *Column, prior int) int {
switch n := n.(type) {
case *ast.RangeVar:
if n.Alias == nil && *n.Relname == col.Table.Name {
var tblName string
if col.Table != nil {
tblName = col.Table.Name
} else if col.EmbedTable != nil {
tblName = col.EmbedTable.Name
}
if tblName == "" {
return tableNotFound
}
if n.Alias == nil && *n.Relname == tblName {
return prior
}
if n.Alias != nil && *n.Alias.Aliasname == col.TableAlias && *n.Relname == tblName {
return prior
}
case *ast.RangeSubselect:
if n.Alias != nil && n.Alias.Aliasname != nil && *n.Alias.Aliasname == col.TableAlias {
return prior
}
if n.Alias != nil && *n.Alias.Aliasname == col.TableAlias && *n.Relname == col.Table.Name {
case *ast.RangeFunction:
if n.Alias != nil && n.Alias.Aliasname != nil && *n.Alias.Aliasname == col.TableAlias {
return prior
}
case *ast.JoinExpr:
Expand Down