Skip to content

Commit 29452b3

Browse files
nielspardonzabetak
authored andcommitted
[CALCITE-6877] Generate LogicalProject in RelRoot.project() when mapping is not name trivial
Signed-off-by: Niels Pardon <par@zurich.ibm.com> Close apache#4230
1 parent c550296 commit 29452b3

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

core/src/main/java/org/apache/calcite/rel/RelRoot.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public RelNode project(boolean force) {
164164
if (isRefTrivial()
165165
&& (SqlKind.DML.contains(kind)
166166
|| !force
167-
|| rel instanceof LogicalProject)) {
167+
|| (rel instanceof LogicalProject && isNameTrivial()))) {
168168
return rel;
169169
}
170170
final List<RexNode> projects = new ArrayList<>(fields.size());

core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
import org.apache.calcite.rel.RelFieldCollation.Direction;
2828
import org.apache.calcite.rel.RelFieldCollation.NullDirection;
2929
import org.apache.calcite.rel.RelNode;
30+
import org.apache.calcite.rel.RelRoot;
3031
import org.apache.calcite.rel.core.JoinRelType;
3132
import org.apache.calcite.rel.hint.HintPredicates;
3233
import org.apache.calcite.rel.hint.HintStrategyTable;
3334
import org.apache.calcite.rel.hint.RelHint;
3435
import org.apache.calcite.rel.logical.LogicalAggregate;
3536
import org.apache.calcite.rel.logical.LogicalFilter;
37+
import org.apache.calcite.rel.logical.LogicalProject;
3638
import org.apache.calcite.rel.rules.AggregateJoinTransposeRule;
3739
import org.apache.calcite.rel.rules.AggregateProjectMergeRule;
3840
import org.apache.calcite.rel.rules.CoreRules;
@@ -42,14 +44,18 @@
4244
import org.apache.calcite.rel.rules.PruneEmptyRules;
4345
import org.apache.calcite.rel.type.RelDataType;
4446
import org.apache.calcite.rel.type.RelDataTypeFactory;
47+
import org.apache.calcite.rel.type.RelDataTypeField;
48+
import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
4549
import org.apache.calcite.rel.type.RelDataTypeSystem;
4650
import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
51+
import org.apache.calcite.rel.type.RelRecordType;
4752
import org.apache.calcite.runtime.FlatLists;
4853
import org.apache.calcite.runtime.Hook;
4954
import org.apache.calcite.schema.SchemaPlus;
5055
import org.apache.calcite.sql.SqlCall;
5156
import org.apache.calcite.sql.SqlDialect;
5257
import org.apache.calcite.sql.SqlDialect.DatabaseProduct;
58+
import org.apache.calcite.sql.SqlKind;
5359
import org.apache.calcite.sql.SqlNode;
5460
import org.apache.calcite.sql.SqlSelect;
5561
import org.apache.calcite.sql.SqlWriter;
@@ -99,6 +105,7 @@
99105

100106
import java.math.BigDecimal;
101107
import java.util.Collection;
108+
import java.util.Collections;
102109
import java.util.List;
103110
import java.util.Map;
104111
import java.util.Set;
@@ -114,7 +121,10 @@
114121
import static org.hamcrest.CoreMatchers.notNullValue;
115122
import static org.hamcrest.MatcherAssert.assertThat;
116123
import static org.hamcrest.Matchers.hasToString;
124+
import static org.junit.jupiter.api.Assertions.assertEquals;
117125
import static org.junit.jupiter.api.Assertions.assertFalse;
126+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
127+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
118128
import static org.junit.jupiter.api.Assertions.assertTrue;
119129

