Ejemplo n.º 1
0
  public void onMatch(RelOptRuleCall call) {
    assert matches(call);
    final JoinRel join = (JoinRel) call.rels[0];
    final List<Integer> leftKeys = new ArrayList<Integer>();
    final List<Integer> rightKeys = new ArrayList<Integer>();
    RelNode right = join.getRight();
    final RelNode left = join.getLeft();
    RexNode remainingCondition =
        RelOptUtil.splitJoinCondition(left, right, join.getCondition(), leftKeys, rightKeys);
    assert leftKeys.size() == rightKeys.size();
    final List<CorrelatorRel.Correlation> correlationList =
        new ArrayList<CorrelatorRel.Correlation>();
    if (leftKeys.size() > 0) {
      final RelOptCluster cluster = join.getCluster();
      final RexBuilder rexBuilder = cluster.getRexBuilder();
      int k = 0;
      RexNode condition = null;
      for (Integer leftKey : leftKeys) {
        Integer rightKey = rightKeys.get(k++);
        final String dyn_inIdStr = cluster.getQuery().createCorrel();
        final int dyn_inId = RelOptQuery.getCorrelOrdinal(dyn_inIdStr);

        // Create correlation to say 'each row, set variable #id
        // to the value of column #leftKey'.
        correlationList.add(new CorrelatorRel.Correlation(dyn_inId, leftKey));
        condition =
            RelOptUtil.andJoinFilters(
                rexBuilder,
                condition,
                rexBuilder.makeCall(
                    SqlStdOperatorTable.equalsOperator,
                    rexBuilder.makeInputRef(
                        right.getRowType().getFieldList().get(rightKey).getType(), rightKey),
                    rexBuilder.makeCorrel(
                        left.getRowType().getFieldList().get(leftKey).getType(), dyn_inIdStr)));
      }
      right = CalcRel.createFilter(right, condition);
    }
    RelNode newRel =
        new CorrelatorRel(
            join.getCluster(),
            left,
            right,
            remainingCondition,
            correlationList,
            join.getJoinType());
    call.transformTo(newRel);
  }
  /**
   * Reduces a list of expressions.
   *
   * @param rel Relational expression
   * @param expList List of expressions, modified in place
   * @return whether reduction found something to change, and succeeded
   */
  static boolean reduceExpressions(RelNode rel, List<RexNode> expList) {
    RexBuilder rexBuilder = rel.getCluster().getRexBuilder();

    // Find reducible expressions.
    FarragoSessionPlanner planner = (FarragoSessionPlanner) rel.getCluster().getPlanner();
    FarragoSessionPreparingStmt preparingStmt = planner.getPreparingStmt();
    List<RexNode> constExps = new ArrayList<RexNode>();
    List<Boolean> addCasts = new ArrayList<Boolean>();
    List<RexNode> removableCasts = new ArrayList<RexNode>();
    findReducibleExps(preparingStmt, expList, constExps, addCasts, removableCasts);
    if (constExps.isEmpty() && removableCasts.isEmpty()) {
      return false;
    }

    // Remove redundant casts before reducing constant expressions.
    // If the argument to the redundant cast is a reducible constant,
    // reducing that argument to a constant first will result in not being
    // able to locate the original cast expression.
    if (!removableCasts.isEmpty()) {
      List<RexNode> reducedExprs = new ArrayList<RexNode>();
      List<Boolean> noCasts = new ArrayList<Boolean>();
      for (RexNode exp : removableCasts) {
        RexCall call = (RexCall) exp;
        reducedExprs.add(call.getOperands()[0]);
        noCasts.add(false);
      }
      RexReplacer replacer = new RexReplacer(rexBuilder, removableCasts, reducedExprs, noCasts);
      replacer.apply(expList);
    }

    if (constExps.isEmpty()) {
      return true;
    }

    // Compute the values they reduce to.
    List<RexNode> reducedValues = new ArrayList<RexNode>();
    ReentrantValuesStmt reentrantStmt =
        new ReentrantValuesStmt(
            preparingStmt.getRootStmtContext(), rexBuilder, constExps, reducedValues);
    FarragoSession session = getSession(rel);
    reentrantStmt.execute(session, true);
    if (reentrantStmt.failed) {
      return false;
    }

    // For ProjectRel, we have to be sure to preserve the result
    // types, so always cast regardless of the expression type.
    // For other RelNodes like FilterRel, in general, this isn't necessary,
    // and the presence of casts could hinder other rules such as sarg
    // analysis, which require bare literals.  But there are special cases,
    // like when the expression is a UDR argument, that need to be
    // handled as special cases.
    if (rel instanceof ProjectRel) {
      for (int i = 0; i < reducedValues.size(); i++) {
        addCasts.set(i, true);
      }
    }

    RexReplacer replacer = new RexReplacer(rexBuilder, constExps, reducedValues, addCasts);
    replacer.apply(expList);
    return true;
  }
 static FarragoSession getSession(RelNode rel) {
   FarragoSessionPlanner planner = (FarragoSessionPlanner) rel.getCluster().getPlanner();
   FarragoSessionPreparingStmt preparingStmt = planner.getPreparingStmt();
   return preparingStmt.getSession();
 }
  public Boolean areColumnsUnique(JoinRelBase rel, BitSet columns, boolean ignoreNulls) {
    if (columns.cardinality() == 0) {
      return false;
    }

    final RelNode left = rel.getLeft();
    final RelNode right = rel.getRight();

    // Divide up the input column mask into column masks for the left and
    // right sides of the join
    BitSet leftColumns = new BitSet();
    BitSet rightColumns = new BitSet();
    int nLeftColumns = left.getRowType().getFieldCount();
    for (int bit : BitSets.toIter(columns)) {
      if (bit < nLeftColumns) {
        leftColumns.set(bit);
      } else {
        rightColumns.set(bit - nLeftColumns);
      }
    }

    // If the original column mask contains columns from both the left and
    // right hand side, then the columns are unique if and only if they're
    // unique for their respective join inputs
    Boolean leftUnique = RelMetadataQuery.areColumnsUnique(left, leftColumns, ignoreNulls);
    Boolean rightUnique = RelMetadataQuery.areColumnsUnique(right, rightColumns, ignoreNulls);
    if ((leftColumns.cardinality() > 0) && (rightColumns.cardinality() > 0)) {
      if ((leftUnique == null) || (rightUnique == null)) {
        return null;
      } else {
        return leftUnique && rightUnique;
      }
    }

    // If we're only trying to determine uniqueness for columns that
    // originate from one join input, then determine if the equijoin
    // columns from the other join input are unique.  If they are, then
    // the columns are unique for the entire join if they're unique for
    // the corresponding join input, provided that input is not null
    // generating.
    final JoinInfo joinInfo = rel.analyzeCondition();
    if (leftColumns.cardinality() > 0) {
      if (rel.getJoinType().generatesNullsOnLeft()) {
        return false;
      }
      Boolean rightJoinColsUnique =
          RelMetadataQuery.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls);
      if ((rightJoinColsUnique == null) || (leftUnique == null)) {
        return null;
      }
      return rightJoinColsUnique && leftUnique;
    } else if (rightColumns.cardinality() > 0) {
      if (rel.getJoinType().generatesNullsOnRight()) {
        return false;
      }
      Boolean leftJoinColsUnique =
          RelMetadataQuery.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls);
      if ((leftJoinColsUnique == null) || (rightUnique == null)) {
        return null;
      }
      return leftJoinColsUnique && rightUnique;
    }

    throw new AssertionError();
  }