spanner/spansql: parse OPTIONS of column definition in DDL. Fixes #1693
Add parse `option_def` such as `OPTIONS (allow_commit_timestamp = {true | null})`.
ref. cloud.google.com/spanner/docs/data-definition-language
Change-Id: Icefe76d3da11842f76ea983afc349bf6fc87cecd
Reviewed-on: https://code-review.googlesource.com/c/gocloud/+/46390
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: David Symonds <dsymonds@golang.org>
diff --git a/spanner/spansql/parser.go b/spanner/spansql/parser.go
index 75a3381..801770b 100644
--- a/spanner/spansql/parser.go
+++ b/spanner/spansql/parser.go
@@ -1021,20 +1021,54 @@
return ColumnDef{}, err
}
- tok := p.next()
- if tok.err != nil || tok.value != "NOT" {
- // End of the column_def.
- p.back()
- return cd, nil
+ if p.eat("NOT", "NULL") {
+ cd.NotNull = true
}
- if err := p.expect("NULL"); err != nil {
- return ColumnDef{}, err
+
+ if p.eat("OPTIONS") {
+ if cd.AllowCommitTimestamp, err = p.parseColumnOptions(); err != nil {
+ return ColumnDef{}, err
+ }
}
- cd.NotNull = true
return cd, nil
}
+// parseColumnOptions returns allow_commit_timestamp.
+func (p *parser) parseColumnOptions() (allowCommitTimestamp *bool, err error) {
+ debugf("parseColumnOptions: %v", p)
+ /*
+ options_def:
+ OPTIONS (allow_commit_timestamp = { true | null })
+ */
+
+ if err = p.expect("("); err != nil {
+ return nil, err
+ }
+
+ if p.eat("allow_commit_timestamp", "=") {
+ tok := p.next()
+ if tok.err != nil {
+ return nil, tok.err
+ }
+ allowCommitTimestamp = new(bool)
+ switch tok.value {
+ case "true":
+ *allowCommitTimestamp = true
+ case "null":
+ *allowCommitTimestamp = false
+ default:
+ return nil, p.errorf("got %q, want true or null", tok.value)
+ }
+ }
+
+ if err := p.expect(")"); err != nil {
+ return nil, err
+ }
+
+ return
+}
+
func (p *parser) parseKeyPartList() ([]KeyPart, error) {
var list []KeyPart
err := p.parseCommaList(func(p *parser) error {
diff --git a/spanner/spansql/parser_test.go b/spanner/spansql/parser_test.go
index 078e319..777f929 100644
--- a/spanner/spansql/parser_test.go
+++ b/spanner/spansql/parser_test.go
@@ -219,7 +219,8 @@
System STRING(MAX) NOT NULL, # This is a comment.
RepoPath STRING(MAX) NOT NULL, -- This is another comment.
Count INT64, /* This is a
- * multiline comment. */
+ * multiline comment. */
+ UpdatedAt TIMESTAMP OPTIONS (allow_commit_timestamp = true),
) PRIMARY KEY(System, RepoPath);
CREATE UNIQUE INDEX MyFirstIndex ON FooBar (
Count DESC
@@ -250,6 +251,7 @@
{Name: "System", Type: Type{Base: String, Len: MaxLen}, NotNull: true},
{Name: "RepoPath", Type: Type{Base: String, Len: MaxLen}, NotNull: true},
{Name: "Count", Type: Type{Base: Int64}},
+ {Name: "UpdatedAt", Type: Type{Base: Timestamp}, AllowCommitTimestamp: boolAddr(true)},
},
PrimaryKey: []KeyPart{
{Column: "System"},
diff --git a/spanner/spansql/sql.go b/spanner/spansql/sql.go
index a9d9072..5390c4a 100644
--- a/spanner/spansql/sql.go
+++ b/spanner/spansql/sql.go
@@ -111,6 +111,13 @@
if cd.NotNull {
str += " NOT NULL"
}
+ if cd.Type.Base == Timestamp && cd.AllowCommitTimestamp != nil {
+ if *cd.AllowCommitTimestamp {
+ str += " OPTIONS (allow_commit_timestamp = true)"
+ } else {
+ str += " OPTIONS (allow_commit_timestamp = null)"
+ }
+ }
return str
}
diff --git a/spanner/spansql/sql_test.go b/spanner/spansql/sql_test.go
index 46d4c99..394150c 100644
--- a/spanner/spansql/sql_test.go
+++ b/spanner/spansql/sql_test.go
@@ -21,6 +21,10 @@
"testing"
)
+func boolAddr(b bool) *bool {
+ return &b
+}
+
func TestSQL(t *testing.T) {
reparseDDL := func(s string) (interface{}, error) {
ddl, err := ParseDDLStmt(s)
@@ -52,9 +56,10 @@
{Name: "Cf", Type: Type{Base: Bytes, Len: 4711}},
{Name: "Cg", Type: Type{Base: Bytes, Len: MaxLen}},
{Name: "Ch", Type: Type{Base: Date}},
- {Name: "Ci", Type: Type{Base: Timestamp}},
+ {Name: "Ci", Type: Type{Base: Timestamp}, AllowCommitTimestamp: boolAddr(true)},
{Name: "Cj", Type: Type{Array: true, Base: Int64}},
{Name: "Ck", Type: Type{Array: true, Base: String, Len: MaxLen}},
+ {Name: "Cl", Type: Type{Base: Timestamp}, AllowCommitTimestamp: boolAddr(false)},
},
PrimaryKey: []KeyPart{
{Column: "Ca"},
@@ -70,9 +75,10 @@
Cf BYTES(4711),
Cg BYTES(MAX),
Ch DATE,
- Ci TIMESTAMP,
+ Ci TIMESTAMP OPTIONS (allow_commit_timestamp = true),
Cj ARRAY<INT64>,
Ck ARRAY<STRING(MAX)>,
+ Cl TIMESTAMP OPTIONS (allow_commit_timestamp = null),
) PRIMARY KEY(Ca, Cb DESC)`,
reparseDDL,
},
diff --git a/spanner/spansql/types.go b/spanner/spansql/types.go
index ff7da97..21ff143 100644
--- a/spanner/spansql/types.go
+++ b/spanner/spansql/types.go
@@ -100,6 +100,12 @@
Name string
Type Type
NotNull bool
+
+ // AllowCommitTimestamp represents a column OPTIONS.
+ // `true` if query is `OPTIONS (allow_commit_timestamp = true)`
+ // `false` if query is `OPTIONS (allow_commit_timestamp = null)`
+ // `nil` if there are no OPTIONS
+ AllowCommitTimestamp *bool
}
// Type represents a column type.