blob: 0a4c52d1de285abcebb23c418989b17e6a6ce76b [file] [log] [blame]
/*
* 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 java.util.function.Predicate.not;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.AggregateCall;
import org.apache.ignite.internal.sql.engine.rel.IgniteCorrelatedNestedLoopJoin;
import org.apache.ignite.internal.sql.engine.rel.IgniteExchange;
import org.apache.ignite.internal.sql.engine.rel.IgniteLimit;
import org.apache.ignite.internal.sql.engine.rel.IgniteMergeJoin;
import org.apache.ignite.internal.sql.engine.rel.IgniteProject;
import org.apache.ignite.internal.sql.engine.rel.IgniteSort;
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.IgniteIndex.Collation;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
import org.apache.ignite.internal.sql.engine.trait.TraitUtils;
import org.apache.ignite.internal.util.ArrayUtils;
import org.junit.jupiter.api.Test;
/**
* This test verifies that queries defined in {@link TestCase TestCase} can be optimized with usage of
* 2 phase hash aggregates only.
*
* <p>See {@link AbstractAggregatePlannerTest base class} for more details.
*/
public class MapReduceHashAggregatePlannerTest extends AbstractAggregatePlannerTest {
private final String[] disableRules = {
"MapReduceSortAggregateConverterRule",
"ColocatedHashAggregateConverterRule",
"ColocatedSortAggregateConverterRule"
};
/**
* Validates a plan for simple query with aggregate.
*/
@Test
protected void simpleAggregate() throws Exception {
checkSimpleAggSingle(TestCase.CASE_1);
checkSimpleAggHash(TestCase.CASE_1A);
checkSimpleAggHash(TestCase.CASE_1B);
}
/**
* Validates a plan for simple query with DISTINCT aggregates.
*
* @see #minMaxDistinctAggregate()
*/
@Test
public void distinctAggregate() throws Exception {
checkDistinctAggSingle(TestCase.CASE_2_1);
checkDistinctAggSingle(TestCase.CASE_2_2);
checkDistinctAggHash(TestCase.CASE_2_1A);
checkDistinctAggHash(TestCase.CASE_2_2A);
checkDistinctAggHash(TestCase.CASE_2_1B);
checkDistinctAggHash(TestCase.CASE_2_2B);
checkDistinctAggHash(TestCase.CASE_2_1C);
checkDistinctAggHash(TestCase.CASE_2_2C);
checkDistinctAggHash(TestCase.CASE_2_1D);
checkDistinctAggHash(TestCase.CASE_2_2D);
}
/**
* Validates a plan for a query with min/max distinct aggregate.
*
* <p>NB: DISTINCT make no sense for MIN/MAX, thus expected plan is the same as in {@link #simpleAggregate()} ()}
*/
@Test
public void minMaxDistinctAggregate() throws Exception {
checkSimpleAggSingle(TestCase.CASE_3_1);
checkSimpleAggSingle(TestCase.CASE_3_2);
checkSimpleAggHash(TestCase.CASE_3_1A);
checkSimpleAggHash(TestCase.CASE_3_2A);
checkSimpleAggHash(TestCase.CASE_3_1B);
checkSimpleAggHash(TestCase.CASE_3_2B);
checkSimpleAggHash(TestCase.CASE_3_1C);
checkSimpleAggHash(TestCase.CASE_3_2C);
checkSimpleAggHash(TestCase.CASE_3_1D);
checkSimpleAggHash(TestCase.CASE_3_2D);
}
/**
* Validates a plan for a query with aggregate and groups.
*/
@Test
public void simpleAggregateWithGroupBy() throws Exception {
checkSimpleAggWithGroupBySingle(TestCase.CASE_5);
checkSimpleAggWithGroupBySingle(TestCase.CASE_6);
checkSimpleAggWithGroupByHash(TestCase.CASE_5A);
checkSimpleAggWithGroupByHash(TestCase.CASE_6A);
checkSimpleAggWithGroupByHash(TestCase.CASE_5B);
checkSimpleAggWithGroupByHash(TestCase.CASE_6B);
checkSimpleAggWithGroupByHash(TestCase.CASE_5C);
checkSimpleAggWithGroupByHash(TestCase.CASE_6C);
checkSimpleAggWithGroupByHash(TestCase.CASE_5D);
}
/**
* Validates a plan for a query with DISTINCT aggregates and groups.
*
* @see #minMaxDistinctAggregateWithGroupBy()
*/
@Test
public void distinctAggregateWithGroups() throws Exception {
checkDistinctAggWithGroupBySingle(TestCase.CASE_7_1);
checkDistinctAggWithGroupBySingle(TestCase.CASE_7_2);
checkDistinctAggWithGroupBySingle(TestCase.CASE_7_3);
checkDistinctAggWithGroupByHash(TestCase.CASE_7_1A);
checkDistinctAggWithGroupByHash(TestCase.CASE_7_2A);
checkDistinctAggWithGroupByHash(TestCase.CASE_7_3A);
checkDistinctAggWithGroupByHash(TestCase.CASE_7_1B);
checkDistinctAggWithGroupByHash(TestCase.CASE_7_2B);
checkDistinctAggWithGroupByHash(TestCase.CASE_7_3B);
checkDistinctAggWithColocatedGroupByHash(TestCase.CASE_7_1C);
checkDistinctAggWithColocatedGroupByHash(TestCase.CASE_7_2C);
checkDistinctAggWithColocatedGroupByHash(TestCase.CASE_7_3C);
checkDistinctAggWithColocatedGroupByHash(TestCase.CASE_7_1D);
checkDistinctAggWithColocatedGroupByHash(TestCase.CASE_7_2D);
checkDistinctAggWithColocatedGroupByHash(TestCase.CASE_7_3D);
}
/**
* Validates a plan for a query with min/max distinct aggregates and groups.
*
* <p>NB: DISTINCT make no sense for MIN/MAX, thus expected plan is the same as in {@link #simpleAggregateWithGroupBy()}
*/
@Test
public void minMaxDistinctAggregateWithGroupBy() throws Exception {
checkSimpleAggWithGroupBySingle(TestCase.CASE_8_1);
checkSimpleAggWithGroupBySingle(TestCase.CASE_8_2);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_1A);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_2A);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_1B);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_2B);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_1C);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_2C);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_1D);
checkSimpleAggWithGroupByHash(TestCase.CASE_8_2D);
}
/**
* Validates a plan uses an index for a query with aggregate if grouped by index prefix.
*
* <p>NB: GROUP BY columns order permutation shouldn't affect the plan.
*/
@Test
public void aggregateWithGroupByIndexPrefixColumns() throws Exception {
checkAggWithGroupByIndexColumnsSingle(TestCase.CASE_9);
checkAggWithGroupByIndexColumnsSingle(TestCase.CASE_10);
checkAggWithGroupByIndexColumnsSingle(TestCase.CASE_11);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_9A);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_10A);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_11A);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_9B);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_10B);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_11B);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_9C);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_10C);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_11C);
checkAggWithGroupByIndexColumnsHash(TestCase.CASE_9D);
}
/**
* Validates a plan for a query with DISTINCT and without aggregation function.
*/
@Test
public void distinctWithoutAggregate() throws Exception {
checkGroupWithNoAggregateSingle(TestCase.CASE_12);
checkGroupWithNoAggregateHash(TestCase.CASE_12A);
checkGroupWithNoAggregateHash(TestCase.CASE_12B);
checkGroupWithNoAggregateHash(TestCase.CASE_12C);
checkGroupWithNoAggregateHash(TestCase.CASE_12D);
}
/**
* Validates a plan uses index for a query with DISTINCT and without aggregation functions.
*/
@Test
public void distinctWithoutAggregateUseIndex() throws Exception {
checkGroupWithNoAggregateSingle(TestCase.CASE_13);
checkGroupWithNoAggregateHash(TestCase.CASE_13A);
checkGroupWithNoAggregateHash(TestCase.CASE_13B);
checkGroupWithNoAggregateHash(TestCase.CASE_13C);
checkGroupWithNoAggregateHash(TestCase.CASE_13D);
}
/**
* Validates a plan for a query which WHERE clause contains a sub-query with aggregate.
*/
@Test
public void subqueryWithAggregateInWhereClause() throws Exception {
checkSimpleAggSingle(TestCase.CASE_14);
checkSimpleAggHash(TestCase.CASE_14A);
checkSimpleAggHash(TestCase.CASE_14B);
}
/**
* Validates a plan for a query with DISTINCT aggregate in WHERE clause.
*/
@Test
public void distinctAggregateInWhereClause() throws Exception {
checkGroupWithNoAggregateSingle(TestCase.CASE_15);
checkGroupWithNoAggregateHash(TestCase.CASE_15A);
checkGroupWithNoAggregateHash(TestCase.CASE_15B);
}
/**
* Validates a plan with merge-sort utilizes index if collation fits.
*/
@Test
public void noSortAppendingWithCorrectCollation() throws Exception {
String[] additionalRulesToDisable = {"NestedLoopJoinConverter", "CorrelatedNestedLoopJoin", "CorrelateToNestedLoopRule",
"HashJoinConverter"};
assertPlan(TestCase.CASE_16,
nodeOrAnyChild(isInstanceOf(IgniteSort.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isTableScan("TEST")))
))
))
),
ArrayUtils.concat(disableRules, additionalRulesToDisable)
);
assertPlan(TestCase.CASE_16A,
nodeOrAnyChild(isInstanceOf(IgniteSort.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isTableScan("TEST")))
))
))
))
),
ArrayUtils.concat(disableRules, additionalRulesToDisable)
);
assertPlan(TestCase.CASE_16B,
nodeOrAnyChild(isInstanceOf(IgniteSort.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isTableScan("TEST")))
))
))
))
),
ArrayUtils.concat(disableRules, additionalRulesToDisable)
);
}
/**
* Validates a plan for a sub-query with order and limit.
*/
@Test
public void emptyCollationPassThroughLimit() throws Exception {
assertPlan(TestCase.CASE_17,
hasChildThat(isInstanceOf(IgniteCorrelatedNestedLoopJoin.class)
.and(input(1, isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isInstanceOf(IgniteLimit.class)
.and(input(isInstanceOf(IgniteSort.class)
.and(input(isTableScan("TEST")))
))
))
))
))
),
disableRules
);
assertPlan(TestCase.CASE_17A,
hasChildThat(isInstanceOf(IgniteCorrelatedNestedLoopJoin.class)
.and(input(1, isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isInstanceOf(IgniteLimit.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteSort.class)
.and(input(isTableScan("TEST")))
))
))
))
))
))
),
disableRules
);
assertPlan(TestCase.CASE_17B,
hasChildThat(isInstanceOf(IgniteCorrelatedNestedLoopJoin.class)
.and(input(1, isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isInstanceOf(IgniteLimit.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteSort.class)
.and(input(isTableScan("TEST")))
))
))
))
))
))
),
disableRules
);
}
/**
* Validates a plan for a query with aggregate and with groups and sorting by the same column set.
*/
@Test
public void groupsWithOrderByGroupColumns() throws Exception {
checkGroupsWithOrderByGroupColumnsSingle(TestCase.CASE_18_1, TraitUtils.createCollation(List.of(0, 1)));
checkGroupsWithOrderByGroupColumnsSingle(TestCase.CASE_18_2, TraitUtils.createCollation(List.of(1, 0)));
checkGroupsWithOrderByGroupColumnsSingle(TestCase.CASE_18_3, TraitUtils.createCollation(List.of(1, 0)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_18_1A, TraitUtils.createCollation(List.of(0, 1)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_18_2A, TraitUtils.createCollation(List.of(1, 0)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_18_3A, TraitUtils.createCollation(List.of(1, 0)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_18_1B, TraitUtils.createCollation(List.of(0, 1)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_18_2B, TraitUtils.createCollation(List.of(1, 0)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_18_3B, TraitUtils.createCollation(List.of(1, 0)));
}
/**
* Validates a plan for a query with aggregate and with sorting by subset of group columns.
*/
@Test
public void aggregateWithOrderByGroupColumns() throws Exception {
checkGroupsWithOrderByGroupColumnsSingle(TestCase.CASE_19_1, TraitUtils.createCollation(List.of(0)));
checkGroupsWithOrderByGroupColumnsSingle(TestCase.CASE_19_2, TraitUtils.createCollation(List.of(1)));
checkGroupsWithOrderByGroupColumnsSingle(TestCase.CASE_20, TraitUtils.createCollation(List.of(0, 1, 2)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_19_1A, TraitUtils.createCollation(List.of(0)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_19_2A, TraitUtils.createCollation(List.of(1)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_20A, TraitUtils.createCollation(List.of(0, 1, 2)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_19_1B, TraitUtils.createCollation(List.of(0)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_19_2B, TraitUtils.createCollation(List.of(1)));
checkGroupsWithOrderByGroupColumnsHash(TestCase.CASE_20B, TraitUtils.createCollation(List.of(0, 1, 2)));
}
/**
* Validates a plan for a query with aggregate and groups, and EXPAND_DISTINCT_AGG hint.
*/
@Test
public void expandDistinctAggregates() throws Exception {
Predicate<? extends RelNode> subtreePredicate = nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
// Check the second aggregation step contains accumulators.
// Plan must not contain distinct accumulators.
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
// Check the first aggregation step is SELECT DISTINCT (doesn't contain any accumulators)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
))
))
))
);
assertPlan(TestCase.CASE_21, nodeOrAnyChild(isInstanceOf(IgniteMergeJoin.class)
.and(input(0, subtreePredicate))
.and(input(1, subtreePredicate))
), disableRules);
subtreePredicate = nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
// Check the second aggregation step contains accumulators.
// Plan must not contain distinct accumulators.
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
// Check the first aggregation step is SELECT DISTINCT (doesn't contain any accumulators)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
))
))
))
))
);
assertPlan(TestCase.CASE_21A, nodeOrAnyChild(isInstanceOf(IgniteMergeJoin.class)
.and(input(0, subtreePredicate))
.and(input(1, subtreePredicate))
), disableRules);
assertPlan(TestCase.CASE_21B, nodeOrAnyChild(isInstanceOf(IgniteMergeJoin.class)
.and(input(0, subtreePredicate))
.and(input(1, subtreePredicate))
), disableRules);
}
/**
* Validates that COUNT aggregate is split into COUNT and $SUM0.
*/
@Test
public void twoPhaseCountAgg() throws Exception {
Predicate<AggregateCall> countMap = (a) -> {
String aggName = a.getAggregation().getName();
return Objects.equals(aggName, "COUNT") && a.getArgList().equals(List.of(1));
};
Predicate<AggregateCall> countReduce = (a) -> {
String aggName = a.getAggregation().getName();
return Objects.equals(aggName, "$SUM0") && a.getArgList().equals(List.of(1));
};
Predicate<RelNode> nonColocated = hasChildThat(isInstanceOf(IgniteReduceHashAggregate.class)
.and(in -> hasAggregates(countReduce).test(in.getAggregateCalls()))
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(in -> hasAggregates(countMap).test(in.getAggCallList()))
.and(input(isTableScan("TEST")))
)
))
));
assertPlan(TestCase.CASE_22, nonColocated, disableRules);
assertPlan(TestCase.CASE_22A, nonColocated, disableRules);
assertPlan(TestCase.CASE_22B, nonColocated, disableRules);
assertPlan(TestCase.CASE_22C, nonColocated, disableRules);
}
/**
* Validates that AVG aggregate is split into multiple expressions.
*/
@Test
public void twoPhaseAvgAgg() throws Exception {
Predicate<AggregateCall> sumMap = (a) ->
Objects.equals(a.getAggregation().getName(), "SUM") && a.getArgList().equals(List.of(1));
Predicate<AggregateCall> countMap = (a) ->
Objects.equals(a.getAggregation().getName(), "COUNT") && a.getArgList().equals(List.of(1));
Predicate<AggregateCall> sumReduce = (a) ->
Objects.equals(a.getAggregation().getName(), "SUM") && a.getArgList().equals(List.of(1));
Predicate<AggregateCall> sum0Reduce = (a) ->
Objects.equals(a.getAggregation().getName(), "$SUM0") && a.getArgList().equals(List.of(2));
Predicate<RelNode> nonColocated = hasChildThat(isInstanceOf(IgniteReduceHashAggregate.class)
.and(in -> hasAggregates(sumReduce, sum0Reduce).test(in.getAggregateCalls()))
.and(input(isInstanceOf(IgniteExchange.class)
.and(hasDistribution(IgniteDistributions.single()))
.and(input(isInstanceOf(IgniteProject.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(in -> hasAggregates(sumMap, countMap).test(in.getAggCallList()))
)
))
))));
assertPlan(TestCase.CASE_23, nonColocated, disableRules);
assertPlan(TestCase.CASE_23A, nonColocated, disableRules);
assertPlan(TestCase.CASE_23B, nonColocated, disableRules);
assertPlan(TestCase.CASE_23C, nonColocated, disableRules);
}
/**
* Validate query with two aggregates: one w/o DISTINCT and one with DISTINCT: hash distribution.
*/
@Test
public void countDistinctGroupSetSingle() throws Exception {
Predicate<IgniteReduceHashAggregate> inputAgg = isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasGroupSets(IgniteReduceHashAggregate::getGroupSets, 0))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasGroupSets(Aggregate::getGroupSets, 1))
));
assertPlan(TestCase.CASE_24_1, nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasNoGroupSets(IgniteReduceHashAggregate::getGroupSets))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasNoGroupSets(IgniteMapHashAggregate::getGroupSets))
.and(input(isInstanceOf(IgniteProject.class).and(input(inputAgg)))
))
)),
disableRules);
}
/**
* Validates a plan for a query with two aggregates: one w/o DISTINCT and one with DISTINCT: single distribution.
*/
@Test
public void countDistinctGroupSetHash() throws Exception {
checkCountDistinctHash(TestCase.CASE_24_1A);
checkCountDistinctHash(TestCase.CASE_24_1B);
checkCountDistinctHash(TestCase.CASE_24_1C);
checkCountDistinctHash(TestCase.CASE_24_1D);
checkCountDistinctHash(TestCase.CASE_24_1E);
}
/**
* Validates a plan for a query with aggregate and with groups and sorting by the same column set in descending order.
*/
@Test
public void groupsWithOrderByGroupColumnDescending() throws Exception {
checkDerivedCollationWithOrderByGroupColumnSingle(TestCase.CASE_25);
checkDerivedCollationWithOrderByGroupColumnHash(TestCase.CASE_25A);
}
/**
* Validates a plan for a query with aggregate and with sorting in descending order by a subset of grouping column.
*/
@Test
public void groupsWithOrderBySubsetOfGroupColumnDescending() throws Exception {
checkDerivedCollationWithOrderBySubsetOfGroupColumnsSingle(TestCase.CASE_26);
checkDerivedCollationWithOrderBySubsetOfGroupColumnsHash(TestCase.CASE_26A);
}
private void checkSimpleAggSingle(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(input(isTableScan("TEST")))
))
),
disableRules
);
}
private void checkSimpleAggHash(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(input(isTableScan("TEST")))
))
))
),
disableRules
);
}
private void checkSimpleAggWithGroupBySingle(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(hasGroups())
.and(input(isTableScan("TEST")))
))
),
disableRules
);
}
private void checkSimpleAggWithGroupByHash(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(hasGroups())
.and(input(isTableScan("TEST")))
))
))
),
disableRules
);
}
private void checkDistinctAggSingle(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(input(isTableScan("TEST")))
))
))
))
),
disableRules
);
}
private void checkDistinctAggHash(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(input(isTableScan("TEST")))
))
))
))
))),
disableRules
);
}
private void checkDistinctAggWithGroupBySingle(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isTableScan("TEST")))
))
))
))
),
disableRules
);
}
private void checkDistinctAggWithGroupByHash(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isTableScan("TEST")))
))
))
))
))
),
disableRules
);
}
private void checkDistinctAggWithColocatedGroupByHash(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasAggregate())
.and(not(hasDistinctAggregate()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isTableScan("TEST")))
))
))
))
))
),
disableRules
);
}
private void checkAggWithGroupByIndexColumnsSingle(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(input(isTableScan("TEST")))
))
),
disableRules
);
}
private void checkAggWithGroupByIndexColumnsHash(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
.and(input(isTableScan("TEST")))
))
))
),
disableRules
);
}
private void checkGroupWithNoAggregateSingle(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isTableScan("TEST")))
))
),
disableRules
);
}
private void checkGroupWithNoAggregateHash(TestCase testCase) throws Exception {
assertPlan(testCase,
nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(not(hasAggregate()))
.and(hasGroups())
.and(input(isTableScan("TEST")))
))
))
),
disableRules
);
}
private void checkGroupsWithOrderByGroupColumnsSingle(TestCase testCase, RelCollation collation) throws Exception {
assertPlan(testCase,
isInstanceOf(IgniteSort.class)
.and(s -> s.collation().equals(collation))
.and(input(isInstanceOf(IgniteProject.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isTableScan("TEST")))
))
))
)),
disableRules
);
}
private void checkGroupsWithOrderByGroupColumnsHash(TestCase testCase, RelCollation collation) throws Exception {
assertPlan(testCase,
isInstanceOf(IgniteSort.class)
.and(s -> s.collation().equals(collation))
.and(input(isInstanceOf(IgniteProject.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(input(isTableScan("TEST")))
))
))
))
)),
disableRules
);
}
private void checkCountDistinctHash(TestCase testCase) throws Exception {
Predicate<IgniteReduceHashAggregate> inputAgg = isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasGroupSets(IgniteReduceHashAggregate::getGroupSets, 0))
.and(input(isInstanceOf(IgniteExchange.class)
.and(hasDistribution(IgniteDistributions.single()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasGroupSets(Aggregate::getGroupSets, 1))
))
));
assertPlan(testCase, nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasNoGroupSets(IgniteReduceHashAggregate::getGroupSets))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasNoGroupSets(IgniteMapHashAggregate::getGroupSets))
.and(input(isInstanceOf(IgniteProject.class).and(input(inputAgg)))
))
)),
disableRules);
}
private void checkDerivedCollationWithOrderByGroupColumnSingle(TestCase testCase) throws Exception {
RelCollation requiredCollation = RelCollations.of(TraitUtils.createFieldCollation(0, Collation.DESC_NULLS_FIRST));
assertPlan(testCase, isInstanceOf(IgniteSort.class)
.and(hasCollation(requiredCollation))
.and(nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasAggregate())
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
))
)),
disableRules);
}
private void checkDerivedCollationWithOrderByGroupColumnHash(TestCase testCase) throws Exception {
RelCollation requiredCollation = RelCollations.of(TraitUtils.createFieldCollation(0, Collation.DESC_NULLS_FIRST));
assertPlan(testCase, isInstanceOf(IgniteSort.class)
.and(hasCollation(requiredCollation))
.and(nodeOrAnyChild(isInstanceOf(IgniteReduceHashAggregate.class)
.and(hasAggregate())
.and(input(isInstanceOf(IgniteExchange.class)
.and(hasDistribution(IgniteDistributions.single()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)
.and(hasAggregate())
))
))
)),
disableRules);
}
private void checkDerivedCollationWithOrderBySubsetOfGroupColumnsSingle(TestCase testCase) throws Exception {
RelCollation outputCollation = RelCollations.of(
TraitUtils.createFieldCollation(1, Collation.DESC_NULLS_FIRST)
);
assertPlan(testCase,
isInstanceOf(IgniteSort.class)
.and(hasCollation(outputCollation))
.and(input(isInstanceOf(IgniteProject.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteMapHashAggregate.class)))
))
)),
disableRules);
}
private void checkDerivedCollationWithOrderBySubsetOfGroupColumnsHash(TestCase testCase) throws Exception {
RelCollation outputCollation = RelCollations.of(
TraitUtils.createFieldCollation(1, Collation.DESC_NULLS_FIRST)
);
assertPlan(testCase,
isInstanceOf(IgniteSort.class)
.and(hasCollation(outputCollation))
.and(input(isInstanceOf(IgniteProject.class)
.and(input(isInstanceOf(IgniteReduceHashAggregate.class)
.and(input(isInstanceOf(IgniteExchange.class)
.and(hasDistribution(IgniteDistributions.single()))
.and(input(isInstanceOf(IgniteMapHashAggregate.class)))
))
))
)),
disableRules);
}
}