Java Code Examples for org.apache.calcite.plan.RelOptCluster#getRexBuilder()

The following examples show how to use org.apache.calcite.plan.RelOptCluster#getRexBuilder() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: CalcitePrepareImpl.java    From calcite with Apache License 2.0 6 votes vote down vote up
CalcitePreparingStmt(CalcitePrepareImpl prepare,
    Context context,
    CatalogReader catalogReader,
    RelDataTypeFactory typeFactory,
    CalciteSchema schema,
    EnumerableRel.Prefer prefer,
    RelOptCluster cluster,
    Convention resultConvention,
    SqlRexConvertletTable convertletTable) {
  super(context, catalogReader, resultConvention);
  this.prepare = prepare;
  this.schema = schema;
  this.prefer = prefer;
  this.cluster = cluster;
  this.planner = cluster.getPlanner();
  this.rexBuilder = cluster.getRexBuilder();
  this.typeFactory = typeFactory;
  this.convertletTable = convertletTable;
}
 
Example 2
Source File: RelBuilder.java    From calcite with Apache License 2.0 6 votes vote down vote up
protected RelBuilder(Context context, RelOptCluster cluster,
    RelOptSchema relOptSchema) {
  this.cluster = cluster;
  this.relOptSchema = relOptSchema;
  if (context == null) {
    context = Contexts.EMPTY_CONTEXT;
  }
  this.config = getConfig(context);
  this.viewExpander = getViewExpander(cluster, context);
  this.struct =
      Objects.requireNonNull(RelFactories.Struct.fromContext(context));
  final RexExecutor executor =
      Util.first(context.unwrap(RexExecutor.class),
          Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR));
  final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
  this.simplifier =
      new RexSimplify(cluster.getRexBuilder(), predicates, executor);
}
 
Example 3
Source File: SubQueryDecorrelator.java    From flink with Apache License 2.0 6 votes vote down vote up
/**
 * Decorrelates a subquery.
 *
 * <p>This is the main entry point to {@code SubQueryDecorrelator}.
 *
 * @param rootRel The node which has SubQuery.
 * @return Decorrelate result.
 */
public static Result decorrelateQuery(RelNode rootRel) {
	int maxCnfNodeCount = FlinkRelOptUtil.getMaxCnfNodeCount(rootRel);

	final CorelMapBuilder builder = new CorelMapBuilder(maxCnfNodeCount);
	final CorelMap corelMap = builder.build(rootRel);
	if (builder.hasNestedCorScope || builder.hasUnsupportedCorCondition) {
		return null;
	}

	if (!corelMap.hasCorrelation()) {
		return Result.EMPTY;
	}

	RelOptCluster cluster = rootRel.getCluster();
	RelBuilder relBuilder = new FlinkRelBuilder(cluster.getPlanner().getContext(), cluster, null);
	RexBuilder rexBuilder = cluster.getRexBuilder();

	final SubQueryDecorrelator decorrelator = new SubQueryDecorrelator(
			new SubQueryRelDecorrelator(corelMap, relBuilder, rexBuilder, maxCnfNodeCount),
			relBuilder);
	rootRel.accept(decorrelator);

	return new Result(decorrelator.subQueryMap);
}
 
Example 4
Source File: SubQueryDecorrelator.java    From flink with Apache License 2.0 6 votes vote down vote up
/**
 * Decorrelates a subquery.
 *
 * <p>This is the main entry point to {@code SubQueryDecorrelator}.
 *
 * @param rootRel The node which has SubQuery.
 * @return Decorrelate result.
 */
