Search in sources :

Example 16 with CorrelationId

use of org.apache.calcite.rel.core.CorrelationId in project calcite by apache.

the class EnumerableBatchNestedLoopJoinRule method onMatch.

@Override
public void onMatch(RelOptRuleCall call) {
    final Join join = call.rel(0);
    final int leftFieldCount = join.getLeft().getRowType().getFieldCount();
    final RelOptCluster cluster = join.getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    final RelBuilder relBuilder = call.builder();
    final Set<CorrelationId> correlationIds = new HashSet<>();
    final List<RexNode> corrVarList = new ArrayList<>();
    final int batchSize = config.batchSize();
    for (int i = 0; i < batchSize; i++) {
        CorrelationId correlationId = cluster.createCorrel();
        correlationIds.add(correlationId);
        corrVarList.add(rexBuilder.makeCorrel(join.getLeft().getRowType(), correlationId));
    }
    final RexNode corrVar0 = corrVarList.get(0);
    final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
    // Generate first condition
    final RexNode condition = join.getCondition().accept(new RexShuttle() {

        @Override
        public RexNode visitInputRef(RexInputRef input) {
            int field = input.getIndex();
            if (field >= leftFieldCount) {
                return rexBuilder.makeInputRef(input.getType(), input.getIndex() - leftFieldCount);
            }
            requiredColumns.set(field);
            return rexBuilder.makeFieldAccess(corrVar0, field);
        }
    });
    final List<RexNode> conditionList = new ArrayList<>();
    conditionList.add(condition);
    // Add batchSize-1 other conditions
    for (int i = 1; i < batchSize; i++) {
        final int corrIndex = i;
        final RexNode condition2 = condition.accept(new RexShuttle() {

            @Override
            public RexNode visitCorrelVariable(RexCorrelVariable variable) {
                return variable.equals(corrVar0) ? corrVarList.get(corrIndex) : variable;
            }
        });
        conditionList.add(condition2);
    }
    // Push a filter with batchSize disjunctions
    relBuilder.push(join.getRight()).filter(relBuilder.or(conditionList));
    final RelNode right = relBuilder.build();
    call.transformTo(EnumerableBatchNestedLoopJoin.create(convert(join.getLeft(), join.getLeft().getTraitSet().replace(EnumerableConvention.INSTANCE)), convert(right, right.getTraitSet().replace(EnumerableConvention.INSTANCE)), join.getCondition(), requiredColumns.build(), correlationIds, join.getJoinType()));
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RexCorrelVariable(org.apache.calcite.rex.RexCorrelVariable) RelBuilder(org.apache.calcite.tools.RelBuilder) RexShuttle(org.apache.calcite.rex.RexShuttle) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) Join(org.apache.calcite.rel.core.Join) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) RelNode(org.apache.calcite.rel.RelNode) RexBuilder(org.apache.calcite.rex.RexBuilder) RexInputRef(org.apache.calcite.rex.RexInputRef) CorrelationId(org.apache.calcite.rel.core.CorrelationId) HashSet(java.util.HashSet) RexNode(org.apache.calcite.rex.RexNode)

Example 17 with CorrelationId

use of org.apache.calcite.rel.core.CorrelationId in project calcite by apache.

the class RelOptUtil method getVariablesSetAndUsed.

// to be removed before 2.0
@Deprecated
@SuppressWarnings("MixedMutabilityReturnType")
public static List<CorrelationId> getVariablesSetAndUsed(RelNode rel0, RelNode rel1) {
    Set<CorrelationId> set = getVariablesSet(rel0);
    if (set.size() == 0) {
        return ImmutableList.of();
    }
    Set<CorrelationId> used = getVariablesUsed(rel1);
    if (used.size() == 0) {
        return ImmutableList.of();
    }
    final List<CorrelationId> result = new ArrayList<>();
    for (CorrelationId s : set) {
        if (used.contains(s) && !result.contains(s)) {
            result.add(s);
        }
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) CorrelationId(org.apache.calcite.rel.core.CorrelationId)

Example 18 with CorrelationId

use of org.apache.calcite.rel.core.CorrelationId in project calcite by apache.

the class JoinToCorrelateRule method onMatch.

@Override
public void onMatch(RelOptRuleCall call) {
    assert matches(call);
    final Join join = call.rel(0);
    RelNode right = join.getRight();
    final RelNode left = join.getLeft();
    final int leftFieldCount = left.getRowType().getFieldCount();
    final RelOptCluster cluster = join.getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    final RelBuilder relBuilder = call.builder();
    final CorrelationId correlationId = cluster.createCorrel();
    final RexNode corrVar = rexBuilder.makeCorrel(left.getRowType(), correlationId);
    final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
    // Replace all references of left input with FieldAccess(corrVar, field)
    final RexNode joinCondition = join.getCondition().accept(new RexShuttle() {

        @Override
        public RexNode visitInputRef(RexInputRef input) {
            int field = input.getIndex();
            if (field >= leftFieldCount) {
                return rexBuilder.makeInputRef(input.getType(), input.getIndex() - leftFieldCount);
            }
            requiredColumns.set(field);
            return rexBuilder.makeFieldAccess(corrVar, field);
        }
    });
    relBuilder.push(right).filter(joinCondition);
    RelNode newRel = LogicalCorrelate.create(left, relBuilder.build(), join.getHints(), correlationId, requiredColumns.build(), join.getJoinType());
    call.transformTo(newRel);
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RelBuilder(org.apache.calcite.tools.RelBuilder) RexShuttle(org.apache.calcite.rex.RexShuttle) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) Join(org.apache.calcite.rel.core.Join) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) RelNode(org.apache.calcite.rel.RelNode) RexBuilder(org.apache.calcite.rex.RexBuilder) RexInputRef(org.apache.calcite.rex.RexInputRef) CorrelationId(org.apache.calcite.rel.core.CorrelationId) RexNode(org.apache.calcite.rex.RexNode)

