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);
          }
        }
    private void addResult(RexNode exp) {
      // Cast of literal can't be reduced, so skip those (otherwise we'd
      // go into an infinite loop as we add them back).
      if (exp.getKind() == RexKind.Cast) {
        RexCall cast = (RexCall) exp;
        RexNode operand = cast.getOperands()[0];
        if (operand instanceof RexLiteral) {
          return;
        }
      }
      constExprs.add(exp);

      // In the case where the expression corresponds to a UDR argument,
      // we need to preserve casts.  Note that this only applies to
      // the topmost argument, not expressions nested within the UDR
      // call.
      //
      // REVIEW zfong 6/13/08 - Are there other expressions where we
      // also need to preserve casts?
      if (parentCallTypeStack.isEmpty()) {
        addCasts.add(false);
      } else {
        addCasts.add(
            parentCallTypeStack.get(parentCallTypeStack.size() - 1)
                instanceof FarragoUserDefinedRoutine);
      }
    }
 // override RexShuttle
 public RexNode visitCall(final RexCall call) {
   int i = reducibleExps.indexOf(call);
   if (i == -1) {
     return super.visitCall(call);
   }
   RexNode replacement = reducedValues.get(i);
   if (addCasts.get(i) && (replacement.getType() != call.getType())) {
     // Handle change from nullable to NOT NULL by claiming
     // that the result is still nullable, even though
     // we know it isn't.
     //
     // Also, we cannot reduce CAST('abc' AS VARCHAR(4)) to 'abc'.
     // If we make 'abc' of type VARCHAR(4), we may later encounter
     // the same expression in a ProjectRel's digest where it has
     // type VARCHAR(3), and that's wrong.
     replacement = rexBuilder.makeCast(call.getType(), replacement);
   }
   return replacement;
 }
        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);
        }
    public void analyze(RexNode exp) {
      assert (stack.isEmpty());

      exp.accept(this);

      // Deal with top of stack
      assert (stack.size() == 1);
      assert (parentCallTypeStack.isEmpty());
      Constancy rootConstancy = stack.get(0);
      if (rootConstancy == Constancy.REDUCIBLE_CONSTANT) {
        // The entire subtree was constant, so add it to the result.
        addResult(exp);
      }
      stack.clear();
    }
コード例 #6
0
  protected void executeImpl() throws Exception {
    SqlCall call = (SqlCall) subq;
    SqlSelect select = (SqlSelect) call.getOperands()[0];

    // Convert the SqlNode tree to a RelNode tree; we need to do this
    // here so the RelNode tree is associated with the new preparing
    // stmt.
    FarragoPreparingStmt preparingStmt = (FarragoPreparingStmt) getPreparingStmt();
    SqlValidator validator = preparingStmt.getSqlValidator();
    SqlToRelConverter sqlConverter = preparingStmt.getSqlToRelConverter(validator, preparingStmt);
    preparingStmt.setParentStmt(FennelRelUtil.getPreparingStmt(parentConverter.getCluster()));

    // Add to the new converter any subqueries that have already been
    // converted by the parent so we can avoid re-executing them
    sqlConverter.addConvertedNonCorrSubqs(parentConverter.getMapConvertedNonCorrSubqs());
    RelNode plan = sqlConverter.convertQuery(select, true, true);

    // The subquery cannot have dynamic parameters
    if (sqlConverter.getDynamicParamCount() > 0) {
      failed = true;
      return;
    }

    List<RexNode> exprs = new ArrayList<RexNode>();
    RelDataType resultType = null;

    if (!isExists) {
      // Non-EXISTS subqueries need to be converted to single-value
      // subqueries
      plan = sqlConverter.convertToSingleValueSubq(select, plan);

      // Create a dummy expression to store the type of the result.
      // When setting the type, derive the type based on what a
      // scalar subquery should return and create the type from the
      // type factory of the parent query.
      resultType = call.getOperator().deriveType(validator, validator.getFromScope(select), call);
      resultType = rexBuilder.getTypeFactory().copyType(resultType);
      exprs.add(rexBuilder.makeInputRef(resultType, 0));
    }

    plan = sqlConverter.decorrelate(select, plan);

    // If the subquery is part of an EXPLAIN PLAN statement, don't
    // execute the subquery, but instead just return a dynamic parameter
    // as a placeholder for the subquery result.  Otherwise, execute
    // the query to produce the constant expression.  Cast the expression
    // as needed so the type matches the expected result type.
    RexNode constExpr;
    if (isExplain) {
      if (isExists) {
        resultType = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN);
      }
      constExpr =
          rexBuilder.makeDynamicParam(
              resultType, parentConverter.getDynamicParamCountInExplain(true));
      results.add(constExpr);
    } else {
      executePlan(plan, exprs, isExists, false);
      if (!failed && !isExists) {
        constExpr = results.get(0);
        if (constExpr.getType() != resultType) {
          constExpr = rexBuilder.makeCast(resultType, constExpr);
          results.set(0, constExpr);
        }
      }
    }
  }