use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class FrameworksTest method testOptimize.
@Test
public void testOptimize() {
RelNode x = Frameworks.withPlanner(new Frameworks.PlannerAction<RelNode>() {
public RelNode apply(RelOptCluster cluster, RelOptSchema relOptSchema, SchemaPlus rootSchema) {
final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
final Table table = new AbstractTable() {
public RelDataType getRowType(RelDataTypeFactory typeFactory) {
final RelDataType stringType = typeFactory.createJavaType(String.class);
final RelDataType integerType = typeFactory.createJavaType(Integer.class);
return typeFactory.builder().add("s", stringType).add("i", integerType).build();
}
};
// "SELECT * FROM myTable"
final RelOptAbstractTable relOptTable = new RelOptAbstractTable(relOptSchema, "myTable", table.getRowType(typeFactory)) {
};
final EnumerableTableScan tableRel = EnumerableTableScan.create(cluster, relOptTable);
// "WHERE i > 1"
final RexBuilder rexBuilder = cluster.getRexBuilder();
final RexNode condition = rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN, rexBuilder.makeFieldAccess(rexBuilder.makeRangeReference(tableRel), "i", true), rexBuilder.makeExactLiteral(BigDecimal.ONE));
final LogicalFilter filter = LogicalFilter.create(tableRel, condition);
// Specify that the result should be in Enumerable convention.
final RelNode rootRel = filter;
final RelOptPlanner planner = cluster.getPlanner();
RelTraitSet desiredTraits = cluster.traitSet().replace(EnumerableConvention.INSTANCE);
final RelNode rootRel2 = planner.changeTraits(rootRel, desiredTraits);
planner.setRoot(rootRel2);
// Now, plan.
return planner.findBestExp();
}
});
String s = RelOptUtil.dumpPlan("", x, SqlExplainFormat.TEXT, SqlExplainLevel.DIGEST_ATTRIBUTES);
assertThat(Util.toLinux(s), equalTo("EnumerableFilter(condition=[>($1, 1)])\n" + " EnumerableTableScan(table=[[myTable]])\n"));
}
use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class FrameworksTest method executeQuery.
private void executeQuery(FrameworkConfig config, @SuppressWarnings("SameParameterValue") String query, boolean debug) throws RelConversionException, SqlParseException, ValidationException {
Planner planner = Frameworks.getPlanner(config);
if (debug) {
System.out.println("Query:" + query);
}
SqlNode n = planner.parse(query);
n = planner.validate(n);
RelNode root = planner.rel(n).project();
if (debug) {
System.out.println(RelOptUtil.dumpPlan("-- Logical Plan", root, SqlExplainFormat.TEXT, SqlExplainLevel.DIGEST_ATTRIBUTES));
}
RelOptCluster cluster = root.getCluster();
final RelOptPlanner optPlanner = cluster.getPlanner();
RelTraitSet desiredTraits = cluster.traitSet().replace(EnumerableConvention.INSTANCE);
final RelNode newRoot = optPlanner.changeTraits(root, desiredTraits);
if (debug) {
System.out.println(RelOptUtil.dumpPlan("-- Mid Plan", newRoot, SqlExplainFormat.TEXT, SqlExplainLevel.DIGEST_ATTRIBUTES));
}
optPlanner.setRoot(newRoot);
RelNode bestExp = optPlanner.findBestExp();
if (debug) {
System.out.println(RelOptUtil.dumpPlan("-- Best Plan", bestExp, SqlExplainFormat.TEXT, SqlExplainLevel.DIGEST_ATTRIBUTES));
}
}
use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class ProjectWindowTransposeRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final LogicalProject project = call.rel(0);
final LogicalWindow window = call.rel(1);
final RelOptCluster cluster = window.getCluster();
final List<RelDataTypeField> rowTypeWindowInput = window.getInput().getRowType().getFieldList();
final int windowInputColumn = rowTypeWindowInput.size();
// Record the window input columns which are actually referred
// either in the LogicalProject above LogicalWindow or LogicalWindow itself
// (Note that the constants used in LogicalWindow are not considered here)
final ImmutableBitSet beReferred = findReference(project, window);
// it is impossible to trim anyone of them out
if (beReferred.cardinality() == windowInputColumn) {
return;
}
// Put a DrillProjectRel below LogicalWindow
final List<RexNode> exps = new ArrayList<>();
final RelDataTypeFactory.Builder builder = cluster.getTypeFactory().builder();
// Keep only the fields which are referred
for (int index : BitSets.toIter(beReferred)) {
final RelDataTypeField relDataTypeField = rowTypeWindowInput.get(index);
exps.add(new RexInputRef(index, relDataTypeField.getType()));
builder.add(relDataTypeField);
}
final LogicalProject projectBelowWindow = new LogicalProject(cluster, window.getTraitSet(), window.getInput(), exps, builder.build());
// Create a new LogicalWindow with necessary inputs only
final List<Window.Group> groups = new ArrayList<>();
// As the un-referred columns are trimmed by the LogicalProject,
// the indices specified in LogicalWindow would need to be adjusted
final RexShuttle indexAdjustment = new RexShuttle() {
@Override
public RexNode visitInputRef(RexInputRef inputRef) {
final int newIndex = getAdjustedIndex(inputRef.getIndex(), beReferred, windowInputColumn);
return new RexInputRef(newIndex, inputRef.getType());
}
@Override
public RexNode visitCall(final RexCall call) {
if (call instanceof Window.RexWinAggCall) {
boolean[] update = { false };
final List<RexNode> clonedOperands = visitList(call.operands, update);
if (update[0]) {
return new Window.RexWinAggCall((SqlAggFunction) call.getOperator(), call.getType(), clonedOperands, ((Window.RexWinAggCall) call).ordinal, ((Window.RexWinAggCall) call).distinct);
} else {
return call;
}
} else {
return super.visitCall(call);
}
}
};
int aggCallIndex = windowInputColumn;
final RelDataTypeFactory.Builder outputBuilder = cluster.getTypeFactory().builder();
outputBuilder.addAll(projectBelowWindow.getRowType().getFieldList());
for (Window.Group group : window.groups) {
final ImmutableBitSet.Builder keys = ImmutableBitSet.builder();
final List<RelFieldCollation> orderKeys = new ArrayList<>();
final List<Window.RexWinAggCall> aggCalls = new ArrayList<>();
// Adjust keys
for (int index : group.keys) {
keys.set(getAdjustedIndex(index, beReferred, windowInputColumn));
}
// Adjust orderKeys
for (RelFieldCollation relFieldCollation : group.orderKeys.getFieldCollations()) {
final int index = relFieldCollation.getFieldIndex();
orderKeys.add(relFieldCollation.copy(getAdjustedIndex(index, beReferred, windowInputColumn)));
}
// Adjust Window Functions
for (Window.RexWinAggCall rexWinAggCall : group.aggCalls) {
aggCalls.add((Window.RexWinAggCall) rexWinAggCall.accept(indexAdjustment));
final RelDataTypeField relDataTypeField = window.getRowType().getFieldList().get(aggCallIndex);
outputBuilder.add(relDataTypeField);
++aggCallIndex;
}
groups.add(new Window.Group(keys.build(), group.isRows, group.lowerBound, group.upperBound, RelCollations.of(orderKeys), aggCalls));
}
final LogicalWindow newLogicalWindow = LogicalWindow.create(window.getTraitSet(), projectBelowWindow, window.constants, outputBuilder.build(), groups);
// Modify the top LogicalProject
final List<RexNode> topProjExps = new ArrayList<>();
for (RexNode rexNode : project.getChildExps()) {
topProjExps.add(rexNode.accept(indexAdjustment));
}
final LogicalProject newTopProj = project.copy(newLogicalWindow.getTraitSet(), newLogicalWindow, topProjExps, project.getRowType());
if (ProjectRemoveRule.isTrivial(newTopProj)) {
call.transformTo(newLogicalWindow);
} else {
call.transformTo(newTopProj);
}
}
use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class SemiJoinRule method perform.
protected void perform(RelOptRuleCall call, Project project, Join join, RelNode left, Aggregate aggregate) {
final RelOptCluster cluster = join.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
if (project != null) {
final ImmutableBitSet bits = RelOptUtil.InputFinder.bits(project.getProjects(), null);
final ImmutableBitSet rightBits = ImmutableBitSet.range(left.getRowType().getFieldCount(), join.getRowType().getFieldCount());
if (bits.intersects(rightBits)) {
return;
}
}
final JoinInfo joinInfo = join.analyzeCondition();
if (!joinInfo.rightSet().equals(ImmutableBitSet.range(aggregate.getGroupCount()))) {
// By the way, neither a super-set nor a sub-set would work.
return;
}
if (!joinInfo.isEqui()) {
return;
}
final RelBuilder relBuilder = call.builder();
relBuilder.push(left);
switch(join.getJoinType()) {
case INNER:
final List<Integer> newRightKeyBuilder = Lists.newArrayList();
final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
for (int key : joinInfo.rightKeys) {
newRightKeyBuilder.add(aggregateKeys.get(key));
}
final ImmutableIntList newRightKeys = ImmutableIntList.copyOf(newRightKeyBuilder);
relBuilder.push(aggregate.getInput());
final RexNode newCondition = RelOptUtil.createEquiJoinCondition(relBuilder.peek(2, 0), joinInfo.leftKeys, relBuilder.peek(2, 1), newRightKeys, rexBuilder);
relBuilder.semiJoin(newCondition);
break;
case LEFT:
// we can eliminate the semi-join.
break;
default:
throw new AssertionError(join.getJoinType());
}
if (project != null) {
relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
}
call.transformTo(relBuilder.build());
}
use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class SortProjectTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
final Sort sort = call.rel(0);
final Project project = call.rel(1);
final RelOptCluster cluster = project.getCluster();
if (sort.getConvention() != project.getConvention()) {
return;
}
// Determine mapping between project input and output fields. If sort
// relies on non-trivial expressions, we can't push.
final Mappings.TargetMapping map = RelOptUtil.permutationIgnoreCast(project.getProjects(), project.getInput().getRowType());
for (RelFieldCollation fc : sort.getCollation().getFieldCollations()) {
if (map.getTargetOpt(fc.getFieldIndex()) < 0) {
return;
}
final RexNode node = project.getProjects().get(fc.getFieldIndex());
if (node.isA(SqlKind.CAST)) {
// Check whether it is a monotonic preserving cast, otherwise we cannot push
final RexCall cast = (RexCall) node;
final RexCallBinding binding = RexCallBinding.create(cluster.getTypeFactory(), cast, ImmutableList.of(RelCollations.of(RexUtil.apply(map, fc))));
if (cast.getOperator().getMonotonicity(binding) == SqlMonotonicity.NOT_MONOTONIC) {
return;
}
}
}
final RelCollation newCollation = cluster.traitSet().canonize(RexUtil.apply(map, sort.getCollation()));
final Sort newSort = sort.copy(sort.getTraitSet().replace(newCollation), project.getInput(), newCollation, sort.offset, sort.fetch);
RelNode newProject = project.copy(sort.getTraitSet(), ImmutableList.<RelNode>of(newSort));
// Not only is newProject equivalent to sort;
// newSort is equivalent to project's input
// (but only if the sort is not also applying an offset/limit).
Map<RelNode, RelNode> equiv;
if (sort.offset == null && sort.fetch == null && cluster.getPlanner().getRelTraitDefs().contains(RelCollationTraitDef.INSTANCE)) {
equiv = ImmutableMap.of((RelNode) newSort, project.getInput());
} else {
equiv = ImmutableMap.of();
}
call.transformTo(newProject, equiv);
}
Aggregations