Skip to content

Commit

Permalink
feat(spanner/spansql): add support for foreign key actions (#8296)
Browse files Browse the repository at this point in the history
Co-authored-by: rahul2393 <irahul@google.com>
  • Loading branch information
toga4 and rahul2393 committed Jul 24, 2023
1 parent 432864c commit d78b851
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 1 deletion.
10 changes: 9 additions & 1 deletion spanner/spansql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2227,7 +2227,7 @@ func (p *parser) parseForeignKey() (ForeignKey, *parseError) {

/*
foreign_key:
FOREIGN KEY ( column_name [, ... ] ) REFERENCES ref_table ( ref_column [, ... ] )
FOREIGN KEY ( column_name [, ... ] ) REFERENCES ref_table ( ref_column [, ... ] ) [ ON DELETE { CASCADE | NO ACTION } ]
*/

if err := p.expect("FOREIGN"); err != nil {
Expand All @@ -2253,6 +2253,14 @@ func (p *parser) parseForeignKey() (ForeignKey, *parseError) {
if err != nil {
return ForeignKey{}, err
}
// The ON DELETE clause is optional; it defaults to NoActionOnDelete.
fk.OnDelete = NoActionOnDelete
if p.eat("ON", "DELETE") {
fk.OnDelete, err = p.parseOnDelete()
if err != nil {
return ForeignKey{}, err
}
}
return fk, nil
}

Expand Down
53 changes: 53 additions & 0 deletions spanner/spansql/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,59 @@ func TestParseDDL(t *testing.T) {
},
},
},
{
`CREATE TABLE tname1 (col1 INT64, col2 INT64, CONSTRAINT con1 FOREIGN KEY (col2) REFERENCES tname2 (col3) ON DELETE CASCADE) PRIMARY KEY (col1);
CREATE TABLE tname1 (col1 INT64, col2 INT64, CONSTRAINT con1 FOREIGN KEY (col2) REFERENCES tname2 (col3) ON DELETE NO ACTION) PRIMARY KEY (col1);
ALTER TABLE tname1 ADD CONSTRAINT con1 FOREIGN KEY (col2) REFERENCES tname2 (col3) ON DELETE CASCADE;
ALTER TABLE tname1 ADD CONSTRAINT con1 FOREIGN KEY (col2) REFERENCES tname2 (col3) ON DELETE NO ACTION;`,
&DDL{
Filename: "filename",
List: []DDLStmt{
&CreateTable{
Name: "tname1",
Columns: []ColumnDef{
{Name: "col1", Type: Type{Base: Int64}, Position: line(1)},
{Name: "col2", Type: Type{Base: Int64}, Position: line(1)},
},
Constraints: []TableConstraint{
{Name: "con1", Constraint: ForeignKey{Columns: []ID{"col2"}, RefTable: "tname2", RefColumns: []ID{"col3"}, OnDelete: CascadeOnDelete, Position: line(1)}, Position: line(1)},
},
PrimaryKey: []KeyPart{
{Column: "col1"},
},
Position: line(1),
},
&CreateTable{
Name: "tname1",
Columns: []ColumnDef{
{Name: "col1", Type: Type{Base: Int64}, Position: line(2)},
{Name: "col2", Type: Type{Base: Int64}, Position: line(2)},
},
Constraints: []TableConstraint{
{Name: "con1", Constraint: ForeignKey{Columns: []ID{"col2"}, RefTable: "tname2", RefColumns: []ID{"col3"}, OnDelete: NoActionOnDelete, Position: line(2)}, Position: line(2)},
},
PrimaryKey: []KeyPart{
{Column: "col1"},
},
Position: line(2),
},
&AlterTable{
Name: "tname1",
Alteration: AddConstraint{
Constraint: TableConstraint{Name: "con1", Constraint: ForeignKey{Columns: []ID{"col2"}, RefTable: "tname2", RefColumns: []ID{"col3"}, OnDelete: CascadeOnDelete, Position: line(3)}, Position: line(3)},
},
Position: line(3),
},
&AlterTable{
Name: "tname1",
Alteration: AddConstraint{
Constraint: TableConstraint{Name: "con1", Constraint: ForeignKey{Columns: []ID{"col2"}, RefTable: "tname2", RefColumns: []ID{"col3"}, OnDelete: NoActionOnDelete, Position: line(4)}, Position: line(4)},
},
Position: line(4),
},
},
},
},
}
for _, test := range tests {
got, err := ParseDDL("filename", test.in)
Expand Down
1 change: 1 addition & 0 deletions spanner/spansql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ func (fk ForeignKey) SQL() string {
str := "FOREIGN KEY (" + idList(fk.Columns, ", ")
str += ") REFERENCES " + fk.RefTable.SQL() + " ("
str += idList(fk.RefColumns, ", ") + ")"
str += " ON DELETE " + fk.OnDelete.SQL()
return str
}

Expand Down
41 changes: 41 additions & 0 deletions spanner/spansql/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,47 @@ func TestSQL(t *testing.T) {
"DROP INDEX IF EXISTS iname",
reparseDDL,
},
{
&CreateTable{
Name: "tname1",
Columns: []ColumnDef{
{Name: "cname1", Type: Type{Base: Int64}, NotNull: true, Position: line(2)},
{Name: "cname2", Type: Type{Base: Int64}, NotNull: true, Position: line(3)},
},
Constraints: []TableConstraint{
{
Name: "con1",
Constraint: ForeignKey{Columns: []ID{"cname2"}, RefTable: "tname2", RefColumns: []ID{"cname3"}, OnDelete: NoActionOnDelete, Position: line(4)},
Position: line(4),
},
},
PrimaryKey: []KeyPart{
{Column: "cname1"},
},
Position: line(1),
},
`CREATE TABLE tname1 (
cname1 INT64 NOT NULL,
cname2 INT64 NOT NULL,
CONSTRAINT con1 FOREIGN KEY (cname2) REFERENCES tname2 (cname3) ON DELETE NO ACTION,
) PRIMARY KEY(cname1)`,
reparseDDL,
},
{
&AlterTable{
Name: "tname1",
Alteration: AddConstraint{
Constraint: TableConstraint{
Name: "con1",
Constraint: ForeignKey{Columns: []ID{"cname2"}, RefTable: "tname2", RefColumns: []ID{"cname3"}, OnDelete: CascadeOnDelete, Position: line(1)},
Position: line(1),
},
},
Position: line(1),
},
`ALTER TABLE tname1 ADD CONSTRAINT con1 FOREIGN KEY (cname2) REFERENCES tname2 (cname3) ON DELETE CASCADE`,
reparseDDL,
},
{
&Insert{
Table: "Singers",
Expand Down
1 change: 1 addition & 0 deletions spanner/spansql/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ type ForeignKey struct {
Columns []ID
RefTable ID
RefColumns []ID
OnDelete OnDelete

Position Position // position of the "FOREIGN" token
}
Expand Down

0 comments on commit d78b851

Please sign in to comment.