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

rubenql pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new 27cc692611 [CALCITE-7199] Improve column uniqueness computation for 
Join
27cc692611 is described below

commit 27cc69261131e397590c0dd60187f4eb3b4a1a03
Author: Claude Brisson <[email protected]>
AuthorDate: Thu Sep 25 09:25:13 2025 +0200

    [CALCITE-7199] Improve column uniqueness computation for Join
---
 .../rel/metadata/RelMdColumnUniqueness.java        | 47 +++++++++++++---------
 .../org/apache/calcite/test/RelMetadataTest.java   | 24 +++++++++++
 2 files changed, 53 insertions(+), 18 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java 
b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
index 81d3e9a9e7..a4ac2e9c5a 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
@@ -334,7 +334,7 @@ public Boolean areColumnsUnique(Intersect rel, 
RelMetadataQuery mq,
     }
 
     // If the original column mask contains columns from both the left and
-    // right hand side, then the columns are unique if and only if they're
+    // right hand side, then the columns are unique if (but not only if) 
they're
     // unique for their respective join inputs
     Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls);
     Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, 
ignoreNulls);
@@ -342,37 +342,48 @@ public Boolean areColumnsUnique(Intersect rel, 
RelMetadataQuery mq,
         && (rightColumns.cardinality() > 0)) {
       if ((leftUnique == null) || (rightUnique == null)) {
         return null;
-      } else {
-        return leftUnique && rightUnique;
+      } else if (leftUnique && rightUnique) {
+        return true;
       }
     }
 
-    // If we're only trying to determine uniqueness for columns that
-    // originate from one join input, then determine if the equijoin
-    // columns from the other join input are unique.  If they are, then
-    // the columns are unique for the entire join if they're unique for
-    // the corresponding join input, provided that input is not null
-    // generating.
+    // Determine if the equijoin columns from the other join input are unique.
+    // If they are, then the columns are unique for the entire join if they're 
unique for
+    // the corresponding join input, provided that input is not null 
generating.
     if (leftColumns.cardinality() > 0) {
       if (rel.getJoinType().generatesNullsOnLeft()) {
         return false;
       }
-      Boolean rightJoinColsUnique =
-          mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls);
-      if ((rightJoinColsUnique == null) || (leftUnique == null)) {
+      if (leftUnique == null) {
         return null;
       }
-      return rightJoinColsUnique && leftUnique;
-    } else if (rightColumns.cardinality() > 0) {
+      if (leftUnique) {
+        Boolean joinRightKeyUnique = mq.areColumnsUnique(right, 
joinInfo.rightSet(), ignoreNulls);
+        if (joinRightKeyUnique == null) {
+          return null;
+        }
+        if (joinRightKeyUnique) {
+          return true;
+        }
+      }
+    }
+    // Similarly, if the columns originate from the right input
+    if (rightColumns.cardinality() > 0) {
       if (rel.getJoinType().generatesNullsOnRight()) {
         return false;
       }
-      Boolean leftJoinColsUnique =
-          mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls);
-      if ((leftJoinColsUnique == null) || (rightUnique == null)) {
+      if (rightUnique == null) {
         return null;
       }
-      return leftJoinColsUnique && rightUnique;
+      if (rightUnique) {
+        Boolean joinLeftKeyUnique = mq.areColumnsUnique(left, 
joinInfo.leftSet(), ignoreNulls);
+        if (joinLeftKeyUnique == null) {
+          return null;
+        }
+        if (joinLeftKeyUnique) {
+          return true;
+        }
+      }
     }
 
     return false;
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java 
b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index 72f0cd958d..c1afc5f92d 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -1425,6 +1425,30 @@ private void 
checkColumnUniquenessForFilterWithConstantColumns(String sql) {
         .assertThatUniqueKeysAre(bitSetOf());
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7199";>[CALCITE-7199]
+   * Improve column uniqueness computation for Join</a>. */
+  @Test void testColumnUniquenessForJoin() {
+    final String sql1 = ""
+        + "select A.empno, B.ename\n"
+        + "from emp A join emp B\n"
+        + "on A.empno = B.empno";
+    final String sql2 = ""
+        + "select B.empno, A.ename\n"
+        + "from emp A join emp B\n"
+        + "on A.empno = B.empno";
+    checkColumnUniquenessForJoin(sql1);
+    checkColumnUniquenessForJoin(sql2);
+  }
+
+  private void checkColumnUniquenessForJoin(String sql) {
+    sql(sql)
+        .assertThatAreColumnsUnique(bitSetOf(0), is(true))
+        .assertThatAreColumnsUnique(bitSetOf(0, 1), is(true))
+        .assertThatAreColumnsUnique(bitSetOf(1), is(false))
+        .assertThatUniqueKeysAre(bitSetOf(0));
+  }
+
   @Test void testColumnUniquenessForJoinOnLimit1() {
     final String sql = ""
         + "select *\n"

Reply via email to