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();