Skip to content

Commit

Permalink
Add support for foreign key actions (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
toga4 authored Sep 2, 2023
1 parent 2117271 commit 9247a6a
Show file tree
Hide file tree
Showing 17 changed files with 520 additions and 122 deletions.
12 changes: 7 additions & 5 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1490,17 +1490,19 @@ type TableConstraint struct {

// ForeignKey is foreign key specifier in CREATE TABLE and ALTER TABLE.
//
// FOREIGN KEY ({{.ColumnNames | sqlJoin ","}}) REFERENCES {{.ReferenceTable}} ({{.ReferenceColumns | sqlJoin ","}})
// FOREIGN KEY ({{.ColumnNames | sqlJoin ","}}) REFERENCES {{.ReferenceTable}} ({{.ReferenceColumns | sqlJoin ","}}) {{.OnDelete}}
type ForeignKey struct {
// pos = Foreign
// end = Rparen + 1
// end = OnDeleteEnd || Rparen + 1

Foreign token.Pos // position of "FOREIGN" keyword
Rparen token.Pos // position of ")" after reference columns
Foreign token.Pos // position of "FOREIGN" keyword
Rparen token.Pos // position of ")" after reference columns
OnDeleteEnd token.Pos // end position of ON DELETE clause

Columns []*Ident
ReferenceTable *Ident
ReferenceColumns []*Ident // len(ReferenceColumns) > 0
ReferenceColumns []*Ident // len(ReferenceColumns) > 0
OnDelete OnDeleteAction // optional
}

// Check is check constraint in CREATE TABLE and ALTER TABLE.
Expand Down
7 changes: 6 additions & 1 deletion ast/pos.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,12 @@ func (c *TableConstraint) End() token.Pos { return c.Constraint.End() }
func (f *ForeignKey) Pos() token.Pos {
return f.Foreign
}
func (f *ForeignKey) End() token.Pos { return f.Rparen + 1 }
func (f *ForeignKey) End() token.Pos {
if !f.OnDeleteEnd.Invalid() {
return f.OnDeleteEnd
}
return f.Rparen + 1
}

func (c *Check) Pos() token.Pos { return c.Check }
func (c *Check) End() token.Pos { return c.Rparen + 1 }
Expand Down
3 changes: 3 additions & 0 deletions ast/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,9 @@ func (f *ForeignKey) SQL() string {
sql += k.SQL()
}
sql += ")"
if f.OnDelete != "" {
sql += " " + string(f.OnDelete)
}
return sql
}

Expand Down
4 changes: 4 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2226,12 +2226,16 @@ func (p *Parser) parseForeignKey() *ast.ForeignKey {
}
rparen := p.expect(")").End

onDelete, onDeleteEnd := p.tryParseOnDeleteAction()

return &ast.ForeignKey{
Foreign: pos,
Rparen: rparen,
OnDeleteEnd: onDeleteEnd,
Columns: columns,
ReferenceTable: refTable,
ReferenceColumns: refColumns,
OnDelete: onDelete,
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table foo add constraint fkname foreign key (foo, bar) references t2 (t2key1, t2key2) on delete cascade
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table foo add constraint fkname foreign key (foo, bar) references t2 (t2key1, t2key2) on delete no action
2 changes: 2 additions & 0 deletions testdata/input/ddl/create_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ create table foo (
baz string(255) not null options(allow_commit_timestamp = null),
qux string(255) not null as (concat(baz, "a")) stored,
foreign key (foo) references t2 (t2key1),
foreign key (bar) references t2 (t2key2) on delete cascade,
foreign key (baz) references t2 (t2key3) on delete no action,
constraint fkname foreign key (foo, bar) references t2 (t2key1, t2key2),
check (foo > 0),
constraint cname check (bar > 0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ alter table foo add constraint fkname foreign key (foo, bar) references t2 (t2ke
Name: "fkname",
},
Constraint: &ast.ForeignKey{
Foreign: 38,
Rparen: 91,
Columns: []*ast.Ident{
Foreign: 38,
Rparen: 91,
OnDeleteEnd: -1,
Columns: []*ast.Ident{
&ast.Ident{
NamePos: 51,
NameEnd: 54,
Expand Down Expand Up @@ -50,6 +51,7 @@ alter table foo add constraint fkname foreign key (foo, bar) references t2 (t2ke
Name: "t2key2",
},
},
OnDelete: "",
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
--- alter_table_add_constraint_foreign_key_on_delete_cascade.sql
alter table foo add constraint fkname foreign key (foo, bar) references t2 (t2key1, t2key2) on delete cascade

--- AST
&ast.AlterTable{
Alter: 0,
Name: &ast.Ident{
NamePos: 12,
NameEnd: 15,
Name: "foo",
},
TableAlternation: &ast.AddTableConstraint{
Add: 16,
TableConstraint: &ast.TableConstraint{
ConstraintPos: 20,
Name: &ast.Ident{
NamePos: 31,
NameEnd: 37,
Name: "fkname",
},
Constraint: &ast.ForeignKey{
Foreign: 38,
Rparen: 91,
OnDeleteEnd: 109,
Columns: []*ast.Ident{
&ast.Ident{
NamePos: 51,
NameEnd: 54,
Name: "foo",
},
&ast.Ident{
NamePos: 56,
NameEnd: 59,
Name: "bar",
},
},
ReferenceTable: &ast.Ident{
NamePos: 72,
NameEnd: 74,
Name: "t2",
},
ReferenceColumns: []*ast.Ident{
&ast.Ident{
NamePos: 76,
NameEnd: 82,
Name: "t2key1",
},
&ast.Ident{
NamePos: 84,
NameEnd: 90,
Name: "t2key2",
},
},
OnDelete: "ON DELETE CASCADE",
},
},
},
}

--- SQL
ALTER TABLE foo ADD CONSTRAINT fkname FOREIGN KEY (foo, bar) REFERENCES t2 (t2key1, t2key2) ON DELETE CASCADE
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
--- alter_table_add_constraint_foreign_key_on_delete_no_action.sql
alter table foo add constraint fkname foreign key (foo, bar) references t2 (t2key1, t2key2) on delete no action

--- AST
&ast.AlterTable{
Alter: 0,
Name: &ast.Ident{
NamePos: 12,
NameEnd: 15,
Name: "foo",
},
TableAlternation: &ast.AddTableConstraint{
Add: 16,
TableConstraint: &ast.TableConstraint{
ConstraintPos: 20,
Name: &ast.Ident{
NamePos: 31,
NameEnd: 37,
Name: "fkname",
},
Constraint: &ast.ForeignKey{
Foreign: 38,
Rparen: 91,
OnDeleteEnd: 111,
Columns: []*ast.Ident{
&ast.Ident{
NamePos: 51,
NameEnd: 54,
Name: "foo",
},
&ast.Ident{
NamePos: 56,
NameEnd: 59,
Name: "bar",
},
},
ReferenceTable: &ast.Ident{
NamePos: 72,
NameEnd: 74,
Name: "t2",
},
ReferenceColumns: []*ast.Ident{
&ast.Ident{
NamePos: 76,
NameEnd: 82,
Name: "t2key1",
},
&ast.Ident{
NamePos: 84,
NameEnd: 90,
Name: "t2key2",
},
},
OnDelete: "ON DELETE NO ACTION",
},
},
},
}

--- SQL
ALTER TABLE foo ADD CONSTRAINT fkname FOREIGN KEY (foo, bar) REFERENCES t2 (t2key1, t2key2) ON DELETE NO ACTION
8 changes: 5 additions & 3 deletions testdata/result/ddl/alter_table_add_foreign_key.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ alter table foo add foreign key (bar) references t2 (t2key1)
ConstraintPos: 0,
Name: (*ast.Ident)(nil),
Constraint: &ast.ForeignKey{
Foreign: 20,
Rparen: 60,
Columns: []*ast.Ident{
Foreign: 20,
Rparen: 60,
OnDeleteEnd: -1,
Columns: []*ast.Ident{
&ast.Ident{
NamePos: 33,
NameEnd: 36,
Expand All @@ -36,6 +37,7 @@ alter table foo add foreign key (bar) references t2 (t2key1)
Name: "t2key1",
},
},
OnDelete: "",
},
},
},
Expand Down
Loading

0 comments on commit 9247a6a

Please sign in to comment.