This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.2 by this push:
     new 6db5d4285ff branch-4.2: [fix](constraint) Preserve table identity in 
foreign key join elimination #67699 (#70045)
6db5d4285ff is described below

commit 6db5d4285ffe1a285b5f14757cfb5116aa25aac7
Author: morrySnow <[email protected]>
AuthorDate: Tue Nov 3 17:25:37 2026 +0800

    branch-4.2: [fix](constraint) Preserve table identity in foreign key join 
elimination #67699 (#70045)
    
    picked from master #67699
---
 .../nereids/rules/rewrite/ForeignKeyContext.java   | 63 +++++++++++++++++-----
 .../rules/rewrite/EliminateJoinByFkTest.java       | 18 +++++++
 2 files changed, 68 insertions(+), 13 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ForeignKeyContext.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ForeignKeyContext.java
index 52021622ff8..731599a0ad3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ForeignKeyContext.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ForeignKeyContext.java
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.rules.rewrite;
 
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.constraint.TableIdentifier;
 import org.apache.doris.nereids.trees.expressions.Alias;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
@@ -36,6 +37,7 @@ import com.google.common.collect.ImmutableMap;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -43,10 +45,10 @@ import java.util.stream.Collectors;
  * Record Foreign Key Context
  */
 public class ForeignKeyContext {
-    Set<Map<Column, Column>> constraints = new HashSet<>();
-    Set<Column> foreignKeys = new HashSet<>();
-    Set<Column> primaryKeys = new HashSet<>();
-    Map<Slot, Column> slotToColumn = new HashMap<>();
+    Set<Map<QualifiedColumn, QualifiedColumn>> constraints = new HashSet<>();
+    Set<QualifiedColumn> foreignKeys = new HashSet<>();
+    Set<QualifiedColumn> primaryKeys = new HashSet<>();
+    Map<Slot, QualifiedColumn> slotToColumn = new HashMap<>();
     Map<Slot, Set<Expression>> slotWithPredicates = new HashMap<>();
 
     /**
@@ -66,12 +68,13 @@ public class ForeignKeyContext {
             @Override
             public Void visitLogicalRelation(LogicalRelation relation, 
ForeignKeyContext context) {
                 if (relation instanceof LogicalCatalogRelation) {
-                    context.putAllForeignKeys(((LogicalCatalogRelation) 
relation).getTable());
-                    context.putAllPrimaryKeys(((LogicalCatalogRelation) 
relation).getTable());
+                    TableIf table = ((LogicalCatalogRelation) 
relation).getTable();
+                    context.putAllForeignKeys(table);
+                    context.putAllPrimaryKeys(table);
                     relation.getOutput().stream()
                             .filter(SlotReference.class::isInstance)
                             .map(SlotReference.class::cast)
-                            .forEach(context::putSlot);
+                            .forEach(slot -> context.putSlot(slot, table));
                 }
                 return null;
             }
@@ -99,15 +102,21 @@ public class ForeignKeyContext {
 
     void putAllForeignKeys(TableIf table) {
         table.getForeignKeyConstraints().forEach(c -> {
-            Map<Column, Column> constraint = c.getForeignToPrimary(table);
-            constraints.add(c.getForeignToPrimary(table));
+            TableIf referencedTable = c.getReferencedTable();
+            Map<QualifiedColumn, QualifiedColumn> constraint = 
c.getForeignToReference().entrySet().stream()
+                    .collect(ImmutableMap.toImmutableMap(
+                            entry -> new QualifiedColumn(table, 
table.getColumn(entry.getKey())),
+                            entry -> new QualifiedColumn(
+                                    referencedTable, 
referencedTable.getColumn(entry.getValue()))));
+            constraints.add(constraint);
             foreignKeys.addAll(constraint.keySet());
         });
     }
 
     void putAllPrimaryKeys(TableIf table) {
         table.getPrimaryKeyConstraints().forEach(c -> {
-            Set<Column> primaryKey = c.getPrimaryKeys(table);
+            Set<QualifiedColumn> primaryKey = c.getPrimaryKeys(table).stream()
+                    .map(column -> new QualifiedColumn(table, 
column)).collect(Collectors.toSet());
             primaryKeys.addAll(primaryKey);
         });
     }
@@ -122,12 +131,12 @@ public class ForeignKeyContext {
                 key.stream().map(s -> 
slotToColumn.get(s)).collect(Collectors.toSet()));
     }
 
-    void putSlot(SlotReference slot) {
+    void putSlot(SlotReference slot, TableIf table) {
         if (!slot.getOriginalColumn().isPresent()) {
             return;
         }
         Column c = slot.getOriginalColumn().get();
-        slotToColumn.put(slot, c);
+        slotToColumn.put(slot, new QualifiedColumn(table, c));
     }
 
     void putAlias(Slot newSlot, Slot originSlot) {
@@ -171,7 +180,7 @@ public class ForeignKeyContext {
      * Check whether the given mapping relation satisfies any constraints
      */
     public boolean satisfyConstraint(Map<Slot, Slot> primaryToForeign) {
-        Map<Column, Column> foreignToPrimary = 
primaryToForeign.entrySet().stream()
+        Map<QualifiedColumn, QualifiedColumn> foreignToPrimary = 
primaryToForeign.entrySet().stream()
                 .collect(ImmutableMap.toImmutableMap(
                         e -> slotToColumn.get(e.getValue()),
                         e -> slotToColumn.get(e.getKey())));
@@ -203,4 +212,32 @@ public class ForeignKeyContext {
             return 
slotWithPredicates.get(pf.getValue()).containsAll(primaryPredicates);
         });
     }
