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 d5b6b5c01f [CALCITE-6338] RelMdCollation#project can return an incomplete list of collations in the presence of aliasing d5b6b5c01f is described below commit d5b6b5c01ff17cac100a591a4cc4c9e83d4e1ace Author: Ruben Quesada Lopez <rube...@gmail.com> AuthorDate: Thu Mar 21 16:43:37 2024 +0000 [CALCITE-6338] RelMdCollation#project can return an incomplete list of collations in the presence of aliasing --- .../calcite/rel/metadata/RelMdCollation.java | 20 ++++++++--- .../org/apache/calcite/test/RelMetadataTest.java | 40 ++++++++++++++++++++++ core/src/test/resources/sql/sub-query.iq | 5 ++- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java index 7c107d39d6..9c728384f4 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java @@ -316,22 +316,32 @@ public class RelMdCollation targetsWithMonotonicity.put(project.i, call.getOperator().getMonotonicity(binding)); } } - final List<RelFieldCollation> fieldCollations = new ArrayList<>(); + List<List<RelFieldCollation>> fieldCollationsList = new ArrayList<>(); loop: for (RelCollation ic : inputCollations) { if (ic.getFieldCollations().isEmpty()) { continue; } - fieldCollations.clear(); + fieldCollationsList.clear(); + fieldCollationsList.add(new ArrayList<>()); for (RelFieldCollation ifc : ic.getFieldCollations()) { final Collection<Integer> integers = targets.get(ifc.getFieldIndex()); if (integers.isEmpty()) { continue loop; // cannot do this collation } - fieldCollations.add(ifc.withFieldIndex(integers.iterator().next())); + fieldCollationsList = fieldCollationsList.stream() + .flatMap(fieldCollations -> integers.stream() + .map(integer -> { + List<RelFieldCollation> newFieldCollations = new ArrayList<>(fieldCollations); + newFieldCollations.add(ifc.withFieldIndex(integer)); + return newFieldCollations; + })).collect(Collectors.toList()); + } + assert !fieldCollationsList.isEmpty(); + for (List<RelFieldCollation> fieldCollations : fieldCollationsList) { + assert !fieldCollations.isEmpty(); + collations.add(RelCollations.of(fieldCollations)); } - assert !fieldCollations.isEmpty(); - collations.add(RelCollations.of(fieldCollations)); } final List<RelFieldCollation> fieldCollationsForRexCalls = 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 db1f65c242..d9733486bd 100644 --- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java @@ -1948,6 +1948,46 @@ public class RelMetadataTest { assertEquals("[[0]]", collations.toString()); } + /** + * Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-6338">[CALCITE-6338] + * RelMdCollation#project can return an incomplete list of collations + * in the presence of aliasing</a>. + */ + @Test void testCollationProjectAliasing() { + final RelBuilder builder = RelBuilderTest.createBuilder(); + final RelNode relNode1 = builder + .scan("EMP") + .sort(2, 3) + .project(builder.field(0), builder.field(2), builder.field(2), builder.field(3)) + .build(); + checkCollationProjectAliasing(relNode1, "[[1, 3], [2, 3]]"); + final RelNode relNode2 = builder + .scan("EMP") + .sort(0, 1) + .project(builder.field(0), builder.field(0), builder.field(1), builder.field(1)) + .build(); + checkCollationProjectAliasing(relNode2, "[[0, 2], [0, 3], [1, 2], [1, 3]]"); + final RelNode relNode3 = builder + .scan("EMP") + .sort(0, 1, 2) + .project( + builder.field(0), builder.field(0), + builder.field(1), builder.field(1), builder.field(1), + builder.field(2)) + .build(); + checkCollationProjectAliasing(relNode3, + "[[0, 2, 5], [0, 3, 5], [0, 4, 5], [1, 2, 5], [1, 3, 5], [1, 4, 5]]"); + } + + private void checkCollationProjectAliasing(RelNode relNode, String expectedCollation) { + final RelMetadataQuery mq = relNode.getCluster().getMetadataQuery(); + assertThat(relNode, instanceOf(Project.class)); + final ImmutableList<RelCollation> collations = mq.collations(relNode); + assertThat(collations, notNullValue()); + assertEquals(expectedCollation, collations.toString()); + } + /** Unit test for * {@link org.apache.calcite.rel.metadata.RelMdCollation#project} * and other helper functions for deducing collations. */ diff --git a/core/src/test/resources/sql/sub-query.iq b/core/src/test/resources/sql/sub-query.iq index 4d76b3fb6b..16cf991f13 100644 --- a/core/src/test/resources/sql/sub-query.iq +++ b/core/src/test/resources/sql/sub-query.iq @@ -2260,9 +2260,8 @@ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[<>($t2, $t1)], expr#7=[1], expr#8=[ EnumerableMergeJoin(condition=[=($0, $5)], joinType=[left]) EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0]) EnumerableTableScan(table=[[scott, EMP]]) - EnumerableSort(sort0=[$4], dir0=[ASC]) - EnumerableCalc(expr#0..7=[{inputs}], expr#8=[1:BIGINT], expr#9=[true], c=[$t8], d=[$t8], m=[$t0], trueLiteral=[$t9], EMPNO1=[$t0]) - EnumerableTableScan(table=[[scott, EMP]]) + EnumerableCalc(expr#0..7=[{inputs}], expr#8=[1:BIGINT], expr#9=[true], c=[$t8], d=[$t8], m=[$t0], trueLiteral=[$t9], EMPNO1=[$t0]) + EnumerableTableScan(table=[[scott, EMP]]) !plan +-------+ | EMPNO |