// implement RelOptRule
  public void onMatch(RelOptRuleCall call) {
    CalcRel calcRel = (CalcRel) call.rels[0];
    RexProgram program = calcRel.getProgram();

    // check the projection
    List<Integer> projOrdinals = new ArrayList<Integer>();
    RelDataType outputRowType = isProjectSimple(calcRel, projOrdinals);
    if (outputRowType == null) {
      return;
    }

    RexLocalRef condition = program.getCondition();
    CompOperatorEnum compOp = CompOperatorEnum.COMP_NOOP;
    Integer[] filterOrdinals = {};
    List<RexLiteral> filterLiterals = new ArrayList<RexLiteral>();

    // check the condition
    if (condition != null) {
      RexNode filterExprs = program.expandLocalRef(condition);
      List<Integer> filterList = new ArrayList<Integer>();

      List<CompOperatorEnum> op = new ArrayList<CompOperatorEnum>();
      if (!isConditionSimple(calcRel, filterExprs, filterList, filterLiterals, op)) {
        return;
      }

      compOp = op.get(0);
      filterOrdinals = filterList.toArray(new Integer[filterList.size()]);
    }

    RelNode fennelInput =
        mergeTraitsAndConvert(
            calcRel.getTraits(), FennelRel.FENNEL_EXEC_CONVENTION, calcRel.getChild());
    if (fennelInput == null) {
      return;
    }

    Integer[] projection = projOrdinals.toArray(new Integer[projOrdinals.size()]);
    FennelReshapeRel reshapeRel =
        new FennelReshapeRel(
            calcRel.getCluster(),
            fennelInput,
            projection,
            outputRowType,
            compOp,
            filterOrdinals,
            filterLiterals,
            new FennelRelParamId[] {},
            new Integer[] {},
            null);

    call.transformTo(reshapeRel);
  }
  /**
   * Determines if a filter condition is a simple one and returns the parameters corresponding to
   * the simple filters.
   *
   * @param calcRel original CalcRel
   * @param filterExprs filter expression being analyzed
   * @param filterList returns the list of filter ordinals in the simple expression
   * @param literals returns the list of literals to be used in the simple comparisons
   * @param op returns the operator to be used in the simple comparison
   * @return true if the filter condition is simple
   */
  private boolean isConditionSimple(
      CalcRel calcRel,
      RexNode filterExprs,
      List<Integer> filterList,
      List<RexLiteral> literals,
      List<CompOperatorEnum> op) {
    SargFactory sargFactory = new SargFactory(calcRel.getCluster().getRexBuilder());
    SargRexAnalyzer rexAnalyzer = sargFactory.newRexAnalyzer(true);
    List<SargBinding> sargBindingList = rexAnalyzer.analyzeAll(filterExprs);

    // Currently, it's all or nothing.  So, if there are filters rejected
    // by the analyzer, we can't process a subset using the reshape
    // exec stream
    if (rexAnalyzer.getNonSargFilterRexNode() != null) {
      return false;
    }

    List<RexInputRef> filterCols = new ArrayList<RexInputRef>();
    List<RexNode> filterOperands = new ArrayList<RexNode>();
    if (FennelRelUtil.extractSimplePredicates(sargBindingList, filterCols, filterOperands, op)) {
      for (RexInputRef filterCol : filterCols) {
        filterList.add(filterCol.getIndex());
      }
      for (RexNode operand : filterOperands) {
        literals.add((RexLiteral) operand);
      }
      return true;
    } else {
      return false;
    }
  }
  /**
   * Determines if a projection is simple.
   *
   * @param calcRel CalcRel containing the projection
   * @param projOrdinals if the projection is simple, returns the ordinals of the projection inputs
   * @return rowtype corresponding to the projection, provided it is simple; otherwise null is
   *     returned
   */
  private RelDataType isProjectSimple(CalcRel calcRel, List<Integer> projOrdinals) {
    // Loop through projection expressions.  If we find a non-simple
    // projection expression, simply return.
    RexProgram program = calcRel.getProgram();
    List<RexLocalRef> projList = program.getProjectList();
    int nProjExprs = projList.size();
    RelDataType[] types = new RelDataType[nProjExprs];
    String[] fieldNames = new String[nProjExprs];
    RelDataTypeField[] projFields = calcRel.getRowType().getFields();

    for (int i = 0; i < nProjExprs; i++) {
      RexNode projExpr = program.expandLocalRef(projList.get(i));
      if (projExpr instanceof RexInputRef) {
        projOrdinals.add(((RexInputRef) projExpr).getIndex());
        types[i] = projExpr.getType();
        fieldNames[i] = projFields[i].getName();
        continue;
      } else if (!(projExpr instanceof RexCall)) {
        return null;
      }

      RexCall rexCall = (RexCall) projExpr;
      if (rexCall.getOperator() != SqlStdOperatorTable.castFunc) {
        return null;
      }
      RexNode castOperand = rexCall.getOperands()[0];
      if (!(castOperand instanceof RexInputRef)) {
        return null;
      }
      RelDataType castType = projExpr.getType();
      RelDataType origType = castOperand.getType();
      if (isCastSimple(origType, castType)) {
        projOrdinals.add(((RexInputRef) castOperand).getIndex());
        types[i] = castType;
        fieldNames[i] = projFields[i].getName();
      } else {
        return null;
      }
    }

    // return the rowtype corresponding to the output of the projection
    return calcRel.getCluster().getTypeFactory().createStructType(types, fieldNames);
  }
