Skip to content

Commit

Permalink
feat(spanner/spansql): add support for nullif expressions (#6423)
Browse files Browse the repository at this point in the history
Co-authored-by: rahul2393 <irahul@google.com>
  • Loading branch information
neglect-yp and rahul2393 committed Jul 28, 2022
1 parent 417ef94 commit 5b7bfeb
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 0 deletions.
27 changes: 27 additions & 0 deletions spanner/spansql/parser.go
Expand Up @@ -3044,6 +3044,9 @@ func (p *parser) parseLit() (Expr, *parseError) {
case tok.caseEqual("IFNULL"):
p.back()
return p.parseIfNullExpr()
case tok.caseEqual("NULLIF"):
p.back()
return p.parseNullIfExpr()
}

// Handle typed literals.
Expand Down Expand Up @@ -3210,6 +3213,30 @@ func (p *parser) parseIfNullExpr() (IfNull, *parseError) {
return IfNull{Expr: expr, NullResult: nullResult}, nil
}

func (p *parser) parseNullIfExpr() (NullIf, *parseError) {
if err := p.expect("NULLIF", "("); err != nil {
return NullIf{}, err
}

expr, err := p.parseExpr()
if err != nil {
return NullIf{}, err
}
if err := p.expect(","); err != nil {
return NullIf{}, err
}

exprToMatch, err := p.parseExpr()
if err != nil {
return NullIf{}, err
}
if err := p.expect(")"); err != nil {
return NullIf{}, err
}

return NullIf{Expr: expr, ExprToMatch: exprToMatch}, nil
}

func (p *parser) parseArrayLit() (Array, *parseError) {
// ARRAY keyword is optional.
// TODO: If it is present, consume any <T> after it.
Expand Down
6 changes: 6 additions & 0 deletions spanner/spansql/parser_test.go
Expand Up @@ -446,6 +446,12 @@ func TestParseExpr(t *testing.T) {
NullResult: True,
},
},
{`NULLIF("a", "b")`,
NullIf{
Expr: StringLiteral("a"),
ExprToMatch: StringLiteral("b"),
},
},

// String literal:
// Accept double quote and single quote.
Expand Down
9 changes: 9 additions & 0 deletions spanner/spansql/sql.go
Expand Up @@ -753,6 +753,15 @@ func (in IfNull) addSQL(sb *strings.Builder) {
sb.WriteString(")")
}

func (ni NullIf) SQL() string { return buildSQL(ni) }
func (ni NullIf) addSQL(sb *strings.Builder) {
sb.WriteString("NULLIF(")
ni.Expr.addSQL(sb)
sb.WriteString(", ")
ni.ExprToMatch.addSQL(sb)
sb.WriteString(")")
}

func (b BoolLiteral) SQL() string { return buildSQL(b) }
func (b BoolLiteral) addSQL(sb *strings.Builder) {
if b {
Expand Down
14 changes: 14 additions & 0 deletions spanner/spansql/sql_test.go
Expand Up @@ -685,6 +685,20 @@ func TestSQL(t *testing.T) {
`SELECT IFNULL(10, 0)`,
reparseQuery,
},
{
Query{
Select: Select{
List: []Expr{
NullIf{
Expr: IntegerLiteral(10),
ExprToMatch: IntegerLiteral(0),
},
},
},
},
`SELECT NULLIF(10, 0)`,
reparseQuery,
},
}
for _, test := range tests {
sql := test.data.SQL()
Expand Down
8 changes: 8 additions & 0 deletions spanner/spansql/types.go
Expand Up @@ -760,6 +760,14 @@ type IfNull struct {
func (IfNull) isBoolExpr() {} // possibly bool
func (IfNull) isExpr() {}

type NullIf struct {
Expr Expr
ExprToMatch Expr
}

func (NullIf) isBoolExpr() {} // possibly bool
func (NullIf) isExpr() {}

type BoolLiteral bool

const (
Expand Down

0 comments on commit 5b7bfeb

Please sign in to comment.