From d098c602ec557f077d0db70f69fd8fbc487aa7bb Mon Sep 17 00:00:00 2001 From: gurminder71 <86370145+gurminder71@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:17:01 -0800 Subject: [PATCH] Support ON DELETE clause in table foreign constraint (#59) * Support ON DELETE clause in table foreign constraint * Ran mvn spotless:apply --- .../spannerddl/parser/ASTforeign_key.java | 12 +++++- .../spannerddl/parser/ASTon_delete.java | 40 +++++++++++++++++++ .../parser/ASTreferential_action.java | 38 ++++++++++++++++++ src/main/jjtree-sources/ddl_parser.jjt | 7 ++++ .../spannerddl/parser/DDLParserTest.java | 6 ++- src/test/resources/expectedDdlDiff.txt | 8 ++++ src/test/resources/newDdl.txt | 16 +++++++- src/test/resources/originalDdl.txt | 16 ++++++++ 8 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTon_delete.java create mode 100644 src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTreferential_action.java diff --git a/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTforeign_key.java b/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTforeign_key.java index af4911c..549b69b 100644 --- a/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTforeign_key.java +++ b/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTforeign_key.java @@ -69,6 +69,15 @@ public List getReferencedColumnNames() { (ASTidentifier_list) ((ASTreferenced_columns) children[child]).children[0]); } + public String getDeleteOption() { + ASTon_delete deleteOption = ASTTreeUtils.getOptionalChildByType(children, ASTon_delete.class); + if (deleteOption != null) { + return " " + deleteOption; + } else { + return ""; + } + } + public String toString() { return "CONSTRAINT " @@ -79,7 +88,8 @@ public String toString() { + getReferencedTableName() + " (" + Joiner.on(", ").join(getReferencedColumnNames()) - + ")"; + + ")" + + getDeleteOption(); } @Override diff --git a/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTon_delete.java b/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTon_delete.java new file mode 100644 index 0000000..16c03a0 --- /dev/null +++ b/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTon_delete.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.solutions.spannerddl.parser; + +public class ASTon_delete extends SimpleNode { + public ASTon_delete(int id) { + super(id); + } + + public ASTon_delete(DdlParser p, int id) { + super(p, id); + } + + @Override + public String toString() { + if (children[0] instanceof ASTreferential_action) { + return "ON DELETE " + children[0]; + } else { + throw new UnsupportedOperationException("Not Implemented"); + } + } + + @Override + public boolean equals(Object other) { + return (other instanceof ASTon_delete && this.toString().equals(other.toString())); + } +} diff --git a/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTreferential_action.java b/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTreferential_action.java new file mode 100644 index 0000000..f1f9837 --- /dev/null +++ b/src/main/java/com/google/cloud/solutions/spannerddl/parser/ASTreferential_action.java @@ -0,0 +1,38 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.solutions.spannerddl.parser; + +import com.google.cloud.solutions.spannerddl.diff.ASTTreeUtils; + +public class ASTreferential_action extends SimpleNode { + public ASTreferential_action(int id) { + super(id); + } + + public ASTreferential_action(DdlParser p, int id) { + super(p, id); + } + + @Override + public String toString() { + return ASTTreeUtils.tokensToString(this); + } + + @Override + public boolean equals(Object other) { + return (other instanceof ASTreferential_action && this.toString().equals(other.toString())); + } +} diff --git a/src/main/jjtree-sources/ddl_parser.jjt b/src/main/jjtree-sources/ddl_parser.jjt index 111ede9..267d388 100644 --- a/src/main/jjtree-sources/ddl_parser.jjt +++ b/src/main/jjtree-sources/ddl_parser.jjt @@ -219,8 +219,15 @@ void foreign_key() : "(" identifier_list() #referencing_columns ")" qualified_identifier() #referenced_table "(" identifier_list() #referenced_columns ")" + [ referential_action() #on_delete ] } +void referential_action() : +{} +{ + #no_action + | #cascade +} void statement_token_no_paren() : {} diff --git a/src/test/java/com/google/cloud/solutions/spannerddl/parser/DDLParserTest.java b/src/test/java/com/google/cloud/solutions/spannerddl/parser/DDLParserTest.java index eced978..f22aff8 100644 --- a/src/test/java/com/google/cloud/solutions/spannerddl/parser/DDLParserTest.java +++ b/src/test/java/com/google/cloud/solutions/spannerddl/parser/DDLParserTest.java @@ -45,7 +45,8 @@ public void parseCreateTable() throws ParseException { + "jsoncol json, " + "pgcolumn pg.something, " + "generatedcol string(max) as (sizedstring+ strstr(maxstring,strpos(maxstring,'xxx'),length(maxstring)) +2.0) STORED, " - + "constraint fk_col_remote FOREIGN KEY(col1, col2) REFERENCES test.other_table(other_col1, other_col2), " + + "constraint fk_col_remote FOREIGN KEY(col1, col2) REFERENCES test.other_table(other_col1, other_col2) on delete cascade, " + + "constraint fk_col_remote2 FOREIGN KEY(col1) REFERENCES test.other_table(other_col1) on delete no action, " + "constraint check_some_value CHECK ((length(sizedstring)>100 or sizedstring= \"xxx\") AND boolcol= true and intcol > -123.4 and numericcol < 1.5)" + ") " + "primary key (intcol ASC, floatcol desc, boolcol), " @@ -70,7 +71,8 @@ public void parseCreateTable() throws ParseException { + "jsoncol JSON, " + "pgcolumn PG.SOMETHING, " + "generatedcol STRING(MAX) AS ( sizedstring + strstr ( maxstring, strpos ( maxstring, 'xxx' ), length ( maxstring ) ) + 2.0 ) STORED, " - + "CONSTRAINT fk_col_remote FOREIGN KEY (col1, col2) REFERENCES test.other_table (other_col1, other_col2), " + + "CONSTRAINT fk_col_remote FOREIGN KEY (col1, col2) REFERENCES test.other_table (other_col1, other_col2) ON DELETE CASCADE, " + + "CONSTRAINT fk_col_remote2 FOREIGN KEY (col1) REFERENCES test.other_table (other_col1) ON DELETE NO ACTION, " + "CONSTRAINT check_some_value CHECK (( length ( sizedstring ) > 100 OR sizedstring = \"xxx\" ) AND boolcol = TRUE AND intcol > -123.4 AND numericcol < 1.5)" + ") PRIMARY KEY (intcol ASC, floatcol DESC, boolcol ASC), " + "INTERLEAVE IN PARENT `other_table` ON DELETE CASCADE, " diff --git a/src/test/resources/expectedDdlDiff.txt b/src/test/resources/expectedDdlDiff.txt index 08a8687..d5a9dfa 100644 --- a/src/test/resources/expectedDdlDiff.txt +++ b/src/test/resources/expectedDdlDiff.txt @@ -226,6 +226,14 @@ ALTER DATABASE dbname SET OPTIONS (nothing=NULL,othervalue=456) ALTER DATABASE dbname SET OPTIONS (othervalue=456,removeme=NULL) +== TEST 42 add foreign key in table with delete cascade + +ALTER TABLE test1 ADD CONSTRAINT fk_in_table FOREIGN KEY (col2) REFERENCES othertable (othercol) ON DELETE CASCADE + +== TEST 43 add foreign key in table with delete no action + +ALTER TABLE test1 ADD CONSTRAINT fk_in_table FOREIGN KEY (col2) REFERENCES othertable (othercol) ON DELETE NO ACTION + == diff --git a/src/test/resources/newDdl.txt b/src/test/resources/newDdl.txt index 540e30f..dd1ee9f 100644 --- a/src/test/resources/newDdl.txt +++ b/src/test/resources/newDdl.txt @@ -379,8 +379,22 @@ ALTER DATABASE dbname SET OPTIONS(hello='world'); ALTER DATABASE dbname SET OPTIONS(hello='world', othervalue=456); -== +== TEST 42 add foreign key in table with delete cascade +create table test1 ( + col1 int64, + col2 int64 NOT NULL, + constraint fk_in_table foreign key (col2) references othertable(othercol) ON DELETE CASCADE +) +primary key (col1); +== TEST 43 add foreign key in table with delete no action +create table test1 ( + col1 int64, + col2 int64 NOT NULL, + constraint fk_in_table foreign key (col2) references othertable(othercol) ON DELETE NO ACTION +) +primary key (col1); +== diff --git a/src/test/resources/originalDdl.txt b/src/test/resources/originalDdl.txt index aa99109..cee2d36 100644 --- a/src/test/resources/originalDdl.txt +++ b/src/test/resources/originalDdl.txt @@ -380,6 +380,22 @@ ALTER DATABASE dbname SET OPTIONS(hello='world'); ALTER DATABASE dbname SET OPTIONS(hello='world', othervalue=123, removeme='please'); +== TEST 42 add foreign key in table with delete cascade + +create table test1 ( + col1 int64, + col2 int64 NOT NULL +) +primary key (col1); + +== TEST 43 add foreign key in table with delete no action + +create table test1 ( + col1 int64, + col2 int64 NOT NULL +) +primary key (col1); + ==