You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by vl...@apache.org on 2015/01/06 14:25:32 UTC
incubator-calcite git commit: [CALCITE-92] Optimize away Project that
merely renames fields
Repository: incubator-calcite
Updated Branches:
refs/heads/master dd05f6cd9 -> 3c508b5c4
[CALCITE-92] Optimize away Project that merely renames fields
Fixes #32
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/3c508b5c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/3c508b5c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/3c508b5c
Branch: refs/heads/master
Commit: 3c508b5c4fa3aa3eff3837df77a06f3361103dee
Parents: dd05f6c
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Tue Jan 6 16:25:34 2015 +0300
Committer: Vladimir Sitnikov <si...@gmail.com>
Committed: Tue Jan 6 16:25:34 2015 +0300
----------------------------------------------------------------------
.../org/apache/calcite/plan/RelOptUtil.java | 9 +++-
.../calcite/plan/SubstitutionVisitor.java | 11 +---
.../calcite/rel/rules/ProjectRemoveRule.java | 46 +++++-----------
.../java/org/apache/calcite/rex/RexUtil.java | 2 +-
.../apache/calcite/sql2rel/RelFieldTrimmer.java | 1 -
.../java/org/apache/calcite/test/JdbcTest.java | 57 ++++++++++++++++++++
.../org/apache/calcite/test/RelOptRulesTest.xml | 31 +++++------
.../calcite/test/SqlToRelConverterTest.xml | 5 +-
core/src/test/resources/sql/join.oq | 6 +--
core/src/test/resources/sql/outer.oq | 3 +-
10 files changed, 96 insertions(+), 75 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 9cc2401..c0a83ae 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -2709,7 +2709,14 @@ public abstract class RelOptUtil {
: SqlValidatorUtil.uniquify(
fieldNames, SqlValidatorUtil.F_SUGGESTER));
if (optimize
- && ProjectRemoveRule.isIdentity(exprs, rowType, child.getRowType())) {
+ && ProjectRemoveRule.isIdentity(exprs, child.getRowType())) {
+ if (child instanceof Project && fieldNames != null) {
+ // Rename columns of child projection if desired field names are given.
+ Project childProject = (Project) child;
+ child = childProject.copy(childProject.getTraitSet(),
+ childProject.getInput(), childProject.getProjects(),
+ rowType);
+ }
return child;
}
return new LogicalProject(cluster,
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index e0889dc..54fe7b8 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -1886,16 +1886,7 @@ public class SubstitutionVisitor {
public static boolean isTrivial(MutableProject project) {
MutableRel child = project.getInput();
final RelDataType childRowType = child.getRowType();
- if (!childRowType.isStruct()) {
- return false;
- }
- if (!ProjectRemoveRule.isIdentity(
- project.getProjects(),
- project.getRowType(),
- childRowType)) {
- return false;
- }
- return true;
+ return ProjectRemoveRule.isIdentity(project.getProjects(), childRowType);
}
/** Equivalent to
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
index b74f532..5e39853 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
@@ -21,9 +21,8 @@ import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
import com.google.common.base.Predicate;
@@ -66,6 +65,13 @@ public class ProjectRemoveRule extends RelOptRule {
Project project = call.rel(0);
assert isTrivial(project);
RelNode stripped = project.getInput();
+ if (stripped instanceof Project) {
+ // Rename columns of child projection if desired field names are given.
+ Project childProject = (Project) stripped;
+ stripped = childProject.copy(childProject.getTraitSet(),
+ childProject.getInput(), childProject.getProjects(),
+ project.getRowType());
+ }
RelNode child = call.getPlanner().register(stripped, project);
call.transformTo(child);
}
@@ -81,41 +87,13 @@ public class ProjectRemoveRule extends RelOptRule {
public static boolean isTrivial(Project project) {
RelNode child = project.getInput();
final RelDataType childRowType = child.getRowType();
- if (!childRowType.isStruct()) {
- return false;
- }
- if (!project.isBoxed()) {
- return false;
- }
- if (!isIdentity(project.getProjects(), project.getRowType(),
- childRowType)) {
- return false;
- }
- return true;
+ return isIdentity(project.getProjects(), childRowType);
}
public static boolean isIdentity(List<? extends RexNode> exps,
- RelDataType rowType, RelDataType childRowType) {
- List<RelDataTypeField> fields = rowType.getFieldList();
- List<RelDataTypeField> childFields = childRowType.getFieldList();
- int fieldCount = childFields.size();
- if (exps.size() != fieldCount) {
- return false;
- }
- for (int i = 0; i < exps.size(); i++) {
- RexNode exp = exps.get(i);
- if (!(exp instanceof RexInputRef)) {
- return false;
- }
- RexInputRef var = (RexInputRef) exp;
- if (var.getIndex() != i) {
- return false;
- }
- if (!fields.get(i).getName().equals(childFields.get(i).getName())) {
- return false;
- }
- }
- return true;
+ RelDataType childRowType) {
+ return childRowType.getFieldCount() == exps.size()
+ && RexUtil.containIdentity(exps, childRowType, false);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index c5efd29..ef430d8 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -583,7 +583,7 @@ public class RexUtil {
* underlying datatype.
*/
public static boolean containIdentity(
- List<RexNode> exprs,
+ List<? extends RexNode> exprs,
RelDataType rowType,
boolean fail) {
final List<RelDataTypeField> fields = rowType.getFieldList();
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
----------------------------------------------------------------------
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 4bfe35b..a41606e 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -380,7 +380,6 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
final RelNode newProject;
if (ProjectRemoveRule.isIdentity(
newProjectExprList,
- newRowType,
newInput.getRowType())) {
// The new project would be the identity. It is equivalent to return
// its child.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index b7b1d39..3493dcb 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -2486,6 +2486,58 @@ public class JdbcTest {
+ "EXPR$0=2; EXPR$1=abc\n");
}
+ /**
+ * Tests that even though trivial "rename columns" projection is removed,
+ * the query still returns proper column names.
+ */
+ @Test public void testValuesCompositeRenamed() {
+ CalciteAssert.that()
+ .query("select EXPR$0 q, EXPR$1 w from (values (1, 'a'), (2, 'abc'))")
+ .explainContains(
+ "PLAN=EnumerableValues(tuples=[[{ 1, 'a ' }, { 2, 'abc' }]])\n")
+ .returns("Q=1; W=a \n"
+ + "Q=2; W=abc\n");
+ }
+
+ /**
+ * Tests that even though trivial "rename columns" projection is removed,
+ * the query still returns proper column names.
+ */
+ @Test public void testValuesCompositeRenamedSameNames() {
+ CalciteAssert.that()
+ .query("select EXPR$0 q, EXPR$1 q from (values (1, 'a'), (2, 'abc'))")
+ .explainContains(
+ "PLAN=EnumerableValues(tuples=[[{ 1, 'a ' }, { 2, 'abc' }]])\n")
+ .returnsUnordered(
+ "Q=1; Q=a ",
+ "Q=2; Q=abc");
+ }
+
+ /**
+ * Tests that even though trivial "rename columns" projection is removed,
+ * the query still returns proper column names.
+ */
+ @Test public void testUnionWithSameColumnNames() {
+ CalciteAssert.that()
+ .with(CalciteAssert.Config.REGULAR)
+ .query(
+ "select \"deptno\", \"deptno\" from \"hr\".\"depts\" union select \"deptno\", \"empid\" from \"hr\".\"emps\"")
+ .explainContains(""
+ + "PLAN=EnumerableUnion(all=[false])\n"
+ + " EnumerableCalc(expr#0..3=[{inputs}], deptno=[$t0], deptno0=[$t0])\n"
+ + " EnumerableTableScan(table=[[hr, depts]])\n"
+ + " EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1], empid=[$t0])\n"
+ + " EnumerableTableScan(table=[[hr, emps]])\n")
+ .returnsUnordered(
+ "deptno=10; deptno=110",
+ "deptno=10; deptno=10",
+ "deptno=20; deptno=200",
+ "deptno=10; deptno=100",
+ "deptno=10; deptno=150",
+ "deptno=30; deptno=30",
+ "deptno=40; deptno=40");
+ }
+
/** Tests inner join to an inline table ({@code VALUES} clause). */
@Test public void testInnerJoinValues() {
CalciteAssert.that()
@@ -2493,6 +2545,11 @@ public class JdbcTest {
.query("select empno, desc from sales.emps,\n"
+ " (SELECT * FROM (VALUES (10, 'SameName')) AS t (id, desc)) as sn\n"
+ "where emps.deptno = sn.id and sn.desc = 'SameName' group by empno, desc")
+ .explainContains("EnumerableAggregate(group=[{0, 1}])\n"
+ + " EnumerableCalc(expr#0..3=[{inputs}], expr#4=[CAST($t3):INTEGER NOT NULL], expr#5=[=($t4, $t0)], expr#6=['SameName'], expr#7=[=($t1, $t6)], expr#8=[AND($t5, $t7)], EMPNO=[$t2], DESC=[$t1], $condition=[$t8])\n"
+ + " EnumerableJoin(condition=[true], joinType=[inner])\n"
+ + " EnumerableValues(tuples=[[{ 10, 'SameName' }]])\n"
+ + " EnumerableTableScan(table=[[SALES, EMPS]])\n")
.returns("EMPNO=1; DESC=SameName\n");
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 8603a5f..7e1e00b 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -296,8 +296,7 @@ LogicalProject(DDEPTNO=[$0], DNAME=[$1], C=[$2])
LogicalProject(DDEPTNO=[CASE($2, null, $0)], DNAME=[CASE($3, null, $1)], C=[$4])
LogicalFilter(condition=[=(CASE($3, null, $1), 'Charlie')])
LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], C=[COUNT()])
- LogicalProject(DDEPTNO=[$0], DNAME=[$1])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
@@ -306,8 +305,7 @@ LogicalProject(DDEPTNO=[$0], DNAME=[$1], C=[$2])
LogicalProject(DDEPTNO=[CASE($2, null, $0)], DNAME=[CASE($3, null, $1)], C=[$4])
LogicalFilter(condition=[=(CASE($3, null, $1), 'Charlie')])
LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], C=[COUNT()])
- LogicalProject(DDEPTNO=[$0], DNAME=[$1])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
@@ -2764,9 +2762,8 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalProject(SAL=[$5], DEPTNO=[$7])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalAggregate(group=[{0}])
- LogicalProject($f0=[$0])
- LogicalProject(DEPTNO=[$0])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(DEPTNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
@@ -2783,9 +2780,8 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalProject(SAL=[$5], DEPTNO=[$7])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalAggregate(group=[{0}])
- LogicalProject($f0=[$0])
- LogicalProject(DEPTNO=[$0])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(DEPTNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
@@ -2808,9 +2804,8 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalProject(SAL=[$5], DEPTNO=[$7])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalAggregate(group=[{0}])
- LogicalProject($f0=[$0])
- LogicalProject(DEPTNO=[$0])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(DEPTNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
@@ -2823,9 +2818,8 @@ SemiJoin(condition=[=($0, $2)], joinType=[inner])
LogicalProject(SAL=[$5], DEPTNO=[$7])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalAggregate(group=[{0}])
- LogicalProject($f0=[$0])
- LogicalProject(DEPTNO=[$0])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(DEPTNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
@@ -2865,9 +2859,8 @@ LogicalProject(DEPTNO=[$0])
LogicalProject(SAL=[$5], DEPTNO=[$7])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalAggregate(group=[{0}])
- LogicalProject($f0=[$0])
- LogicalProject(DEPTNO=[$0])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(DEPTNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
LogicalProject(ACCTNO=[$0])
LogicalTableScan(table=[[CATALOG, CUSTOMER, ACCOUNT]])
]]>
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index b2990d2..db79eb8 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2226,9 +2226,8 @@ group by rollup(a, b)]]>
LogicalProject(A=[$0], B=[$1], C=[$4])
LogicalProject(A=[CASE($2, null, $0)], B=[CASE($3, null, $1)], i$A=[$2], i$B=[$3], C=[$4])
LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], C=[COUNT()])
- LogicalProject(A=[$0], B=[$1])
- LogicalProject(EXPR$0=[null], EXPR$1=[2])
- LogicalValues(tuples=[[{ 0 }]])
+ LogicalProject(A=[null], B=[2])
+ LogicalValues(tuples=[[{ 0 }]])
]]>
</Resource>
</TestCase>
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/test/resources/sql/join.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/join.oq b/core/src/test/resources/sql/join.oq
index 28031ac..1bbb48c 100644
--- a/core/src/test/resources/sql/join.oq
+++ b/core/src/test/resources/sql/join.oq
@@ -39,8 +39,7 @@ on emp.deptno = dept.deptno or emp.ename = dept.dname;
# As an INNER join, it can be executed as an equi-join followed by a filter
EnumerableCalc(expr#0..5=[{inputs}], expr#6=[=($t3, $t0)], expr#7=[=($t5, $t1)], expr#8=[OR($t6, $t7)], ENAME=[$t2], DEPTNO=[$t3], GENDER=[$t4], DEPTNO0=[$t0], DNAME=[$t1], $condition=[$t8])
EnumerableJoin(condition=[true], joinType=[inner])
- EnumerableCalc(expr#0..1=[{inputs}], proj#0..1=[{exprs}])
- EnumerableValues(tuples=[[{ 10, 'Sales ' }, { 20, 'Marketing ' }, { 30, 'Engineering' }, { 40, 'Empty ' }]])
+ EnumerableValues(tuples=[[{ 10, 'Sales ' }, { 20, 'Marketing ' }, { 30, 'Engineering' }, { 40, 'Empty ' }]])
EnumerableCalc(expr#0..2=[{inputs}], expr#3=[CAST($t0):CHAR(11) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL], proj#0..3=[{exprs}])
EnumerableUnion(all=[true])
EnumerableCalc(expr#0=[{inputs}], expr#1=['Jane'], expr#2=[10], expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
@@ -108,8 +107,7 @@ EnumerableCalc(expr#0..5=[{inputs}], proj#0..2=[{exprs}], DEPTNO0=[$t4], DNAME=[
EnumerableValues(tuples=[[{ 0 }]])
EnumerableCalc(expr#0=[{inputs}], expr#1=['Wilma'], expr#2=[null], expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
EnumerableValues(tuples=[[{ 0 }]])
- EnumerableCalc(expr#0..1=[{inputs}], proj#0..1=[{exprs}])
- EnumerableValues(tuples=[[{ 10, 'Sales ' }, { 20, 'Marketing ' }, { 30, 'Engineering' }, { 40, 'Empty ' }]])
+ EnumerableValues(tuples=[[{ 10, 'Sales ' }, { 20, 'Marketing ' }, { 30, 'Engineering' }, { 40, 'Empty ' }]])
!plan
# End join.oq
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3c508b5c/core/src/test/resources/sql/outer.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/outer.oq b/core/src/test/resources/sql/outer.oq
index 92071b1..fe94a70 100644
--- a/core/src/test/resources/sql/outer.oq
+++ b/core/src/test/resources/sql/outer.oq
@@ -266,8 +266,7 @@ EnumerableThetaJoin(condition=[=(-($1, $3), 0)], joinType=[full])
EnumerableValues(tuples=[[{ 0 }]])
EnumerableCalc(expr#0=[{inputs}], expr#1=['Wilma'], expr#2=[null], expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
EnumerableValues(tuples=[[{ 0 }]])
- EnumerableCalc(expr#0..1=[{inputs}], proj#0..1=[{exprs}])
- EnumerableValues(tuples=[[{ 10, 'Sales ' }, { 20, 'Marketing ' }, { 30, 'Engineering' }, { 40, 'Empty ' }]])
+ EnumerableValues(tuples=[[{ 10, 'Sales ' }, { 20, 'Marketing ' }, { 30, 'Engineering' }, { 40, 'Empty ' }]])
!plan