[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 <[email protected]> Authored: Tue Nov 15 13:29:54 2016 -0800 Committer: Julian Hyde <[email protected]> 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
