Skip to content

Commit e455c29

Browse files
Add Foreign Key ON DELETE SET NULL support for Cloud Spanner Avro template
1 parent d92bde9 commit e455c29

6 files changed

Lines changed: 48 additions & 10 deletions

File tree

v1/src/main/java/com/google/cloud/teleport/spanner/ddl/ForeignKey.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public enum ReferentialAction {
3838
// Supported actions
3939
ON_DELETE_NO_ACTION("ON DELETE NO ACTION"),
4040
ON_DELETE_CASCADE("ON DELETE CASCADE"),
41+
ON_DELETE_SET_NULL("ON DELETE SET NULL"),
4142
// Currently unsupported actions, listed here for completeness
4243
ON_DELETE_RESTRICT("ON DELETE RESTRICT"),
43-
ON_DELETE_SET_NULL("ON DELETE SET NULL"),
4444
ON_DELETE_SET_DEFAULT("ON DELETE SET DEFAULT"),
4545
ON_UPDATE_NO_ACTION("ON UPDATE NO ACTION"),
4646
ON_UPDATE_CASCADE("ON UPDATE CASCADE"),
@@ -69,6 +69,8 @@ public static ReferentialAction getReferentialAction(String changeType, String a
6969
return ReferentialAction.ON_DELETE_CASCADE;
7070
case "NO ACTION":
7171
return ReferentialAction.ON_DELETE_NO_ACTION;
72+
case "SET NULL":
73+
return ReferentialAction.ON_DELETE_SET_NULL;
7274
default:
7375
throw new IllegalArgumentException(
7476
"ON DELETE referential action not supported: " + action);
@@ -131,6 +133,7 @@ private void prettyPrint(Appendable appendable) throws IOException {
131133
switch (action.get()) {
132134
case ON_DELETE_CASCADE:
133135
case ON_DELETE_NO_ACTION:
136+
case ON_DELETE_SET_NULL:
134137
appendable.append(" " + action.get().getSqlString());
135138
break;
136139
default:

v1/src/test/java/com/google/cloud/teleport/spanner/AvroSchemaToDdlConverterTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ public void simple() {
318318
+ " ALTER TABLE `Users` ADD CONSTRAINT `fk_odc`"
319319
+ " FOREIGN KEY (`last_name`) REFERENCES "
320320
+ "`AllowedNames` (`last_name`) ON DELETE CASCADE"
321+
+ " ALTER TABLE `Users` ADD CONSTRAINT `fk_odsn`"
322+
+ " FOREIGN KEY (`last_name`) REFERENCES "
323+
+ "`AllowedNames` (`last_name`) ON DELETE SET NULL"
321324
+ " ALTER TABLE `Users` ADD CONSTRAINT `fk_not_enforced_no_action`"
322325
+ " FOREIGN KEY (`last_name`) REFERENCES "
323326
+ "`AllowedNames` (`last_name`) ON DELETE NO ACTION NOT ENFORCED"
@@ -544,6 +547,9 @@ public void pgSimple() {
544547
+ " \"spannerForeignKey_1\" : \"ALTER TABLE \\\"Users\\\" ADD CONSTRAINT "
545548
+ "\\\"fk_odc\\\" FOREIGN KEY (\\\"last_name\\\") REFERENCES \\\"AllowedNames\\\""
546549
+ " (\\\"last_name\\\") ON DELETE CASCADE\", "
550+
+ " \"spannerForeignKey_2\" : \"ALTER TABLE \\\"Users\\\" ADD CONSTRAINT "
551+
+ "\\\"fk_odsn\\\" FOREIGN KEY (\\\"last_name\\\") REFERENCES \\\"AllowedNames\\\""
552+
+ " (\\\"last_name\\\") ON DELETE SET NULL\", "
547553
+ " \"spannerCheckConstraint_0\" : \"CONSTRAINT \\\"ck\\\""
548554
+ " CHECK(\\\"first_name\\\" != \\\"last_name\\\")\"}";
549555

v1/src/test/java/com/google/cloud/teleport/spanner/DdlToAvroSchemaConverterTest.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ public void simple() {
209209
+ " REFERENCES `AllowedNames` (`first_name`)",
210210
"ALTER TABLE `Users` ADD CONSTRAINT `fk_odc` FOREIGN KEY (`last_name`)"
211211
+ " REFERENCES `AllowedNames` (`last_name`) ON DELETE CASCADE",
212+
"ALTER TABLE `Users` ADD CONSTRAINT `fk_odsn` FOREIGN KEY (`last_name`)"
213+
+ " REFERENCES `AllowedNames` (`last_name`) ON DELETE SET NULL",
212214
"ALTER TABLE `Users` ADD CONSTRAINT `fk_not_enforced_no_action`"
213215
+ " FOREIGN KEY (`last_name`) REFERENCES "
214216
+ "`AllowedNames` (`last_name`) ON DELETE NO ACTION NOT ENFORCED",
@@ -395,11 +397,16 @@ public void simple() {
395397
+ " REFERENCES `AllowedNames` (`last_name`) ON DELETE CASCADE"));
396398
assertThat(
397399
avroSchema.getProp(SPANNER_FOREIGN_KEY + "2"),
400+
equalTo(
401+
"ALTER TABLE `Users` ADD CONSTRAINT `fk_odsn` FOREIGN KEY (`last_name`)"
402+
+ " REFERENCES `AllowedNames` (`last_name`) ON DELETE SET NULL"));
403+
assertThat(
404+
avroSchema.getProp(SPANNER_FOREIGN_KEY + "3"),
398405
equalTo(
399406
"ALTER TABLE `Users` ADD CONSTRAINT `fk_not_enforced_no_action` FOREIGN KEY (`last_name`)"
400407
+ " REFERENCES `AllowedNames` (`last_name`) ON DELETE NO ACTION NOT ENFORCED"));
401408
assertThat(
402-
avroSchema.getProp(SPANNER_FOREIGN_KEY + "3"),
409+
avroSchema.getProp(SPANNER_FOREIGN_KEY + "4"),
403410
equalTo(
404411
"ALTER TABLE `Users` ADD CONSTRAINT `fk_enforced` FOREIGN KEY (`last_name`)"
405412
+ " REFERENCES `AllowedNames` (`last_name`) ENFORCED"));

v1/src/test/java/com/google/cloud/teleport/spanner/ddl/DdlTest.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,21 +1764,32 @@ public void testForeignKeyBuilderActions() {
17641764
ForeignKey fkWithDeleteNoAction = fkWithDeleteNoActionBuilder.build();
17651765
assertTrue(fkWithDeleteNoAction.equals(fkWithDeleteNoAction));
17661766
assertFalse(fkWithDeleteCascade1.equals(fkWithDeleteNoAction));
1767+
1768+
ForeignKey.Builder fkWithDeleteSetNullBuilder =
1769+
ForeignKey.builder().name("fk_odsn").table("Users").referencedTable("AllowedNames");
1770+
fkWithDeleteSetNullBuilder.columnsBuilder().add("first_name", "last_name");
1771+
fkWithDeleteSetNullBuilder.referencedColumnsBuilder().add("first_name", "last_name");
1772+
fkWithDeleteSetNullBuilder.referentialAction(
1773+
Optional.of(ReferentialAction.ON_DELETE_SET_NULL));
1774+
ForeignKey fkWithDeleteSetNull = fkWithDeleteSetNullBuilder.build();
1775+
assertTrue(fkWithDeleteSetNull.equals(fkWithDeleteSetNull));
1776+
assertFalse(fkWithDeleteCascade1.equals(fkWithDeleteSetNull));
1777+
assertFalse(fkWithDeleteNoAction.equals(fkWithDeleteSetNull));
17671778
}
17681779

17691780
@Test
17701781
public void testUnsupportedForeignKeyBuilderActionThrowsError() {
17711782
ForeignKey.Builder fkWithUnsupportedActionBuilder =
1772-
ForeignKey.builder().name("fk_odsn").table("Users").referencedTable("AllowedNames");
1783+
ForeignKey.builder().name("fk_odr").table("Users").referencedTable("AllowedNames");
17731784
fkWithUnsupportedActionBuilder.columnsBuilder().add("first_name", "last_name");
17741785
fkWithUnsupportedActionBuilder.referencedColumnsBuilder().add("first_name", "last_name");
17751786
fkWithUnsupportedActionBuilder.referentialAction(
1776-
Optional.of(ReferentialAction.ON_DELETE_SET_NULL));
1787+
Optional.of(ReferentialAction.ON_DELETE_RESTRICT));
17771788
ForeignKey fkWithUnsupportedAction = fkWithUnsupportedActionBuilder.build();
17781789
Throwable exception =
17791790
assertThrows(IllegalArgumentException.class, () -> fkWithUnsupportedAction.prettyPrint());
17801791
assertThat(exception.getMessage())
1781-
.matches("Foreign Key action not supported: ON DELETE SET NULL");
1792+
.matches("Foreign Key action not supported: ON DELETE RESTRICT");
17821793
}
17831794

17841795
@Test

v1/src/test/java/com/google/cloud/teleport/spanner/ddl/ForeignKeyTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,16 @@
2828
public final class ForeignKeyTest {
2929

3030
@Test
31-
public void testParsingOnDeleteCascadeActions() {
31+
public void testParsingOnDeleteActions() {
3232
var onDeleteCascadeAction = ReferentialAction.getReferentialAction("DELETE", "CASCADE");
3333
assertThat(onDeleteCascadeAction)
3434
.isEquivalentAccordingToCompareTo(ReferentialAction.ON_DELETE_CASCADE);
3535
var onDeleteNoAction = ReferentialAction.getReferentialAction("DELETE", "no action");
3636
assertThat(onDeleteNoAction)
3737
.isEquivalentAccordingToCompareTo(ReferentialAction.ON_DELETE_NO_ACTION);
38+
var onDeleteSetNullAction = ReferentialAction.getReferentialAction("DELETE", "set null");
39+
assertThat(onDeleteSetNullAction)
40+
.isEquivalentAccordingToCompareTo(ReferentialAction.ON_DELETE_SET_NULL);
3841
}
3942

4043
@Test

v1/src/test/java/com/google/cloud/teleport/spanner/ddl/RandomDdlGenerator.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,9 @@ private void generateTable(Ddl.Builder builder, Table parent, int level) {
571571
}
572572
if (rnd.nextBoolean()) {
573573
ReferentialAction action = generateRandomReferentialAction(rnd);
574-
if (!isEnforced && action == ReferentialAction.ON_DELETE_CASCADE) {
574+
if (!isEnforced
575+
&& (action == ReferentialAction.ON_DELETE_CASCADE
576+
|| action == ReferentialAction.ON_DELETE_SET_NULL)) {
575577
action = ReferentialAction.ON_DELETE_NO_ACTION;
576578
}
577579
foreignKeyBuilder.referentialAction(Optional.of(action));
@@ -625,9 +627,15 @@ private void generateTable(Ddl.Builder builder, Table parent, int level) {
625627
}
626628

627629
private ReferentialAction generateRandomReferentialAction(Random rnd) {
628-
return rnd.nextBoolean()
629-
? ReferentialAction.ON_DELETE_CASCADE
630-
: ReferentialAction.ON_DELETE_NO_ACTION;
630+
int actionChoice = rnd.nextInt(3);
631+
switch (actionChoice) {
632+
case 0:
633+
return ReferentialAction.ON_DELETE_CASCADE;
634+
case 1:
635+
return ReferentialAction.ON_DELETE_SET_NULL;
636+
default:
637+
return ReferentialAction.ON_DELETE_NO_ACTION;
638+
}
631639
}
632640

633641
private String addDefaultValueToColumn(Type type) {

0 commit comments

Comments
 (0)