public static Result decorrelateQuery(RelNode rootRel) {
	int maxCnfNodeCount = FlinkRelOptUtil.getMaxCnfNodeCount(rootRel);

	final CorelMapBuilder builder = new CorelMapBuilder(maxCnfNodeCount);
	final CorelMap corelMap = builder.build(rootRel);
	if (builder.hasNestedCorScope || builder.hasUnsupportedCorCondition) {
		return null;
	}

	if (!corelMap.hasCorrelation()) {
		return Result.EMPTY;
	}

	RelOptCluster cluster = rootRel.getCluster();
	RelBuilder relBuilder = new FlinkRelBuilder(cluster.getPlanner().getContext(), cluster, null);
	RexBuilder rexBuilder = cluster.getRexBuilder();

	final SubQueryDecorrelator decorrelator = new SubQueryDecorrelator(
			new SubQueryRelDecorrelator(corelMap, relBuilder, rexBuilder, maxCnfNodeCount),
			relBuilder);
	rootRel.accept(decorrelator);

	return new Result(decorrelator.subQueryMap);
}
 
Example 5
Source File: FilterFlattenTransposeRule.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
private static List<RexInputRef> asNodes(final RelOptCluster cluster, Iterable<Integer> indices){
  final RexBuilder builder = cluster.getRexBuilder();
  final RelDataTypeFactory factory = cluster.getTypeFactory();

  return FluentIterable.from(indices).transform(new Function<Integer, RexInputRef>(){
    @Override
    public RexInputRef apply(Integer input) {
      return builder.makeInputRef(factory.createTypeWithNullability(factory.createSqlType(SqlTypeName.ANY), true), input);
    }}).toList();
}
 
Example 6
Source File: ReduceExpressionsRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Reduces a list of expressions.
 *
 * <p>The {@code matchNullability} flag comes into play when reducing a
 * expression whose type is nullable. Suppose we are reducing an expression
 * {@code CASE WHEN 'a' = 'a' THEN 1 ELSE NULL END}. Before reduction the
 * type is {@code INTEGER} (nullable), but after reduction the literal 1 has
 * type {@code INTEGER NOT NULL}.
 *
 * <p>In some situations it is more important to preserve types; in this
 * case you should use {@code matchNullability = true} (which used to be
 * the default behavior of this method), and it will cast the literal to
 * {@code INTEGER} (nullable).
 *
 * <p>In other situations, you would rather propagate the new stronger type,
 * because it may allow further optimizations later; pass
 * {@code matchNullability = false} and no cast will be added, but you may
 * need to adjust types elsewhere in the expression tree.
 *
 * @param rel     Relational expression
 * @param expList List of expressions, modified in place
 * @param predicates Constraints known to hold on input expressions
 * @param unknownAsFalse Whether UNKNOWN will be treated as FALSE
 * @param matchNullability Whether Calcite should add a CAST to a literal
 *                         resulting from simplification and expression if the
 *                         expression had nullable type and the literal is
 *                         NOT NULL
 *
 * @return whether reduction found something to change, and succeeded
 */
protected static boolean reduceExpressions(RelNode rel, List<RexNode> expList,
    RelOptPredicateList predicates, boolean unknownAsFalse,
    boolean matchNullability) {
  final RelOptCluster cluster = rel.getCluster();
  final RexBuilder rexBuilder = cluster.getRexBuilder();
  final List<RexNode> originExpList = Lists.newArrayList(expList);
  final RexExecutor executor =
      Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
  final RexSimplify simplify =
      new RexSimplify(rexBuilder, predicates, executor);

  // Simplify predicates in place
  final RexUnknownAs unknownAs = RexUnknownAs.falseIf(unknownAsFalse);
  final boolean reduced = reduceExpressionsInternal(rel, simplify, unknownAs,
      expList, predicates);

  boolean simplified = false;
  for (int i = 0; i < expList.size(); i++) {
    final RexNode expr2 =
        simplify.simplifyPreservingType(expList.get(i), unknownAs,
            matchNullability);
    if (!expr2.equals(expList.get(i))) {
      expList.set(i, expr2);
      simplified = true;
    }
  }

  if (reduced && simplified) {
    return !originExpList.equals(expList);
  }

  return reduced || simplified;
}
 
