use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class RelMetadataTest method testCustomProvider.
@Test
public void testCustomProvider() {
final List<String> buf = Lists.newArrayList();
ColTypeImpl.THREAD_LIST.set(buf);
final String sql = "select deptno, count(*) from emp where deptno > 10 " + "group by deptno having count(*) = 0";
final RelRoot root = tester.withClusterFactory(new Function<RelOptCluster, RelOptCluster>() {
public RelOptCluster apply(RelOptCluster cluster) {
// Create a custom provider that includes ColType.
// Include the same provider twice just to be devious.
final ImmutableList<RelMetadataProvider> list = ImmutableList.of(ColTypeImpl.SOURCE, ColTypeImpl.SOURCE, cluster.getMetadataProvider());
cluster.setMetadataProvider(ChainedRelMetadataProvider.of(list));
return cluster;
}
}).convertSqlToRel(sql);
final RelNode rel = root.rel;
// Top node is a filter. Its metadata uses getColType(RelNode, int).
assertThat(rel, instanceOf(LogicalFilter.class));
final RelMetadataQuery mq = RelMetadataQuery.instance();
assertThat(colType(mq, rel, 0), equalTo("DEPTNO-rel"));
assertThat(colType(mq, rel, 1), equalTo("EXPR$1-rel"));
// Next node is an aggregate. Its metadata uses
// getColType(LogicalAggregate, int).
final RelNode input = rel.getInput(0);
assertThat(input, instanceOf(LogicalAggregate.class));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
// There is no caching. Another request causes another call to the provider.
assertThat(buf.toString(), equalTo("[DEPTNO-rel, EXPR$1-rel, DEPTNO-agg]"));
assertThat(buf.size(), equalTo(3));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(4));
// Now add a cache. Only the first request for each piece of metadata
// generates a new call to the provider.
final RelOptPlanner planner = rel.getCluster().getPlanner();
rel.getCluster().setMetadataProvider(new CachingRelMetadataProvider(rel.getCluster().getMetadataProvider(), planner));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(5));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(5));
assertThat(colType(mq, input, 1), equalTo("EXPR$1-agg"));
assertThat(buf.size(), equalTo(6));
assertThat(colType(mq, input, 1), equalTo("EXPR$1-agg"));
assertThat(buf.size(), equalTo(6));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(6));
// With a different timestamp, a metadata item is re-computed on first call.
long timestamp = planner.getRelMetadataTimestamp(rel);
assertThat(timestamp, equalTo(0L));
((MockRelOptPlanner) planner).setRelMetadataTimestamp(timestamp + 1);
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(7));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(7));
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class RelMetadataTest method testPredicates.
/**
* Unit test for
* {@link org.apache.calcite.rel.metadata.RelMdPredicates#getPredicates(Join, RelMetadataQuery)}.
*/
@Test
public void testPredicates() {
final Project rel = (Project) convertSql("select * from emp, dept");
final Join join = (Join) rel.getInput();
final RelOptTable empTable = join.getInput(0).getTable();
final RelOptTable deptTable = join.getInput(1).getTable();
Frameworks.withPlanner(new Frameworks.PlannerAction<Void>() {
public Void apply(RelOptCluster cluster, RelOptSchema relOptSchema, SchemaPlus rootSchema) {
checkPredicates(cluster, empTable, deptTable);
return null;
}
});
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class ProjectCalcMergeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
final LogicalProject project = call.rel(0);
final LogicalCalc calc = call.rel(1);
// Don't merge a project which contains windowed aggregates onto a
// calc. That would effectively be pushing a windowed aggregate down
// through a filter. Transform the project into an identical calc,
// which we'll have chance to merge later, after the over is
// expanded.
final RelOptCluster cluster = project.getCluster();
RexProgram program = RexProgram.create(calc.getRowType(), project.getProjects(), null, project.getRowType(), cluster.getRexBuilder());
if (RexOver.containsOver(program)) {
LogicalCalc projectAsCalc = LogicalCalc.create(calc, program);
call.transformTo(projectAsCalc);
return;
}
// Create a program containing the project node's expressions.
final RexBuilder rexBuilder = cluster.getRexBuilder();
final RexProgramBuilder progBuilder = new RexProgramBuilder(calc.getRowType(), rexBuilder);
for (Pair<RexNode, String> field : project.getNamedProjects()) {
progBuilder.addProject(field.left, field.right);
}
RexProgram topProgram = progBuilder.getProgram();
RexProgram bottomProgram = calc.getProgram();
// Merge the programs together.
RexProgram mergedProgram = RexProgramBuilder.mergePrograms(topProgram, bottomProgram, rexBuilder);
final LogicalCalc newCalc = LogicalCalc.create(calc.getInput(), mergedProgram);
call.transformTo(newCalc);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class JoinPushThroughJoinRule method onMatchRight.
private void onMatchRight(RelOptRuleCall call) {
final Join topJoin = call.rel(0);
final Join bottomJoin = call.rel(1);
final RelNode relC = call.rel(2);
final RelNode relA = bottomJoin.getLeft();
final RelNode relB = bottomJoin.getRight();
final RelOptCluster cluster = topJoin.getCluster();
// topJoin
// / \
// bottomJoin C
// / \
// A B
final int aCount = relA.getRowType().getFieldCount();
final int bCount = relB.getRowType().getFieldCount();
final int cCount = relC.getRowType().getFieldCount();
final ImmutableBitSet bBitSet = ImmutableBitSet.range(aCount, aCount + bCount);
// (Is this too strict?)
if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
return;
}
// Split the condition of topJoin into a conjunction. Each of the
// parts that does not use columns from B can be pushed down.
final List<RexNode> intersecting = new ArrayList<>();
final List<RexNode> nonIntersecting = new ArrayList<>();
split(topJoin.getCondition(), bBitSet, intersecting, nonIntersecting);
// If there's nothing to push down, it's not worth proceeding.
if (nonIntersecting.isEmpty()) {
return;
}
// Split the condition of bottomJoin into a conjunction. Each of the
// parts that use columns from B will need to be pulled up.
final List<RexNode> bottomIntersecting = new ArrayList<>();
final List<RexNode> bottomNonIntersecting = new ArrayList<>();
split(bottomJoin.getCondition(), bBitSet, bottomIntersecting, bottomNonIntersecting);
// target: | A | C |
// source: | A | B | C |
final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount, aCount + bCount, cCount);
final List<RexNode> newBottomList = new ArrayList<>();
new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(nonIntersecting, newBottomList);
new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(bottomNonIntersecting, newBottomList);
final RexBuilder rexBuilder = cluster.getRexBuilder();
RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relA, relC, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
// target: | A | C | B |
// source: | A | B | C |
final Mappings.TargetMapping topMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount + cCount, aCount, bCount, aCount, aCount + bCount, cCount);
final List<RexNode> newTopList = new ArrayList<>();
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(intersecting, newTopList);
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(bottomIntersecting, newTopList);
RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
@SuppressWarnings("SuspiciousNameCombination") final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relB, topJoin.getJoinType(), topJoin.isSemiJoinDone());
assert !Mappings.isIdentity(topMapping);
final RelBuilder relBuilder = call.builder();
relBuilder.push(newTopJoin);
relBuilder.project(relBuilder.fields(topMapping));
call.transformTo(relBuilder.build());
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.plan.RelOptCluster in project calcite by apache.
the class JoinPushThroughJoinRule method onMatchLeft.
/**
* Similar to {@link #onMatch}, but swaps the upper sibling with the left
* of the two lower siblings, rather than the right.
*/
private void onMatchLeft(RelOptRuleCall call) {
final Join topJoin = call.rel(0);
final Join bottomJoin = call.rel(1);
final RelNode relC = call.rel(2);
final RelNode relA = bottomJoin.getLeft();
final RelNode relB = bottomJoin.getRight();
final RelOptCluster cluster = topJoin.getCluster();
// topJoin
// / \
// bottomJoin C
// / \
// A B
final int aCount = relA.getRowType().getFieldCount();
final int bCount = relB.getRowType().getFieldCount();
final int cCount = relC.getRowType().getFieldCount();
final ImmutableBitSet aBitSet = ImmutableBitSet.range(aCount);
// (Is this too strict?)
if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
return;
}
// Split the condition of topJoin into a conjunction. Each of the
// parts that does not use columns from A can be pushed down.
final List<RexNode> intersecting = new ArrayList<>();
final List<RexNode> nonIntersecting = new ArrayList<>();
split(topJoin.getCondition(), aBitSet, intersecting, nonIntersecting);
// If there's nothing to push down, it's not worth proceeding.
if (nonIntersecting.isEmpty()) {
return;
}
// Split the condition of bottomJoin into a conjunction. Each of the
// parts that use columns from A will need to be pulled up.
final List<RexNode> bottomIntersecting = new ArrayList<>();
final List<RexNode> bottomNonIntersecting = new ArrayList<>();
split(bottomJoin.getCondition(), aBitSet, bottomIntersecting, bottomNonIntersecting);
// target: | C | B |
// source: | A | B | C |
final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, cCount, aCount, bCount, 0, aCount + bCount, cCount);
final List<RexNode> newBottomList = new ArrayList<>();
new RexPermuteInputsShuttle(bottomMapping, relC, relB).visitList(nonIntersecting, newBottomList);
new RexPermuteInputsShuttle(bottomMapping, relC, relB).visitList(bottomNonIntersecting, newBottomList);
final RexBuilder rexBuilder = cluster.getRexBuilder();
RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relC, relB, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
// target: | C | B | A |
// source: | A | B | C |
final Mappings.TargetMapping topMapping = Mappings.createShiftMapping(aCount + bCount + cCount, cCount + bCount, 0, aCount, cCount, aCount, bCount, 0, aCount + bCount, cCount);
final List<RexNode> newTopList = new ArrayList<>();
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA).visitList(intersecting, newTopList);
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA).visitList(bottomIntersecting, newTopList);
RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
@SuppressWarnings("SuspiciousNameCombination") final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relA, topJoin.getJoinType(), topJoin.isSemiJoinDone());
final RelBuilder relBuilder = call.builder();
relBuilder.push(newTopJoin);
relBuilder.project(relBuilder.fields(topMapping));
call.transformTo(relBuilder.build());
}
Aggregations