Skip to content

Commit ccd0205

Browse files
TOGASHI Tomokiharshachintarahul2393
authored
feat(spanner/spansql): add support for SEQUENCE statements (#8481)
* feat(spanner/spansql): add support for SEQUENCE statements * feat(spanner/spansql): remove using generics for CI env --------- Co-authored-by: Sri Harsha CH <[email protected]> Co-authored-by: rahul2393 <[email protected]>
1 parent c90dd00 commit ccd0205

File tree

5 files changed

+435
-1
lines changed

5 files changed

+435
-1
lines changed

spanner/spansql/parser.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,16 @@ func (p *parser) parseDDLStmt() (DDLStmt, *parseError) {
10581058
return nil, err
10591059
}
10601060
return &DropChangeStream{Name: name, Position: pos}, nil
1061+
case tok.caseEqual("SEQUENCE"):
1062+
var ifExists bool
1063+
if p.eat("IF", "EXISTS") {
1064+
ifExists = true
1065+
}
1066+
name, err := p.parseTableOrIndexOrColumnName()
1067+
if err != nil {
1068+
return nil, err
1069+
}
1070+
return &DropSequence{Name: name, IfExists: ifExists, Position: pos}, nil
10611071
}
10621072
} else if p.sniff("ALTER", "DATABASE") {
10631073
a, err := p.parseAlterDatabase()
@@ -1080,6 +1090,12 @@ func (p *parser) parseDDLStmt() (DDLStmt, *parseError) {
10801090
} else if p.sniff("ALTER", "INDEX") {
10811091
ai, err := p.parseAlterIndex()
10821092
return ai, err
1093+
} else if p.sniff("CREATE", "SEQUENCE") {
1094+
cs, err := p.parseCreateSequence()
1095+
return cs, err
1096+
} else if p.sniff("ALTER", "SEQUENCE") {
1097+
as, err := p.parseAlterSequence()
1098+
return as, err
10831099
}
10841100

10851101
return nil, p.errorf("unknown DDL statement")
@@ -2673,6 +2689,159 @@ func (p *parser) parseAlterIndex() (*AlterIndex, *parseError) {
26732689
return nil, p.errorf("got %q, expected ADD or DROP", tok.value)
26742690
}
26752691

2692+
func (p *parser) parseCreateSequence() (*CreateSequence, *parseError) {
2693+
debugf("parseCreateSequence: %v", p)
2694+
2695+
/*
2696+
CREATE SEQUENCE
2697+
[ IF NOT EXISTS ] sequence_name
2698+
[ OPTIONS ( sequence_options ) ]
2699+
*/
2700+
2701+
if err := p.expect("CREATE"); err != nil {
2702+
return nil, err
2703+
}
2704+
pos := p.Pos()
2705+
if err := p.expect("SEQUENCE"); err != nil {
2706+
return nil, err
2707+
}
2708+
var ifNotExists bool
2709+
if p.eat("IF", "NOT", "EXISTS") {
2710+
ifNotExists = true
2711+
}
2712+
sname, err := p.parseTableOrIndexOrColumnName()
2713+
if err != nil {
2714+
return nil, err
2715+
}
2716+
2717+
cs := &CreateSequence{Name: sname, IfNotExists: ifNotExists, Position: pos}
2718+
2719+
if p.sniff("OPTIONS") {
2720+
cs.Options, err = p.parseSequenceOptions()
2721+
if err != nil {
2722+
return nil, err
2723+
}
2724+
}
2725+
2726+
return cs, nil
2727+
}
2728+
2729+
func (p *parser) parseAlterSequence() (*AlterSequence, *parseError) {
2730+
debugf("parseAlterSequence: %v", p)
2731+
2732+
/*
2733+
ALTER SEQUENCE sequence_name
2734+
SET OPTIONS sequence_options
2735+
*/
2736+
2737+
if err := p.expect("ALTER"); err != nil {
2738+
return nil, err
2739+
}
2740+
pos := p.Pos()
2741+
if err := p.expect("SEQUENCE"); err != nil {
2742+
return nil, err
2743+
}
2744+
sname, err := p.parseTableOrIndexOrColumnName()
2745+
if err != nil {
2746+
return nil, err
2747+
}
2748+
2749+
as := &AlterSequence{Name: sname, Position: pos}
2750+
2751+
tok := p.next()
2752+
if tok.err != nil {
2753+
return nil, tok.err
2754+
}
2755+
switch {
2756+
default:
2757+
return nil, p.errorf("got %q, expected SET", tok.value)
2758+
case tok.caseEqual("SET"):
2759+
options, err := p.parseSequenceOptions()
2760+
if err != nil {
2761+
return nil, err
2762+
}
2763+
as.Alteration = SetSequenceOptions{Options: options}
2764+
return as, nil
2765+
}
2766+
}
2767+
2768+
func (p *parser) parseSequenceOptions() (SequenceOptions, *parseError) {
2769+
debugf("parseSequenceOptions: %v", p)
2770+
2771+
if err := p.expect("OPTIONS", "("); err != nil {
2772+
return SequenceOptions{}, err
2773+
}
2774+
2775+
// We ignore case for the key (because it is easier) but not the value.
2776+
var so SequenceOptions
2777+
for {
2778+
if p.eat("sequence_kind", "=") {
2779+
tok := p.next()
2780+
if tok.err != nil {
2781+
return SequenceOptions{}, tok.err
2782+
}
2783+
if tok.typ != stringToken {
2784+
return SequenceOptions{}, p.errorf("invalid sequence_kind value: %v", tok.value)
2785+
}
2786+
sequenceKind := tok.string
2787+
so.SequenceKind = &sequenceKind
2788+
} else if p.eat("skip_range_min", "=") {
2789+
tok := p.next()
2790+
if tok.err != nil {
2791+
return SequenceOptions{}, tok.err
2792+
}
2793+
if tok.typ != int64Token {
2794+
return SequenceOptions{}, p.errorf("invalid skip_range_min value: %v", tok.value)
2795+
}
2796+
value, err := strconv.Atoi(tok.value)
2797+
if err != nil {
2798+
return SequenceOptions{}, p.errorf("invalid skip_range_min value: %v", tok.value)
2799+
}
2800+
so.SkipRangeMin = &value
2801+
} else if p.eat("skip_range_max", "=") {
2802+
tok := p.next()
2803+
if tok.err != nil {
2804+
return SequenceOptions{}, tok.err
2805+
}
2806+
if tok.typ != int64Token {
2807+
return SequenceOptions{}, p.errorf("invalid skip_range_max value: %v", tok.value)
2808+
}
2809+
value, err := strconv.Atoi(tok.value)
2810+
if err != nil {
2811+
return SequenceOptions{}, p.errorf("invalid skip_range_max value: %v", tok.value)
2812+
}
2813+
so.SkipRangeMax = &value
2814+
} else if p.eat("start_with_counter", "=") {
2815+
tok := p.next()
2816+
if tok.err != nil {
2817+
return SequenceOptions{}, tok.err
2818+
}
2819+
if tok.typ != int64Token {
2820+
return SequenceOptions{}, p.errorf("invalid start_with_counter value: %v", tok.value)
2821+
}
2822+
value, err := strconv.Atoi(tok.value)
2823+
if err != nil {
2824+
return SequenceOptions{}, p.errorf("invalid start_with_counter value: %v", tok.value)
2825+
}
2826+
so.StartWithCounter = &value
2827+
} else {
2828+
tok := p.next()
2829+
return SequenceOptions{}, p.errorf("unknown sequence option: %v", tok.value)
2830+
}
2831+
if p.sniff(")") {
2832+
break
2833+
}
2834+
if !p.eat(",") {
2835+
return SequenceOptions{}, p.errorf("missing ',' in options list")
2836+
}
2837+
}
2838+
if err := p.expect(")"); err != nil {
2839+
return SequenceOptions{}, err
2840+
}
2841+
2842+
return so, nil
2843+
}
2844+
26762845
var baseTypes = map[string]TypeBase{
26772846
"BOOL": Bool,
26782847
"INT64": Int64,

spanner/spansql/parser_test.go

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,20 @@ func TestParseDDL(t *testing.T) {
693693
ALTER INDEX MyFirstIndex ADD STORED COLUMN UpdatedAt;
694694
ALTER INDEX MyFirstIndex DROP STORED COLUMN UpdatedAt;
695695
696+
CREATE SEQUENCE MySequence OPTIONS (
697+
sequence_kind='bit_reversed_positive',
698+
skip_range_min = 1,
699+
skip_range_max = 1000,
700+
start_with_counter = 50
701+
);
702+
ALTER SEQUENCE MySequence SET OPTIONS (
703+
sequence_kind='bit_reversed_positive',
704+
skip_range_min = 1,
705+
skip_range_max = 1000,
706+
start_with_counter = 50
707+
);
708+
DROP SEQUENCE MySequence;
709+
696710
-- Trailing comment at end of file.
697711
`, &DDL{Filename: "filename", List: []DDLStmt{
698712
&CreateTable{
@@ -1119,6 +1133,29 @@ func TestParseDDL(t *testing.T) {
11191133
Alteration: DropStoredColumn{Name: "UpdatedAt"},
11201134
Position: line(106),
11211135
},
1136+
&CreateSequence{
1137+
Name: "MySequence",
1138+
Options: SequenceOptions{
1139+
SequenceKind: stringAddr("bit_reversed_positive"),
1140+
SkipRangeMin: intAddr(1),
1141+
SkipRangeMax: intAddr(1000),
1142+
StartWithCounter: intAddr(50),
1143+
},
1144+
Position: line(108),
1145+
},
1146+
&AlterSequence{
1147+
Name: "MySequence",
1148+
Alteration: SetSequenceOptions{
1149+
Options: SequenceOptions{
1150+
SequenceKind: stringAddr("bit_reversed_positive"),
1151+
SkipRangeMin: intAddr(1),
1152+
SkipRangeMax: intAddr(1000),
1153+
StartWithCounter: intAddr(50),
1154+
},
1155+
},
1156+
Position: line(114),
1157+
},
1158+
&DropSequence{Name: "MySequence", Position: line(120)},
11221159
}, Comments: []*Comment{
11231160
{
11241161
Marker: "#", Start: line(2), End: line(2),
@@ -1154,7 +1191,7 @@ func TestParseDDL(t *testing.T) {
11541191
{Marker: "--", Isolated: true, Start: line(75), End: line(75), Text: []string{"Table has a column with a default value."}},
11551192

11561193
// Comment after everything else.
1157-
{Marker: "--", Isolated: true, Start: line(108), End: line(108), Text: []string{"Trailing comment at end of file."}},
1194+
{Marker: "--", Isolated: true, Start: line(122), End: line(122), Text: []string{"Trailing comment at end of file."}},
11581195
}}},
11591196
// No trailing comma:
11601197
{`ALTER TABLE T ADD COLUMN C2 INT64`, &DDL{Filename: "filename", List: []DDLStmt{
@@ -1610,6 +1647,38 @@ func TestParseDDL(t *testing.T) {
16101647
},
16111648
},
16121649
},
1650+
{
1651+
`CREATE SEQUENCE IF NOT EXISTS sname OPTIONS (sequence_kind='bit_reversed_positive');
1652+
ALTER SEQUENCE sname SET OPTIONS (start_with_counter=1);
1653+
DROP SEQUENCE IF EXISTS sname;`,
1654+
&DDL{
1655+
Filename: "filename",
1656+
List: []DDLStmt{
1657+
&CreateSequence{
1658+
Name: "sname",
1659+
IfNotExists: true,
1660+
Options: SequenceOptions{
1661+
SequenceKind: stringAddr("bit_reversed_positive"),
1662+
},
1663+
Position: line(1),
1664+
},
1665+
&AlterSequence{
1666+
Name: "sname",
1667+
Alteration: SetSequenceOptions{
1668+
Options: SequenceOptions{
1669+
StartWithCounter: intAddr(1),
1670+
},
1671+
},
1672+
Position: line(2),
1673+
},
1674+
&DropSequence{
1675+
Name: "sname",
1676+
IfExists: true,
1677+
Position: line(3),
1678+
},
1679+
},
1680+
},
1681+
},
16131682
}
16141683
for _, test := range tests {
16151684
got, err := ParseDDL("filename", test.in)

spanner/spansql/sql.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,61 @@ func (dsc DropStoredColumn) SQL() string {
459459
return "DROP STORED COLUMN " + dsc.Name.SQL()
460460
}
461461

462+
func (cs CreateSequence) SQL() string {
463+
str := "CREATE SEQUENCE "
464+
if cs.IfNotExists {
465+
str += "IF NOT EXISTS "
466+
}
467+
return str + cs.Name.SQL() + " " + cs.Options.SQL()
468+
}
469+
470+
func (as AlterSequence) SQL() string {
471+
return "ALTER SEQUENCE " + as.Name.SQL() + " " + as.Alteration.SQL()
472+
}
473+
474+
func (sa SetSequenceOptions) SQL() string {
475+
return "SET " + sa.Options.SQL()
476+
}
477+
478+
func (so SequenceOptions) SQL() string {
479+
str := "OPTIONS ("
480+
hasOpt := false
481+
if so.SequenceKind != nil {
482+
hasOpt = true
483+
str += fmt.Sprintf("sequence_kind='%s'", *so.SequenceKind)
484+
}
485+
if so.SkipRangeMin != nil {
486+
if hasOpt {
487+
str += ", "
488+
}
489+
hasOpt = true
490+
str += fmt.Sprintf("skip_range_min=%v", *so.SkipRangeMin)
491+
}
492+
if so.SkipRangeMax != nil {
493+
if hasOpt {
494+
str += ", "
495+
}
496+
hasOpt = true
497+
str += fmt.Sprintf("skip_range_max=%v", *so.SkipRangeMax)
498+
}
499+
if so.StartWithCounter != nil {
500+
if hasOpt {
501+
str += ", "
502+
}
503+
hasOpt = true
504+
str += fmt.Sprintf("start_with_counter=%v", *so.StartWithCounter)
505+
}
506+
return str + ")"
507+
}
508+
509+
func (do DropSequence) SQL() string {
510+
str := "DROP SEQUENCE "
511+
if do.IfExists {
512+
str += "IF EXISTS "
513+
}
514+
return str + do.Name.SQL()
515+
}
516+
462517
func (d *Delete) SQL() string {
463518
return "DELETE FROM " + d.Table.SQL() + " WHERE " + d.Where.SQL()
464519
}

0 commit comments

Comments
 (0)