Skip to content

Commit 3562768

Browse files
[CALCITE-7242] Implement a rule to eliminate LITERAL_AGG so that other databases can handle it
1 parent f398d74 commit 3562768

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.calcite.rel.rules;
18+
19+
import org.apache.calcite.plan.RelOptRuleCall;
20+
import org.apache.calcite.plan.RelRule;
21+
import org.apache.calcite.rel.RelNode;
22+
import org.apache.calcite.rel.core.Aggregate;
23+
import org.apache.calcite.rel.core.AggregateCall;
24+
import org.apache.calcite.rel.logical.LogicalAggregate;
25+
import org.apache.calcite.rel.logical.LogicalProject;
26+
import org.apache.calcite.rex.RexBuilder;
27+
import org.apache.calcite.rex.RexNode;
28+
import org.apache.calcite.tools.RelBuilder;
29+
30+
import com.google.common.collect.ImmutableSet;
31+
32+
import org.immutables.value.Value;
33+
34+
import java.util.ArrayList;
35+
import java.util.HashMap;
36+
import java.util.List;
37+
import java.util.Map;
38+
39+
/**
40+
* AggregateExtractLiteralAggRule gets rid of the LITERAL_AGG into most databases can handle.
41+
*/
42+
@Value.Enclosing
43+
public class AggregateExtractLiteralAggRule
44+
extends RelRule<AggregateExtractLiteralAggRule.Config>
45+
implements TransformationRule {
46+
47+
protected AggregateExtractLiteralAggRule(Config config) {
48+
super(config);
49+
}
50+
51+
@Override public void onMatch(RelOptRuleCall call) {
52+
final LogicalAggregate aggregate = call.rel(0);
53+
54+
final List<AggregateCall> aggCalls = aggregate.getAggCallList();
55+
if (aggCalls.isEmpty()) {
56+
return;
57+
}
58+
59+
// Collect indices of LITERAL_AGG calls.
60+
final List<Integer> literalAggIndices = new ArrayList<>();
61+
for (int i = 0; i < aggCalls.size(); i++) {
62+
final AggregateCall ac = aggCalls.get(i);
63+
if (ac.getAggregation().getName().equals("LITERAL_AGG")) {
64+
literalAggIndices.add(i);
65+
}
66+
}
67+
68+
if (literalAggIndices.isEmpty()) {
69+
// nothing to do
70+
return;
71+
}
72+
73+
// Build new AggregateCall list without LITERAL_AGG entries.
74+
final List<AggregateCall> newAggCalls = new ArrayList<>();
75+
final Map<Integer, Integer> oldAggIndexToNewAggIndex = new HashMap<>();
76+
int newAggPos = 0;
77+
for (int i = 0; i < aggCalls.size(); i++) {
78+
if (!literalAggIndices.contains(i)) {
79+
newAggCalls.add(aggCalls.get(i));
80+
oldAggIndexToNewAggIndex.put(i, newAggPos++);
81+
}
82+
}
83+
84+
// Create new Aggregate preserving groupSet/groupSets/hints.
85+
final LogicalAggregate newAggregate =
86+
LogicalAggregate.create(aggregate.getInput(),
87+
aggregate.getHints(),
88+
aggregate.getGroupSet(),
89+
aggregate.getGroupSets(),
90+
newAggCalls);
91+
92+
final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
93+
94+
// Number of group columns in output (group keys appear first).
95+
final int groupCount = aggregate.getGroupSet().cardinality();
96+
final int origAggCount = aggCalls.size();
97+
final int origOutputCount = groupCount + origAggCount;
98+
99+
// Build projection expressions to restore original output layout.
100+
final List<RexNode> projects = new ArrayList<>(origOutputCount);
101+
102+
for (int outPos = 0; outPos < origOutputCount; outPos++) {
103+
if (outPos < groupCount) {
104+
// Group key columns remain in the same positions.
105+
projects.add(rexBuilder.makeInputRef(newAggregate, outPos));
106+
} else {
107+
// Aggregate output: determine original aggregate index.
108+
final int origAggIndex = outPos - groupCount;
109+
if (literalAggIndices.contains(origAggIndex)) {
110+
// Replacement for LITERAL_AGG: try to extract literal from the original AggregateCall.
111+
projects.add(aggCalls.get(origAggIndex).rexList.get(0));
112+
} else {
113+
// Non-literal aggregate: compute its new output index in newAggregate.
114+
final Integer newAggIndex = oldAggIndexToNewAggIndex.get(origAggIndex);
115+
if (newAggIndex != null) {
116+
projects.add(rexBuilder.makeInputRef(newAggregate, groupCount + newAggIndex));
117+
}
118+
}
119+
}
120+
}
121+
122+
final RelNode projectRelNode =
123+
LogicalProject.create(newAggregate, new ArrayList<>(), projects,
124+
aggregate.getRowType(), ImmutableSet.of());
125+
call.transformTo(projectRelNode);
126+
}
127+
128+
/** Rule configuration. */
129+
@Value.Immutable
130+
public interface Config extends RelRule.Config {
131+
Config DEFAULT = ImmutableAggregateExtractLiteralAggRule.Config.of()
132+
.withRelBuilderFactory(RelBuilder.proto())
133+
.withOperandSupplier(b0 ->
134+
b0.operand(Aggregate.class).anyInputs());
135+
136+
@Override default AggregateExtractLiteralAggRule toRule() {
137+
return new AggregateExtractLiteralAggRule(this);
138+
}
139+
}
140+
}

core/src/main/java/org/apache/calcite/rel/rules/CoreRules.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,4 +945,8 @@ private CoreRules() {}
945945
* into equivalent {@link Union} ALL of GROUP BY operations. */
946946
public static final AggregateGroupingSetsToUnionRule AGGREGATE_GROUPING_SETS_TO_UNION =
947947
AggregateGroupingSetsToUnionRule.Config.DEFAULT.toRule();
948+
949+
/** Rule that gets rid of the LITERAL_AGG into most databases can handle. */
950+
public static final AggregateExtractLiteralAggRule AGGREGATE_EXTRACT_LITERAL_AGG =
951+
AggregateExtractLiteralAggRule.Config.DEFAULT.toRule();
948952
}

0 commit comments

Comments
 (0)