Search in sources :

Example 21 with LogicalJoin

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));
}
Also used : RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RelNode(org.apache.calcite.rel.RelNode) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) ArrayList(java.util.ArrayList) LogicalProject(org.apache.calcite.rel.logical.LogicalProject) RexNode(org.apache.calcite.rex.RexNode) Test(org.junit.Test)

Example 22 with LogicalJoin

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");
}
Also used : TableScan(org.apache.calcite.rel.core.TableScan) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) LogicalProject(org.apache.calcite.rel.logical.LogicalProject) RexNode(org.apache.calcite.rex.RexNode)

Example 23 with LogicalJoin

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());
}
Also used : TableScan(org.apache.calcite.rel.core.TableScan) LogicalTableScan(org.apache.calcite.rel.logical.LogicalTableScan) Table(org.apache.calcite.schema.Table) StarTable(org.apache.calcite.schema.impl.StarTable) Program(org.apache.calcite.tools.Program) RelShuttleImpl(org.apache.calcite.rel.RelShuttleImpl) RexUtil(org.apache.calcite.rex.RexUtil) Util(org.apache.calcite.util.Util) RelNode(org.apache.calcite.rel.RelNode) StarTable(org.apache.calcite.schema.impl.StarTable) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List)

Example 24 with LogicalJoin

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);
}
Also used : RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) RelNode(org.apache.calcite.rel.RelNode) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) ArrayList(java.util.ArrayList) Join(org.apache.calcite.rel.core.Join) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) RexNode(org.apache.calcite.rex.RexNode)

Example 25 with LogicalJoin

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);
}
Also used : LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin)

Aggregations

LogicalJoin (org.apache.calcite.rel.logical.LogicalJoin)27 RelNode (org.apache.calcite.rel.RelNode)20 RexNode (org.apache.calcite.rex.RexNode)14 LogicalProject (org.apache.calcite.rel.logical.LogicalProject)13 ArrayList (java.util.ArrayList)8 LogicalFilter (org.apache.calcite.rel.logical.LogicalFilter)8 TableScan (org.apache.calcite.rel.core.TableScan)5 LogicalTableScan (org.apache.calcite.rel.logical.LogicalTableScan)5 RelDataType (org.apache.calcite.rel.type.RelDataType)5 RelTraitSet (org.apache.calcite.plan.RelTraitSet)4 InvalidRelException (org.apache.calcite.rel.InvalidRelException)4 Join (org.apache.calcite.rel.core.Join)4 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)4 RexBuilder (org.apache.calcite.rex.RexBuilder)4 RexInputRef (org.apache.calcite.rex.RexInputRef)4 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)4 RelOptCluster (org.apache.calcite.plan.RelOptCluster)3 RelRoot (org.apache.calcite.rel.RelRoot)3 JoinRelType (org.apache.calcite.rel.core.JoinRelType)3 LogicalAggregate (org.apache.calcite.rel.logical.LogicalAggregate)3