Example 7
Source File: RexVisitorComplexExprSplitter.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
public RexVisitorComplexExprSplitter(RelOptCluster cluster, FunctionImplementationRegistry funcReg, int firstUnused) {
  super(true);
  this.factory = cluster.getTypeFactory();
  this.builder = cluster.getRexBuilder();
  this.funcReg = funcReg;
  this.complexExprs = new ArrayList<>();
  this.lastUsedIndex = firstUnused;
}
 
Example 8
Source File: RelBuilder.java    From Bats with Apache License 2.0 5 votes vote down vote up
protected RelBuilder(Context context, RelOptCluster cluster, RelOptSchema relOptSchema) {
    this.cluster = cluster;
    this.relOptSchema = relOptSchema;
    if (context == null) {
        context = Contexts.EMPTY_CONTEXT;
    }
    this.simplify = Hook.REL_BUILDER_SIMPLIFY.get(true);
    this.aggregateFactory = Util.first(context.unwrap(RelFactories.AggregateFactory.class),
            RelFactories.DEFAULT_AGGREGATE_FACTORY);
    this.filterFactory = Util.first(context.unwrap(RelFactories.FilterFactory.class),
            RelFactories.DEFAULT_FILTER_FACTORY);
    this.projectFactory = Util.first(context.unwrap(RelFactories.ProjectFactory.class),
            RelFactories.DEFAULT_PROJECT_FACTORY);
    this.sortFactory = Util.first(context.unwrap(RelFactories.SortFactory.class),
            RelFactories.DEFAULT_SORT_FACTORY);
    this.exchangeFactory = Util.first(context.unwrap(RelFactories.ExchangeFactory.class),
            RelFactories.DEFAULT_EXCHANGE_FACTORY);
    this.sortExchangeFactory = Util.first(context.unwrap(RelFactories.SortExchangeFactory.class),
            RelFactories.DEFAULT_SORT_EXCHANGE_FACTORY);
    this.setOpFactory = Util.first(context.unwrap(RelFactories.SetOpFactory.class),
            RelFactories.DEFAULT_SET_OP_FACTORY);
    this.joinFactory = Util.first(context.unwrap(RelFactories.JoinFactory.class),
            RelFactories.DEFAULT_JOIN_FACTORY);
    this.semiJoinFactory = Util.first(context.unwrap(RelFactories.SemiJoinFactory.class),
            RelFactories.DEFAULT_SEMI_JOIN_FACTORY);
    this.correlateFactory = Util.first(context.unwrap(RelFactories.CorrelateFactory.class),
            RelFactories.DEFAULT_CORRELATE_FACTORY);
    this.valuesFactory = Util.first(context.unwrap(RelFactories.ValuesFactory.class),
            RelFactories.DEFAULT_VALUES_FACTORY);
    this.scanFactory = Util.first(context.unwrap(RelFactories.TableScanFactory.class),
            RelFactories.DEFAULT_TABLE_SCAN_FACTORY);
    this.snapshotFactory = Util.first(context.unwrap(RelFactories.SnapshotFactory.class),
            RelFactories.DEFAULT_SNAPSHOT_FACTORY);
    this.matchFactory = Util.first(context.unwrap(RelFactories.MatchFactory.class),
            RelFactories.DEFAULT_MATCH_FACTORY);
    final RexExecutor executor = Util.first(context.unwrap(RexExecutor.class),
            Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR));
    final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
    this.simplifier = new RexSimplify(cluster.getRexBuilder(), predicates, executor);
}
 
