use of org.apache.calcite.rel.logical.LogicalJoin in project calcite by apache.
the class RexTransformerTest method testSplitJoinCondition.
/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-833">[CALCITE-833]
* RelOptUtil.splitJoinCondition attempts to split a Join-Condition which
* has a remaining condition</a>.
*/
@Test
public void testSplitJoinCondition() {
final String sql = "select * \n" + "from emp a \n" + "INNER JOIN dept b \n" + "ON CAST(a.empno AS int) <> b.deptno";
final RelNode relNode = toRel(sql);
final LogicalProject project = (LogicalProject) relNode;
final LogicalJoin join = (LogicalJoin) project.getInput(0);
final List<RexNode> leftJoinKeys = new ArrayList<>();
final List<RexNode> rightJoinKeys = new ArrayList<>();
final ArrayList<RelDataTypeField> sysFieldList = new ArrayList<>();
final RexNode remaining = RelOptUtil.splitJoinCondition(sysFieldList, join.getInputs().get(0), join.getInputs().get(1), join.getCondition(), leftJoinKeys, rightJoinKeys, null, null);
assertThat(remaining.toString(), is("<>(CAST($0):INTEGER NOT NULL, $9)"));
assertThat(leftJoinKeys.isEmpty(), is(true));
assertThat(rightJoinKeys.isEmpty(), is(true));
}
use of org.apache.calcite.rel.logical.LogicalJoin in project calcite by apache.
the class Lattice method populate.
private static boolean populate(List<RelNode> nodes, List<int[][]> tempLinks, RelNode rel) {
if (nodes.isEmpty() && rel instanceof LogicalProject) {
return populate(nodes, tempLinks, ((LogicalProject) rel).getInput());
}
if (rel instanceof TableScan) {
nodes.add(rel);
return true;
}
if (rel instanceof LogicalJoin) {
LogicalJoin join = (LogicalJoin) rel;
if (join.getJoinType() != JoinRelType.INNER) {
throw new RuntimeException("only inner join allowed, but got " + join.getJoinType());
}
populate(nodes, tempLinks, join.getLeft());
populate(nodes, tempLinks, join.getRight());
for (RexNode rex : RelOptUtil.conjunctions(join.getCondition())) {
tempLinks.add(grab(nodes, rex));
}
return true;
}
throw new RuntimeException("Invalid node type " + rel.getClass().getSimpleName() + " in lattice query");
}
use of org.apache.calcite.rel.logical.LogicalJoin in project calcite by apache.
the class RelOptMaterialization method tryUseStar.
/**
* Converts a relational expression to one that uses a
* {@link org.apache.calcite.schema.impl.StarTable}.
*
* <p>The relational expression is already in leaf-join-form, per
* {@link #toLeafJoinForm(org.apache.calcite.rel.RelNode)}.
*
* @return Rewritten expression, or null if expression cannot be rewritten
* to use the star
*/
public static RelNode tryUseStar(RelNode rel, final RelOptTable starRelOptTable) {
final StarTable starTable = starRelOptTable.unwrap(StarTable.class);
assert starTable != null;
RelNode rel2 = rel.accept(new RelShuttleImpl() {
@Override
public RelNode visit(TableScan scan) {
RelOptTable relOptTable = scan.getTable();
final Table table = relOptTable.unwrap(Table.class);
if (table.equals(starTable.tables.get(0))) {
Mappings.TargetMapping mapping = Mappings.createShiftMapping(starRelOptTable.getRowType().getFieldCount(), 0, 0, relOptTable.getRowType().getFieldCount());
final RelOptCluster cluster = scan.getCluster();
final RelNode scan2 = starRelOptTable.toRel(RelOptUtil.getContext(cluster));
return RelOptUtil.createProject(scan2, Mappings.asList(mapping.inverse()));
}
return scan;
}
@Override
public RelNode visit(LogicalJoin join) {
for (; ; ) {
RelNode rel = super.visit(join);
if (rel == join || !(rel instanceof LogicalJoin)) {
return rel;
}
join = (LogicalJoin) rel;
final ProjectFilterTable left = ProjectFilterTable.of(join.getLeft());
if (left != null) {
final ProjectFilterTable right = ProjectFilterTable.of(join.getRight());
if (right != null) {
try {
match(left, right, join.getCluster());
} catch (Util.FoundOne e) {
return (RelNode) e.getNode();
}
}
}
}
}
/**
* Throws a {@link org.apache.calcite.util.Util.FoundOne} containing
* a {@link org.apache.calcite.rel.logical.LogicalTableScan} on
* success. (Yes, an exception for normal operation.)
*/
private void match(ProjectFilterTable left, ProjectFilterTable right, RelOptCluster cluster) {
final Mappings.TargetMapping leftMapping = left.mapping();
final Mappings.TargetMapping rightMapping = right.mapping();
final RelOptTable leftRelOptTable = left.getTable();
final Table leftTable = leftRelOptTable.unwrap(Table.class);
final int leftCount = leftRelOptTable.getRowType().getFieldCount();
final RelOptTable rightRelOptTable = right.getTable();
final Table rightTable = rightRelOptTable.unwrap(Table.class);
if (leftTable instanceof StarTable && ((StarTable) leftTable).tables.contains(rightTable)) {
final int offset = ((StarTable) leftTable).columnOffset(rightTable);
Mappings.TargetMapping mapping = Mappings.merge(leftMapping, Mappings.offsetTarget(Mappings.offsetSource(rightMapping, offset), leftMapping.getTargetCount()));
final RelNode project = RelOptUtil.createProject(LogicalTableScan.create(cluster, leftRelOptTable), Mappings.asList(mapping.inverse()));
final List<RexNode> conditions = Lists.newArrayList();
if (left.condition != null) {
conditions.add(left.condition);
}
if (right.condition != null) {
conditions.add(RexUtil.apply(mapping, RexUtil.shift(right.condition, offset)));
}
final RelNode filter = RelOptUtil.createFilter(project, conditions);
throw new Util.FoundOne(filter);
}
if (rightTable instanceof StarTable && ((StarTable) rightTable).tables.contains(leftTable)) {
final int offset = ((StarTable) rightTable).columnOffset(leftTable);
Mappings.TargetMapping mapping = Mappings.merge(Mappings.offsetSource(leftMapping, offset), Mappings.offsetTarget(rightMapping, leftCount));
final RelNode project = RelOptUtil.createProject(LogicalTableScan.create(cluster, rightRelOptTable), Mappings.asList(mapping.inverse()));
final List<RexNode> conditions = Lists.newArrayList();
if (left.condition != null) {
conditions.add(RexUtil.apply(mapping, RexUtil.shift(left.condition, offset)));
}
if (right.condition != null) {
conditions.add(RexUtil.apply(mapping, right.condition));
}
final RelNode filter = RelOptUtil.createFilter(project, conditions);
throw new Util.FoundOne(filter);
}
}
});
if (rel2 == rel) {
// No rewrite happened.
return null;
}
final Program program = Programs.hep(ImmutableList.of(ProjectFilterTransposeRule.INSTANCE, AggregateProjectMergeRule.INSTANCE, AggregateFilterTransposeRule.INSTANCE), false, DefaultRelMetadataProvider.INSTANCE);
return program.run(null, rel2, null, ImmutableList.<RelOptMaterialization>of(), ImmutableList.<RelOptLattice>of());
}
use of org.apache.calcite.rel.logical.LogicalJoin in project flink by apache.
the class FlinkSemiAntiJoinJoinTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
LogicalJoin semiAntiJoin = call.rel(0);
if (semiAntiJoin.getJoinType() != JoinRelType.SEMI && semiAntiJoin.getJoinType() != JoinRelType.ANTI) {
return;
}
final Join join = call.rel(1);
if (join.getJoinType() == JoinRelType.SEMI || join.getJoinType() == JoinRelType.ANTI) {
return;
}
// TODO support other join type
if (join.getJoinType() != JoinRelType.INNER) {
return;
}
// unsupported cases:
// 1. (NOT) EXISTS with uncorrelation
// 2. keys in SemiJoin condition are from both Join's left and Join's right
Pair<ImmutableBitSet, ImmutableBitSet> inputRefs = getSemiAntiJoinConditionInputRefs(semiAntiJoin);
final ImmutableBitSet leftInputRefs = inputRefs.left;
final ImmutableBitSet rightInputRefs = inputRefs.right;
// TODO currently we does not handle this
if (leftInputRefs.isEmpty() || rightInputRefs.isEmpty()) {
return;
}
// X is the left child of the join below the semi-join
// Y is the right child of the join below the semi-join
// Z is the right child of the semi-join
int nFieldsX = join.getLeft().getRowType().getFieldList().size();
int nFieldsY = join.getRight().getRowType().getFieldList().size();
int nFieldsZ = semiAntiJoin.getRight().getRowType().getFieldList().size();
int nTotalFields = nFieldsX + nFieldsY + nFieldsZ;
List<RelDataTypeField> fields = new ArrayList<RelDataTypeField>();
// create a list of fields for the full join result; note that
// we can't simply use the fields from the semi-join because the
// row-type of a semi-join only includes the left hand side fields
List<RelDataTypeField> joinFields = semiAntiJoin.getRowType().getFieldList();
for (int i = 0; i < (nFieldsX + nFieldsY); i++) {
fields.add(joinFields.get(i));
}
joinFields = semiAntiJoin.getRight().getRowType().getFieldList();
for (int i = 0; i < nFieldsZ; i++) {
fields.add(joinFields.get(i));
}
// determine which operands below the semi-join are the actual
// Rels that participate in the semi-join
int nKeysFromX = 0;
int nKeysFromY = 0;
for (int leftKey : leftInputRefs) {
if (leftKey < nFieldsX) {
nKeysFromX++;
} else {
nKeysFromY++;
}
}
// e.g. SELECT * FROM x, y WHERE x.c = y.f AND x.a IN (SELECT z.i FROM z WHERE y.e = z.j)
if (nKeysFromX > 0 && nKeysFromY > 0) {
return;
}
// otherwise, a semi-join wouldn't have been created
assert (nKeysFromX == 0) || (nKeysFromX == leftInputRefs.cardinality());
assert (nKeysFromY == 0) || (nKeysFromY == leftInputRefs.cardinality());
// need to convert the semi/anti join condition and possibly the keys
RexNode newSemiAntiJoinFilter;
int[] adjustments = new int[nTotalFields];
if (nKeysFromX > 0) {
// (X, Y, Z) --> (X, Z, Y)
// semiJoin(X, Z)
// pass 0 as Y's adjustment because there shouldn't be any
// references to Y in the semi/anti join filter
setJoinAdjustments(adjustments, nFieldsX, nFieldsY, nFieldsZ, 0, -nFieldsY);
newSemiAntiJoinFilter = semiAntiJoin.getCondition().accept(new RelOptUtil.RexInputConverter(semiAntiJoin.getCluster().getRexBuilder(), fields, adjustments));
} else {
// (X, Y, Z) --> (X, Y, Z)
// semiJoin(Y, Z)
setJoinAdjustments(adjustments, nFieldsX, nFieldsY, nFieldsZ, -nFieldsX, -nFieldsX);
newSemiAntiJoinFilter = semiAntiJoin.getCondition().accept(new RelOptUtil.RexInputConverter(semiAntiJoin.getCluster().getRexBuilder(), fields, adjustments));
}
// create the new join
RelNode newSemiAntiJoinLeft;
if (nKeysFromX > 0) {
newSemiAntiJoinLeft = join.getLeft();
} else {
newSemiAntiJoinLeft = join.getRight();
}
Join newSemiAntiJoin = LogicalJoin.create(newSemiAntiJoinLeft, semiAntiJoin.getRight(), join.getHints(), newSemiAntiJoinFilter, semiAntiJoin.getVariablesSet(), semiAntiJoin.getJoinType());
RelNode leftJoinRel;
RelNode rightJoinRel;
if (nKeysFromX > 0) {
leftJoinRel = newSemiAntiJoin;
rightJoinRel = join.getRight();
} else {
leftJoinRel = join.getLeft();
rightJoinRel = newSemiAntiJoin;
}
RelNode newJoinRel = join.copy(join.getTraitSet(), join.getCondition(), leftJoinRel, rightJoinRel, join.getJoinType(), join.isSemiJoinDone());
call.transformTo(newJoinRel);
}
use of org.apache.calcite.rel.logical.LogicalJoin in project calcite by apache.
the class RelStructuredTypeFlattener method rewriteRel.
public void rewriteRel(LogicalJoin rel) {
LogicalJoin newRel = LogicalJoin.create(getNewForOldRel(rel.getLeft()), getNewForOldRel(rel.getRight()), rel.getCondition().accept(new RewriteRexShuttle()), rel.getVariablesSet(), rel.getJoinType());
setNewForOldRel(rel, newRel);
}
Aggregations