Skip to content

Commit 49c19a9

Browse files
feat(spanner/spansql): support DEFAULT keyword (#5932)
* feat(spanner/spansql): support DEFAULT keyword * refactor(spanner/spansql): update column def spec * refactor(spanner/spansql): fix receiver names Co-authored-by: rahul2393 <rahulyadavsep92@gmail.com>
1 parent bca8d50 commit 49c19a9

6 files changed

Lines changed: 166 additions & 3 deletions

File tree

spanner/spannertest/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ by ascending esotericism:
2323
- more aggregation functions
2424
- SELECT HAVING
2525
- more literal types
26+
- DEFAULT
2627
- expressions that return null for generated columns
2728
- generated columns referencing other generated columns
2829
- checking dependencies on a generated column before deleting a column

spanner/spansql/parser.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,7 +1528,7 @@ func (p *parser) parseColumnDef() (ColumnDef, *parseError) {
15281528

15291529
/*
15301530
column_def:
1531-
column_name {scalar_type | array_type} [NOT NULL] [AS ( expression ) STORED] [options_def]
1531+
column_name {scalar_type | array_type} [NOT NULL] [{DEFAULT ( expression ) | AS ( expression ) STORED}] [options_def]
15321532
*/
15331533

15341534
name, err := p.parseTableOrIndexOrColumnName()
@@ -1547,6 +1547,16 @@ func (p *parser) parseColumnDef() (ColumnDef, *parseError) {
15471547
cd.NotNull = true
15481548
}
15491549

1550+
if p.eat("DEFAULT", "(") {
1551+
cd.Default, err = p.parseExpr()
1552+
if err != nil {
1553+
return ColumnDef{}, err
1554+
}
1555+
if err := p.expect(")"); err != nil {
1556+
return ColumnDef{}, err
1557+
}
1558+
}
1559+
15501560
if p.eat("AS", "(") {
15511561
cd.Generated, err = p.parseExpr()
15521562
if err != nil {
@@ -1573,9 +1583,29 @@ func (p *parser) parseColumnDef() (ColumnDef, *parseError) {
15731583
func (p *parser) parseColumnAlteration() (ColumnAlteration, *parseError) {
15741584
debugf("parseColumnAlteration: %v", p)
15751585
/*
1576-
{ data_type } [ NOT NULL ] | SET [ options_def ]
1586+
{
1587+
data_type [ NOT NULL ] [ DEFAULT ( expression ) ]
1588+
| SET ( options_def )
1589+
| SET DEFAULT ( expression )
1590+
| DROP DEFAULT
1591+
}
15771592
*/
15781593

1594+
if p.eat("SET", "DEFAULT", "(") {
1595+
d, err := p.parseExpr()
1596+
if err != nil {
1597+
return nil, err
1598+
}
1599+
if err := p.expect(")"); err != nil {
1600+
return nil, err
1601+
}
1602+
return SetDefault{Default: d}, nil
1603+
}
1604+
1605+
if p.eat("DROP", "DEFAULT") {
1606+
return DropDefault{}, nil
1607+
}
1608+
15791609
if p.eat("SET") {
15801610
co, err := p.parseColumnOptions()
15811611
if err != nil {
@@ -1594,6 +1624,16 @@ func (p *parser) parseColumnAlteration() (ColumnAlteration, *parseError) {
15941624
sct.NotNull = true
15951625
}
15961626

1627+
if p.eat("DEFAULT", "(") {
1628+
sct.Default, err = p.parseExpr()
1629+
if err != nil {
1630+
return nil, err
1631+
}
1632+
if err := p.expect(")"); err != nil {
1633+
return nil, err
1634+
}
1635+
}
1636+
15971637
return sct, nil
15981638
}
15991639

spanner/spansql/parser_test.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,16 @@ func TestParseDDL(t *testing.T) {
552552
shard_id INT64 AS (MOD(FARM_FINGERPRINT(user_id), 19)) STORED,
553553
) PRIMARY KEY(user_id);
554554
555+
-- Table has a column with a default value.
556+
CREATE TABLE DefaultCol (
557+
Name STRING(MAX) NOT NULL,
558+
Age INT64 DEFAULT (0),
559+
) PRIMARY KEY (Name);
560+
561+
ALTER TABLE DefaultCol ALTER COLUMN Age DROP DEFAULT;
562+
ALTER TABLE DefaultCol ALTER COLUMN Age SET DEFAULT (0);
563+
ALTER TABLE DefaultCol ALTER COLUMN Age STRING(MAX) DEFAULT ("0");
564+
555565
-- Trailing comment at end of file.
556566
`, &DDL{Filename: "filename", List: []DDLStmt{
557567
&CreateTable{
@@ -795,6 +805,49 @@ func TestParseDDL(t *testing.T) {
795805
PrimaryKey: []KeyPart{{Column: "user_id"}},
796806
Position: line(66),
797807
},
808+
809+
&CreateTable{
810+
Name: "DefaultCol",
811+
Columns: []ColumnDef{
812+
{Name: "Name", Type: Type{Base: String, Len: MaxLen}, NotNull: true, Position: line(77)},
813+
{
814+
Name: "Age", Type: Type{Base: Int64},
815+
Default: IntegerLiteral(0),
816+
Position: line(78),
817+
},
818+
},
819+
PrimaryKey: []KeyPart{{Column: "Name"}},
820+
Position: line(76),
821+
},
822+
&AlterTable{
823+
Name: "DefaultCol",
824+
Alteration: AlterColumn{
825+
Name: "Age",
826+
Alteration: DropDefault{},
827+
},
828+
Position: line(81),
829+
},
830+
&AlterTable{
831+
Name: "DefaultCol",
832+
Alteration: AlterColumn{
833+
Name: "Age",
834+
Alteration: SetDefault{
835+
Default: IntegerLiteral(0),
836+
},
837+
},
838+
Position: line(82),
839+
},
840+
&AlterTable{
841+
Name: "DefaultCol",
842+
Alteration: AlterColumn{
843+
Name: "Age",
844+
Alteration: SetColumnType{
845+
Type: Type{Base: String, Len: MaxLen},
846+
Default: StringLiteral("0"),
847+
},
848+
},
849+
Position: line(83),
850+
},
798851
}, Comments: []*Comment{
799852
{Marker: "#", Start: line(2), End: line(2),
800853
Text: []string{"This is a comment."}},
@@ -815,9 +868,10 @@ func TestParseDDL(t *testing.T) {
815868

816869
{Marker: "--", Isolated: true, Start: line(43), End: line(43), Text: []string{"Table with generated column."}},
817870
{Marker: "--", Isolated: true, Start: line(49), End: line(49), Text: []string{"Table with row deletion policy."}},
871+
{Marker: "--", Isolated: true, Start: line(75), End: line(75), Text: []string{"Table has a column with a default value."}},
818872

819873
// Comment after everything else.
820-
{Marker: "--", Isolated: true, Start: line(75), End: line(75), Text: []string{"Trailing comment at end of file."}},
874+
{Marker: "--", Isolated: true, Start: line(85), End: line(85), Text: []string{"Trailing comment at end of file."}},
821875
}}},
822876
// No trailing comma:
823877
{`ALTER TABLE T ADD COLUMN C2 INT64`, &DDL{Filename: "filename", List: []DDLStmt{

spanner/spansql/sql.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ func (sct SetColumnType) SQL() string {
162162
if sct.NotNull {
163163
str += " NOT NULL"
164164
}
165+
if sct.Default != nil {
166+
str += " DEFAULT (" + sct.Default.SQL() + ")"
167+
}
165168
return str
166169
}
167170

@@ -170,6 +173,14 @@ func (sco SetColumnOptions) SQL() string {
170173
return "SET " + sco.Options.SQL()
171174
}
172175

176+
func (sd SetDefault) SQL() string {
177+
return "SET DEFAULT (" + sd.Default.SQL() + ")"
178+
}
179+
180+
func (dp DropDefault) SQL() string {
181+
return "DROP DEFAULT"
182+
}
183+
173184
func (co ColumnOptions) SQL() string {
174185
str := "OPTIONS ("
175186
if co.AllowCommitTimestamp != nil {
@@ -254,6 +265,9 @@ func (cd ColumnDef) SQL() string {
254265
if cd.NotNull {
255266
str += " NOT NULL"
256267
}
268+
if cd.Default != nil {
269+
str += " DEFAULT (" + cd.Default.SQL() + ")"
270+
}
257271
if cd.Generated != nil {
258272
str += " AS (" + cd.Generated.SQL() + ") STORED"
259273
}

spanner/spansql/sql_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func TestSQL(t *testing.T) {
8585
{Name: "Cl", Type: Type{Base: Timestamp}, Options: ColumnOptions{AllowCommitTimestamp: boolAddr(false)}, Position: line(13)},
8686
{Name: "Cm", Type: Type{Base: Int64}, Generated: Func{Name: "CHAR_LENGTH", Args: []Expr{ID("Ce")}}, Position: line(14)},
8787
{Name: "Cn", Type: Type{Base: JSON}, Position: line(15)},
88+
{Name: "Co", Type: Type{Base: Int64}, Default: IntegerLiteral(1), Position: line(16)},
8889
},
8990
PrimaryKey: []KeyPart{
9091
{Column: "Ca"},
@@ -107,6 +108,7 @@ func TestSQL(t *testing.T) {
107108
Cl TIMESTAMP OPTIONS (allow_commit_timestamp = null),
108109
Cm INT64 AS (CHAR_LENGTH(Ce)) STORED,
109110
Cn JSON,
111+
Co INT64 DEFAULT (1),
110112
) PRIMARY KEY(Ca, Cb DESC)`,
111113
reparseDDL,
112114
},
@@ -266,6 +268,22 @@ func TestSQL(t *testing.T) {
266268
"ALTER TABLE Ta ALTER COLUMN Cg STRING(MAX)",
267269
reparseDDL,
268270
},
271+
{
272+
&AlterTable{
273+
Name: "Ta",
274+
Alteration: AlterColumn{
275+
Name: "Ch",
276+
Alteration: SetColumnType{
277+
Type: Type{Base: String, Len: MaxLen},
278+
NotNull: true,
279+
Default: StringLiteral("1"),
280+
},
281+
},
282+
Position: line(1),
283+
},
284+
"ALTER TABLE Ta ALTER COLUMN Ch STRING(MAX) NOT NULL DEFAULT (\"1\")",
285+
reparseDDL,
286+
},
269287
{
270288
&AlterTable{
271289
Name: "Ta",
@@ -282,6 +300,32 @@ func TestSQL(t *testing.T) {
282300
"ALTER TABLE Ta ALTER COLUMN Ci SET OPTIONS (allow_commit_timestamp = null)",
283301
reparseDDL,
284302
},
303+
{
304+
&AlterTable{
305+
Name: "Ta",
306+
Alteration: AlterColumn{
307+
Name: "Cj",
308+
Alteration: SetDefault{
309+
Default: StringLiteral("1"),
310+
},
311+
},
312+
Position: line(1),
313+
},
314+
"ALTER TABLE Ta ALTER COLUMN Cj SET DEFAULT (\"1\")",
315+
reparseDDL,
316+
},
317+
{
318+
&AlterTable{
319+
Name: "Ta",
320+
Alteration: AlterColumn{
321+
Name: "Ck",
322+
Alteration: DropDefault{},
323+
},
324+
Position: line(1),
325+
},
326+
"ALTER TABLE Ta ALTER COLUMN Ck DROP DEFAULT",
327+
reparseDDL,
328+
},
285329
{
286330
&AlterTable{
287331
Name: "WithRowDeletionPolicy",

spanner/spansql/types.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,14 +235,23 @@ type ColumnAlteration interface {
235235

236236
func (SetColumnType) isColumnAlteration() {}
237237
func (SetColumnOptions) isColumnAlteration() {}
238+
func (SetDefault) isColumnAlteration() {}
239+
func (DropDefault) isColumnAlteration() {}
238240

239241
type SetColumnType struct {
240242
Type Type
241243
NotNull bool
244+
Default Expr
242245
}
243246

244247
type SetColumnOptions struct{ Options ColumnOptions }
245248

249+
type SetDefault struct {
250+
Default Expr
251+
}
252+
253+
type DropDefault struct{}
254+
246255
type OnDelete int
247256

248257
const (
@@ -320,6 +329,7 @@ type ColumnDef struct {
320329
Type Type
321330
NotNull bool
322331

332+
Default Expr // set if this column has a default value
323333
Generated Expr // set of this is a generated column
324334

325335
Options ColumnOptions

0 commit comments

Comments
 (0)