From 3d305fa09287cf015aab55990ac66a26869e3675 Mon Sep 17 00:00:00 2001 From: "takeshi.nakata" Date: Wed, 21 Jul 2021 10:57:27 +0900 Subject: [PATCH] feat(spanner/spansql): fix (date|timestamp) comparison parse. This fixes case when query has `date = @date` or `timestamp = @timestamp` case. Since date and timestamp are not reserved keyword, they can be used as ID --- spanner/spansql/parser.go | 12 ++++++++---- spanner/spansql/parser_test.go | 11 +++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/spanner/spansql/parser.go b/spanner/spansql/parser.go index ab3220271d5..10b659a1e84 100644 --- a/spanner/spansql/parser.go +++ b/spanner/spansql/parser.go @@ -2714,11 +2714,15 @@ func (p *parser) parseLit() (Expr, *parseError) { p.back() return p.parseArrayLit() case tok.caseEqual("DATE"): - p.back() - return p.parseDateLit() + if !p.sniff("=") { + p.back() + return p.parseDateLit() + } case tok.caseEqual("TIMESTAMP"): - p.back() - return p.parseTimestampLit() + if !p.sniff("=") { + p.back() + return p.parseTimestampLit() + } } // TODO: struct literals diff --git a/spanner/spansql/parser_test.go b/spanner/spansql/parser_test.go index fd1360c8506..566096380b9 100644 --- a/spanner/spansql/parser_test.go +++ b/spanner/spansql/parser_test.go @@ -250,6 +250,13 @@ func TestParseQuery(t *testing.T) { } func TestParseExpr(t *testing.T) { + timef := func(format, s string) time.Time { + ti, err := time.ParseInLocation(format, string(s), defaultLocation) + if err != nil { + t.Errorf("parsing %s [%s] time.ParseInLocation failed.", s, format) + } + return ti + } tests := []struct { in string want Expr @@ -336,7 +343,11 @@ func TestParseExpr(t *testing.T) { // Date and timestamp literals: {`DATE '2014-09-27'`, DateLiteral(civil.Date{Year: 2014, Month: time.September, Day: 27})}, + {`TIMESTAMP '2014-09-27 12:30:00'`, TimestampLiteral(timef("2006-01-02 15:04:05", "2014-09-27 12:30:00"))}, + // date and timestamp + {`DATE = '2014-09-27'`, ComparisonOp{LHS: ID("DATE"), Op: Eq, RHS: StringLiteral("2014-09-27")}}, + {`TIMESTAMP = '2014-09-27 12:30:00'`, ComparisonOp{LHS: ID("TIMESTAMP"), Op: Eq, RHS: StringLiteral("2014-09-27 12:30:00")}}, // Array literals: // https://cloud.google.com/spanner/docs/lexical#array_literals {`[1, 2, 3]`, Array{IntegerLiteral(1), IntegerLiteral(2), IntegerLiteral(3)}},