This is an automated email from the ASF dual-hosted git repository. amashenkov pushed a commit to branch ignite-18208 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit 0aa0268750413a21b0a92e226dc7d134fb77eb4a Author: amashenkov <[email protected]> AuthorDate: Tue Feb 14 14:30:05 2023 +0300 Merge aggregates tests. --- .../planner/AbstractAggregatePlannerTest.java | 56 +- .../planner/AggregateDistinctPlannerTest.java | 122 ----- .../sql/engine/planner/AggregatePlannerTest.java | 569 +++++++++++++++------ .../engine/planner/HashAggregatePlannerTest.java | 129 ----- .../engine/planner/SortAggregatePlannerTest.java | 251 --------- 5 files changed, 469 insertions(+), 658 deletions(-) diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java index 547320af33..53e1bb1574 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java @@ -18,7 +18,20 @@ package org.apache.ignite.internal.sql.engine.planner; import java.util.UUID; +import java.util.function.Supplier; +import org.apache.calcite.plan.RelOptUtil; import org.apache.calcite.rel.type.RelDataTypeFactory; +import org.apache.calcite.sql.SqlExplainLevel; +import org.apache.ignite.internal.sql.engine.rel.IgniteRel; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedAggregateBase; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedHashAggregate; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedSortAggregate; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapAggregateBase; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapHashAggregate; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapSortAggregate; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceAggregateBase; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceHashAggregate; +import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceSortAggregate; import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions; import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory; import org.apache.ignite.internal.sql.engine.type.IgniteTypeSystem; @@ -26,7 +39,7 @@ import org.apache.ignite.internal.sql.engine.type.IgniteTypeSystem; /** * Base class for further planner test implementations. */ -public class AbstractAggregatePlannerTest extends AbstractPlannerTest { +public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest { /** * Creates table with broadcast distribution. * @@ -70,4 +83,45 @@ public class AbstractAggregatePlannerTest extends AbstractPlannerTest { IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID) ); } + + protected static Supplier<String> invalidPlanErrorMessage(IgniteRel phys) { + return () -> "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES); + } + + enum AggregateAlgorithm { + SORT( + IgniteColocatedSortAggregate.class, + IgniteMapSortAggregate.class, + IgniteReduceSortAggregate.class, + "MapReduceHashAggregateConverterRule", + "ColocatedHashAggregateConverterRule" + ), + + HASH( + IgniteColocatedHashAggregate.class, + IgniteMapHashAggregate.class, + IgniteReduceHashAggregate.class, + "MapReduceSortAggregateConverterRule", + "ColocatedSortAggregateConverterRule" + ); + + public final Class<? extends IgniteColocatedAggregateBase> colocated; + + public final Class<? extends IgniteMapAggregateBase> map; + + public final Class<? extends IgniteReduceAggregateBase> reduce; + + public final String[] rulesToDisable; + + AggregateAlgorithm( + Class<? extends IgniteColocatedAggregateBase> colocated, + Class<? extends IgniteMapAggregateBase> map, + Class<? extends IgniteReduceAggregateBase> reduce, + String... rulesToDisable) { + this.colocated = colocated; + this.map = map; + this.reduce = reduce; + this.rulesToDisable = rulesToDisable; + } + } } diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregateDistinctPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregateDistinctPlannerTest.java deleted file mode 100644 index bc0118fa8f..0000000000 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregateDistinctPlannerTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.internal.sql.engine.planner; - -import static org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.apache.calcite.plan.RelOptUtil; -import org.apache.calcite.sql.SqlExplainLevel; -import org.apache.ignite.internal.sql.engine.rel.IgniteAggregate; -import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan; -import org.apache.ignite.internal.sql.engine.rel.IgniteRel; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedAggregateBase; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedHashAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedSortAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapAggregateBase; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapHashAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapSortAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceAggregateBase; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceHashAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceSortAggregate; -import org.apache.ignite.internal.sql.engine.schema.IgniteSchema; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; - -/** - * AggregateDistinctPlannerTest. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - */ -public class AggregateDistinctPlannerTest extends AbstractAggregatePlannerTest { - /** - * MapReduceDistinctWithIndex. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - * - * @throws Exception If failed. - */ - @ParameterizedTest - @EnumSource - public void mapReduceDistinctWithIndex(AggregateAlgorithm algo) throws Exception { - TestTable tbl = createAffinityTable("TEST").addIndex("val0_val1", 1, 2); - - IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); - - publicSchema.addTable(tbl); - - String sql = "SELECT DISTINCT val0, val1 FROM test"; - - IgniteRel phys = physicalPlan( - sql, - publicSchema, - algo.rulesToDisable - ); - - IgniteAggregate mapAgg = findFirstNode(phys, byClass(algo.map)); - IgniteReduceAggregateBase rdcAgg = findFirstNode(phys, byClass(algo.reduce)); - - assertNotNull(rdcAgg, "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES)); - assertNotNull(mapAgg, "Invalid plan\n" + RelOptUtil.toString(phys)); - - assertTrue(nullOrEmpty(rdcAgg.getAggregateCalls()), "Invalid plan\n" + RelOptUtil.toString(phys)); - assertTrue(nullOrEmpty(mapAgg.getAggCallList()), "Invalid plan\n" + RelOptUtil.toString(phys)); - - if (algo == AggregateAlgorithm.SORT) { - assertNotNull(findFirstNode(phys, byClass(IgniteIndexScan.class))); - } - } - - enum AggregateAlgorithm { - SORT( - IgniteColocatedSortAggregate.class, - IgniteMapSortAggregate.class, - IgniteReduceSortAggregate.class, - "ColocatedHashAggregateConverterRule", - "MapReduceHashAggregateConverterRule", - "ColocatedSortAggregateConverterRule" - ), - - HASH( - IgniteColocatedHashAggregate.class, - IgniteMapHashAggregate.class, - IgniteReduceHashAggregate.class, - "ColocatedSortAggregateConverterRule", - "MapReduceSortAggregateConverterRule", - "ColocatedHashAggregateConverterRule" - ); - - public final Class<? extends IgniteColocatedAggregateBase> single; - - public final Class<? extends IgniteMapAggregateBase> map; - - public final Class<? extends IgniteReduceAggregateBase> reduce; - - public final String[] rulesToDisable; - - AggregateAlgorithm( - Class<? extends IgniteColocatedAggregateBase> single, - Class<? extends IgniteMapAggregateBase> map, - Class<? extends IgniteReduceAggregateBase> reduce, - String... rulesToDisable) { - this.single = single; - this.map = map; - this.reduce = reduce; - this.rulesToDisable = rulesToDisable; - } - } -} diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java index 0c882f1c4d..209bf79f5f 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java @@ -19,19 +19,21 @@ package org.apache.ignite.internal.sql.engine.planner; import static org.apache.ignite.internal.util.ArrayUtils.concat; import static org.apache.ignite.internal.util.CollectionUtils.first; +import static org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.math.BigDecimal; -import java.util.Arrays; import java.util.List; import java.util.UUID; -import java.util.function.Predicate; import java.util.stream.Stream; import org.apache.calcite.plan.RelOptUtil; +import org.apache.calcite.rel.RelCollations; +import org.apache.calcite.rel.RelFieldCollation; import org.apache.calcite.rel.SingleRel; import org.apache.calcite.rel.core.Aggregate; import org.apache.calcite.rel.core.AggregateCall; @@ -40,24 +42,26 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.sql.SqlExplainLevel; import org.apache.calcite.sql.fun.SqlAvgAggFunction; +import org.apache.calcite.sql.fun.SqlCountAggFunction; import org.apache.ignite.internal.sql.engine.rel.IgniteAggregate; +import org.apache.ignite.internal.sql.engine.rel.IgniteCorrelatedNestedLoopJoin; import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan; +import org.apache.ignite.internal.sql.engine.rel.IgniteLimit; import org.apache.ignite.internal.sql.engine.rel.IgniteRel; import org.apache.ignite.internal.sql.engine.rel.IgniteSort; +import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan; import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedAggregateBase; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedHashAggregate; import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedSortAggregate; import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapAggregateBase; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapHashAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapSortAggregate; import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceAggregateBase; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceHashAggregate; import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceSortAggregate; import org.apache.ignite.internal.sql.engine.schema.IgniteSchema; import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution; import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions; import org.apache.ignite.internal.sql.engine.trait.TraitUtils; -import org.apache.ignite.internal.util.Pair; +import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory; +import org.apache.ignite.internal.sql.engine.type.IgniteTypeSystem; +import org.apache.ignite.internal.util.ArrayUtils; import org.hamcrest.core.IsInstanceOf; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -95,10 +99,10 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { IgniteColocatedAggregateBase agg = findFirstNode(phys, byClass(algo.colocated)); - assertNotNull(agg, "Invalid plan\n" + RelOptUtil.toString(phys)); + assertNotNull(agg, invalidPlanErrorMessage(phys)); assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), + invalidPlanErrorMessage(phys).get(), first(agg.getAggCallList()).getAggregation(), IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); @@ -122,7 +126,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { publicSchema.addTable(tbl); - String sql = "SELECT AVG(val0) FILTER(WHERE val1 > 10) FROM test GROUP BY grp0"; + String sql = "SELECT AVG(val0) FROM test GROUP BY grp0"; IgniteRel phys = physicalPlan( sql, @@ -132,10 +136,9 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { IgniteColocatedAggregateBase agg = findFirstNode(phys, byClass(algo.colocated)); - assertNotNull(agg, "Invalid plan\n" + RelOptUtil.toString(phys)); + assertNotNull(agg, invalidPlanErrorMessage(phys)); - assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), + assertThat(invalidPlanErrorMessage(phys).get(), first(agg.getAggCallList()).getAggregation(), IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); @@ -144,48 +147,38 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { } } - /** - * MapReduceGroupBy. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - * - * @throws Exception If failed. - */ @ParameterizedTest - @EnumSource - public void mapReduceGroupBy(AggregateAlgorithm algo) throws Exception { - TestTable tbl = createAffinityTable("TEST"); - - IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); - - publicSchema.addTable(tbl); - - String sql = "SELECT AVG(val0) FILTER (WHERE val1 > 10) FROM test GROUP BY grp1, grp0"; - - IgniteRel phys = physicalPlan( - sql, - publicSchema, - algo.rulesToDisable + @EnumSource(AggregateAlgorithm.class) + public void colocated(AggregateAlgorithm algo) throws Exception { + IgniteSchema schema = createSchema( + createTable( + "EMP", IgniteDistributions.affinity(1, UUID.randomUUID(), DEFAULT_ZONE_ID), + "EMPID", Integer.class, + "DEPTID", Integer.class, + "NAME", String.class, + "SALARY", Integer.class + ).addIndex("DEPTID", 1), + createTable( + "DEPT", IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID), + "DEPTID", Integer.class, + "NAME", String.class + ).addIndex("DEPTID", 0) ); - IgniteMapAggregateBase mapAgg = findFirstNode(phys, byClass(algo.map)); - IgniteReduceAggregateBase rdcAgg = findFirstNode(phys, byClass(algo.reduce)); - - assertNotNull(rdcAgg, "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES)); - assertNotNull(mapAgg, "Invalid plan\n" + RelOptUtil.toString(phys)); + String sql = "SELECT SUM(SALARY) FROM emp GROUP BY deptid"; - assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), - first(rdcAgg.getAggregateCalls()).getAggregation(), - IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); + assertPlan(sql, schema, hasChildThat(isInstanceOf(algo.colocated) + .and(hasDistribution(IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID)))), + algo.rulesToDisable); - assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), - first(mapAgg.getAggCallList()).getAggregation(), - IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); + sql = "SELECT dept.deptid, agg.cnt " + + "FROM dept " + + "JOIN (SELECT deptid, COUNT(*) AS cnt FROM emp GROUP BY deptid) AS agg ON dept.deptid = agg.deptid"; - if (algo == AggregateAlgorithm.SORT) { - assertNotNull(findFirstNode(phys, byClass(IgniteSort.class))); - } + assertPlan(sql, schema, hasChildThat(isInstanceOf(Join.class) + .and(input(0, hasDistribution(IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID)))) + .and(input(1, hasDistribution(IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID))))), + algo.rulesToDisable); } /** @@ -202,7 +195,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { publicSchema.addTable(tbl); - String sql = "SELECT AVG(val0), grp0 FROM TEST GROUP BY grp0 UNION ALL SELECT val0, grp0 FROM test"; + String sql = "SELECT AVG(val0), grp0 FROM test GROUP BY grp0 UNION ALL SELECT val0, grp0 FROM test"; IgniteRel phys = physicalPlan( sql, @@ -218,8 +211,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { phys = physicalPlan( sql, publicSchema, - concat(algo.rulesToDisable, "SortSingleAggregateConverterRule", - "HashSingleAggregateConverterRule") + concat(algo.rulesToDisable) ); IgniteReduceAggregateBase rdcAgg = findFirstNode(phys, byClass(algo.reduce)); @@ -227,6 +219,38 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { assertEquals(IgniteDistributions.single(), TraitUtils.distribution(rdcAgg)); } + /** + * CollationPermuteSingle. + * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 + * + * @throws Exception If failed. + */ + @Test + public void collationPermuteSingle() throws Exception { + TestTable tbl = createAffinityTable("TEST").addIndex("grp0_1", 3, 4); + + IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); + + publicSchema.addTable(tbl); + + String sql = "SELECT MIN(val0) FROM test GROUP BY grp1, grp0"; + + IgniteRel phys = physicalPlan( + sql, + publicSchema, + AggregateAlgorithm.SORT.rulesToDisable + ); + + IgniteColocatedSortAggregate agg = findFirstNode(phys, byClass(IgniteColocatedSortAggregate.class)); + + assertNotNull(agg, "Invalid plan\n" + RelOptUtil.toString(phys)); + + assertNull( + findFirstNode(phys, byClass(IgniteSort.class)), + "Invalid plan\n" + RelOptUtil.toString(phys) + ); + } + /** * ExpandDistinctAggregates. * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 @@ -259,7 +283,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { .anyMatch(n -> ((Aggregate) n).getAggCallList().stream() .anyMatch(AggregateCall::isDistinct) ), - "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES) + invalidPlanErrorMessage(phys) ); assertNotNull( @@ -271,23 +295,95 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { assertTrue( findNodes(phys, byClass(algo.reduce)).stream() .allMatch(n -> ((IgniteReduceAggregateBase) n).getAggregateCalls().isEmpty()), - "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES) + invalidPlanErrorMessage(phys) ); assertTrue( findNodes(phys, byClass(algo.map)).stream() .allMatch(n -> ((Aggregate) n).getAggCallList().isEmpty()), - "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES) + invalidPlanErrorMessage(phys) ); // Check the second aggregation step contains accumulators. assertTrue( findNodes(phys, byClass(algo.colocated)).stream() .noneMatch(n -> ((Aggregate) n).getAggCallList().isEmpty()), - "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES) + invalidPlanErrorMessage(phys) ); } + /** + * MapReduceGroupBy. + * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 + * + * @throws Exception If failed. + */ + @ParameterizedTest + @EnumSource + public void mapReduceGroupBy(AggregateAlgorithm algo) throws Exception { + TestTable tbl = createAffinityTable("TEST"); + + IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); + + publicSchema.addTable(tbl); + + String sql = "SELECT AVG(val0) FILTER (WHERE val1 > 10) FROM test GROUP BY grp1, grp0"; + + IgniteRel phys = physicalPlan( + sql, + publicSchema, + algo.rulesToDisable + ); + + IgniteMapAggregateBase mapAgg = findFirstNode(phys, byClass(algo.map)); + IgniteReduceAggregateBase rdcAgg = findFirstNode(phys, byClass(algo.reduce)); + + assertNotNull(rdcAgg, invalidPlanErrorMessage(phys)); + assertNotNull(mapAgg, invalidPlanErrorMessage(phys)); + + assertThat(invalidPlanErrorMessage(phys).get(), + first(rdcAgg.getAggregateCalls()).getAggregation(), + IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); + + assertThat(invalidPlanErrorMessage(phys).get(), + first(mapAgg.getAggCallList()).getAggregation(), + IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); + + if (algo == AggregateAlgorithm.SORT) { + assertNotNull(findFirstNode(phys, byClass(IgniteSort.class))); + } + } + + /** + * Check that map aggregate does not contain distinct accumulator and can be planned at all. + * + * @throws Exception If failed. + */ + @ParameterizedTest + @EnumSource + public void mapAggregateWithoutDistinctAcc(AggregateAlgorithm algo) throws Exception { + TestTable tbl = createAffinityTable("TEST"); + + IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); + + publicSchema.addTable(tbl); + + checkDistinctInMapAggNode("SELECT COUNT(*) FROM test", publicSchema, algo); + checkDistinctInMapAggNode("SELECT COUNT(DISTINCT val0) FROM test", publicSchema, algo); + checkDistinctInMapAggNode("SELECT AVG(DISTINCT val0) FROM test", publicSchema, algo); + checkDistinctInMapAggNode("SELECT SUM(DISTINCT val0) FROM test", publicSchema, algo); + checkDistinctInMapAggNode("SELECT MIN(DISTINCT val0) FROM test", publicSchema, algo); + checkDistinctInMapAggNode("SELECT MAX(DISTINCT val0) FROM test", publicSchema, algo); + + checkDistinctInMapAggNode("SELECT COUNT(DISTINCT val0) FROM test GROUP BY val1, grp0", publicSchema, algo); + checkDistinctInMapAggNode("SELECT val1, COUNT(DISTINCT val0) as v1 FROM test GROUP BY val1", publicSchema, algo); + checkDistinctInMapAggNode("SELECT AVG(DISTINCT val0) FROM test GROUP BY val1", publicSchema, algo); + checkDistinctInMapAggNode("SELECT SUM(DISTINCT val0) FROM test GROUP BY val1", publicSchema, algo); + checkDistinctInMapAggNode("SELECT MIN(DISTINCT val0) FROM test GROUP BY val1", publicSchema, algo); + checkDistinctInMapAggNode("SELECT MAX(DISTINCT val0) FROM test GROUP BY val1", publicSchema, algo); + checkDistinctInMapAggNode("SELECT val0 FROM test WHERE VAL1 = ANY(SELECT DISTINCT val1 FROM test)", publicSchema, algo); + } + @ParameterizedTest @MethodSource("provideAlgoAndDistribution") public void singleSumTypes(AggregateAlgorithm algo, IgniteDistribution distr) throws Exception { @@ -328,7 +424,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { SingleRel agg = findFirstNode(phys, byClass(cls)); - assertNotNull(agg, "Invalid plan\n" + RelOptUtil.toString(phys)); + assertNotNull(agg, invalidPlanErrorMessage(phys)); RelDataType rowTypes = agg.getRowType(); @@ -343,67 +439,271 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { assertEquals(tf.createJavaType(Double.class), rowTypes.getFieldList().get(7).getType()); } + + /** + * CollationPermuteMapReduce. + * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 + * + * @throws Exception If failed. + */ + @Test + public void collationPermuteMapReduce() throws Exception { + TestTable tbl = createAffinityTable("TEST").addIndex("grp0_1", 3, 4); + + IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); + + publicSchema.addTable(tbl); + + String sql = "SELECT MIN(val0) FROM test GROUP BY grp1, grp0"; + + IgniteRel phys = physicalPlan( + sql, + publicSchema, + AggregateAlgorithm.SORT.rulesToDisable + ); + + IgniteReduceSortAggregate agg = findFirstNode(phys, byClass(IgniteReduceSortAggregate.class)); + + assertNotNull(agg, "Invalid plan\n" + RelOptUtil.toString(phys)); + + assertNull( + findFirstNode(phys, byClass(IgniteSort.class)), + "Invalid plan\n" + RelOptUtil.toString(phys) + ); + } + + @Test + public void testEmptyCollationPassThroughLimit() throws Exception { + IgniteSchema publicSchema = createSchema( + createTable("TEST", IgniteDistributions.single(), "A", Integer.class)); + + assertPlan("SELECT (SELECT test.a FROM test t ORDER BY 1 LIMIT 1) FROM test", publicSchema, + hasChildThat(isInstanceOf(IgniteCorrelatedNestedLoopJoin.class) + .and(input(1, hasChildThat(isInstanceOf(IgniteLimit.class) + .and(input(isInstanceOf(IgniteSort.class))))))) + ); + } + + @Test + public void testCollationPassThrough() throws Exception { + IgniteSchema publicSchema = createSchema( + createTable("TEST", IgniteDistributions.single(), "A", Integer.class, "B", Integer.class)); + + // Sort order equals to grouping set. + assertPlan("SELECT a, b, COUNT(*) FROM test GROUP BY a, b ORDER BY a, b", publicSchema, + isInstanceOf(IgniteAggregate.class) + .and(input(isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) + .and(input(isTableScan("TEST"))))), + AggregateAlgorithm.SORT.rulesToDisable + ); + + // Sort order equals to grouping set (permuted collation). + assertPlan("SELECT a, b, COUNT(*) FROM test GROUP BY a, b ORDER BY b, a", publicSchema, + isInstanceOf(IgniteAggregate.class) + .and(input(isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(1, 0)))) + .and(input(isTableScan("TEST"))))), + AggregateAlgorithm.SORT.rulesToDisable + ); + + // Sort order is a subset of grouping set. + assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY a", publicSchema, + isInstanceOf(IgniteAggregate.class) + .and(input(isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) + .and(input(isTableScan("TEST"))))), + AggregateAlgorithm.SORT.rulesToDisable + ); + + // Sort order is a subset of grouping set (permuted collation). + assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY b", publicSchema, + isInstanceOf(IgniteAggregate.class) + .and(input(isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(1, 0)))) + .and(input(isTableScan("TEST"))))), + AggregateAlgorithm.SORT.rulesToDisable + ); + + // Sort order is a superset of grouping set (additional sorting required). + assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY a, b, cnt", publicSchema, + isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1, 2)))) + .and(input(isInstanceOf(IgniteAggregate.class) + .and(input(isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) + .and(input(isTableScan("TEST"))))))), + AggregateAlgorithm.SORT.rulesToDisable + ); + + // Sort order is not equals to grouping set (additional sorting required). + assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY cnt, b", publicSchema, + isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(2, 1)))) + .and(input(isInstanceOf(IgniteAggregate.class) + .and(input(isInstanceOf(IgniteSort.class) + .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) + .and(input(isTableScan("TEST"))))))), + AggregateAlgorithm.SORT.rulesToDisable + ); + } + + /** + * Test simple query with aggregate and no groups. + */ @ParameterizedTest - @EnumSource(AggregateAlgorithm.class) - public void colocated(AggregateAlgorithm algo) throws Exception { - IgniteSchema schema = createSchema( - createTable( - "EMP", IgniteDistributions.affinity(1, UUID.randomUUID(), DEFAULT_ZONE_ID), - "EMPID", Integer.class, - "DEPTID", Integer.class, - "NAME", String.class, - "SALARY", Integer.class - ).addIndex("DEPTID", 1), - createTable( - "DEPT", IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID), - "DEPTID", Integer.class, - "NAME", String.class - ).addIndex("DEPTID", 0) + @EnumSource + public void noGroupByAggregate(AggregateAlgorithm algo) throws Exception { + TestTable tbl = createAffinityTable("TEST").addIndex("val0_val1", 1, 2); + + IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); + + publicSchema.addTable(tbl); + + String sqlCount = "SELECT COUNT(*) FROM test"; + + IgniteRel phys = physicalPlan( + sqlCount, + publicSchema, + algo.rulesToDisable ); + assertNotNull(phys); - String sql = "SELECT SUM(SALARY) FROM emp GROUP BY deptid"; + IgniteReduceAggregateBase rdcAgg = findFirstNode(phys, byClass(algo.reduce)); + IgniteMapAggregateBase mapAgg = findFirstNode(phys, byClass(algo.map)); - assertPlan(sql, schema, hasChildThat(isInstanceOf(algo.colocated) - .and(hasDistribution(IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID)))), - algo.rulesToDisable); + assertNotNull(rdcAgg, invalidPlanErrorMessage(phys)); + assertNotNull(mapAgg, invalidPlanErrorMessage(phys)); - sql = "SELECT dept.deptid, agg.cnt " - + "FROM dept " - + "JOIN (SELECT deptid, COUNT(*) AS cnt FROM emp GROUP BY deptid) AS agg ON dept.deptid = agg.deptid"; + assertThat( + invalidPlanErrorMessage(phys).get(), + first(rdcAgg.getAggregateCalls()).getAggregation(), + IsInstanceOf.instanceOf(SqlCountAggFunction.class)); - assertPlan(sql, schema, hasChildThat(isInstanceOf(Join.class) - .and(input(0, hasDistribution(IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID)))) - .and(input(1, hasDistribution(IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID))))), - algo.rulesToDisable); + assertThat( + invalidPlanErrorMessage(phys).get(), + first(mapAgg.getAggCallList()).getAggregation(), + IsInstanceOf.instanceOf(SqlCountAggFunction.class)); } /** - * Check that map aggregate does not contain distinct accumulator and can be planned at all. + * Test subquery with aggregate. * * @throws Exception If failed. */ - @Test - public void mapAggregateWithoutDistinctAcc() throws Exception { - TestTable tbl = createAffinityTable("TEST"); + @ParameterizedTest + @EnumSource + public void subqueryWithAggregate(AggregateAlgorithm algo) throws Exception { + IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE); + + IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); + + createTable(publicSchema, + "EMPS", + new RelDataTypeFactory.Builder(f) + .add("ID", f.createJavaType(Integer.class)) + .add("NAME", f.createJavaType(String.class)) + .add("SALARY", f.createJavaType(Double.class)) + .build(), + IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID) + ); + + String sql = "SELECT * FROM emps WHERE emps.salary = (SELECT AVG(emps.salary) FROM emps)"; + + IgniteRel phys = physicalPlan( + sql, + publicSchema, + algo.rulesToDisable + ); + assertNotNull(phys); + + IgniteReduceAggregateBase rdcAgg = findFirstNode(phys, byClass(algo.reduce)); + IgniteMapAggregateBase mapAgg = findFirstNode(phys, byClass(algo.map)); + + assertNotNull(rdcAgg, invalidPlanErrorMessage(phys)); + assertNotNull(mapAgg, invalidPlanErrorMessage(phys)); + + assertThat( + invalidPlanErrorMessage(phys).get(), + first(rdcAgg.getAggregateCalls()).getAggregation(), + IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); + + assertThat( + invalidPlanErrorMessage(phys).get(), + first(mapAgg.getAggCallList()).getAggregation(), + IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); + } + + /** + * Check distinct aggregate with no aggregate function. + * + * @throws Exception If failed. + */ + @ParameterizedTest + @EnumSource + public void mapReduceDistinctWithIndex(AggregateAlgorithm algo) throws Exception { + TestTable tbl = createAffinityTable("TEST").addIndex("val0_val1", 1, 2); IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); publicSchema.addTable(tbl); - checkDistinctInMapAggNode("SELECT COUNT(*) FROM test", publicSchema); - checkDistinctInMapAggNode("SELECT COUNT(DISTINCT val0) FROM test", publicSchema); - checkDistinctInMapAggNode("SELECT AVG(DISTINCT val0) FROM test", publicSchema); - checkDistinctInMapAggNode("SELECT SUM(DISTINCT val0) FROM test", publicSchema); - checkDistinctInMapAggNode("SELECT MIN(DISTINCT val0) FROM test", publicSchema); - checkDistinctInMapAggNode("SELECT MAX(DISTINCT val0) FROM test", publicSchema); - - checkDistinctInMapAggNode("SELECT COUNT(DISTINCT val0) FROM test GROUP BY val1, grp0", publicSchema); - checkDistinctInMapAggNode("SELECT val1, COUNT(DISTINCT val0) as v1 FROM test GROUP BY val1", publicSchema); - checkDistinctInMapAggNode("SELECT AVG(DISTINCT val0) FROM test GROUP BY val1", publicSchema); - checkDistinctInMapAggNode("SELECT SUM(DISTINCT val0) FROM test GROUP BY val1", publicSchema); - checkDistinctInMapAggNode("SELECT MIN(DISTINCT val0) FROM test GROUP BY val1", publicSchema); - checkDistinctInMapAggNode("SELECT MAX(DISTINCT val0) FROM test GROUP BY val1", publicSchema); - checkDistinctInMapAggNode("SELECT val0 FROM test WHERE VAL1 = ANY(SELECT DISTINCT val1 FROM test)", publicSchema); + String sql = "SELECT DISTINCT val0, val1 FROM test"; + + IgniteRel phys = physicalPlan( + sql, + publicSchema, + algo.rulesToDisable + ); + + IgniteAggregate mapAgg = findFirstNode(phys, byClass(algo.map)); + IgniteReduceAggregateBase rdcAgg = findFirstNode(phys, byClass(algo.reduce)); + + assertNotNull(rdcAgg, invalidPlanErrorMessage(phys)); + assertNotNull(mapAgg, invalidPlanErrorMessage(phys)); + + assertTrue(nullOrEmpty(rdcAgg.getAggregateCalls()), invalidPlanErrorMessage(phys)); + assertTrue(nullOrEmpty(mapAgg.getAggCallList()), invalidPlanErrorMessage(phys)); + + if (algo == AggregateAlgorithm.SORT) { + assertNotNull(findFirstNode(phys, byClass(IgniteIndexScan.class))); + } + } + + /** + * Checks if already sorted input exist and involved [Map|Reduce]SortAggregate. + */ + @ParameterizedTest + @EnumSource + public void testNoSortAppendingWithCorrectCollation(AggregateAlgorithm algo) throws Exception { + RelFieldCollation coll = new RelFieldCollation(1, RelFieldCollation.Direction.DESCENDING); + + TestTable tbl = createAffinityTable("TEST").addIndex(RelCollations.of(coll), "val0Idx"); + + IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); + + publicSchema.addTable(tbl); + + String sql = "SELECT ID FROM test WHERE VAL0 IN (SELECT VAL0 FROM test)"; + + IgniteRel phys = physicalPlan( + sql, + publicSchema, + ArrayUtils.concat( + algo.rulesToDisable, + "NestedLoopJoinConverter", + "CorrelatedNestedLoopJoin", + "CorrelateToNestedLoopRule" + ) + ); + + if (algo == AggregateAlgorithm.SORT) { + assertNull(findFirstNode(phys, byClass(IgniteSort.class)), invalidPlanErrorMessage(phys)); + assertNull(findFirstNode(phys, byClass(IgniteTableScan.class)), invalidPlanErrorMessage(phys)); + } else { + assertNotNull(findFirstNode(phys, byClass(IgniteSort.class)), invalidPlanErrorMessage(phys)); + assertNotNull(findFirstNode(phys, byClass(IgniteTableScan.class)), invalidPlanErrorMessage(phys)); + } } /** @@ -411,29 +711,23 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { * * @param sql Request string. * @param publicSchema Schema. + * @param algo * @throws Exception If failed. */ - private void checkDistinctInMapAggNode(String sql, IgniteSchema publicSchema) throws Exception { - List<Pair<String[], Predicate<IgniteRel>>> disabledRules = List.of( - new Pair<>(new String[]{"ColocatedHashAggregateConverterRule", "ColocatedSortAggregateConverterRule", - "MapReduceSortAggregateConverterRule"}, node -> !findNodes(node, byClass(IgniteMapAggregateBase.class)).isEmpty()), - new Pair<>(new String[]{"MapReduceHashAggregateConverterRule", "MapReduceSortAggregateConverterRule", - "ColocatedHashAggregateConverterRule"}, node -> true), - new Pair<>(new String[]{"MapReduceHashAggregateConverterRule", "MapReduceSortAggregateConverterRule", - "ColocatedSortAggregateConverterRule"}, node -> true) - ); - - for (Pair<String[], Predicate<IgniteRel>> rules : disabledRules) { - IgniteRel phys = physicalPlan(sql, publicSchema, rules.getFirst()); + private void checkDistinctInMapAggNode(String sql, IgniteSchema publicSchema, AggregateAlgorithm algo) throws Exception { + IgniteRel phys = physicalPlan( + sql, + publicSchema, + concat(algo.rulesToDisable, "ColocatedSortAggregateConverterRule", "ColocatedHashAggregateConverterRule")); - assertTrue(rules.getSecond().test(phys), "[" + sql + "] Failed with disabled rules: " + Arrays.toString(rules.getFirst())); + assertFalse(findNodes(phys, byClass(IgniteMapAggregateBase.class)).isEmpty(), + invalidPlanErrorMessage(phys)); - assertFalse(findNodes(phys, byClass(IgniteMapAggregateBase.class)).stream() - .anyMatch(n -> ((Aggregate) n).getAggCallList().stream() - .anyMatch(AggregateCall::isDistinct) - ), - "Invalid plan\n" + RelOptUtil.toString(phys, SqlExplainLevel.ALL_ATTRIBUTES)); - } + assertFalse(findNodes(phys, byClass(IgniteMapAggregateBase.class)).stream() + .anyMatch(n -> ((Aggregate) n).getAggCallList().stream() + .anyMatch(AggregateCall::isDistinct) + ), + invalidPlanErrorMessage(phys)); } private static Stream<Arguments> provideAlgoAndDistribution() { @@ -444,39 +738,4 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest { Arguments.of(AggregateAlgorithm.HASH, IgniteDistributions.random()) ); } - - enum AggregateAlgorithm { - SORT( - IgniteColocatedSortAggregate.class, - IgniteMapSortAggregate.class, - IgniteReduceSortAggregate.class, - "ColocatedHashAggregateConverterRule", "MapReduceHashAggregateConverterRule" - ), - - HASH( - IgniteColocatedHashAggregate.class, - IgniteMapHashAggregate.class, - IgniteReduceHashAggregate.class, - "ColocatedSortAggregateConverterRule", "MapReduceSortAggregateConverterRule" - ); - - public final Class<? extends IgniteColocatedAggregateBase> colocated; - - public final Class<? extends IgniteMapAggregateBase> map; - - public final Class<? extends IgniteReduceAggregateBase> reduce; - - public final String[] rulesToDisable; - - AggregateAlgorithm( - Class<? extends IgniteColocatedAggregateBase> colocated, - Class<? extends IgniteMapAggregateBase> map, - Class<? extends IgniteReduceAggregateBase> reduce, - String... rulesToDisable) { - this.colocated = colocated; - this.map = map; - this.reduce = reduce; - this.rulesToDisable = rulesToDisable; - } - } } diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashAggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashAggregatePlannerTest.java deleted file mode 100644 index 51b86e455c..0000000000 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashAggregatePlannerTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.internal.sql.engine.planner; - -import static org.apache.ignite.internal.util.CollectionUtils.first; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.util.UUID; -import org.apache.calcite.plan.RelOptUtil; -import org.apache.calcite.rel.type.RelDataTypeFactory; -import org.apache.calcite.sql.fun.SqlAvgAggFunction; -import org.apache.calcite.sql.fun.SqlCountAggFunction; -import org.apache.ignite.internal.sql.engine.rel.IgniteRel; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteMapHashAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceHashAggregate; -import org.apache.ignite.internal.sql.engine.schema.IgniteSchema; -import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions; -import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory; -import org.apache.ignite.internal.sql.engine.type.IgniteTypeSystem; -import org.hamcrest.core.IsInstanceOf; -import org.junit.jupiter.api.Test; - -/** - * HashAggregatePlannerTest. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - */ -public class HashAggregatePlannerTest extends AbstractAggregatePlannerTest { - /** - * SubqueryWithAggregate. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - * - * @throws Exception If failed. - */ - @Test - public void subqueryWithAggregate() throws Exception { - IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE); - - IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); - - createTable(publicSchema, - "EMPS", - new RelDataTypeFactory.Builder(f) - .add("ID", f.createJavaType(Integer.class)) - .add("NAME", f.createJavaType(String.class)) - .add("SALARY", f.createJavaType(Double.class)) - .build(), - IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID) - ); - - String sql = "SELECT /*+ DISABLE_RULE('MapReduceSortAggregateConverterRule', 'ColocatedHashAggregateConverterRule', " - + "'ColocatedSortAggregateConverterRule') */ * FROM emps WHERE emps.salary = (SELECT AVG(emps.salary) FROM emps)"; - - IgniteRel phys = physicalPlan( - sql, - publicSchema - ); - - assertNotNull(phys); - - IgniteReduceHashAggregate rdcAgg = findFirstNode(phys, byClass(IgniteReduceHashAggregate.class)); - IgniteMapHashAggregate mapAgg = findFirstNode(phys, byClass(IgniteMapHashAggregate.class)); - - assertNotNull(rdcAgg, "Invalid plan\n" + RelOptUtil.toString(phys)); - assertNotNull(mapAgg, "Invalid plan\n" + RelOptUtil.toString(phys)); - - assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), - first(rdcAgg.getAggregateCalls()).getAggregation(), - IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); - - assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), - first(mapAgg.getAggCallList()).getAggregation(), - IsInstanceOf.instanceOf(SqlAvgAggFunction.class)); - } - - /** - * NoGroupByAggregate. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - */ - @Test - public void noGroupByAggregate() throws Exception { - TestTable tbl = createAffinityTable("TEST").addIndex("val0_val1", 1, 2); - - IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); - - publicSchema.addTable(tbl); - - String sqlCount = "SELECT /*+ DISABLE_RULE('MapReduceSortAggregateConverterRule', 'ColocatedHashAggregateConverterRule', " - + "'ColocatedSortAggregateConverterRule') */ COUNT(*) FROM test"; - - IgniteRel phys = physicalPlan( - sqlCount, - publicSchema - ); - - IgniteMapHashAggregate mapAgg = findFirstNode(phys, byClass(IgniteMapHashAggregate.class)); - IgniteReduceHashAggregate rdcAgg = findFirstNode(phys, byClass(IgniteReduceHashAggregate.class)); - - assertNotNull(rdcAgg, "Invalid plan\n" + RelOptUtil.toString(phys)); - assertNotNull(mapAgg, "Invalid plan\n" + RelOptUtil.toString(phys)); - - assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), - first(rdcAgg.getAggregateCalls()).getAggregation(), - IsInstanceOf.instanceOf(SqlCountAggFunction.class)); - - assertThat( - "Invalid plan\n" + RelOptUtil.toString(phys), - first(mapAgg.getAggCallList()).getAggregation(), - IsInstanceOf.instanceOf(SqlCountAggFunction.class)); - } -} diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortAggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortAggregatePlannerTest.java deleted file mode 100644 index 8aed84b631..0000000000 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortAggregatePlannerTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.internal.sql.engine.planner; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import java.util.UUID; -import org.apache.calcite.plan.RelOptUtil; -import org.apache.calcite.rel.RelCollations; -import org.apache.calcite.rel.RelFieldCollation; -import org.apache.calcite.rel.type.RelDataTypeFactory; -import org.apache.ignite.internal.sql.engine.rel.IgniteAggregate; -import org.apache.ignite.internal.sql.engine.rel.IgniteCorrelatedNestedLoopJoin; -import org.apache.ignite.internal.sql.engine.rel.IgniteLimit; -import org.apache.ignite.internal.sql.engine.rel.IgniteRel; -import org.apache.ignite.internal.sql.engine.rel.IgniteSort; -import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteColocatedSortAggregate; -import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceSortAggregate; -import org.apache.ignite.internal.sql.engine.schema.IgniteSchema; -import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution; -import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions; -import org.apache.ignite.internal.sql.engine.trait.TraitUtils; -import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory; -import org.apache.ignite.internal.sql.engine.type.IgniteTypeSystem; -import org.apache.ignite.internal.util.ArrayUtils; -import org.junit.jupiter.api.Test; - -/** - * SortAggregatePlannerTest. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - */ -public class SortAggregatePlannerTest extends AbstractAggregatePlannerTest { - /** Hash aggregate rules. */ - private static final String[] HASH_AGG_RULES = - {"ColocatedHashAggregateConverterRule", "MapReduceHashAggregateConverterRule"}; - - /** Checks if already sorted input exist and involved [Map|Reduce]SortAggregate. */ - @Test - public void testNoSortAppendingWithCorrectCollation() throws Exception { - RelFieldCollation coll = new RelFieldCollation(1, RelFieldCollation.Direction.DESCENDING); - - TestTable tbl = createAffinityTable("TEST").addIndex(RelCollations.of(coll), "val0Idx"); - - IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); - - publicSchema.addTable(tbl); - - String sql = "SELECT ID FROM test WHERE VAL0 IN (SELECT VAL0 FROM test)"; - - IgniteRel phys = physicalPlan( - sql, - publicSchema, - ArrayUtils.concat( - HASH_AGG_RULES, - "NestedLoopJoinConverter", - "CorrelatedNestedLoopJoin", - "CorrelateToNestedLoopRule" - ) - ); - - assertTrue( - findFirstNode(phys, byClass(IgniteSort.class)) == null - && findFirstNode(phys, byClass(IgniteTableScan.class)) == null, - "Invalid plan\n" + RelOptUtil.toString(phys) - ); - } - - /** - * CollationPermuteSingle. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - * - * @throws Exception If failed. - */ - @Test - public void collationPermuteSingle() throws Exception { - IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE); - - TestTable tbl = new TestTable( - new RelDataTypeFactory.Builder(f) - .add("ID", f.createJavaType(Integer.class)) - .add("VAL0", f.createJavaType(Integer.class)) - .add("VAL1", f.createJavaType(Integer.class)) - .add("GRP0", f.createJavaType(Integer.class)) - .add("GRP1", f.createJavaType(Integer.class)) - .build(), "TEST") { - - @Override - public IgniteDistribution distribution() { - return IgniteDistributions.broadcast(); - } - } - .addIndex("grp0_1", 3, 4); - - IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); - - publicSchema.addTable(tbl); - - String sql = "SELECT MIN(val0) FROM test GROUP BY grp1, grp0"; - - IgniteRel phys = physicalPlan( - sql, - publicSchema, - HASH_AGG_RULES - ); - - IgniteColocatedSortAggregate agg = findFirstNode(phys, byClass(IgniteColocatedSortAggregate.class)); - - assertNotNull(agg, "Invalid plan\n" + RelOptUtil.toString(phys)); - - assertNull( - findFirstNode(phys, byClass(IgniteSort.class)), - "Invalid plan\n" + RelOptUtil.toString(phys) - ); - } - - /** - * CollationPermuteMapReduce. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 - * - * @throws Exception If failed. - */ - @Test - public void collationPermuteMapReduce() throws Exception { - IgniteSchema publicSchema = new IgniteSchema("PUBLIC"); - IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE); - - createTable(publicSchema, - "TEST", - new RelDataTypeFactory.Builder(f) - .add("ID", f.createJavaType(Integer.class)) - .add("VAL0", f.createJavaType(Integer.class)) - .add("VAL1", f.createJavaType(Integer.class)) - .add("GRP0", f.createJavaType(Integer.class)) - .add("GRP1", f.createJavaType(Integer.class)) - .build(), - IgniteDistributions.affinity(0, UUID.randomUUID(), DEFAULT_ZONE_ID) - ).addIndex("grp0_1", 3, 4); - - String sql = "SELECT MIN(val0) FROM test GROUP BY grp1, grp0"; - - IgniteRel phys = physicalPlan( - sql, - publicSchema, - HASH_AGG_RULES - ); - - IgniteReduceSortAggregate agg = findFirstNode(phys, byClass(IgniteReduceSortAggregate.class)); - - assertNotNull(agg, "Invalid plan\n" + RelOptUtil.toString(phys)); - - assertNull( - findFirstNode(phys, byClass(IgniteSort.class)), - "Invalid plan\n" + RelOptUtil.toString(phys) - ); - } - - @Test - public void testEmptyCollationPassThroughLimit() throws Exception { - IgniteSchema publicSchema = createSchema( - createTable("TEST", IgniteDistributions.single(), "A", Integer.class)); - - assertPlan("SELECT (SELECT test.a FROM test t ORDER BY 1 LIMIT 1) FROM test", publicSchema, - hasChildThat(isInstanceOf(IgniteCorrelatedNestedLoopJoin.class) - .and(input(1, hasChildThat(isInstanceOf(IgniteLimit.class) - .and(input(isInstanceOf(IgniteSort.class))))))) - ); - } - - @Test - public void testCollationPassThrough() throws Exception { - IgniteSchema publicSchema = createSchema( - createTable("TEST", IgniteDistributions.single(), "A", Integer.class, "B", Integer.class)); - - // Sort order equals to grouping set. - assertPlan("SELECT a, b, COUNT(*) FROM test GROUP BY a, b ORDER BY a, b", publicSchema, - isInstanceOf(IgniteAggregate.class) - .and(input(isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) - .and(input(isTableScan("TEST"))))), - HASH_AGG_RULES - ); - - // Sort order equals to grouping set (permuted collation). - assertPlan("SELECT a, b, COUNT(*) FROM test GROUP BY a, b ORDER BY b, a", publicSchema, - isInstanceOf(IgniteAggregate.class) - .and(input(isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(1, 0)))) - .and(input(isTableScan("TEST"))))), - HASH_AGG_RULES - ); - - // Sort order is a subset of grouping set. - assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY a", publicSchema, - isInstanceOf(IgniteAggregate.class) - .and(input(isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) - .and(input(isTableScan("TEST"))))), - HASH_AGG_RULES - ); - - // Sort order is a subset of grouping set (permuted collation). - assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY b", publicSchema, - isInstanceOf(IgniteAggregate.class) - .and(input(isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(1, 0)))) - .and(input(isTableScan("TEST"))))), - HASH_AGG_RULES - ); - - // Sort order is a superset of grouping set (additional sorting required). - assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY a, b, cnt", publicSchema, - isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1, 2)))) - .and(input(isInstanceOf(IgniteAggregate.class) - .and(input(isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) - .and(input(isTableScan("TEST"))))))), - HASH_AGG_RULES - ); - - // Sort order is not equals to grouping set (additional sorting required). - assertPlan("SELECT a, b, COUNT(*) cnt FROM test GROUP BY a, b ORDER BY cnt, b", publicSchema, - isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(2, 1)))) - .and(input(isInstanceOf(IgniteAggregate.class) - .and(input(isInstanceOf(IgniteSort.class) - .and(s -> s.collation().equals(TraitUtils.createCollation(List.of(0, 1)))) - .and(input(isTableScan("TEST"))))))), - HASH_AGG_RULES - ); - } -}