Example 9
Source File: RelStructuredTypeFlattener.java    From Bats with Apache License 2.0 5 votes vote down vote up
public void rewriteRel(LogicalCalc rel) {
    // Translate the child.
    final RelNode newInput = getNewForOldRel(rel.getInput());

    final RelOptCluster cluster = rel.getCluster();
    RexProgramBuilder programBuilder = new RexProgramBuilder(newInput.getRowType(), cluster.getRexBuilder());

    // Convert the common expressions.
    final RexProgram program = rel.getProgram();
    final RewriteRexShuttle shuttle = new RewriteRexShuttle();
    for (RexNode expr : program.getExprList()) {
        programBuilder.registerInput(expr.accept(shuttle));
    }

    // Convert the projections.
    final List<Pair<RexNode, String>> flattenedExpList = new ArrayList<>();
    List<String> fieldNames = rel.getRowType().getFieldNames();
    flattenProjections(new RewriteRexShuttle(), program.getProjectList(), fieldNames, "", flattenedExpList);

    // Register each of the new projections.
    for (Pair<RexNode, String> flattenedExp : flattenedExpList) {
        programBuilder.addProject(flattenedExp.left, flattenedExp.right);
    }

    // Translate the condition.
    final RexLocalRef conditionRef = program.getCondition();
    if (conditionRef != null) {
        final Ord<RelDataType> newField = getNewFieldForOldInput(conditionRef.getIndex());
        programBuilder.addCondition(RexBuilder.getRexFactory().makeInputRef(newField.i, newField.e));
    }

    RexProgram newProgram = programBuilder.getProgram();

    // Create a new calc relational expression.
    LogicalCalc newRel = LogicalCalc.create(newInput, newProgram);
    setNewForOldRel(rel, newRel);
}
 
Example 10
Source File: JoinAssociateRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
public void onMatch(final RelOptRuleCall call) {
  final Join topJoin = call.rel(0);
  final Join bottomJoin = call.rel(1);
  final RelNode relA = bottomJoin.getLeft();
  final RelNode relB = bottomJoin.getRight();
  final RelSubset relC = call.rel(2);
  final RelOptCluster cluster = topJoin.getCluster();
  final RexBuilder rexBuilder = cluster.getRexBuilder();

  if (relC.getConvention() != relA.getConvention()) {
    // relC could have any trait-set. But if we're matching say
    // EnumerableConvention, we're only interested in enumerable subsets.
    return;
  }

  //        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(0, aCount);
  final ImmutableBitSet bBitSet =
      ImmutableBitSet.range(aCount, aCount + bCount);

  if (!topJoin.getSystemFieldList().isEmpty()) {
    // FIXME Enable this rule for joins with system fields
    return;
  }

  // If either join is not inner, we cannot proceed.
  // (Is this too strict?)
  if (topJoin.getJoinType() != JoinRelType.INNER
      || bottomJoin.getJoinType() != JoinRelType.INNER) {
    return;
  }

  // Goal is to transform to
  //
  //       newTopJoin
  //        /     \
  //       A   newBottomJoin
  //               /    \
  //              B      C

  // Split the condition of topJoin and bottomJoin into a conjunctions. A
  // condition can be pushed down if it does not use columns from A.
  final List<RexNode> top = new ArrayList<>();
  final List<RexNode> bottom = new ArrayList<>();
  JoinPushThroughJoinRule.split(topJoin.getCondition(), aBitSet, top, bottom);
  JoinPushThroughJoinRule.split(bottomJoin.getCondition(), aBitSet, top,
      bottom);

  // Mapping for moving conditions from topJoin or bottomJoin to
  // newBottomJoin.
  // target: | B | C      |
  // source: | A       | B | C      |
  final Mappings.TargetMapping bottomMapping =
      Mappings.createShiftMapping(
          aCount + bCount + cCount,
          0, aCount, bCount,
          bCount, aCount + bCount, cCount);
  final List<RexNode> newBottomList = new ArrayList<>();
  new RexPermuteInputsShuttle(bottomMapping, relB, relC)
      .visitList(bottom, newBottomList);
  RexNode newBottomCondition =
      RexUtil.composeConjunction(rexBuilder, newBottomList);

  final Join newBottomJoin =
      bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB,
          relC, JoinRelType.INNER, false);

  // Condition for newTopJoin consists of pieces from bottomJoin and topJoin.
  // Field ordinals do not need to be changed.
  RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, top);
  @SuppressWarnings("SuspiciousNameCombination")
  final Join newTopJoin =
      topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA,
          newBottomJoin, JoinRelType.INNER, false);

  call.transformTo(newTopJoin);
}
 
