You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/09/28 22:19:33 UTC
[2/7] incubator-calcite git commit: [CALCITE-828] Use RelBuilder in
rules rather than type-specific RelNode factories
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
index 2e6667c..477b74a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
@@ -18,7 +18,6 @@ package org.apache.calcite.rel.rules;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.prepare.CalcitePrepareImpl;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.JoinRelType;
@@ -30,6 +29,8 @@ import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexPermuteInputsShuttle;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.rex.RexVisitor;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
@@ -37,7 +38,6 @@ import org.apache.calcite.util.mapping.Mappings;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import java.io.PrintWriter;
@@ -67,25 +67,26 @@ import java.util.List;
*/
public class MultiJoinOptimizeBushyRule extends RelOptRule {
public static final MultiJoinOptimizeBushyRule INSTANCE =
- new MultiJoinOptimizeBushyRule(RelFactories.DEFAULT_JOIN_FACTORY,
- RelFactories.DEFAULT_PROJECT_FACTORY);
+ new MultiJoinOptimizeBushyRule(RelFactories.LOGICAL_BUILDER);
- private final RelFactories.JoinFactory joinFactory;
- private final RelFactories.ProjectFactory projectFactory;
private final PrintWriter pw =
CalcitePrepareImpl.DEBUG ? new PrintWriter(System.out, true) : null;
/** Creates an MultiJoinOptimizeBushyRule. */
+ public MultiJoinOptimizeBushyRule(RelBuilderFactory relBuilderFactory) {
+ super(operand(MultiJoin.class, any()), relBuilderFactory, null);
+ }
+
+ @Deprecated // to be removed before 2.0
public MultiJoinOptimizeBushyRule(RelFactories.JoinFactory joinFactory,
RelFactories.ProjectFactory projectFactory) {
- super(operand(MultiJoin.class, any()));
- this.joinFactory = joinFactory;
- this.projectFactory = projectFactory;
+ this(RelBuilder.proto(joinFactory, projectFactory));
}
@Override public void onMatch(RelOptRuleCall call) {
final MultiJoin multiJoinRel = call.rel(0);
final RexBuilder rexBuilder = multiJoinRel.getCluster().getRexBuilder();
+ final RelBuilder relBuilder = call.builder();
final LoptMultiJoin multiJoin = new LoptMultiJoin(multiJoinRel);
@@ -254,11 +255,12 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule {
final RexNode condition =
RexUtil.composeConjunction(rexBuilder, joinVertex.conditions,
false);
- relNodes.add(
- Pair.of(
- joinFactory.createJoin(left, right, condition.accept(shuttle),
- JoinRelType.INNER, ImmutableSet.<String>of(), false),
- mapping));
+
+ final RelNode join = relBuilder.push(left)
+ .push(right)
+ .join(JoinRelType.INNER, condition.accept(shuttle))
+ .build();
+ relNodes.add(Pair.of(join, mapping));
}
if (pw != null) {
pw.println(Util.last(relNodes));
@@ -266,11 +268,9 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule {
}
final Pair<RelNode, Mappings.TargetMapping> top = Util.last(relNodes);
- final RelNode project =
- RelOptUtil.createProject(projectFactory, top.left,
- Mappings.asList(top.right));
-
- call.transformTo(project);
+ relBuilder.push(top.left)
+ .project(relBuilder.fields(top.right));
+ call.transformTo(relBuilder.build());
}
private void trace(List<Vertex> vertexes,
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
index 89ed15f..4537157 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
@@ -24,6 +24,8 @@ import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.RelFactories.ProjectFactory;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.Permutation;
import java.util.List;
@@ -35,15 +37,13 @@ import java.util.List;
*/
public class ProjectMergeRule extends RelOptRule {
public static final ProjectMergeRule INSTANCE =
- new ProjectMergeRule(true, RelFactories.DEFAULT_PROJECT_FACTORY);
+ new ProjectMergeRule(true, RelFactories.LOGICAL_BUILDER);
//~ Instance fields --------------------------------------------------------
/** Whether to always merge projects. */
private final boolean force;
- private final ProjectFactory projectFactory;
-
//~ Constructors -----------------------------------------------------------
/**
@@ -51,13 +51,18 @@ public class ProjectMergeRule extends RelOptRule {
*
* @param force Whether to always merge projects
*/
- public ProjectMergeRule(boolean force, ProjectFactory projectFactory) {
+ public ProjectMergeRule(boolean force, RelBuilderFactory relBuilderFactory) {
super(
operand(Project.class,
operand(Project.class, any())),
+ relBuilderFactory,
"ProjectMergeRule" + (force ? ":force_mode" : ""));
this.force = force;
- this.projectFactory = projectFactory;
+ }
+
+ @Deprecated // to be removed before 2.0
+ public ProjectMergeRule(boolean force, ProjectFactory projectFactory) {
+ this(force, RelBuilder.proto(projectFactory));
}
//~ Methods ----------------------------------------------------------------
@@ -65,6 +70,7 @@ public class ProjectMergeRule extends RelOptRule {
public void onMatch(RelOptRuleCall call) {
final Project topProject = call.rel(0);
final Project bottomProject = call.rel(1);
+ final RelBuilder relBuilder = call.builder();
// If one or both projects are permutations, short-circuit the complex logic
// of building a RexProgram.
@@ -81,10 +87,10 @@ public class ProjectMergeRule extends RelOptRule {
return;
}
final Permutation product = topPermutation.product(bottomPermutation);
- call.transformTo(
- RelOptUtil.projectMapping(bottomProject.getInput(),
- product.inverse(), topProject.getRowType().getFieldNames(),
- projectFactory));
+ relBuilder.push(bottomProject.getInput());
+ relBuilder.project(relBuilder.fields(product),
+ topProject.getRowType().getFieldNames());
+ call.transformTo(relBuilder.build());
return;
}
}
@@ -111,11 +117,9 @@ public class ProjectMergeRule extends RelOptRule {
}
// replace the two projects with a combined projection
- RelNode newProjectRel = projectFactory.createProject(
- bottomProject.getInput(), newProjects,
- topProject.getRowType().getFieldNames());
-
- call.transformTo(newProjectRel);
+ relBuilder.push(bottomProject.getInput());
+ relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
+ call.transformTo(relBuilder.build());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java
index 065738e..0cf5d58 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java
@@ -19,7 +19,10 @@ package org.apache.calcite.rel.rules;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
/**
* Planner rule that pushes
@@ -31,18 +34,15 @@ import org.apache.calcite.rel.logical.LogicalProject;
*/
public class ProjectMultiJoinMergeRule extends RelOptRule {
public static final ProjectMultiJoinMergeRule INSTANCE =
- new ProjectMultiJoinMergeRule();
+ new ProjectMultiJoinMergeRule(RelFactories.LOGICAL_BUILDER);
//~ Constructors -----------------------------------------------------------
- /**
- * Creates a ProjectMultiJoinMergeRule.
- */
- private ProjectMultiJoinMergeRule() {
+ /** Creates a ProjectMultiJoinMergeRule. */
+ private ProjectMultiJoinMergeRule(RelBuilderFactory relBuilderFactory) {
super(
- operand(
- LogicalProject.class,
- operand(MultiJoin.class, any())));
+ operand(LogicalProject.class,
+ operand(MultiJoin.class, any())), relBuilderFactory, null);
}
//~ Methods ----------------------------------------------------------------
@@ -66,15 +66,13 @@ public class ProjectMultiJoinMergeRule extends RelOptRule {
// create a new MultiJoin that reflects the columns in the projection
// above the MultiJoin
+ final RelBuilder relBuilder = call.builder();
MultiJoin newMultiJoin =
RelOptUtil.projectMultiJoin(multiJoin, project);
- LogicalProject newProject =
- (LogicalProject) RelOptUtil.createProject(
- newMultiJoin,
- project.getProjects(),
- project.getRowType().getFieldNames());
+ relBuilder.push(newMultiJoin)
+ .project(project.getProjects(), project.getRowType().getFieldNames());
- call.transformTo(newProject);
+ call.transformTo(relBuilder.build());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java
index fe53113..1287f84 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java
@@ -19,14 +19,14 @@ package org.apache.calcite.rel.rules;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.Sort;
-import org.apache.calcite.rel.logical.LogicalProject;
import com.google.common.collect.ImmutableList;
/**
* Planner rule that pushes
- * a {@link org.apache.calcite.rel.logical.LogicalProject}
+ * a {@link org.apache.calcite.rel.core.Project}
* past a {@link org.apache.calcite.rel.core.Sort}.
*
* @see org.apache.calcite.rel.rules.SortProjectTransposeRule
@@ -42,15 +42,15 @@ public class ProjectSortTransposeRule extends RelOptRule {
*/
private ProjectSortTransposeRule() {
super(
- operand(LogicalProject.class,
+ operand(Project.class,
operand(Sort.class, any())));
}
//~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
- LogicalProject project = call.rel(0);
- Sort sort = call.rel(1);
+ final Project project = call.rel(0);
+ final Sort sort = call.rel(1);
if (sort.getClass() != Sort.class) {
return;
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
index 92fd282..fe6334e 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
@@ -21,13 +21,11 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelOptRuleOperand;
-import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Calc;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.logical.LogicalCalc;
-import org.apache.calcite.rel.logical.LogicalFilter;
import org.apache.calcite.rel.logical.LogicalWindow;
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexDynamicParam;
@@ -40,6 +38,7 @@ import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexProgramBuilder;
import org.apache.calcite.rex.RexVisitorImpl;
import org.apache.calcite.rex.RexWindow;
+import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
@@ -104,7 +103,8 @@ public abstract class ProjectToWindowRule extends RelOptRule {
public void onMatch(RelOptRuleCall call) {
Calc calc = call.rel(0);
assert RexOver.containsOver(calc.getProgram());
- CalcRelSplitter transform = new WindowedAggRelSplitter(calc);
+ final CalcRelSplitter transform =
+ new WindowedAggRelSplitter(calc, call.builder());
RelNode newRel = transform.execute();
call.transformTo(newRel);
}
@@ -133,31 +133,30 @@ public abstract class ProjectToWindowRule extends RelOptRule {
project.getCluster().getRexBuilder());
// temporary LogicalCalc, never registered
final LogicalCalc calc = LogicalCalc.create(input, program);
- CalcRelSplitter transform = new WindowedAggRelSplitter(calc) {
+ final CalcRelSplitter transform = new WindowedAggRelSplitter(calc,
+ call.builder()) {
@Override protected RelNode handle(RelNode rel) {
- if (rel instanceof LogicalCalc) {
- LogicalCalc calc = (LogicalCalc) rel;
- final RexProgram program = calc.getProgram();
- rel = calc.getInput();
- if (program.getCondition() != null) {
- rel = LogicalFilter.create(rel,
- program.expandLocalRef(
- program.getCondition()));
- }
- if (!program.projectsOnlyIdentity()) {
- rel = RelOptUtil.createProject(
- rel,
- Lists.transform(
- program.getProjectList(),
- new Function<RexLocalRef, RexNode>() {
- public RexNode apply(RexLocalRef a0) {
- return program.expandLocalRef(a0);
- }
- }),
- calc.getRowType().getFieldNames());
- }
+ if (!(rel instanceof LogicalCalc)) {
+ return rel;
+ }
+ final LogicalCalc calc = (LogicalCalc) rel;
+ final RexProgram program = calc.getProgram();
+ relBuilder.push(calc.getInput());
+ if (program.getCondition() != null) {
+ relBuilder.filter(
+ program.expandLocalRef(program.getCondition()));
+ }
+ if (!program.projectsOnlyIdentity()) {
+ relBuilder.project(
+ Lists.transform(program.getProjectList(),
+ new Function<RexLocalRef, RexNode>() {
+ public RexNode apply(RexLocalRef a0) {
+ return program.expandLocalRef(a0);
+ }
+ }),
+ calc.getRowType().getFieldNames());
}
- return rel;
+ return relBuilder.build();
}
};
RelNode newRel = transform.execute();
@@ -175,80 +174,69 @@ public abstract class ProjectToWindowRule extends RelOptRule {
//~ Inner Classes ----------------------------------------------------------
/**
- * Splitter which distinguishes between windowed aggregation expressions
+ * Splitter that distinguishes between windowed aggregation expressions
* (calls to {@link RexOver}) and ordinary expressions.
*/
static class WindowedAggRelSplitter extends CalcRelSplitter {
- WindowedAggRelSplitter(Calc calc) {
- super(
- calc,
- new RelType[]{
- new CalcRelSplitter.RelType("CalcRelType") {
- protected boolean canImplement(RexFieldAccess field) {
- return true;
- }
+ private static final RelType[] REL_TYPES = {
+ new RelType("CalcRelType") {
+ protected boolean canImplement(RexFieldAccess field) {
+ return true;
+ }
- protected boolean canImplement(RexDynamicParam param) {
- return true;
- }
+ protected boolean canImplement(RexDynamicParam param) {
+ return true;
+ }
- protected boolean canImplement(RexLiteral literal) {
- return true;
- }
+ protected boolean canImplement(RexLiteral literal) {
+ return true;
+ }
- protected boolean canImplement(RexCall call) {
- return !(call instanceof RexOver);
- }
+ protected boolean canImplement(RexCall call) {
+ return !(call instanceof RexOver);
+ }
- protected RelNode makeRel(
- RelOptCluster cluster,
- RelTraitSet traits,
- RelNode child,
- RexProgram program) {
- assert !program.containsAggs();
- program = RexProgramBuilder.normalize(cluster.getRexBuilder(),
- program);
- return super.makeRel(
- cluster,
- traits,
- child,
- program);
- }
- },
- new CalcRelSplitter.RelType("WinAggRelType") {
- protected boolean canImplement(RexFieldAccess field) {
- return false;
- }
+ protected RelNode makeRel(RelOptCluster cluster, RelTraitSet traitSet,
+ RelBuilder relBuilder, RelNode input, RexProgram program) {
+ assert !program.containsAggs();
+ program = RexProgramBuilder.normalize(cluster.getRexBuilder(),
+ program);
+ return super.makeRel(cluster, traitSet, relBuilder, input, program);
+ }
+ },
+ new RelType("WinAggRelType") {
+ protected boolean canImplement(RexFieldAccess field) {
+ return false;
+ }
- protected boolean canImplement(RexDynamicParam param) {
- return false;
- }
+ protected boolean canImplement(RexDynamicParam param) {
+ return false;
+ }
- protected boolean canImplement(RexLiteral literal) {
- return false;
- }
+ protected boolean canImplement(RexLiteral literal) {
+ return false;
+ }
- protected boolean canImplement(RexCall call) {
- return call instanceof RexOver;
- }
+ protected boolean canImplement(RexCall call) {
+ return call instanceof RexOver;
+ }
- protected boolean supportsCondition() {
- return false;
- }
+ protected boolean supportsCondition() {
+ return false;
+ }
- protected RelNode makeRel(
- RelOptCluster cluster,
- RelTraitSet traits,
- RelNode child,
- RexProgram program) {
- Util.permAssert(
- program.getCondition() == null,
- "WindowedAggregateRel cannot accept a condition");
- return LogicalWindow.create(
- cluster, traits, child, program);
- }
- }
- });
+ protected RelNode makeRel(RelOptCluster cluster, RelTraitSet traitSet,
+ RelBuilder relBuilder, RelNode input, RexProgram program) {
+ Util.permAssert(program.getCondition() == null,
+ "WindowedAggregateRel cannot accept a condition");
+ return LogicalWindow.create(cluster, traitSet, relBuilder, input,
+ program);
+ }
+ }
+ };
+
+ WindowedAggRelSplitter(Calc calc, RelBuilder relBuilder) {
+ super(calc, relBuilder, REL_TYPES);
}
@Override protected List<Set<Integer>> getCohorts() {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
index 8cb450e..6e945e5 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
@@ -18,10 +18,10 @@ package org.apache.calcite.rel.rules;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.SemiJoin;
import org.apache.calcite.rel.logical.LogicalProject;
import org.apache.calcite.rel.type.RelDataType;
@@ -32,6 +32,8 @@ import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexProgramBuilder;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.Pair;
@@ -52,17 +54,18 @@ import java.util.List;
*/
public class SemiJoinProjectTransposeRule extends RelOptRule {
public static final SemiJoinProjectTransposeRule INSTANCE =
- new SemiJoinProjectTransposeRule();
+ new SemiJoinProjectTransposeRule(RelFactories.LOGICAL_BUILDER);
//~ Constructors -----------------------------------------------------------
/**
* Creates a SemiJoinProjectTransposeRule.
*/
- private SemiJoinProjectTransposeRule() {
+ private SemiJoinProjectTransposeRule(RelBuilderFactory relBuilderFactory) {
super(
operand(SemiJoin.class,
- some(operand(LogicalProject.class, any()))));
+ some(operand(LogicalProject.class, any()))),
+ relBuilderFactory, null);
}
//~ Methods ----------------------------------------------------------------
@@ -71,9 +74,9 @@ public class SemiJoinProjectTransposeRule extends RelOptRule {
SemiJoin semiJoin = call.rel(0);
LogicalProject project = call.rel(1);
- // convert the LHS semijoin keys to reference the child projection
+ // Convert the LHS semi-join keys to reference the child projection
// expression; all projection expressions must be RexInputRefs,
- // otherwise, we wouldn't have created this semijoin
+ // otherwise, we wouldn't have created this semi-join.
final List<Integer> newLeftKeys = new ArrayList<>();
final List<Integer> leftKeys = semiJoin.getLeftKeys();
final List<RexNode> projExprs = project.getProjects();
@@ -93,13 +96,11 @@ public class SemiJoinProjectTransposeRule extends RelOptRule {
// Create the new projection. Note that the projection expressions
// are the same as the original because they only reference the LHS
// of the semijoin and the semijoin only projects out the LHS
- RelNode newProject =
- RelOptUtil.createProject(
- newSemiJoin,
- projExprs,
- project.getRowType().getFieldNames());
+ final RelBuilder relBuilder = call.builder();
+ relBuilder.push(newSemiJoin);
+ relBuilder.project(projExprs, project.getRowType().getFieldNames());
- call.transformTo(newProject);
+ call.transformTo(relBuilder.build());
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java
index b6d87f5..4bc11ec 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java
@@ -36,9 +36,10 @@ import com.google.common.collect.ImmutableList;
/**
* Planner rule that pushes a {@link org.apache.calcite.rel.core.Sort} past a
- * {@link org.apache.calcite.rel.core.Join}. At the moment, we only consider
- * left/right outer joins.
- * However, an extesion for full outer joins for this rule could be envision.
+ * {@link org.apache.calcite.rel.core.Join}.
+ *
+ * <p>At the moment, we only consider left/right outer joins.
+ * However, an extension for full outer joins for this rule could be envisioned.
* Special attention should be paid to null values for correctness issues.
*/
public class SortJoinTransposeRule extends RelOptRule {
@@ -59,8 +60,7 @@ public class SortJoinTransposeRule extends RelOptRule {
//~ Methods ----------------------------------------------------------------
- @Override
- public boolean matches(RelOptRuleCall call) {
+ @Override public boolean matches(RelOptRuleCall call) {
final Sort sort = call.rel(0);
final Join join = call.rel(1);
@@ -95,8 +95,7 @@ public class SortJoinTransposeRule extends RelOptRule {
return true;
}
- @Override
- public void onMatch(RelOptRuleCall call) {
+ @Override public void onMatch(RelOptRuleCall call) {
final Sort sort = call.rel(0);
final Join join = call.rel(1);
@@ -150,8 +149,7 @@ public class SortJoinTransposeRule extends RelOptRule {
if (rowCount != null && fetch != null) {
final int offsetVal = offset == null ? 0 : RexLiteral.intValue(offset);
final int limit = RexLiteral.intValue(fetch);
- final Double offsetLimit = new Double(offsetVal + limit);
- if (offsetLimit < rowCount) {
+ if ((double) offsetVal + (double) limit < rowCount) {
alreadySmaller = false;
}
}
@@ -159,3 +157,5 @@ public class SortJoinTransposeRule extends RelOptRule {
}
}
+
+// End SortJoinTransposeRule.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
index 2240c38..b86bbe3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
@@ -24,6 +24,7 @@ import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollationTraitDef;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.Sort;
import org.apache.calcite.rel.logical.LogicalProject;
import org.apache.calcite.rex.RexUtil;
@@ -37,7 +38,7 @@ import java.util.Map;
/**
* Planner rule that pushes
* a {@link org.apache.calcite.rel.core.Sort}
- * past a {@link org.apache.calcite.rel.logical.LogicalProject}.
+ * past a {@link org.apache.calcite.rel.core.Project}.
*
* @see org.apache.calcite.rel.rules.ProjectSortTransposeRule
*/
@@ -52,17 +53,15 @@ public class SortProjectTransposeRule extends RelOptRule {
*/
private SortProjectTransposeRule() {
super(
- operand(
- Sort.class,
+ operand(Sort.class,
operand(LogicalProject.class, any())));
}
//~ Methods ----------------------------------------------------------------
- // implement RelOptRule
public void onMatch(RelOptRuleCall call) {
final Sort sort = call.rel(0);
- final LogicalProject project = call.rel(1);
+ final Project project = call.rel(1);
final RelOptCluster cluster = project.getCluster();
if (sort.getConvention() != project.getConvention()) {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
index 1d4cfcc..fbd3e76 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
@@ -22,12 +22,10 @@ import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.Union;
import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.Util;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* UnionMergeRule implements the rule for combining two
* non-distinct {@link org.apache.calcite.rel.core.Union}s
@@ -35,38 +33,37 @@ import java.util.List;
*/
public class UnionMergeRule extends RelOptRule {
public static final UnionMergeRule INSTANCE =
- new UnionMergeRule(LogicalUnion.class,
- RelFactories.DEFAULT_SET_OP_FACTORY);
-
- private final RelFactories.SetOpFactory setOpFactory;
+ new UnionMergeRule(LogicalUnion.class, RelFactories.LOGICAL_BUILDER);
//~ Constructors -----------------------------------------------------------
- /**
- * Creates a UnionMergeRule.
- */
- public UnionMergeRule(Class<? extends Union> clazz,
- RelFactories.SetOpFactory setOpFactory) {
+ /** Creates a UnionMergeRule. */
+ public UnionMergeRule(Class<? extends Union> unionClazz,
+ RelBuilderFactory relBuilderFactory) {
super(
- operand(
- clazz,
+ operand(unionClazz,
operand(RelNode.class, any()),
- operand(RelNode.class, any())));
- this.setOpFactory = setOpFactory;
+ operand(RelNode.class, any())),
+ relBuilderFactory, null);
+ }
+
+ @Deprecated // to be removed before 2.0
+ public UnionMergeRule(Class<? extends Union> unionClazz,
+ RelFactories.SetOpFactory setOpFactory) {
+ this(unionClazz, RelBuilder.proto(setOpFactory));
}
//~ Methods ----------------------------------------------------------------
- // implement RelOptRule
public void onMatch(RelOptRuleCall call) {
- Union topUnion = call.rel(0);
- Union bottomUnion;
+ final Union topUnion = call.rel(0);
// We want to combine the Union that's in the second input first.
// Hence, that's why the rule pattern matches on generic RelNodes
// rather than explicit UnionRels. By doing so, and firing this rule
// in a bottom-up order, it allows us to only specify a single
// pattern for this rule.
+ final Union bottomUnion;
if (call.rel(2) instanceof Union) {
bottomUnion = call.rel(2);
} else if (call.rel(1) instanceof Union) {
@@ -82,22 +79,20 @@ public class UnionMergeRule extends RelOptRule {
// Combine the inputs from the bottom union with the other inputs from
// the top union
- List<RelNode> unionInputs = new ArrayList<RelNode>();
+ final RelBuilder relBuilder = call.builder();
if (call.rel(2) instanceof Union) {
assert topUnion.getInputs().size() == 2;
- unionInputs.add(topUnion.getInput(0));
- unionInputs.addAll(bottomUnion.getInputs());
+ relBuilder.push(topUnion.getInput(0));
+ relBuilder.pushAll(bottomUnion.getInputs());
} else {
- unionInputs.addAll(bottomUnion.getInputs());
- unionInputs.addAll(Util.skip(topUnion.getInputs()));
+ relBuilder.pushAll(bottomUnion.getInputs());
+ relBuilder.pushAll(Util.skip(topUnion.getInputs()));
}
- assert unionInputs.size()
- == bottomUnion.getInputs().size()
+ int n = bottomUnion.getInputs().size()
+ topUnion.getInputs().size()
- 1;
- RelNode newUnion = setOpFactory.createSetOp(SqlKind.UNION,
- unionInputs, true);
- call.transformTo(newUnion);
+ relBuilder.union(true, n);
+ call.transformTo(relBuilder.build());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java b/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
index 5bb9562..10ae1f4 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
@@ -18,12 +18,11 @@ package org.apache.calcite.rel.rules;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.Union;
import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
/**
* Planner rule that translates a distinct
@@ -35,32 +34,36 @@ import org.apache.calcite.sql.SqlKind;
*/
public class UnionToDistinctRule extends RelOptRule {
public static final UnionToDistinctRule INSTANCE =
- new UnionToDistinctRule(LogicalUnion.class,
- RelFactories.DEFAULT_SET_OP_FACTORY);
-
- private final RelFactories.SetOpFactory setOpFactory;
+ new UnionToDistinctRule(LogicalUnion.class, RelFactories.LOGICAL_BUILDER);
//~ Constructors -----------------------------------------------------------
/**
* Creates a UnionToDistinctRule.
*/
- public UnionToDistinctRule(Class<? extends Union> clazz,
+ public UnionToDistinctRule(Class<? extends Union> unionClazz,
+ RelBuilderFactory relBuilderFactory) {
+ super(operand(unionClazz, any()), relBuilderFactory, null);
+ }
+
+ @Deprecated // to be removed before 2.0
+ public UnionToDistinctRule(Class<? extends Union> unionClazz,
RelFactories.SetOpFactory setOpFactory) {
- super(operand(clazz, any()));
- this.setOpFactory = setOpFactory;
+ this(unionClazz, RelBuilder.proto(setOpFactory));
}
//~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
- Union union = call.rel(0);
+ final Union union = call.rel(0);
if (union.all) {
return; // nothing to do
}
- RelNode unionAll = setOpFactory.createSetOp(SqlKind.UNION,
- union.getInputs(), true);
- call.transformTo(RelOptUtil.createDistinctRel(unionAll));
+ final RelBuilder relBuilder = call.builder();
+ relBuilder.pushAll(union.getInputs());
+ relBuilder.union(true, union.getInputs().size());
+ relBuilder.distinct();
+ call.transformTo(relBuilder.build());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/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 9e17837..0863332 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -36,7 +36,6 @@ import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
import org.apache.calcite.rel.logical.LogicalTableModify;
import org.apache.calcite.rel.logical.LogicalValues;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
-import org.apache.calcite.rel.rules.ProjectRemoveRule;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rel.type.RelDataTypeImpl;
@@ -47,6 +46,7 @@ import org.apache.calcite.rex.RexPermuteInputsShuttle;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.rex.RexVisitor;
import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.util.Bug;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.Pair;
@@ -59,7 +59,6 @@ import org.apache.calcite.util.mapping.MappingType;
import org.apache.calcite.util.mapping.Mappings;
import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -99,13 +98,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
//~ Instance fields --------------------------------------------------------
private final ReflectUtil.MethodDispatcher<TrimResult> trimFieldsDispatcher;
- private final RelFactories.ProjectFactory projectFactory;
- private final RelFactories.FilterFactory filterFactory;
- private final RelFactories.JoinFactory joinFactory;
- private final RelFactories.SemiJoinFactory semiJoinFactory;
- private final RelFactories.SortFactory sortFactory;
- private final RelFactories.AggregateFactory aggregateFactory;
- private final RelFactories.SetOpFactory setOpFactory;
+ private final RelBuilder relBuilder;
//~ Constructors -----------------------------------------------------------
@@ -114,23 +107,22 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
*
* @param validator Validator
*/
- public RelFieldTrimmer(SqlValidator validator) {
- this(validator,
- RelFactories.DEFAULT_PROJECT_FACTORY,
- RelFactories.DEFAULT_FILTER_FACTORY,
- RelFactories.DEFAULT_JOIN_FACTORY,
- RelFactories.DEFAULT_SEMI_JOIN_FACTORY,
- RelFactories.DEFAULT_SORT_FACTORY,
- RelFactories.DEFAULT_AGGREGATE_FACTORY,
- RelFactories.DEFAULT_SET_OP_FACTORY);
+ public RelFieldTrimmer(SqlValidator validator, RelBuilder relBuilder) {
+ Util.discard(validator); // may be useful one day
+ this.relBuilder = relBuilder;
+ this.trimFieldsDispatcher =
+ ReflectUtil.createMethodDispatcher(
+ TrimResult.class,
+ this,
+ "trimFields",
+ RelNode.class,
+ ImmutableBitSet.class,
+ Set.class);
}
- /**
- * Creates a RelFieldTrimmer.
- *
- * @param validator Validator
- */
+ @Deprecated // to be removed before 2.0
public RelFieldTrimmer(SqlValidator validator,
+ RelOptCluster cluster,
RelFactories.ProjectFactory projectFactory,
RelFactories.FilterFactory filterFactory,
RelFactories.JoinFactory joinFactory,
@@ -138,22 +130,10 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
RelFactories.SortFactory sortFactory,
RelFactories.AggregateFactory aggregateFactory,
RelFactories.SetOpFactory setOpFactory) {
- Util.discard(validator); // may be useful one day
- this.trimFieldsDispatcher =
- ReflectUtil.createMethodDispatcher(
- TrimResult.class,
- this,
- "trimFields",
- RelNode.class,
- ImmutableBitSet.class,
- Set.class);
- this.projectFactory = Preconditions.checkNotNull(projectFactory);
- this.filterFactory = Preconditions.checkNotNull(filterFactory);
- this.joinFactory = Preconditions.checkNotNull(joinFactory);
- this.semiJoinFactory = Preconditions.checkNotNull(semiJoinFactory);
- this.sortFactory = Preconditions.checkNotNull(sortFactory);
- this.aggregateFactory = Preconditions.checkNotNull(aggregateFactory);
- this.setOpFactory = Preconditions.checkNotNull(setOpFactory);
+ this(validator,
+ RelBuilder.proto(projectFactory, filterFactory, joinFactory,
+ semiJoinFactory, sortFactory, aggregateFactory, setOpFactory)
+ .create(cluster, null));
}
//~ Methods ----------------------------------------------------------------
@@ -245,11 +225,10 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
? rexBuilder.makeZeroLiteral(field.getType())
: rexBuilder.makeInputRef(field.getType(), source));
}
- RelNode project =
- projectFactory.createProject(
- trimResult.left, exprList, nameList);
+ relBuilder.push(trimResult.left)
+ .project(exprList, nameList);
return new TrimResult(
- project,
+ relBuilder.build(),
Mappings.createIdentity(fieldList.size()));
}
@@ -383,17 +362,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
RelOptUtil.permute(project.getCluster().getTypeFactory(), rowType,
mapping);
- final RelNode newProject;
- if (ProjectRemoveRule.isIdentity(newProjects, newInput.getRowType())) {
- // The new project would be the identity. It is equivalent to return
- // its child.
- newProject = newInput;
- } else {
- newProject = projectFactory.createProject(newInput, newProjects,
- newRowType.getFieldNames());
- assert newProject.getClass() == project.getClass();
- }
- return new TrimResult(newProject, mapping);
+ relBuilder.push(newInput);
+ relBuilder.project(newProjects, newRowType.getFieldNames());
+ return new TrimResult(relBuilder.build(), mapping);
}
/** Creates a project with a dummy column, to protect the parts of the system
@@ -414,9 +385,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
}
final RexLiteral expr =
cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
- final RelNode newProject = projectFactory.createProject(input,
- ImmutableList.<RexNode>of(expr), ImmutableList.of("DUMMY"));
- return new TrimResult(newProject, mapping);
+ relBuilder.push(input);
+ relBuilder.project(ImmutableList.<RexNode>of(expr), ImmutableList.of("DUMMY"));
+ return new TrimResult(relBuilder.build(), mapping);
}
/**
@@ -463,13 +434,13 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
RexNode newConditionExpr =
conditionExpr.accept(shuttle);
- final RelNode newFilter = filterFactory.createFilter(
- newInput, newConditionExpr);
+ relBuilder.push(newInput);
+ relBuilder.filter(newConditionExpr);
// The result has the same mapping as the input gave us. Sometimes we
// return fields that the consumer didn't ask for, because the filter
// needs them for its condition.
- return new TrimResult(newFilter, inputMapping);
+ return new TrimResult(relBuilder.build(), inputMapping);
}
/**
@@ -510,15 +481,19 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
Mappings.createIdentity(fieldCount));
}
- final RelCollation newCollation =
- sort.getTraitSet().canonize(RexUtil.apply(inputMapping, collation));
- final RelNode newSort =
- sortFactory.createSort(newInput, newCollation, sort.offset, sort.fetch);
+ relBuilder.push(newInput);
+ final int offset =
+ sort.offset == null ? 0 : RexLiteral.intValue(sort.offset);
+ final int fetch =
+ sort.fetch == null ? -1 : RexLiteral.intValue(sort.fetch);
+ final ImmutableList<RexNode> fields =
+ relBuilder.fields(RexUtil.apply(inputMapping, collation));
+ relBuilder.sortLimit(offset, fetch, fields);
// The result has the same mapping as the input gave us. Sometimes we
// return fields that the consumer didn't ask for, because the filter
// needs them for its condition.
- return new TrimResult(newSort, inputMapping);
+ return new TrimResult(relBuilder.build(), inputMapping);
}
/**
@@ -636,10 +611,11 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
RexNode newConditionExpr =
conditionExpr.accept(shuttle);
- final RelNode newJoin;
+ relBuilder.push(newInputs.get(0));
+ relBuilder.push(newInputs.get(1));
+
if (join instanceof SemiJoin) {
- newJoin = semiJoinFactory.createSemiJoin(newInputs.get(0),
- newInputs.get(1), newConditionExpr);
+ relBuilder.semiJoin(newConditionExpr);
// For SemiJoins only map fields from the left-side
Mapping inputMapping = inputMappings.get(0);
mapping = Mappings.create(MappingType.INVERSE_SURJECTION,
@@ -654,12 +630,10 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
mapping.set(pair.source + offset, pair.target + newOffset);
}
} else {
- newJoin = joinFactory.createJoin(newInputs.get(0), newInputs.get(1),
- newConditionExpr, join.getJoinType(), join.getVariablesStopped(),
- join.isSemiJoinDone());
+ relBuilder.join(join.getJoinType(), newConditionExpr);
}
- return new TrimResult(newJoin, mapping);
+ return new TrimResult(relBuilder.build(), mapping);
}
/**
@@ -686,12 +660,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
final Mapping mapping = createMapping(fieldsUsed, fieldCount);
// Create input with trimmed columns.
- final List<RelNode> newInputs = new ArrayList<>();
for (RelNode input : setOp.getInputs()) {
TrimResult trimResult =
trimChild(setOp, input, fieldsUsed, extraFields);
- RelNode newInput = trimResult.left;
- final Mapping inputMapping = trimResult.right;
// We want "mapping", the input gave us "inputMapping", compute
// "remaining" mapping.
@@ -704,30 +675,44 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
// the consumer asked for mapping = [b, d],
// and the transformed input has columns inputMapping = [d, a, b].
// remaining will permute [b, d] to [d, a, b].
- Mapping remaining = Mappings.divide(mapping, inputMapping);
+ Mapping remaining = Mappings.divide(mapping, trimResult.right);
// Create a projection; does nothing if remaining is identity.
- newInput = RelOptUtil.projectMapping(newInput, remaining, null,
- projectFactory);
+ relBuilder.push(trimResult.left);
+ relBuilder.permute(remaining);
- if (input != newInput) {
+ if (input != relBuilder.peek()) {
++changeCount;
}
- newInputs.add(newInput);
}
// If the input is unchanged, and we need to project all columns,
// there's to do.
if (changeCount == 0
&& mapping.isIdentity()) {
+ for (RelNode input : setOp.getInputs()) {
+ relBuilder.build();
+ }
return new TrimResult(
setOp,
mapping);
}
- RelNode newSetOp =
- setOpFactory.createSetOp(setOp.kind, newInputs, setOp.all);
- return new TrimResult(newSetOp, mapping);
+ switch (setOp.kind) {
+ case UNION:
+ relBuilder.union(setOp.all, setOp.getInputs().size());
+ break;
+ case INTERSECT:
+ relBuilder.intersect(setOp.all, setOp.getInputs().size());
+ break;
+ case EXCEPT:
+ assert setOp.getInputs().size() == 2;
+ relBuilder.minus(setOp.all);
+ break;
+ default:
+ throw new AssertionError("unknown setOp " + setOp);
+ }
+ return new TrimResult(relBuilder.build(), mapping);
}
/**
@@ -831,28 +816,29 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
}
// Now create new agg calls, and populate mapping for them.
- final List<AggregateCall> newAggCallList = new ArrayList<>();
+ relBuilder.push(newInput);
+ final List<RelBuilder.AggCall> newAggCallList = new ArrayList<>();
j = groupCount + indicatorCount;
for (AggregateCall aggCall : aggregate.getAggCallList()) {
if (fieldsUsed.get(j)) {
- AggregateCall newAggCall =
- aggCall.copy(Mappings.apply2(inputMapping, aggCall.getArgList()),
- Mappings.apply(inputMapping, aggCall.filterArg));
- if (newAggCall.equals(aggCall)) {
- newAggCall = aggCall; // immutable -> canonize to save space
- }
+ final ImmutableList<RexNode> args =
+ relBuilder.fields(
+ Mappings.apply2(inputMapping, aggCall.getArgList()));
+ final RexNode filterArg = aggCall.filterArg < 0 ? null
+ : relBuilder.field(Mappings.apply(inputMapping, aggCall.filterArg));
+ RelBuilder.AggCall newAggCall =
+ relBuilder.aggregateCall(aggCall.getAggregation(),
+ aggCall.isDistinct(), filterArg, aggCall.name, args);
mapping.set(j, groupCount + indicatorCount + newAggCallList.size());
newAggCallList.add(newAggCall);
}
++j;
}
- RelNode newAggregate = aggregateFactory.createAggregate(newInput,
- aggregate.indicator, newGroupSet, newGroupSets, newAggCallList);
-
- assert newAggregate.getClass() == aggregate.getClass();
+ final RelBuilder.GroupKey groupKey = relBuilder.groupKey(newGroupSet, newGroupSets);
+ relBuilder.aggregate(groupKey, newAggCallList);
- return new TrimResult(newAggregate, mapping);
+ return new TrimResult(relBuilder.build(), mapping);
}
/**
@@ -1015,7 +1001,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
(RelNode) tableAccessRel, fieldsUsed, extraFields);
}
final RelNode newTableAccessRel =
- tableAccessRel.project(fieldsUsed, extraFields, this.projectFactory);
+ tableAccessRel.project(fieldsUsed, extraFields, relBuilder);
// Some parts of the system can't handle rows with zero fields, so
// pretend that one field is used.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index b51a0dc..c6c03b2 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -142,6 +142,7 @@ import org.apache.calcite.sql.validate.SqlValidatorImpl;
import org.apache.calcite.sql.validate.SqlValidatorNamespace;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.NlsString;
@@ -543,7 +544,9 @@ public class SqlToRelConverter {
* @return Field trimmer
*/
protected RelFieldTrimmer newFieldTrimmer() {
- return new RelFieldTrimmer(validator);
+ final RelBuilder relBuilder =
+ RelFactories.LOGICAL_BUILDER.create(cluster, null);
+ return new RelFieldTrimmer(validator, relBuilder);
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 696e22c..34eb219 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -20,12 +20,14 @@ import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.plan.Context;
import org.apache.calcite.plan.Contexts;
import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptSchema;
import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.AggregateCall;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.core.Project;
@@ -33,6 +35,7 @@ import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.Sort;
import org.apache.calcite.rel.core.TableScan;
import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.rules.ProjectRemoveRule;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeField;
@@ -50,10 +53,13 @@ import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.NlsString;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Stacks;
import org.apache.calcite.util.Util;
+import org.apache.calcite.util.mapping.Mapping;
+import org.apache.calcite.util.mapping.Mappings;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
@@ -64,7 +70,11 @@ import com.google.common.collect.Lists;
import java.math.BigDecimal;
import java.util.AbstractList;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* Builder for relational expressions.
@@ -98,6 +108,7 @@ public class RelBuilder {
private final RelFactories.SortFactory sortFactory;
private final RelFactories.SetOpFactory setOpFactory;
private final RelFactories.JoinFactory joinFactory;
+ private final RelFactories.SemiJoinFactory semiJoinFactory;
private final RelFactories.ValuesFactory valuesFactory;
private final RelFactories.TableScanFactory scanFactory;
private final List<Frame> stack = new ArrayList<>();
@@ -127,6 +138,9 @@ public class RelBuilder {
this.joinFactory =
Util.first(context.unwrap(RelFactories.JoinFactory.class),
RelFactories.DEFAULT_JOIN_FACTORY);
+ this.semiJoinFactory =
+ Util.first(context.unwrap(RelFactories.SemiJoinFactory.class),
+ RelFactories.DEFAULT_SEMI_JOIN_FACTORY);
this.valuesFactory =
Util.first(context.unwrap(RelFactories.ValuesFactory.class),
RelFactories.DEFAULT_VALUES_FACTORY);
@@ -156,16 +170,21 @@ public class RelBuilder {
return cluster.getTypeFactory();
}
- /** Creates a {@link ProtoRelBuilder}, a partially-created RelBuilder.
+ /** Creates a {@link RelBuilderFactory}, a partially-created RelBuilder.
* Just add a {@link RelOptCluster} and a {@link RelOptSchema} */
- public static ProtoRelBuilder proto(final Context context) {
- return new ProtoRelBuilder() {
+ public static RelBuilderFactory proto(final Context context) {
+ return new RelBuilderFactory() {
public RelBuilder create(RelOptCluster cluster, RelOptSchema schema) {
return new RelBuilder(context, cluster, schema);
}
};
}
+ /** Creates a {@link RelBuilderFactory} that uses a given set of factories. */
+ public static RelBuilderFactory proto(Object... factories) {
+ return proto(Contexts.of(factories));
+ }
+
// Methods for manipulating the stack
/** Adds a relational expression to be the input to the next relational
@@ -180,6 +199,14 @@ public class RelBuilder {
return this;
}
+ /** Pushes a collection of relational expressions. */
+ public RelBuilder pushAll(Iterable<? extends RelNode> nodes) {
+ for (RelNode node : nodes) {
+ push(node);
+ }
+ return this;
+ }
+
/** Returns the final relational expression.
*
* <p>Throws if the stack is empty.
@@ -328,6 +355,52 @@ public class RelBuilder {
return nodes.build();
}
+ /** Returns references to fields for a given collation. */
+ public ImmutableList<RexNode> fields(RelCollation collation) {
+ final ImmutableList.Builder<RexNode> nodes = ImmutableList.builder();
+ for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
+ RexNode node = field(fieldCollation.getFieldIndex());
+ switch (fieldCollation.direction) {
+ case DESCENDING:
+ node = desc(node);
+ }
+ switch (fieldCollation.nullDirection) {
+ case FIRST:
+ node = nullsFirst(node);
+ break;
+ case LAST:
+ node = nullsLast(node);
+ break;
+ }
+ nodes.add(node);
+ }
+ return nodes.build();
+ }
+
+ /** Returns references to fields for a given list of input ordinals. */
+ public ImmutableList<RexNode> fields(List<? extends Number> ordinals) {
+ final ImmutableList.Builder<RexNode> nodes = ImmutableList.builder();
+ for (Number ordinal : ordinals) {
+ RexNode node = field(ordinal.intValue());
+ nodes.add(node);
+ }
+ return nodes.build();
+ }
+
+ /** Returns references to fields identified by name. */
+ public ImmutableList<RexNode> fields(Iterable<String> fieldNames) {
+ final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
+ for (String fieldName : fieldNames) {
+ builder.add(field(fieldName));
+ }
+ return builder.build();
+ }
+
+ /** Returns references to fields identified by a mapping. */
+ public ImmutableList<RexNode> fields(Mappings.TargetMapping mapping) {
+ return fields(Mappings.asList(mapping));
+ }
+
/** Creates a call to a scalar operator. */
public RexNode call(SqlOperator operator, RexNode... operands) {
final RexBuilder builder = cluster.getRexBuilder();
@@ -448,69 +521,101 @@ public class RelBuilder {
/** Creates a group key. */
public GroupKey groupKey(Iterable<? extends RexNode> nodes) {
- return new GroupKeyImpl(ImmutableList.copyOf(nodes));
+ return new GroupKeyImpl(ImmutableList.copyOf(nodes), null);
+ }
+
+ /** Creates a group key with grouping sets. */
+ public GroupKey groupKey(Iterable<? extends RexNode> nodes,
+ Iterable<? extends Iterable<? extends RexNode>> nodeLists) {
+ final ImmutableList.Builder<ImmutableList<RexNode>> builder =
+ ImmutableList.builder();
+ for (Iterable<? extends RexNode> nodeList : nodeLists) {
+ builder.add(ImmutableList.copyOf(nodeList));
+ }
+ return new GroupKeyImpl(ImmutableList.copyOf(nodes), builder.build());
}
/** Creates a group key of fields identified by ordinal. */
public GroupKey groupKey(int... fieldOrdinals) {
- final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
- for (int fieldOrdinal : fieldOrdinals) {
- builder.add(field(fieldOrdinal));
- }
- return groupKey(builder.build());
+ return groupKey(fields(ImmutableIntList.of(fieldOrdinals)));
}
/** Creates a group key of fields identified by name. */
public GroupKey groupKey(String... fieldNames) {
- final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
- for (String fieldName : fieldNames) {
- builder.add(field(fieldName));
+ return groupKey(fields(ImmutableList.copyOf(fieldNames)));
+ }
+
+ /** Creates a group key with grouping sets, both identified by field positions
+ * in the underlying relational expression.
+ *
+ * <p>This method of creating a group key does not allow you to group on new
+ * expressions, only column projections, but is efficient, especially when you
+ * are coming from an existing {@link Aggregate}. */
+ public GroupKey groupKey(ImmutableBitSet groupSet,
+ ImmutableList<ImmutableBitSet> groupSets) {
+ if (groupSet.length() > peek().getRowType().getFieldCount()) {
+ throw new IllegalArgumentException("out of bounds: " + groupSet);
+ }
+ if (groupSets == null) {
+ groupSets = ImmutableList.of(groupSet);
}
- return groupKey(builder.build());
+ final ImmutableList<RexNode> nodes =
+ fields(ImmutableIntList.of(groupSet.toArray()));
+ final List<ImmutableList<RexNode>> nodeLists =
+ Lists.transform(groupSets,
+ new Function<ImmutableBitSet, ImmutableList<RexNode>>() {
+ public ImmutableList<RexNode> apply(ImmutableBitSet input) {
+ return fields(ImmutableIntList.of(input.toArray()));
+ }
+ });
+ return groupKey(nodes, nodeLists);
}
/** Creates a call to an aggregate function. */
- public AggCall aggregateCall(SqlAggFunction aggFunction,
- boolean distinct, String alias, RexNode... operands) {
- return aggregateCall(aggFunction, distinct, alias,
+ public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct,
+ RexNode filter, String alias, RexNode... operands) {
+ return aggregateCall(aggFunction, distinct, filter, alias,
ImmutableList.copyOf(operands));
}
/** Creates a call to an aggregate function. */
- public AggCall aggregateCall(SqlAggFunction aggFunction,
- boolean distinct, String alias, Iterable<? extends RexNode> operands) {
- return new AggCallImpl(aggFunction, distinct, alias,
+ public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct,
+ RexNode filter, String alias, Iterable<? extends RexNode> operands) {
+ return new AggCallImpl(aggFunction, distinct, filter, alias,
ImmutableList.copyOf(operands));
}
/** Creates a call to the COUNT aggregate function. */
public AggCall count(boolean distinct, String alias, RexNode... operands) {
- return aggregateCall(SqlStdOperatorTable.COUNT, distinct, alias, operands);
+ return aggregateCall(SqlStdOperatorTable.COUNT, distinct, null, alias,
+ operands);
}
/** Creates a call to the COUNT(*) aggregate function. */
public AggCall countStar(String alias) {
- return aggregateCall(SqlStdOperatorTable.COUNT, false, alias);
+ return aggregateCall(SqlStdOperatorTable.COUNT, false, null, alias);
}
/** Creates a call to the SUM aggregate function. */
public AggCall sum(boolean distinct, String alias, RexNode operand) {
- return aggregateCall(SqlStdOperatorTable.SUM, distinct, alias, operand);
+ return aggregateCall(SqlStdOperatorTable.SUM, distinct, null, alias,
+ operand);
}
/** Creates a call to the AVG aggregate function. */
public AggCall avg(boolean distinct, String alias, RexNode operand) {
- return aggregateCall(SqlStdOperatorTable.AVG, distinct, alias, operand);
+ return aggregateCall(
+ SqlStdOperatorTable.AVG, distinct, null, alias, operand);
}
/** Creates a call to the MIN aggregate function. */
public AggCall min(String alias, RexNode operand) {
- return aggregateCall(SqlStdOperatorTable.MIN, false, alias, operand);
+ return aggregateCall(SqlStdOperatorTable.MIN, false, null, alias, operand);
}
/** Creates a call to the MAX aggregate function. */
public AggCall max(String alias, RexNode operand) {
- return aggregateCall(SqlStdOperatorTable.MAX, false, alias, operand);
+ return aggregateCall(SqlStdOperatorTable.MAX, false, null, alias, operand);
}
// Methods that create relational expressions
@@ -562,21 +667,49 @@ public class RelBuilder {
/** Creates a {@link org.apache.calcite.rel.core.Project} of the given list
* of expressions.
*
- * <p>Infers all field names.
- * If an expression projects an input field,
- * or is a cast an input field,
- * uses the input field name.
- * If an expression is a call to
- * {@link org.apache.calcite.sql.fun.SqlStdOperatorTable#AS}
- * (see {@link #alias}), removes the
- * call but uses the intended alias.
- * After the field names have been inferred, makes the
- * field names unique by appending numeric suffixes. */
+ * <p>Infers names as would {@link #project(Iterable, Iterable)} if all
+ * suggested names were null.
+ *
+ * @param nodes Expressions
+ */
public RelBuilder project(Iterable<? extends RexNode> nodes) {
+ return project(nodes, ImmutableList.<String>of());
+ }
+
+ /** Creates a {@link org.apache.calcite.rel.core.Project} of the given list
+ * of expressions, using the given names.
+ *
+ * <p>Names are deduced as follows:
+ * <ul>
+ * <li>If the length of {@code fieldNames} is greater than the index of
+ * the current entry in {@code nodes}, and the entry in
+ * {@code fieldNames} is not null, uses it; otherwise
+ * <li>If an expression projects an input field,
+ * or is a cast an input field,
+ * uses the input field name; otherwise
+ * <li>If an expression is a call to
+ * {@link org.apache.calcite.sql.fun.SqlStdOperatorTable#AS}
+ * (see {@link #alias}), removes the call but uses the intended alias.
+ * </ul>
+ *
+ * <p>After the field names have been inferred, makes the
+ * field names unique by appending numeric suffixes.
+ *
+ * @param nodes Expressions
+ * @param fieldNames Suggested field names
+ */
+ public RelBuilder project(Iterable<? extends RexNode> nodes,
+ Iterable<String> fieldNames) {
final List<String> names = new ArrayList<>();
final List<RexNode> exprList = Lists.newArrayList(nodes);
+ final Iterator<String> nameIterator = fieldNames.iterator();
for (RexNode node : nodes) {
- names.add(inferAlias(exprList, node));
+ final String name = nameIterator.hasNext() ? nameIterator.next() : null;
+ final String name2 = inferAlias(exprList, node);
+ names.add(Util.first(name, name2));
+ }
+ if (ProjectRemoveRule.isIdentity(exprList, peek().getRowType())) {
+ return this;
}
final RelNode project =
projectFactory.createProject(build(), ImmutableList.copyOf(exprList),
@@ -634,17 +767,41 @@ public class RelBuilder {
/** Creates an {@link org.apache.calcite.rel.core.Aggregate} with a list of
* calls. */
public RelBuilder aggregate(GroupKey groupKey, Iterable<AggCall> aggCalls) {
- final ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
final RelDataType inputRowType = peek().getRowType();
final List<RexNode> extraNodes = projects(inputRowType);
- for (RexNode node : ((GroupKeyImpl) groupKey).nodes) {
- builder.set(registerExpression(extraNodes, node));
+ final GroupKeyImpl groupKey_ = (GroupKeyImpl) groupKey;
+ final ImmutableBitSet groupSet =
+ ImmutableBitSet.of(registerExpressions(extraNodes, groupKey_.nodes));
+ final ImmutableList<ImmutableBitSet> groupSets;
+ if (groupKey_.nodeLists != null) {
+ final int sizeBefore = extraNodes.size();
+ final SortedSet<ImmutableBitSet> groupSetSet =
+ new TreeSet<>(ImmutableBitSet.ORDERING);
+ for (ImmutableList<RexNode> nodeList : groupKey_.nodeLists) {
+ final ImmutableBitSet groupSet2 =
+ ImmutableBitSet.of(registerExpressions(extraNodes, nodeList));
+ if (!groupSet.contains(groupSet2)) {
+ throw new IllegalArgumentException("group set element " + nodeList
+ + " must be a subset of group key");
+ }
+ groupSetSet.add(groupSet2);
+ }
+ groupSets = ImmutableList.copyOf(groupSetSet);
+ if (extraNodes.size() > sizeBefore) {
+ throw new IllegalArgumentException(
+ "group sets contained expressions not in group key: "
+ + extraNodes.subList(sizeBefore, extraNodes.size()));
+ }
+ } else {
+ groupSets = ImmutableList.of(groupSet);
}
- final ImmutableBitSet groupSet = builder.build();
for (AggCall aggCall : aggCalls) {
- final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
- for (RexNode operand : aggCall1.operands) {
- registerExpression(extraNodes, operand);
+ if (aggCall instanceof AggCallImpl) {
+ final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
+ registerExpressions(extraNodes, aggCall1.operands);
+ if (aggCall1.filter != null) {
+ registerExpression(extraNodes, aggCall1.filter);
+ }
}
}
if (extraNodes.size() > inputRowType.getFieldCount()) {
@@ -653,18 +810,27 @@ public class RelBuilder {
final RelNode r = build();
final List<AggregateCall> aggregateCalls = new ArrayList<>();
for (AggCall aggCall : aggCalls) {
- final List<Integer> args = new ArrayList<>();
- final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
- for (RexNode operand : aggCall1.operands) {
- args.add(registerExpression(extraNodes, operand));
+ final AggregateCall aggregateCall;
+ if (aggCall instanceof AggCallImpl) {
+ final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
+ final List<Integer> args = registerExpressions(extraNodes, aggCall1.operands);
+ final int filterArg = aggCall1.filter == null ? -1
+ : registerExpression(extraNodes, aggCall1.filter);
+ aggregateCall =
+ AggregateCall.create(aggCall1.aggFunction, aggCall1.distinct, args,
+ filterArg, groupSet.cardinality(), r, null, aggCall1.alias);
+ } else {
+ aggregateCall = ((AggCallImpl2) aggCall).aggregateCall;
}
- aggregateCalls.add(
- AggregateCall.create(aggCall1.aggFunction, aggCall1.distinct,
- args, -1, groupSet.cardinality(), r, null, aggCall1.alias));
+ aggregateCalls.add(aggregateCall);
}
- RelNode aggregate = aggregateFactory.createAggregate(r, false, groupSet,
- ImmutableList.of(groupSet), aggregateCalls);
+ assert ImmutableBitSet.ORDERING.isStrictlyOrdered(groupSets) : groupSets;
+ for (ImmutableBitSet set : groupSets) {
+ assert groupSet.contains(set);
+ }
+ RelNode aggregate = aggregateFactory.createAggregate(r,
+ groupSets.size() > 1, groupSet, groupSets, aggregateCalls);
push(aggregate);
return this;
}
@@ -687,18 +853,60 @@ public class RelBuilder {
return i;
}
+ private static List<Integer> registerExpressions(List<RexNode> extraNodes,
+ Iterable<? extends RexNode> nodes) {
+ final List<Integer> builder = new ArrayList<>();
+ for (RexNode node : nodes) {
+ builder.add(registerExpression(extraNodes, node));
+ }
+ return builder;
+ }
+
+ private RelBuilder setOp(boolean all, SqlKind kind, int n) {
+ List<RelNode> inputs = new LinkedList<>();
+ for (int i = 0; i < n; i++) {
+ inputs.add(0, build());
+ }
+ switch (kind) {
+ case UNION:
+ case INTERSECT:
+ if (n < 1) {
+ throw new IllegalArgumentException("bad INTERSECT/UNION input count");
+ }
+ break;
+ case EXCEPT:
+ if (n != 2) {
+ throw new AssertionError("bad EXCEPT input count");
+ }
+ break;
+ default:
+ throw new AssertionError("bad setOp " + kind);
+ }
+ switch (n) {
+ case 1:
+ return push(inputs.get(0));
+ default:
+ return push(setOpFactory.createSetOp(kind, inputs, all));
+ }
+ }
+
/** Creates a {@link org.apache.calcite.rel.core.Union} of the two most recent
* relational expressions on the stack.
*
* @param all Whether to create UNION ALL
*/
public RelBuilder union(boolean all) {
- final RelNode left = build();
- final RelNode right = build();
- final RelNode union = setOpFactory.createSetOp(SqlKind.UNION,
- ImmutableList.of(left, right), all);
- push(union);
- return this;
+ return union(all, 2);
+ }
+
+ /** Creates a {@link org.apache.calcite.rel.core.Union} of the {@code n}
+ * most recent relational expressions on the stack.
+ *
+ * @param all Whether to create UNION ALL
+ * @param n Number of inputs to the UNION operator
+ */
+ public RelBuilder union(boolean all, int n) {
+ return setOp(all, SqlKind.UNION, n);
}
/** Creates an {@link org.apache.calcite.rel.core.Intersect} of the two most
@@ -707,12 +915,17 @@ public class RelBuilder {
* @param all Whether to create INTERSECT ALL
*/
public RelBuilder intersect(boolean all) {
- final RelNode left = build();
- final RelNode right = build();
- final RelNode intersect = setOpFactory.createSetOp(SqlKind.INTERSECT,
- ImmutableList.of(left, right), all);
- push(intersect);
- return this;
+ return intersect(all, 2);
+ }
+
+ /** Creates an {@link org.apache.calcite.rel.core.Intersect} of the {@code n}
+ * most recent relational expressions on the stack.
+ *
+ * @param all Whether to create INTERSECT ALL
+ * @param n Number of inputs to the INTERSECT operator
+ */
+ public RelBuilder intersect(boolean all, int n) {
+ return setOp(all, SqlKind.INTERSECT, n);
}
/** Creates a {@link org.apache.calcite.rel.core.Minus} of the two most recent
@@ -721,19 +934,23 @@ public class RelBuilder {
* @param all Whether to create EXCEPT ALL
*/
public RelBuilder minus(boolean all) {
- final RelNode left = build();
- final RelNode right = build();
- final RelNode except = setOpFactory.createSetOp(SqlKind.EXCEPT,
- ImmutableList.of(left, right), all);
- push(except);
- return this;
+ return setOp(all, SqlKind.EXCEPT, 2);
}
/** Creates a {@link org.apache.calcite.rel.core.Join}. */
- public RelBuilder join(JoinRelType joinType, RexNode condition) {
+ public RelBuilder join(JoinRelType joinType, RexNode condition0,
+ RexNode... conditions) {
+ return join(joinType, Lists.asList(condition0, conditions));
+ }
+
+ /** Creates a {@link org.apache.calcite.rel.core.Join} with multiple
+ * conditions. */
+ public RelBuilder join(JoinRelType joinType,
+ Iterable<? extends RexNode> conditions) {
final Frame right = Stacks.pop(stack);
final Frame left = Stacks.pop(stack);
- final RelNode join = joinFactory.createJoin(left.rel, right.rel, condition,
+ final RelNode join = joinFactory.createJoin(left.rel, right.rel,
+ RexUtil.composeConjunction(cluster.getRexBuilder(), conditions, false),
joinType, ImmutableSet.<String>of(), false);
final List<Pair<String, RelDataType>> pairs = new ArrayList<>();
pairs.addAll(left.right);
@@ -759,9 +976,24 @@ public class RelBuilder {
field(2, 0, fieldName),
field(2, 1, fieldName)));
}
- final RexNode condition =
- RexUtil.composeConjunction(cluster.getRexBuilder(), conditions, false);
- return join(joinType, condition);
+ return join(joinType, conditions);
+ }
+
+ /** Creates a {@link org.apache.calcite.rel.core.SemiJoin}. */
+ public RelBuilder semiJoin(Iterable<? extends RexNode> conditions) {
+ final Frame right = Stacks.pop(stack);
+ final Frame left = Stacks.pop(stack);
+ final RelNode semiJoin =
+ semiJoinFactory.createSemiJoin(left.rel, right.rel,
+ RexUtil.composeConjunction(cluster.getRexBuilder(), conditions,
+ false));
+ Stacks.push(stack, new Frame(semiJoin, left.right));
+ return this;
+ }
+
+ /** Creates a {@link org.apache.calcite.rel.core.SemiJoin}. */
+ public RelBuilder semiJoin(RexNode... conditions) {
+ return semiJoin(ImmutableList.copyOf(conditions));
}
/** Assigns a table alias to the top entry on the stack. */
@@ -1007,6 +1239,46 @@ public class RelBuilder {
}
}
+ /**
+ * Creates a projection that converts the current relational expression's
+ * output to a desired row type.
+ *
+ * @param castRowType row type after cast
+ * @param rename if true, use field names from castRowType; if false,
+ * preserve field names from rel
+ */
+ public RelBuilder convert(RelDataType castRowType, boolean rename) {
+ final RelNode r = build();
+ final RelNode r2 =
+ RelOptUtil.createCastRel(r, castRowType, rename, projectFactory);
+ push(r2);
+ return this;
+ }
+
+ public RelBuilder permute(Mapping mapping) {
+ assert mapping.getMappingType().isSingleSource();
+ assert mapping.getMappingType().isMandatorySource();
+ if (mapping.isIdentity()) {
+ return this;
+ }
+ final List<RexNode> exprList = Lists.newArrayList();
+ for (int i = 0; i < mapping.getTargetCount(); i++) {
+ exprList.add(field(mapping.getSource(i)));
+ }
+ return project(exprList);
+ }
+
+ public RelBuilder aggregate(GroupKey groupKey,
+ List<AggregateCall> aggregateCalls) {
+ return aggregate(groupKey,
+ Lists.transform(
+ aggregateCalls, new Function<AggregateCall, AggCall>() {
+ public AggCall apply(AggregateCall input) {
+ return new AggCallImpl2(input);
+ }
+ }));
+ }
+
/** Information necessary to create a call to an aggregate function.
*
* @see RelBuilder#aggregateCall */
@@ -1021,10 +1293,13 @@ public class RelBuilder {
/** Implementation of {@link RelBuilder.GroupKey}. */
private static class GroupKeyImpl implements GroupKey {
- private final ImmutableList<RexNode> nodes;
+ final ImmutableList<RexNode> nodes;
+ final ImmutableList<ImmutableList<RexNode>> nodeLists;
- GroupKeyImpl(ImmutableList<RexNode> nodes) {
- this.nodes = nodes;
+ GroupKeyImpl(ImmutableList<RexNode> nodes,
+ ImmutableList<ImmutableList<RexNode>> nodeLists) {
+ this.nodes = Preconditions.checkNotNull(nodes);
+ this.nodeLists = nodeLists;
}
}
@@ -1032,32 +1307,28 @@ public class RelBuilder {
private static class AggCallImpl implements AggCall {
private final SqlAggFunction aggFunction;
private final boolean distinct;
+ private final RexNode filter;
private final String alias;
private final ImmutableList<RexNode> operands;
- AggCallImpl(SqlAggFunction aggFunction, boolean distinct,
+ AggCallImpl(SqlAggFunction aggFunction, boolean distinct, RexNode filter,
String alias, ImmutableList<RexNode> operands) {
this.aggFunction = aggFunction;
this.distinct = distinct;
+ this.filter = filter;
this.alias = alias;
this.operands = operands;
}
}
- /** A partially-created RelBuilder.
- *
- * <p>Add a cluster, and optionally a schema,
- * when you want to create a builder.
- *
- * <p>A {@code ProtoRelBuilder} can be shared among queries, and thus can
- * be inside a {@link RelOptRule}. It is a nice way to encapsulate the policy
- * that this particular rule instance should create {@code DrillFilter}
- * and {@code DrillProject} versus {@code HiveFilter} and {@code HiveProject}.
- *
- * @see RelFactories#DEFAULT_PROTO
- */
- public interface ProtoRelBuilder {
- RelBuilder create(RelOptCluster cluster, RelOptSchema schema);
+ /** Implementation of {@link RelBuilder.AggCall} that wraps an
+ * {@link AggregateCall}. */
+ private static class AggCallImpl2 implements AggCall {
+ private final AggregateCall aggregateCall;
+
+ AggCallImpl2(AggregateCall aggregateCall) {
+ this.aggregateCall = Preconditions.checkNotNull(aggregateCall);
+ }
}
/** Builder stack frame.
@@ -1079,8 +1350,10 @@ public class RelBuilder {
private static String deriveAlias(RelNode rel) {
if (rel instanceof TableScan) {
- TableScan scan = (TableScan) rel;
- return Util.last(scan.getTable().getQualifiedName());
+ final List<String> names = rel.getTable().getQualifiedName();
+ if (!names.isEmpty()) {
+ return Util.last(names);
+ }
}
return null;
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java b/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java
new file mode 100644
index 0000000..2aefca6
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.tools;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.rel.core.RelFactories;
+
+/** A partially-created RelBuilder.
+ *
+ * <p>Add a cluster, and optionally a schema,
+ * when you want to create a builder.
+ *
+ * <p>A {@code ProtoRelBuilder} can be shared among queries, and thus can
+ * be inside a {@link RelOptRule}. It is a nice way to encapsulate the policy
+ * that this particular rule instance should create {@code DrillFilter}
+ * and {@code DrillProject} versus {@code HiveFilter} and {@code HiveProject}.
+ *
+ * @see RelFactories#LOGICAL_BUILDER
+ */
+public interface RelBuilderFactory {
+ /** Creates a RelBuilder. */
+ RelBuilder create(RelOptCluster cluster, RelOptSchema schema);
+}
+
+// End RelBuilderFactory.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
index cc7ec8c..265990e 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -206,7 +206,7 @@ public class JdbcAdapterTest {
+ "FROM \"SCOTT\".\"EMP\") AS \"t0\" ON \"t\".\"MGR\" = \"t0\".\"EMPNO\" AND (\"t\".\"SAL\" > \"t0\".\"SAL\" OR \"t\".\"HIREDATE\" < \"t0\".\"HIREDATE\")");
}
- @Test public void tesJoin3TablesPlan() {
+ @Test public void testJoin3TablesPlan() {
CalciteAssert.model(JdbcTest.SCOTT_MODEL)
.query("select empno, ename, dname, grade \n"
+ "from scott.emp e inner join scott.dept d \n"