You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/12/05 00:08:19 UTC

calcite git commit: [CALCITE-1037] Column uniqueness is calculated incorrectly for Correlate (Alexey Makhmutov)

Repository: calcite
Updated Branches:
  refs/heads/master 565d63926 -> 1ca155249


[CALCITE-1037] Column uniqueness is calculated incorrectly for Correlate (Alexey Makhmutov)

Add test (Julian Hyde).


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/1ca15524
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/1ca15524
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/1ca15524

Branch: refs/heads/master
Commit: 1ca15524992927eb88b41951a8a6ff3f45dfd4f7
Parents: 565d639
Author: Alexey Makhmutov <be...@mail.ru>
Authored: Sun Dec 27 14:28:57 2015 +0300
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Dec 4 14:37:23 2016 -0800

----------------------------------------------------------------------
 .../rel/metadata/RelMdColumnUniqueness.java     | 75 ++++++++++++++++----
 .../apache/calcite/test/RelMetadataTest.java    | 27 +++++++
 2 files changed, 89 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/1ca15524/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
----------------------------------------------------------------------
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 60fefb5..67ef377 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
@@ -43,7 +43,9 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Pair;
 
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 
 import java.util.ArrayList;
@@ -61,6 +63,14 @@ public class RelMdColumnUniqueness
       ReflectiveRelMetadataProvider.reflectiveSource(
           BuiltInMethod.COLUMN_UNIQUENESS.method, new RelMdColumnUniqueness());
 
+  /** Aggregate and Calc are "safe" children of a RelSubset to delve into. */
+  private static final Predicate<RelNode> SAFE_REL =
+      new Predicate<RelNode>() {
+        public boolean apply(RelNode r) {
+          return r instanceof Aggregate || r instanceof Project;
+        }
+      };
+
   //~ Constructors -----------------------------------------------------------
 
   private RelMdColumnUniqueness() {}
@@ -145,7 +155,38 @@ public class RelMdColumnUniqueness
 
   public Boolean areColumnsUnique(Correlate rel, RelMetadataQuery mq,
       ImmutableBitSet columns, boolean ignoreNulls) {
-    return mq.areColumnsUnique(rel.getLeft(), columns, ignoreNulls);
+    switch (rel.getJoinType()) {
+    case ANTI:
+    case SEMI:
+      return mq.areColumnsUnique(rel.getLeft(), columns, ignoreNulls);
+    case LEFT:
+    case INNER:
+      final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns =
+          splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(),
+              columns);
+      final ImmutableBitSet leftColumns = leftAndRightColumns.left;
+      final ImmutableBitSet rightColumns = leftAndRightColumns.right;
+      final RelNode left = rel.getLeft();
+      final RelNode right = rel.getRight();
+
+      if (leftColumns.cardinality() > 0
+          && rightColumns.cardinality() > 0) {
+        Boolean leftUnique =
+            mq.areColumnsUnique(left, leftColumns, ignoreNulls);
+        Boolean rightUnique =
+            mq.areColumnsUnique(right, rightColumns, ignoreNulls);
+        if (leftUnique == null || rightUnique == null) {
+          return null;
+        } else {
+          return leftUnique && rightUnique;
+        }
+      } else {
+        return null;
+      }
+    default:
+      throw new IllegalStateException("Unknown join type " + rel.getJoinType()
+          + " for correlate relation " + rel);
+    }
   }
 
   public Boolean areColumnsUnique(Project rel, RelMetadataQuery mq,
@@ -216,23 +257,16 @@ public class RelMdColumnUniqueness
 
     // Divide up the input column mask into column masks for the left and
     // right sides of the join
-    ImmutableBitSet.Builder leftBuilder = ImmutableBitSet.builder();
-    ImmutableBitSet.Builder rightBuilder = ImmutableBitSet.builder();
-    int nLeftColumns = left.getRowType().getFieldCount();
-    for (int bit : columns) {
-      if (bit < nLeftColumns) {
-        leftBuilder.set(bit);
-      } else {
-        rightBuilder.set(bit - nLeftColumns);
-      }
-    }
+    final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns =
+        splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(),
+            columns);
+    final ImmutableBitSet leftColumns = leftAndRightColumns.left;
+    final ImmutableBitSet rightColumns = leftAndRightColumns.right;
 
     // 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
     // unique for their respective join inputs
-    final ImmutableBitSet leftColumns = leftBuilder.build();
     Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls);
-    final ImmutableBitSet rightColumns = rightBuilder.build();
     Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, ignoreNulls);
     if ((leftColumns.cardinality() > 0)
         && (rightColumns.cardinality() > 0)) {
@@ -366,6 +400,21 @@ public class RelMdColumnUniqueness
     }
     return true;
   }
+
+  /** Splits a column set between left and right sets. */
+  private static Pair<ImmutableBitSet, ImmutableBitSet>
+  splitLeftAndRightColumns(int leftCount, final ImmutableBitSet columns) {
+    ImmutableBitSet.Builder leftBuilder = ImmutableBitSet.builder();
+    ImmutableBitSet.Builder rightBuilder = ImmutableBitSet.builder();
+    for (int bit : columns) {
+      if (bit < leftCount) {
+        leftBuilder.set(bit);
+      } else {
+        rightBuilder.set(bit - leftCount);
+      }
+    }
+    return Pair.of(leftBuilder.build(), rightBuilder.build());
+  }
 }
 
 // End RelMdColumnUniqueness.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1ca15524/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
----------------------------------------------------------------------
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 b1c2ca5..4a35c52 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -34,6 +34,7 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.Correlate;
 import org.apache.calcite.rel.core.CorrelationId;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
@@ -97,6 +98,7 @@ import java.util.Set;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.isA;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertEquals;
@@ -821,6 +823,31 @@ public class RelMetadataTest extends SqlToRelTestBase {
     assertUniqueConsistent(rel);
   }
 
+  @Test public void testCorrelateUniqueKeys() {
+    final String sql = "select *\n"
+        + "from (select distinct deptno from emp) as e,\n"
+        + "  lateral (\n"
+        + "    select * from dept where dept.deptno = e.deptno)";
+    final RelNode rel = convertSql(sql);
+    final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+    assertThat(rel, isA((Class) Project.class));
+    final Project project = (Project) rel;
+    final Set<ImmutableBitSet> result = mq.getUniqueKeys(project);
+    assertThat(result, sortsAs("[{0}]"));
+    if (false) {
+      assertUniqueConsistent(project);
+    }
+
+    assertThat(project.getInput(), isA((Class) Correlate.class));
+    final Correlate correlate = (Correlate) project.getInput();
+    final Set<ImmutableBitSet> result2 = mq.getUniqueKeys(correlate);
+    assertThat(result2, sortsAs("[{0}]"));
+    if (false) {
+      assertUniqueConsistent(correlate);
+    }
+  }
+
   @Test public void testGroupByEmptyUniqueKeys() {
     RelNode rel = convertSql("select count(*) from emp");
     final RelMetadataQuery mq = RelMetadataQuery.instance();