Example 19 with CorrelationId

use of org.apache.calcite.rel.core.CorrelationId in project calcite by apache.

the class SubQueryRemoveRule method rewriteIn.

/**
 * Rewrites an IN RexSubQuery into a {@link Join}.
 *
 * @param e            IN sub-query to rewrite
 * @param variablesSet A set of variables used by a relational
 *                     expression of the specified RexSubQuery
 * @param logic        Logic for evaluating
 * @param builder      Builder
 * @param offset       Offset to shift {@link RexInputRef}
 *
 * @return Expression that may be used to replace the RexSubQuery
 */
private static RexNode rewriteIn(RexSubQuery e, Set<CorrelationId> variablesSet, RelOptUtil.Logic logic, RelBuilder builder, int offset) {
    // Most general case, where the left and right keys might have nulls, and
    // caller requires 3-valued logic return.
    // 
    // select e.deptno, e.deptno in (select deptno from emp)
    // from emp as e
    // 
    // becomes
    // 
    // select e.deptno,
    // case
    // when ct.c = 0 then false
    // when e.deptno is null then null
    // when dt.i is not null then true
    // when ct.ck < ct.c then null
    // else false
    // end
    // from emp as e
    // left join (
    // (select count(*) as c, count(deptno) as ck from emp) as ct
    // cross join (select distinct deptno, true as i from emp)) as dt
    // on e.deptno = dt.deptno
    // 
    // If keys are not null we can remove "ct" and simplify to
    // 
    // select e.deptno,
    // case
    // when dt.i is not null then true
    // else false
    // end
    // from emp as e
    // left join (select distinct deptno, true as i from emp) as dt
    // on e.deptno = dt.deptno
    // 
    // We could further simplify to
    // 
    // select e.deptno,
    // dt.i is not null
    // from emp as e
    // left join (select distinct deptno, true as i from emp) as dt
    // on e.deptno = dt.deptno
    // 
    // but have not yet.
    // 
    // If the logic is TRUE we can just kill the record if the condition
    // evaluates to FALSE or UNKNOWN. Thus the query simplifies to an inner
    // join:
    // 
    // select e.deptno,
    // true
    // from emp as e
    // inner join (select distinct deptno from emp) as dt
    // on e.deptno = dt.deptno
    // 
    builder.push(e.rel);
    final List<RexNode> fields = new ArrayList<>(builder.fields());
    // for the case when IN has only literal operands, it may be handled
    // in the simpler way:
    // 
    // select e.deptno, 123456 in (select deptno from emp)
    // from emp as e
    // 
    // becomes
    // 
    // select e.deptno,
    // case
    // when dt.c IS NULL THEN FALSE
    // when e.deptno IS NULL THEN NULL
    // when dt.cs IS FALSE THEN NULL
    // when dt.cs IS NOT NULL THEN TRUE
    // else false
    // end
    // from emp AS e
    // cross join (
    // select distinct deptno is not null as cs, count(*) as c
    // from emp
    // where deptno = 123456 or deptno is null or e.deptno is null
    // order by cs desc limit 1) as dt
    // 
    boolean allLiterals = RexUtil.allLiterals(e.getOperands());
    final List<RexNode> expressionOperands = new ArrayList<>(e.getOperands());
    final List<RexNode> keyIsNulls = e.getOperands().stream().filter(operand -> operand.getType().isNullable()).map(builder::isNull).collect(Collectors.toList());
    final RexLiteral trueLiteral = builder.literal(true);
    final RexLiteral falseLiteral = builder.literal(false);
    final RexLiteral unknownLiteral = builder.getRexBuilder().makeNullLiteral(trueLiteral.getType());
    if (allLiterals) {
        final List<RexNode> conditions = Pair.zip(expressionOperands, fields).stream().map(pair -> builder.equals(pair.left, pair.right)).collect(Collectors.toList());
        switch(logic) {
            case TRUE:
            case TRUE_FALSE:
                builder.filter(conditions);
                builder.project(builder.alias(trueLiteral, "cs"));
                builder.distinct();
                break;
            default:
                List<RexNode> isNullOperands = fields.stream().map(builder::isNull).collect(Collectors.toList());
                // uses keyIsNulls conditions in the filter to avoid empty results
                isNullOperands.addAll(keyIsNulls);
                builder.filter(builder.or(builder.and(conditions), builder.or(isNullOperands)));
                RexNode project = builder.and(fields.stream().map(builder::isNotNull).collect(Collectors.toList()));
                builder.project(builder.alias(project, "cs"));
                if (variablesSet.isEmpty()) {
                    builder.aggregate(builder.groupKey(builder.field("cs")), builder.count(false, "c"));
                    // sorts input with desc order since we are interested
                    // only in the case when one of the values is true.
                    // When true value is absent then we are interested
                    // only in false value.
                    builder.sortLimit(0, 1, ImmutableList.of(builder.desc(builder.field("cs"))));
                } else {
                    builder.distinct();
                }
        }
        // clears expressionOperands and fields lists since
        // all expressions were used in the filter
        expressionOperands.clear();
        fields.clear();
    } else {
        switch(logic) {
            case TRUE:
                builder.aggregate(builder.groupKey(fields));
                break;
            case TRUE_FALSE_UNKNOWN:
            case UNKNOWN_AS_TRUE:
                // Builds the cross join
                builder.aggregate(builder.groupKey(), builder.count(false, "c"), builder.count(builder.fields()).as("ck"));
                builder.as("ct");
                if (!variablesSet.isEmpty()) {
                    builder.join(JoinRelType.LEFT, trueLiteral, variablesSet);
                } else {
                    builder.join(JoinRelType.INNER, trueLiteral, variablesSet);
                }
                offset += 2;
                builder.push(e.rel);
            // fall through
            default:
                fields.add(builder.alias(trueLiteral, "i"));
                builder.project(fields);
                builder.distinct();
        }
    }
    builder.as("dt");
    int refOffset = offset;
    final List<RexNode> conditions = Pair.zip(expressionOperands, builder.fields()).stream().map(pair -> builder.equals(pair.left, RexUtil.shift(pair.right, refOffset))).collect(Collectors.toList());
    switch(logic) {
        case TRUE:
            builder.join(JoinRelType.INNER, builder.and(conditions), variablesSet);
            return trueLiteral;
        default:
            break;
    }
    // Now the left join
    builder.join(JoinRelType.LEFT, builder.and(conditions), variablesSet);
    final ImmutableList.Builder<RexNode> operands = ImmutableList.builder();
    RexLiteral b = trueLiteral;
    switch(logic) {
        case TRUE_FALSE_UNKNOWN:
            b = unknownLiteral;
        // fall through
        case UNKNOWN_AS_TRUE:
            if (allLiterals) {
                // for the case of non-correlated sub-queries
                if (variablesSet.isEmpty()) {
                    operands.add(builder.isNull(builder.field("c")), falseLiteral);
                }
                operands.add(builder.equals(builder.field("cs"), falseLiteral), b);
            } else {
                operands.add(builder.equals(builder.field("ct", "c"), builder.literal(0)), falseLiteral);
            }
            break;
        default:
            break;
    }
    if (!keyIsNulls.isEmpty()) {
        operands.add(builder.or(keyIsNulls), unknownLiteral);
    }
    if (allLiterals) {
        operands.add(builder.isNotNull(builder.field("cs")), trueLiteral);
    } else {
        operands.add(builder.isNotNull(last(builder.fields())), trueLiteral);
    }
    if (!allLiterals) {
        switch(logic) {
            case TRUE_FALSE_UNKNOWN:
            case UNKNOWN_AS_TRUE:
                operands.add(builder.lessThan(builder.field("ct", "ck"), builder.field("ct", "c")), b);
                break;
            default:
                break;
        }
    }
    operands.add(falseLiteral);
    return builder.call(SqlStdOperatorTable.CASE, operands.build());
}
Also used : Project(org.apache.calcite.rel.core.Project) Correlate(org.apache.calcite.rel.core.Correlate) Util.last(org.apache.calcite.util.Util.last) Collect(org.apache.calcite.rel.core.Collect) Filter(org.apache.calcite.rel.core.Filter) RelOptUtil(org.apache.calcite.plan.RelOptUtil) Join(org.apache.calcite.rel.core.Join) ArrayList(java.util.ArrayList) RexUtil(org.apache.calcite.rex.RexUtil) CorrelationId(org.apache.calcite.rel.core.CorrelationId) ImmutableList(com.google.common.collect.ImmutableList) RexNode(org.apache.calcite.rex.RexNode) RelBuilder(org.apache.calcite.tools.RelBuilder) Value(org.immutables.value.Value) Pair(org.apache.calcite.util.Pair) RelDecorrelator(org.apache.calcite.sql2rel.RelDecorrelator) LogicVisitor(org.apache.calcite.rex.LogicVisitor) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) SqlKind(org.apache.calcite.sql.SqlKind) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) RexLiteral(org.apache.calcite.rex.RexLiteral) SqlQuantifyOperator(org.apache.calcite.sql.fun.SqlQuantifyOperator) Set(java.util.Set) RexSubQuery(org.apache.calcite.rex.RexSubQuery) RelRule(org.apache.calcite.plan.RelRule) RelNode(org.apache.calcite.rel.RelNode) Collectors(java.util.stream.Collectors) RelOptRuleCall(org.apache.calcite.plan.RelOptRuleCall) RexInputRef(org.apache.calcite.rex.RexInputRef) Objects(java.util.Objects) List(java.util.List) RelMetadataQuery(org.apache.calcite.rel.metadata.RelMetadataQuery) SqlStdOperatorTable(org.apache.calcite.sql.fun.SqlStdOperatorTable) RexCorrelVariable(org.apache.calcite.rex.RexCorrelVariable) JoinRelType(org.apache.calcite.rel.core.JoinRelType) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) RexShuttle(org.apache.calcite.rex.RexShuttle) RexLiteral(org.apache.calcite.rex.RexLiteral) ImmutableList(com.google.common.collect.ImmutableList) ArrayList(java.util.ArrayList) RexNode(org.apache.calcite.rex.RexNode)