Example 11
Source File: RelStructuredTypeFlattener.java    From calcite with Apache License 2.0 4 votes vote down vote up
public void rewriteRel(LogicalCalc rel) {
  // Translate the child.
  final RelNode newInput = getNewForOldRel(rel.getInput());

  final RelOptCluster cluster = rel.getCluster();
  RexProgramBuilder programBuilder =
      new RexProgramBuilder(
          newInput.getRowType(),
          cluster.getRexBuilder());

  // Convert the common expressions.
  final RexProgram program = rel.getProgram();
  final RewriteRexShuttle shuttle = new RewriteRexShuttle();
  for (RexNode expr : program.getExprList()) {
    programBuilder.registerInput(expr.accept(shuttle));
  }

  // Convert the projections.
  final List<Pair<RexNode, String>> flattenedExpList = new ArrayList<>();
  List<String> fieldNames = rel.getRowType().getFieldNames();
  flattenProjections(new RewriteRexShuttle(),
      program.getProjectList(),
      fieldNames,
      "",
      flattenedExpList);

  // Register each of the new projections.
  for (Pair<RexNode, String> flattenedExp : flattenedExpList) {
    programBuilder.addProject(flattenedExp.left, flattenedExp.right);
  }

  // Translate the condition.
  final RexLocalRef conditionRef = program.getCondition();
  if (conditionRef != null) {
    final Ord<RelDataType> newField =
        getNewFieldForOldInput(conditionRef.getIndex());
    programBuilder.addCondition(new RexLocalRef(newField.i, newField.e));
  }

  RexProgram newProgram = programBuilder.getProgram();

  // Create a new calc relational expression.
  LogicalCalc newRel = LogicalCalc.create(newInput, newProgram);
  setNewForOldRel(rel, newRel);
}
 
Example 12
Source File: SemiJoinRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
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()))) {
    // Rule requires that aggregate key to be the same as the join key.
    // 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 = new ArrayList<>();
    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:
    // The right-hand side produces no more than 1 row (because of the
    // Aggregate) and no fewer than 1 row (because of LEFT), and therefore
    // 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());
}
 
Example 13
Source File: JoinPushThroughJoinRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * 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);

  // becomes
  //
  //        newTopJoin
  //        /        \
  //   newBottomJoin  A
  //    /    \
  //   C      B

  // If either join is not inner, we cannot proceed.
  // (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);
  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);
  @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());
}
 
Example 14
Source File: EnumerableBatchNestedLoopJoinRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
@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 ArrayList<RexNode> corrVar = new ArrayList<>();

  for (int i = 0; i < batchSize; i++) {
    CorrelationId correlationId = cluster.createCorrel();
    correlationIds.add(correlationId);
    corrVar.add(
        rexBuilder.makeCorrel(join.getLeft().getRowType(),
            correlationId));
  }

  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(corrVar.get(0), field);
    }
  });

  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 corrVar.get(corrIndex);
      }
    });
    conditionList.add(condition2);
  }

  // Push a filter with batchSize disjunctions
  relBuilder.push(join.getRight()).filter(relBuilder.or(conditionList));
  RelNode right = relBuilder.build();

  JoinRelType joinType = join.getJoinType();
  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,
          joinType));
}
 
