Beispiel #1
0
 /** Returns whether a {@link RexProgram} contains expressions which require decimal expansion. */
 public static boolean requiresDecimalExpansion(RexProgram program, boolean recurse) {
   final List<RexNode> exprList = program.getExprList();
   for (RexNode expr : exprList) {
     if (requiresDecimalExpansion(expr, recurse)) {
       return true;
     }
   }
   return false;
 }
        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);
          }
        }
Beispiel #3
0
 /** Converts an expression from {@link RexNode} to {@link SqlNode} format. */
 SqlNode toSql(RexProgram program, RexNode rex) {
   if (rex instanceof RexLocalRef) {
     final int index = ((RexLocalRef) rex).getIndex();
     return toSql(program, program.getExprList().get(index));
   } else if (rex instanceof RexInputRef) {
     return field(((RexInputRef) rex).getIndex());
   } else if (rex instanceof RexLiteral) {
     final RexLiteral literal = (RexLiteral) rex;
     switch (literal.getTypeName().getFamily()) {
       case CHARACTER:
         return SqlLiteral.createCharString((String) literal.getValue2(), POS);
       case NUMERIC:
       case EXACT_NUMERIC:
         return SqlLiteral.createExactNumeric(literal.getValue().toString(), POS);
       case APPROXIMATE_NUMERIC:
         return SqlLiteral.createApproxNumeric(literal.getValue().toString(), POS);
       case BOOLEAN:
         return SqlLiteral.createBoolean((Boolean) literal.getValue(), POS);
       case DATE:
         return SqlLiteral.createDate((Calendar) literal.getValue(), POS);
       case TIME:
         return SqlLiteral.createTime(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case TIMESTAMP:
         return SqlLiteral.createTimestamp(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case ANY:
         switch (literal.getTypeName()) {
           case NULL:
             return SqlLiteral.createNull(POS);
             // fall through
         }
       default:
         throw new AssertionError(literal + ": " + literal.getTypeName());
     }
   } else if (rex instanceof RexCall) {
     final RexCall call = (RexCall) rex;
     final SqlOperator op = call.getOperator();
     final List<SqlNode> nodeList = toSql(program, call.getOperands());
     if (op == SqlStdOperatorTable.CAST) {
       RelDataType type = call.getType();
       if (type.getSqlTypeName() == SqlTypeName.VARCHAR
           && dialect.getDatabaseProduct() == SqlDialect.DatabaseProduct.MYSQL) {
         // MySQL doesn't have a VARCHAR type, only CHAR.
         nodeList.add(
             new SqlDataTypeSpec(
                 new SqlIdentifier("CHAR", POS), type.getPrecision(), -1, null, null, POS));
       } else {
         nodeList.add(toSql(type));
       }
     }
     if (op == SqlStdOperatorTable.CASE) {
       final SqlNode valueNode;
       final List<SqlNode> whenList = Expressions.list();
       final List<SqlNode> thenList = Expressions.list();
       final SqlNode elseNode;
       if (nodeList.size() % 2 == 0) {
         // switched:
         //   "case x when v1 then t1 when v2 then t2 ... else e end"
         valueNode = nodeList.get(0);
         for (int i = 1; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       } else {
         // other: "case when w1 then t1 when w2 then t2 ... else e end"
         valueNode = null;
         for (int i = 0; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       }
       elseNode = nodeList.get(nodeList.size() - 1);
       return op.createCall(
           POS,
           valueNode,
           new SqlNodeList(whenList, POS),
           new SqlNodeList(thenList, POS),
           elseNode);
     }
     if (op instanceof SqlBinaryOperator && nodeList.size() > 2) {
       // In RexNode trees, OR and AND have any number of children;
       // SqlCall requires exactly 2. So, convert to a left-deep binary tree.
       return createLeftCall(op, nodeList);
     }
     return op.createCall(new SqlNodeList(nodeList, POS));
   } else {
     throw new AssertionError(rex);
   }
 }