Example 20 with CorrelationId

use of org.apache.calcite.rel.core.CorrelationId in project calcite by apache.

the class SubQueryRemoveRule method matchJoin.

private static void matchJoin(SubQueryRemoveRule rule, RelOptRuleCall call) {
    final Join join = call.rel(0);
    final RelBuilder builder = call.builder();
    final RexSubQuery e = RexUtil.SubQueryFinder.find(join.getCondition());
    assert e != null;
    final RelOptUtil.Logic logic = LogicVisitor.find(RelOptUtil.Logic.TRUE, ImmutableList.of(join.getCondition()), e);
    builder.push(join.getLeft());
    builder.push(join.getRight());
    final int fieldCount = join.getRowType().getFieldCount();
    final Set<CorrelationId> variablesSet = RelOptUtil.getVariablesUsed(e.rel);
    final RexNode target = rule.apply(e, variablesSet, logic, builder, 2, fieldCount);
    final RexShuttle shuttle = new ReplaceSubQueryShuttle(e, target);
    builder.join(join.getJoinType(), shuttle.apply(join.getCondition()));
    builder.project(fields(builder, join.getRowType().getFieldCount()));
    call.transformTo(builder.build());
}
Also used : RelBuilder(org.apache.calcite.tools.RelBuilder) RexShuttle(org.apache.calcite.rex.RexShuttle) RelOptUtil(org.apache.calcite.plan.RelOptUtil) Join(org.apache.calcite.rel.core.Join) CorrelationId(org.apache.calcite.rel.core.CorrelationId) RexSubQuery(org.apache.calcite.rex.RexSubQuery) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

CorrelationId (org.apache.calcite.rel.core.CorrelationId)74 RelNode (org.apache.calcite.rel.RelNode)39 RexNode (org.apache.calcite.rex.RexNode)33 RelDataType (org.apache.calcite.rel.type.RelDataType)25 ArrayList (java.util.ArrayList)22 RelOptCluster (org.apache.calcite.plan.RelOptCluster)19 RexBuilder (org.apache.calcite.rex.RexBuilder)18 RelBuilder (org.apache.calcite.tools.RelBuilder)17 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)15 ImmutableList (com.google.common.collect.ImmutableList)12 RelTraitSet (org.apache.calcite.plan.RelTraitSet)12 RexCorrelVariable (org.apache.calcite.rex.RexCorrelVariable)11 RexShuttle (org.apache.calcite.rex.RexShuttle)11 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)10 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)10 List (java.util.List)9 RelOptUtil (org.apache.calcite.plan.RelOptUtil)9 JoinRelType (org.apache.calcite.rel.core.JoinRelType)9 ByteString (org.apache.calcite.avatica.util.ByteString)7 SqlOperator (org.apache.calcite.sql.SqlOperator)7