From f17d29090ea32eb10f0b320edad19e75fb1d57b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E5=81=A5?= Date: Mon, 29 Jan 2024 18:55:44 +0800 Subject: [PATCH] [feat](Nereids): drop foreign key after dropping primary key that is referenced by the foreign key (#30417) --- .../org/apache/doris/catalog/TableIf.java | 10 +++- .../constraint/ForeignKeyConstraint.java | 6 ++- .../nereids/trees/plans/ConstraintTest.java | 31 +++++++++++ .../data/nereids_syntax_p0/constraint.out | 23 ++++++-- .../nereids_syntax_p0/constraint.groovy | 52 +++++++++++++++---- 5 files changed, 106 insertions(+), 16 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java index b59aedfdbf..67efd98fec 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java @@ -45,9 +45,11 @@ import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public interface TableIf { Logger LOG = LogManager.getLogger(TableIf.class); @@ -341,8 +343,12 @@ public interface TableIf { writeLock(); try { Map constraintMap = getConstraintsMapUnsafe(); - constraintMap.entrySet().removeIf(e -> e.getValue() instanceof ForeignKeyConstraint - && ((ForeignKeyConstraint) e.getValue()).isReferringPK(table, constraint)); + Set fkName = constraintMap.entrySet().stream() + .filter(e -> e.getValue() instanceof ForeignKeyConstraint + && ((ForeignKeyConstraint) e.getValue()).isReferringPK(table, constraint)) + .map(Entry::getKey) + .collect(Collectors.toSet()); + fkName.forEach(constraintMap::remove); } finally { writeUnlock(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java index 66d8e0a370..69d16c0753 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/constraint/ForeignKeyConstraint.java @@ -58,6 +58,10 @@ public class ForeignKeyConstraint extends Constraint { return foreignToReference.keySet(); } + public Set getPrimaryKeyNames() { + return ImmutableSet.copyOf(foreignToReference.values()); + } + public Set getReferencedColumnNames() { return ImmutableSet.copyOf(foreignToReference.values()); } @@ -87,7 +91,7 @@ public class ForeignKeyConstraint extends Constraint { } public Boolean isReferringPK(TableIf table, PrimaryKeyConstraint constraint) { - return constraint.getPrimaryKeyNames().equals(getForeignKeyNames()) + return constraint.getPrimaryKeyNames().equals(getPrimaryKeyNames()) && getReferencedTable().equals(table); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/ConstraintTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/ConstraintTest.java index 6d5600909f..ea9d3ab30d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/ConstraintTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/ConstraintTest.java @@ -61,6 +61,15 @@ class ConstraintTest extends TestWithFeService implements PlanPatternMatchSuppor + "properties(\n" + " \"replication_num\"=\"1\"\n" + ")"); + createTable("create table t3 (\n" + + " k1 int,\n" + + " k2 int\n" + + ")\n" + + "unique key(k1, k2)\n" + + "distributed by hash(k1) buckets 4\n" + + "properties(\n" + + " \"replication_num\"=\"1\"\n" + + ")"); } @Test @@ -162,4 +171,26 @@ class ConstraintTest extends TestWithFeService implements PlanPatternMatchSuppor PlanChecker.from(connectContext).parse("select * from t2").analyze().matches( logicalOlapScan().when(o -> o.getTable().getConstraintsMapUnsafe().isEmpty())); } + + @Test + void cascadeDropTest() throws Exception { + addConstraint("alter table t1 add constraint pk primary key (k1)"); + addConstraint("alter table t2 add constraint fk foreign key (k1) references t1(k1)"); + dropConstraint("alter table t1 drop constraint pk"); + + PlanChecker.from(connectContext).parse("select * from t2").analyze().matches( + logicalOlapScan().when(o -> o.getTable().getConstraintsMapUnsafe().isEmpty())); + + addConstraint("alter table t1 add constraint pk primary key (k1)"); + addConstraint("alter table t1 add constraint fk foreign key (k1) references t1(k1)"); + addConstraint("alter table t2 add constraint fk foreign key (k1) references t1(k1)"); + addConstraint("alter table t3 add constraint fk foreign key (k1) references t1(k1)"); + dropConstraint("alter table t1 drop constraint pk"); + PlanChecker.from(connectContext).parse("select * from t1").analyze().matches( + logicalOlapScan().when(o -> o.getTable().getConstraintsMapUnsafe().isEmpty())); + PlanChecker.from(connectContext).parse("select * from t2").analyze().matches( + logicalOlapScan().when(o -> o.getTable().getConstraintsMapUnsafe().isEmpty())); + PlanChecker.from(connectContext).parse("select * from t3").analyze().matches( + logicalOlapScan().when(o -> o.getTable().getConstraintsMapUnsafe().isEmpty())); + } } diff --git a/regression-test/data/nereids_syntax_p0/constraint.out b/regression-test/data/nereids_syntax_p0/constraint.out index 6dbdd84db6..daa4fde774 100644 --- a/regression-test/data/nereids_syntax_p0/constraint.out +++ b/regression-test/data/nereids_syntax_p0/constraint.out @@ -1,10 +1,25 @@ -- This file is automatically generated. You should know what you did if you want to edit this --- !show_constrait -- +-- !add_primary -- +pk PRIMARY KEY PRIMARY KEY (id) + +-- !add_unique -- uk UNIQUE UNIQUE (id) pk PRIMARY KEY PRIMARY KEY (id) -fk2 FOREIGN KEY FOREIGN KEY (id) REFERENCES regression_test_nereids_syntax_p0.t2 (id) -fk1 FOREIGN KEY FOREIGN KEY (id) REFERENCES regression_test_nereids_syntax_p0.t1 (id) --- !show_constrait -- +-- !add_foreign -- +uk UNIQUE UNIQUE (id) +pk PRIMARY KEY PRIMARY KEY (id) +fk1 FOREIGN KEY FOREIGN KEY (id) REFERENCES regression_test_nereids_syntax_p0.t2 (id) + +-- !drop_uk -- +pk PRIMARY KEY PRIMARY KEY (id) +fk1 FOREIGN KEY FOREIGN KEY (id) REFERENCES regression_test_nereids_syntax_p0.t2 (id) + +-- !drop_fk -- +pk PRIMARY KEY PRIMARY KEY (id) + +-- !drop_pk -- + +-- !drop_fk_cascades -- pk PRIMARY KEY PRIMARY KEY (id) diff --git a/regression-test/suites/nereids_syntax_p0/constraint.groovy b/regression-test/suites/nereids_syntax_p0/constraint.groovy index c01f55c0f1..4ede619e5a 100644 --- a/regression-test/suites/nereids_syntax_p0/constraint.groovy +++ b/regression-test/suites/nereids_syntax_p0/constraint.groovy @@ -61,21 +61,55 @@ suite("show_constraint") { alter table t2 add constraint pk primary key (id) """ + qt_add_primary """ + show constraints from t1; + """ + sql """ alter table t1 add constraint uk unique (id) """ - sql """ - alter table t1 add constraint fk1 foreign key (id) references t1(id) - """ - sql """ - alter table t1 add constraint fk2 foreign key (id) references t2(id) - """ - - qt_show_constrait """ + qt_add_unique """ show constraints from t1; """ - qt_show_constrait """ + + sql """ + alter table t1 add constraint fk1 foreign key (id) references t2(id) + """ + sql """ + alter table t2 add constraint fk2 foreign key (id) references t1(id) + """ + + qt_add_foreign """ + show constraints from t1; + """ + + sql """ + alter table t1 drop constraint uk + """ + + qt_drop_uk """ + show constraints from t1; + """ + + sql """ + alter table t1 drop constraint fk1 + """ + + qt_drop_fk """ + show constraints from t1; + """ + + sql """ + alter table t1 drop constraint pk + """ + + qt_drop_pk """ + show constraints from t1; + """ + + qt_drop_fk_cascades """ show constraints from t2; """ + }