Example 15
Source File: AggregateReduceFunctionsRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
private RexNode reduceRegrSzz(
    Aggregate oldAggRel,
    AggregateCall oldCall,
    List<AggregateCall> newCalls,
    Map<AggregateCall, RexNode> aggCallMapping,
    List<RexNode> inputExprs,
    int xIndex,
    int yIndex,
    int nullFilterIndex) {
  // regr_sxx(x, y) ==>
  //    sum(y * y, x) - sum(y, x) * sum(y, x) / regr_count(x, y)
  //

  final RelOptCluster cluster = oldAggRel.getCluster();
  final RexBuilder rexBuilder = cluster.getRexBuilder();
  final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
  final RelDataType argXType = getFieldType(oldAggRel.getInput(), xIndex);
  final RelDataType argYType =
      xIndex == yIndex ? argXType : getFieldType(oldAggRel.getInput(), yIndex);
  final RelDataType nullFilterIndexType =
      nullFilterIndex == yIndex ? argYType : getFieldType(oldAggRel.getInput(), yIndex);

  final RelDataType oldCallType =
      typeFactory.createTypeWithNullability(oldCall.getType(),
          argXType.isNullable() || argYType.isNullable() || nullFilterIndexType.isNullable());

  final RexNode argX =
      rexBuilder.ensureType(oldCallType, inputExprs.get(xIndex), true);
  final RexNode argY =
      rexBuilder.ensureType(oldCallType, inputExprs.get(yIndex), true);
  final RexNode argNullFilter =
      rexBuilder.ensureType(oldCallType, inputExprs.get(nullFilterIndex), true);

  final RexNode argXArgY = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, argX, argY);
  final int argSquaredOrdinal = lookupOrAdd(inputExprs, argXArgY);

  final RexNode argXAndYNotNullFilter = rexBuilder.makeCall(SqlStdOperatorTable.AND,
      rexBuilder.makeCall(SqlStdOperatorTable.AND,
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, argX),
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, argY)),
      rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, argNullFilter));
  final int argXAndYNotNullFilterOrdinal = lookupOrAdd(inputExprs, argXAndYNotNullFilter);
  final RexNode sumXY = getSumAggregatedRexNodeWithBinding(
      oldAggRel, oldCall, newCalls, aggCallMapping, argXArgY.getType(),
      argSquaredOrdinal, argXAndYNotNullFilterOrdinal);
  final RexNode sumXYCast = rexBuilder.ensureType(oldCallType, sumXY, true);

  final RexNode sumX = getSumAggregatedRexNode(oldAggRel, oldCall,
      newCalls, aggCallMapping, rexBuilder, xIndex, argXAndYNotNullFilterOrdinal);
  final RexNode sumY = xIndex == yIndex
      ? sumX
      : getSumAggregatedRexNode(oldAggRel, oldCall, newCalls,
          aggCallMapping, rexBuilder, yIndex, argXAndYNotNullFilterOrdinal);

  final RexNode sumXSumY = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, sumX, sumY);

  final RexNode countArg = getRegrCountRexNode(oldAggRel, oldCall, newCalls, aggCallMapping,
      ImmutableIntList.of(xIndex), ImmutableList.of(argXType), argXAndYNotNullFilterOrdinal);

  RexLiteral zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO);
  RexNode nul = rexBuilder.constantNull();
  final RexNode avgSumXSumY = rexBuilder.makeCall(SqlStdOperatorTable.CASE,
      rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countArg, zero), nul,
          rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, sumXSumY, countArg));
  final RexNode avgSumXSumYCast = rexBuilder.ensureType(oldCallType, avgSumXSumY, true);
  final RexNode result =
      rexBuilder.makeCall(SqlStdOperatorTable.MINUS, sumXYCast, avgSumXSumYCast);
  return rexBuilder.makeCast(oldCall.getType(), result);
}
 
Example 16
Source File: ProjectCalcMergeRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
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);
}
 
