[CALCITE-1932] Project.getPermutation() should return null if not a permutation 
(e.g. repeated InputRef)

Close apache/calcite#512


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

Branch: refs/heads/master
Commit: 01c5446138d419a85678bff7db06eabb4cd39846
Parents: eaa5641
Author: Minji Kim <mi...@dremio.com>
Authored: Tue Nov 15 13:29:54 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Aug 7 15:39:31 2017 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/rel/core/Project.java    | 11 ++++--
 .../calcite/util/PermutationTestCase.java       | 38 ++++++++++++++++++++
 2 files changed, 47 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/01c54461/core/src/main/java/org/apache/calcite/rel/core/Project.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java 
b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index 1a6f3f2..953eb8e 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -45,7 +45,9 @@ import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Relational expression that computes a set of
@@ -330,11 +332,16 @@ public abstract class Project extends SingleRel {
     if (fieldCount != inputFieldCount) {
       return null;
     }
-    Permutation permutation = new Permutation(fieldCount);
+    final Permutation permutation = new Permutation(fieldCount);
+    final Set<Integer> alreadyProjected = new HashSet<>(fieldCount);
     for (int i = 0; i < fieldCount; ++i) {
       final RexNode exp = projects.get(i);
       if (exp instanceof RexInputRef) {
-        permutation.set(i, ((RexInputRef) exp).getIndex());
+        final int index = ((RexInputRef) exp).getIndex();
+        if (!alreadyProjected.add(index)) {
+          return null;
+        }
+        permutation.set(i, index);
       } else {
         return null;
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/01c54461/core/src/test/java/org/apache/calcite/util/PermutationTestCase.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/util/PermutationTestCase.java 
b/core/src/test/java/org/apache/calcite/util/PermutationTestCase.java
index 04beeb1..75c78c0 100644
--- a/core/src/test/java/org/apache/calcite/util/PermutationTestCase.java
+++ b/core/src/test/java/org/apache/calcite/util/PermutationTestCase.java
@@ -17,10 +17,22 @@
 package org.apache.calcite.util;
 
 
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.sql.type.SqlTypeName;
+
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Test;
 
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -152,6 +164,32 @@ public class PermutationTestCase {
       // success
     }
   }
+
+  @Test public void testProjectPermutation() {
+    final RelDataTypeFactory typeFactory = new JavaTypeFactoryImpl();
+    final RexBuilder builder = new RexBuilder(typeFactory);
+    final RelDataType doubleType =
+        typeFactory.createSqlType(SqlTypeName.DOUBLE);
+
+    // A project with [1, 1] is not a permutation, so should return null
+    final Permutation perm = Project.getPermutation(2,
+        ImmutableList.of(builder.makeInputRef(doubleType, 1),
+            builder.makeInputRef(doubleType, 1)));
+    assertThat(perm, nullValue());
+
+    // A project with [0, 1, 0] is not a permutation, so should return null
+    final Permutation perm1 = Project.getPermutation(2,
+        ImmutableList.of(builder.makeInputRef(doubleType, 0),
+            builder.makeInputRef(doubleType, 1),
+            builder.makeInputRef(doubleType, 0)));
+    assertThat(perm1, nullValue());
+
+    // A project of [1, 0] is a valid permutation!
+    final Permutation perm2 = Project.getPermutation(2,
+        ImmutableList.of(builder.makeInputRef(doubleType, 1),
+            builder.makeInputRef(doubleType, 0)));
+    assertThat(perm2, is(new Permutation(new int[]{1, 0})));
+  }
 }
 
 // End PermutationTestCase.java

Reply via email to