120130
/**
@@ -9315,6 +9325,83 @@ private void checkLiteral2(String expression, String expected) {
93159325
}
93169326

93179327

9328+
/** Test case for
9329+
* <a href="https://issues.apache.org/jira/browse/CALCITE-6877">[CALCITE-6877]
9330+
* Generate LogicalProject in RelRoot.project() when mapping is not name trivial</a>. */
9331+
@Test void testRelRootProjectForceNonNameTrivial() {
9332+
final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
9333+
final SchemaPlus defaultSchema =
9334+
CalciteAssert.addSchema(rootSchema, CalciteAssert.SchemaSpec.HR);
9335+
final FrameworkConfig frameworkConfig = RelBuilderTest.config()
9336+
.defaultSchema(defaultSchema)
9337+
.build();
9338+
final RelBuilder relBuilder = RelBuilder.create(frameworkConfig);
9339+
final RelNode inputRel = relBuilder.scan("emps")
9340+
.project(relBuilder.fields(Collections.singletonList("empid"))).build();
9341+
9342+
final List<RelDataTypeField> fields =
9343+
Collections.singletonList(
9344+
// rename empid to empno via RelRoot
9345+
new RelDataTypeFieldImpl("empno",
9346+
inputRel.getRowType().getFieldList().get(0).getIndex(),
9347+
inputRel.getRowType().getFieldList().get(0).getType()));
9348+
9349+
final RelRoot root = RelRoot.of(inputRel, new RelRecordType(fields), SqlKind.SELECT);
9350+
9351+
// inner LogicalProject selects one field and RelRoot only has one field
9352+
assertTrue(root.isRefTrivial());
9353+
9354+
// inner LogicalProject has different field name than RelRoot
9355+
assertFalse(root.isNameTrivial());
9356+
9357+
final RelNode project = root.project();
9358+
assertEquals(inputRel, project);
9359+
9360+
// regular project() and force project() are different
9361+
final RelNode forceProject = root.project(true);
9362+
assertNotEquals(project, forceProject);
9363+
9364+
// new LogicalProject on top of inputRel
9365+
assertInstanceOf(LogicalProject.class, forceProject);
9366+
assertEquals(inputRel, forceProject.getInput(0));
9367+
9368+
// new LogicalProject renames field
9369+
if (forceProject instanceof LogicalProject) {
9370+
assertEquals("empno",
9371+
((LogicalProject) forceProject).getNamedProjects().get(0).getValue());
9372+
}
9373+
}
9374+
9375+
/** Test case for
9376+
* <a href="https://issues.apache.org/jira/browse/CALCITE-6877">[CALCITE-6877]
9377+
* Generate LogicalProject in RelRoot.project() when mapping is not name trivial</a>. */
9378+
@Test void testRelRootProjectForceNameTrivial() {
9379+
final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
9380+
final SchemaPlus defaultSchema =
9381+
CalciteAssert.addSchema(rootSchema, CalciteAssert.SchemaSpec.HR);
9382+
final FrameworkConfig frameworkConfig = RelBuilderTest.config()
9383+
.defaultSchema(defaultSchema)
9384+
.build();
9385+
final RelBuilder relBuilder = RelBuilder.create(frameworkConfig);
9386+
final RelNode inputRel = relBuilder.scan("emps")
9387+
.project(relBuilder.fields(Collections.singletonList("empid"))).build();
9388+
9389+
final RelRoot root = RelRoot.of(inputRel, SqlKind.SELECT);
9390+
9391+
// inner LogicalProject selects one field and RelRoot only has one field
9392+
assertTrue(root.isRefTrivial());
9393+
9394+
// inner LogicalProject has same field name as RelRoot
9395+
assertTrue(root.isNameTrivial());
9396+
9397+
final RelNode project = root.project();
9398+
assertEquals(inputRel, project);
9399+
9400+
// regular project() and force project() are the same
9401+
final RelNode forceProject = root.project(true);
9402+
assertEquals(project, forceProject);
9403+
}
9404+
93189405
/** Fluid interface to run tests. */
93199406
static class Sql {
93209407
private final CalciteAssert.SchemaSpec schemaSpec;

0 commit comments

Comments
 (0)