Example 17
Source File: AggregateReduceFunctionsRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
private RexNode reduceRegrSzz(
    Aggregate oldAggRel,
    AggregateCall oldCall,
    List<AggregateCall> newCalls,
    Map<AggregateCall, RexNode> aggCallMapping,
    List<RexNode> inputExprs,
    int xIndex,
    int yIndex,
    int nullFilterIndex) {
  // regr_sxx(x, y) ==>
  //    sum(y * y, x) - sum(y, x) * sum(y, x) / regr_count(x, y)
  //

  final RelOptCluster cluster = oldAggRel.getCluster();
  final RexBuilder rexBuilder = cluster.getRexBuilder();
  final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
  final RelDataType argXType = getFieldType(oldAggRel.getInput(), xIndex);
  final RelDataType argYType =
      xIndex == yIndex ? argXType : getFieldType(oldAggRel.getInput(), yIndex);
  final RelDataType nullFilterIndexType =
      nullFilterIndex == yIndex ? argYType : getFieldType(oldAggRel.getInput(), yIndex);

  final RelDataType oldCallType =
      typeFactory.createTypeWithNullability(oldCall.getType(),
          argXType.isNullable() || argYType.isNullable() || nullFilterIndexType.isNullable());

  final RexNode argX =
      rexBuilder.ensureType(oldCallType, inputExprs.get(xIndex), true);
  final RexNode argY =
      rexBuilder.ensureType(oldCallType, inputExprs.get(yIndex), true);
  final RexNode argNullFilter =
      rexBuilder.ensureType(oldCallType, inputExprs.get(nullFilterIndex), true);

  final RexNode argXArgY = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, argX, argY);
  final int argSquaredOrdinal = lookupOrAdd(inputExprs, argXArgY);

  final RexNode argXAndYNotNullFilter = rexBuilder.makeCall(SqlStdOperatorTable.AND,
      rexBuilder.makeCall(SqlStdOperatorTable.AND,
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, argX),
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, argY)),
      rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, argNullFilter));
  final int argXAndYNotNullFilterOrdinal = lookupOrAdd(inputExprs, argXAndYNotNullFilter);
  final RexNode sumXY = getSumAggregatedRexNodeWithBinding(
      oldAggRel, oldCall, newCalls, aggCallMapping, argXArgY.getType(),
      argSquaredOrdinal, argXAndYNotNullFilterOrdinal);
  final RexNode sumXYCast = rexBuilder.ensureType(oldCallType, sumXY, true);

  final RexNode sumX = getSumAggregatedRexNode(oldAggRel, oldCall,
      newCalls, aggCallMapping, rexBuilder, xIndex, argXAndYNotNullFilterOrdinal);
  final RexNode sumY = xIndex == yIndex
      ? sumX
      : getSumAggregatedRexNode(oldAggRel, oldCall, newCalls,
          aggCallMapping, rexBuilder, yIndex, argXAndYNotNullFilterOrdinal);

  final RexNode sumXSumY = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, sumX, sumY);

  final RexNode countArg = getRegrCountRexNode(oldAggRel, oldCall, newCalls, aggCallMapping,
      ImmutableIntList.of(xIndex), ImmutableList.of(argXType), argXAndYNotNullFilterOrdinal);

  RexLiteral zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO);
  RexNode nul = rexBuilder.makeNullLiteral(zero.getType());
  final RexNode avgSumXSumY = rexBuilder.makeCall(SqlStdOperatorTable.CASE,
      rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countArg, zero), nul,
          rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, sumXSumY, countArg));
  final RexNode avgSumXSumYCast = rexBuilder.ensureType(oldCallType, avgSumXSumY, true);
  final RexNode result =
      rexBuilder.makeCall(SqlStdOperatorTable.MINUS, sumXYCast, avgSumXSumYCast);
  return rexBuilder.makeCast(oldCall.getType(), result);
}
 
Example 18
Source File: JoinPushThroughJoinRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * 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);

  // becomes
  //
  //        newTopJoin
  //        /        \
  //   newBottomJoin  A
  //    /    \
  //   C      B

  // If either join is not inner, we cannot proceed.
  // (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);
  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);
  @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());
}
 