示例#4
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);
  }
        public void onMatch(RelOptRuleCall call) {
          FilterRel filter = (FilterRel) call.rels[0];
          List<RexNode> expList = new ArrayList<RexNode>(Arrays.asList(filter.getChildExps()));
          RexNode newConditionExp;
          boolean reduced;
          if (reduceExpressions(filter, expList)) {
            assert (expList.size() == 1);
            newConditionExp = expList.get(0);
            reduced = true;
          } else {
            // No reduction, but let's still test the original
            // predicate to see if it was already a constant,
            // in which case we don't need any runtime decision
            // about filtering.
            newConditionExp = filter.getChildExps()[0];
            reduced = false;
          }
          if (newConditionExp.isAlwaysTrue()) {
            call.transformTo(filter.getChild());
          } else if ((newConditionExp instanceof RexLiteral)
              || RexUtil.isNullLiteral(newConditionExp, true)) {
            call.transformTo(new EmptyRel(filter.getCluster(), filter.getRowType()));
          } else if (reduced) {
            call.transformTo(CalcRel.createFilter(filter.getChild(), expList.get(0)));
          } else {
            if (newConditionExp instanceof RexCall) {
              RexCall rexCall = (RexCall) newConditionExp;
              boolean reverse = (rexCall.getOperator() == SqlStdOperatorTable.notOperator);
              if (reverse) {
                rexCall = (RexCall) rexCall.getOperands()[0];
              }
              reduceNotNullableFilter(call, filter, rexCall, reverse);
            }
            return;
          }

          // New plan is absolutely better than old plan.
          call.getPlanner().setImportance(filter, 0.0);
        }
 protected void executeImpl() throws Exception {
   RelNode oneRowRel = new OneRowRel(getPreparingStmt().getRelOptCluster());
   RelNode projectRel = CalcRel.createProject(oneRowRel, exprs, null);
   executePlan(projectRel, exprs, false, true);
 }
        public void onMatch(RelOptRuleCall call) {
          CalcRel calc = (CalcRel) call.getRels()[0];
          RexProgram program = calc.getProgram();
          final List<RexNode> exprList = program.getExprList();

          // Form a list of expressions with sub-expressions fully
          // expanded.
          final List<RexNode> expandedExprList = new ArrayList<RexNode>(exprList.size());
          final RexShuttle shuttle =
              new RexShuttle() {
                public RexNode visitLocalRef(RexLocalRef localRef) {
                  return expandedExprList.get(localRef.getIndex());
                }
              };
          for (RexNode expr : exprList) {
            expandedExprList.add(expr.accept(shuttle));
          }
          if (reduceExpressions(calc, expandedExprList)) {
            final RexProgramBuilder builder =
                new RexProgramBuilder(
                    calc.getChild().getRowType(), calc.getCluster().getRexBuilder());
            List<RexLocalRef> list = new ArrayList<RexLocalRef>();
            for (RexNode expr : expandedExprList) {
              list.add(builder.registerInput(expr));
            }
            if (program.getCondition() != null) {
              final int conditionIndex = program.getCondition().getIndex();
              final RexNode newConditionExp = expandedExprList.get(conditionIndex);
              if (newConditionExp.isAlwaysTrue()) {
                // condition is always TRUE - drop it
              } else if ((newConditionExp instanceof RexLiteral)
                  || RexUtil.isNullLiteral(newConditionExp, true)) {
                // condition is always NULL or FALSE - replace calc
                // with empty
                call.transformTo(new EmptyRel(calc.getCluster(), calc.getRowType()));
                return;
              } else {
                builder.addCondition(list.get(conditionIndex));
              }
            }
            int k = 0;
            for (RexLocalRef projectExpr : program.getProjectList()) {
              final int index = projectExpr.getIndex();
              builder.addProject(
                  list.get(index).getIndex(),
                  program.getOutputRowType().getFieldList().get(k++).getName());
            }
            call.transformTo(
                new CalcRel(
                    calc.getCluster(),
                    calc.getTraits(),
                    calc.getChild(),
                    calc.getRowType(),
                    builder.getProgram(),
                    calc.getCollationList()));

            // New plan is absolutely better than old plan.
            call.getPlanner().setImportance(calc, 0.0);
          }
        }