+
+    /** A column identity qualified by its owning table. */
+    private static final class QualifiedColumn {
+        private final TableIdentifier tableIdentifier;
+        private final Column column;
+
+        private QualifiedColumn(TableIf table, Column column) {
+            this.tableIdentifier = new TableIdentifier(table);
+            this.column = column;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof QualifiedColumn)) {
+                return false;
+            }
+            QualifiedColumn other = (QualifiedColumn) obj;
+            return tableIdentifier.equals(other.tableIdentifier) && 
column.equals(other.column);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(tableIdentifier, column);
+        }
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java
index 0d54ad4f1e5..bbd2046f53a 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java
@@ -68,9 +68,16 @@ class EliminateJoinByFkTest extends TestWithFeService 
implements MemoPatternMatc
                         + ")\n"
                         + "UNIQUE KEY(id3)\n"
                         + "DISTRIBUTED BY HASH(id3) BUCKETS 10\n"
+                        + "PROPERTIES (\"replication_num\" = \"1\")\n",
+                "CREATE TABLE IF NOT EXISTS unrelated_pri (\n"
+                        + "    id1 int not null\n"
+                        + ")\n"
+                        + "UNIQUE KEY(id1)\n"
+                        + "DISTRIBUTED BY HASH(id1) BUCKETS 10\n"
                         + "PROPERTIES (\"replication_num\" = \"1\")\n"
         );
         addConstraint("Alter table pri add constraint pk primary key (id1)");
+        addConstraint("Alter table unrelated_pri add constraint unrelated_pk 
primary key (id1)");
         addConstraint("Alter table foreign_not_null add constraint f_not_null 
foreign key (id2)\n"
                 + "references pri(id1)");
         addConstraint("Alter table foreign_null add constraint f_not_null 
foreign key (id3)\n"
@@ -106,6 +113,17 @@ class EliminateJoinByFkTest extends TestWithFeService 
implements MemoPatternMatc
                 .printlnTree();
     }
 
+    @Test
+    void testDoNotEliminateJoinWithUnrelatedPrimaryTable() {
+        String sql = "select foreign_not_null.id2 from unrelated_pri "
+                + "inner join foreign_not_null on unrelated_pri.id1 = 
foreign_not_null.id2";
+        PlanChecker.from(connectContext)
+                .analyze(sql)
+                .rewrite()
+                .matches(logicalJoin())
+                .printlnTree();
+    }
+
     @Test
     void testNotNullWithPredicate() {
         String sql = "select pri.id1 from pri inner join foreign_not_null on 
pri.id1 = foreign_not_null.id2\n"


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to