This is an automated email from the ASF dual-hosted git repository.
kgyrtkirk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push:
new 8849b62 [CALCITE-3880] Add SortExchange support to RelFieldTrimmer
(Krisztian Kasa)
8849b62 is described below
commit 8849b62e7baff84dcd4262f47809e87a38be7b10
Author: kkasa <[email protected]>
AuthorDate: Thu Mar 12 14:16:18 2020 +0100
[CALCITE-3880] Add SortExchange support to RelFieldTrimmer (Krisztian Kasa)
Close #1879
---
.../org/apache/calcite/rel/RelDistributions.java | 2 +-
.../apache/calcite/sql2rel/RelFieldTrimmer.java | 45 ++++++++
.../calcite/sql2rel/RelFieldTrimmerTest.java | 127 +++++++++++++++++++++
3 files changed, 173 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/calcite/rel/RelDistributions.java
b/core/src/main/java/org/apache/calcite/rel/RelDistributions.java
index 1de39fd..f7a524f 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelDistributions.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelDistributions.java
@@ -141,7 +141,7 @@ public class RelDistributions {
return getTraitDef().canonize(
new RelDistributionImpl(type,
ImmutableIntList.copyOf(
- Mappings.apply((Mapping) mapping, keys))));
+ Mappings.apply2((Mapping) mapping, keys))));
}
public boolean satisfies(RelTrait trait) {
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
index 456b4eb..f8f7da7 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -21,6 +21,7 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelDistribution;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Aggregate;
@@ -33,6 +34,7 @@ import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.SetOp;
import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.core.SortExchange;
import org.apache.calcite.rel.core.TableScan;
import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
import org.apache.calcite.rel.logical.LogicalTableModify;
@@ -548,6 +550,49 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
return result(relBuilder.build(), inputMapping);
}
+ public TrimResult trimFields(
+ SortExchange sortExchange,
+ ImmutableBitSet fieldsUsed,
+ Set<RelDataTypeField> extraFields) {
+ final RelDataType rowType = sortExchange.getRowType();
+ final int fieldCount = rowType.getFieldCount();
+ final RelCollation collation = sortExchange.getCollation();
+ final RelDistribution distribution = sortExchange.getDistribution();
+ final RelNode input = sortExchange.getInput();
+
+ // We use the fields used by the consumer, plus any fields used as
sortExchange
+ // keys.
+ final ImmutableBitSet.Builder inputFieldsUsed = fieldsUsed.rebuild();
+ for (RelFieldCollation field : collation.getFieldCollations()) {
+ inputFieldsUsed.set(field.getFieldIndex());
+ }
+ for (int keyIndex : distribution.getKeys()) {
+ inputFieldsUsed.set(keyIndex);
+ }
+
+ // Create input with trimmed columns.
+ final Set<RelDataTypeField> inputExtraFields = Collections.emptySet();
+ TrimResult trimResult =
+ trimChild(sortExchange, input, inputFieldsUsed.build(),
inputExtraFields);
+ RelNode newInput = trimResult.left;
+ final Mapping inputMapping = trimResult.right;
+
+ // If the input is unchanged, and we need to project all columns,
+ // there's nothing we can do.
+ if (newInput == input
+ && inputMapping.isIdentity()
+ && fieldsUsed.cardinality() == fieldCount) {
+ return result(sortExchange, Mappings.createIdentity(fieldCount));
+ }
+
+ relBuilder.push(newInput);
+ RelCollation newCollation = RexUtil.apply(inputMapping, collation);
+ RelDistribution newDistribution = distribution.apply(inputMapping);
+ relBuilder.sortExchange(newDistribution, newCollation);
+
+ return result(relBuilder.build(), inputMapping);
+ }
+
/**
* Variant of {@link #trimFields(RelNode, ImmutableBitSet, Set)} for
* {@link org.apache.calcite.rel.logical.LogicalJoin}.
diff --git
a/core/src/test/java/org/apache/calcite/sql2rel/RelFieldTrimmerTest.java
b/core/src/test/java/org/apache/calcite/sql2rel/RelFieldTrimmerTest.java
new file mode 100644
index 0000000..d602433
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/sql2rel/RelFieldTrimmerTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.calcite.sql2rel;
+
+import org.apache.calcite.plan.RelTraitDef;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelDistributions;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.test.CalciteAssert;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.tools.Programs;
+import org.apache.calcite.tools.RelBuilder;
+
+import com.google.common.collect.Lists;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.apache.calcite.test.Matchers.hasTree;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+class RelFieldTrimmerTest {
+ public static Frameworks.ConfigBuilder config() {
+ final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
+ return Frameworks.newConfigBuilder()
+ .parserConfig(SqlParser.Config.DEFAULT)
+ .defaultSchema(
+ CalciteAssert.addSchema(rootSchema,
CalciteAssert.SchemaSpec.SCOTT_WITH_TEMPORAL))
+ .traitDefs((List<RelTraitDef>) null)
+ .programs(Programs.heuristicJoinOrder(Programs.RULE_SET, true, 2));
+ }
+
+ @Test public void testSortExchangeFieldTrimmer() {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ final RelNode root =
+ builder.scan("EMP")
+ .project(builder.field("EMPNO"), builder.field("ENAME"),
builder.field("DEPTNO"))
+ .sortExchange(RelDistributions.hash(Lists.newArrayList(1)),
RelCollations.of(0))
+ .project(builder.field("EMPNO"), builder.field("ENAME"))
+ .build();
+
+ RelFieldTrimmer fieldTrimmer = new RelFieldTrimmer(null, builder);
+ RelNode trimmed = fieldTrimmer.trim(root);
+
+ final String expected = ""
+ + "LogicalSortExchange(distribution=[hash[1]], collation=[[0]])\n"
+ + " LogicalProject(EMPNO=[$0], ENAME=[$1])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
+ assertThat(trimmed, hasTree(expected));
+ }
+
+ @Test public void testSortExchangeFieldTrimmerWhenProjectCannotBeMerged() {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ final RelNode root =
+ builder.scan("EMP")
+ .project(builder.field("EMPNO"), builder.field("ENAME"),
builder.field("DEPTNO"))
+ .sortExchange(RelDistributions.hash(Lists.newArrayList(1)),
RelCollations.of(0))
+ .project(builder.field("EMPNO"))
+ .build();
+
+ RelFieldTrimmer fieldTrimmer = new RelFieldTrimmer(null, builder);
+ RelNode trimmed = fieldTrimmer.trim(root);
+
+ final String expected = ""
+ + "LogicalProject(EMPNO=[$0])\n"
+ + " LogicalSortExchange(distribution=[hash[1]], collation=[[0]])\n"
+ + " LogicalProject(EMPNO=[$0], ENAME=[$1])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
+ assertThat(trimmed, hasTree(expected));
+ }
+
+ @Test public void testSortExchangeFieldTrimmerWithEmptyCollation() {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ final RelNode root =
+ builder.scan("EMP")
+ .project(builder.field("EMPNO"), builder.field("ENAME"),
builder.field("DEPTNO"))
+ .sortExchange(RelDistributions.hash(Lists.newArrayList(1)),
RelCollations.EMPTY)
+ .project(builder.field("EMPNO"), builder.field("ENAME"))
+ .build();
+
+ RelFieldTrimmer fieldTrimmer = new RelFieldTrimmer(null, builder);
+ RelNode trimmed = fieldTrimmer.trim(root);
+
+ final String expected = ""
+ + "LogicalSortExchange(distribution=[hash[1]], collation=[[]])\n"
+ + " LogicalProject(EMPNO=[$0], ENAME=[$1])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
+ assertThat(trimmed, hasTree(expected));
+ }
+
+ @Test public void testSortExchangeFieldTrimmerWithSingletonDistribution() {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ final RelNode root =
+ builder.scan("EMP")
+ .project(builder.field("EMPNO"), builder.field("ENAME"),
builder.field("DEPTNO"))
+ .sortExchange(RelDistributions.SINGLETON, RelCollations.of(0))
+ .project(builder.field("EMPNO"), builder.field("ENAME"))
+ .build();
+
+ RelFieldTrimmer fieldTrimmer = new RelFieldTrimmer(null, builder);
+ RelNode trimmed = fieldTrimmer.trim(root);
+
+ final String expected = ""
+ + "LogicalSortExchange(distribution=[single], collation=[[0]])\n"
+ + " LogicalProject(EMPNO=[$0], ENAME=[$1])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
+ assertThat(trimmed, hasTree(expected));
+ }
+}