Example 19
Source File: SemiJoinRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
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;
    }
  } else {
    if (join.getJoinType().projectsRight()
        && !IS_EMPTY_AGGREGATE.test(aggregate)) {
      return;
    }
  }
  final JoinInfo joinInfo = join.analyzeCondition();
  if (!joinInfo.rightSet().equals(
      ImmutableBitSet.range(aggregate.getGroupCount()))) {
    // Rule requires that aggregate key to be the same as the join key.
    // 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 SEMI:
  case INNER:
    final List<Integer> newRightKeyBuilder = new ArrayList<>();
    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:
    // The right-hand side produces no more than 1 row (because of the
    // Aggregate) and no fewer than 1 row (because of LEFT), and therefore
    // we can eliminate the semi-join.
    break;

  default:
    throw new AssertionError(join.getJoinType());
  }
  if (project != null) {
    relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
  }
  final RelNode relNode = relBuilder.build();
  call.transformTo(relNode);
}
 
Example 20
Source File: JoinAssociateRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
public void onMatch(final RelOptRuleCall call) {
  final Join topJoin = call.rel(0);
  final Join bottomJoin = call.rel(1);
  final RelNode relA = bottomJoin.getLeft();
  final RelNode relB = bottomJoin.getRight();
  final RelSubset relC = call.rel(2);
  final RelOptCluster cluster = topJoin.getCluster();
  final RexBuilder rexBuilder = cluster.getRexBuilder();

  if (relC.getConvention() != relA.getConvention()) {
    // relC could have any trait-set. But if we're matching say
    // EnumerableConvention, we're only interested in enumerable subsets.
    return;
  }

  //        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(0, aCount);
  final ImmutableBitSet bBitSet =
      ImmutableBitSet.range(aCount, aCount + bCount);

  if (!topJoin.getSystemFieldList().isEmpty()) {
    // FIXME Enable this rule for joins with system fields
    return;
  }

  // If either join is not inner, we cannot proceed.
  // (Is this too strict?)
  if (topJoin.getJoinType() != JoinRelType.INNER
      || bottomJoin.getJoinType() != JoinRelType.INNER) {
    return;
  }

  // Goal is to transform to
  //
  //       newTopJoin
  //        /     \
  //       A   newBottomJoin
  //               /    \
  //              B      C

  // Split the condition of topJoin and bottomJoin into a conjunctions. A
  // condition can be pushed down if it does not use columns from A.
  final List<RexNode> top = new ArrayList<>();
  final List<RexNode> bottom = new ArrayList<>();
  JoinPushThroughJoinRule.split(topJoin.getCondition(), aBitSet, top, bottom);
  JoinPushThroughJoinRule.split(bottomJoin.getCondition(), aBitSet, top,
      bottom);

  // Mapping for moving conditions from topJoin or bottomJoin to
  // newBottomJoin.
  // target: | B | C      |
  // source: | A       | B | C      |
  final Mappings.TargetMapping bottomMapping =
      Mappings.createShiftMapping(
          aCount + bCount + cCount,
          0, aCount, bCount,
          bCount, aCount + bCount, cCount);
  final List<RexNode> newBottomList =
      new RexPermuteInputsShuttle(bottomMapping, relB, relC)
          .visitList(bottom);
  RexNode newBottomCondition =
      RexUtil.composeConjunction(rexBuilder, newBottomList);

  final Join newBottomJoin =
      bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB,
          relC, JoinRelType.INNER, false);

  // Condition for newTopJoin consists of pieces from bottomJoin and topJoin.
  // Field ordinals do not need to be changed.
  RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, top);
  @SuppressWarnings("SuspiciousNameCombination")
  final Join newTopJoin =
      topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA,
          newBottomJoin, JoinRelType.INNER, false);

  call.transformTo(newTopJoin);
}