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);
      }
    }
 private void reduceNotNullableFilter(
     RelOptRuleCall call, FilterRel filter, RexCall rexCall, boolean reverse) {
   // If the expression is a IS [NOT] NULL on a non-nullable
   // column, then we can either remove the filter or replace
   // it with an EmptyRel.
   SqlOperator op = rexCall.getOperator();
   boolean alwaysTrue;
   if (op == SqlStdOperatorTable.isNullOperator
       || op == SqlStdOperatorTable.isUnknownOperator) {
     alwaysTrue = false;
   } else if (op == SqlStdOperatorTable.isNotNullOperator) {
     alwaysTrue = true;
   } else {
     return;
   }
   if (reverse) {
     alwaysTrue = !alwaysTrue;
   }
   RexNode operand = rexCall.getOperands()[0];
   if (operand instanceof RexInputRef) {
     RexInputRef inputRef = (RexInputRef) operand;
     if (!inputRef.getType().isNullable()) {
       if (alwaysTrue) {
         call.transformTo(filter.getChild());
       } else {
         call.transformTo(new EmptyRel(filter.getCluster(), filter.getRowType()));
       }
     }
   }
 }
Esempio n. 3
0
  private Expression translate0(RexNode expr) {
    if (expr instanceof RexInputRef) {
      // TODO: multiple inputs, e.g. joins
      final Expression input = getInput(0);
      final int index = ((RexInputRef) expr).getIndex();
      final List<RelDataTypeField> fields = program.getInputRowType().getFieldList();
      final RelDataTypeField field = fields.get(index);
      if (fields.size() == 1) {
        return input;
      } else if (input.getType() == Object[].class) {
        return Expressions.convert_(
            Expressions.arrayIndex(input, Expressions.constant(field.getIndex())),
            Types.box(JavaRules.EnumUtil.javaClass(typeFactory, field.getType())));
      } else {
        return Expressions.field(input, field.getName());
      }
    }
    if (expr instanceof RexLocalRef) {
      return translate(program.getExprList().get(((RexLocalRef) expr).getIndex()));
    }
    if (expr instanceof RexLiteral) {
      return Expressions.constant(
          ((RexLiteral) expr).getValue(), typeFactory.getJavaClass(expr.getType()));
    }
    if (expr instanceof RexCall) {
      final RexCall call = (RexCall) expr;
      final SqlOperator operator = call.getOperator();
      final ExpressionType expressionType = SQL_TO_LINQ_OPERATOR_MAP.get(operator);
      if (expressionType != null) {
        switch (operator.getSyntax()) {
          case Binary:
            return Expressions.makeBinary(
                expressionType, translate(call.getOperands()[0]), translate(call.getOperands()[1]));
          case Postfix:
          case Prefix:
            return Expressions.makeUnary(expressionType, translate(call.getOperands()[0]));
          default:
            throw new RuntimeException("unknown syntax " + operator.getSyntax());
        }
      }

      Method method = SQL_OP_TO_JAVA_METHOD_MAP.get(operator);
      if (method != null) {
        List<Expression> exprs = translateList(Arrays.asList(call.operands));
        return !Modifier.isStatic(method.getModifiers())
            ? Expressions.call(exprs.get(0), method, exprs.subList(1, exprs.size()))
            : Expressions.call(method, exprs);
      }

      switch (expr.getKind()) {
        default:
          throw new RuntimeException("cannot translate expression " + expr);
      }
    }
    throw new RuntimeException("cannot translate expression " + expr);
  }
  public Boolean areColumnsUnique(ProjectRelBase rel, BitSet columns, boolean ignoreNulls) {
    // ProjectRel maps a set of rows to a different set;
    // Without knowledge of the mapping function(whether it
    // preserves uniqueness), it is only safe to derive uniqueness
    // info from the child of a project when the mapping is f(a) => a.
    //
    // Also need to map the input column set to the corresponding child
    // references

    List<RexNode> projExprs = rel.getProjects();
    BitSet childColumns = new BitSet();
    for (int bit : BitSets.toIter(columns)) {
      RexNode projExpr = projExprs.get(bit);
      if (projExpr instanceof RexInputRef) {
        childColumns.set(((RexInputRef) projExpr).getIndex());
      } else if (projExpr instanceof RexCall && ignoreNulls) {
        // If the expression is a cast such that the types are the same
        // except for the nullability, then if we're ignoring nulls,
        // it doesn't matter whether the underlying column reference
        // is nullable.  Check that the types are the same by making a
        // nullable copy of both types and then comparing them.
        RexCall call = (RexCall) projExpr;
        if (call.getOperator() != SqlStdOperatorTable.CAST) {
          continue;
        }
        RexNode castOperand = call.getOperands().get(0);
        if (!(castOperand instanceof RexInputRef)) {
          continue;
        }
        RelDataTypeFactory typeFactory = rel.getCluster().getTypeFactory();
        RelDataType castType = typeFactory.createTypeWithNullability(projExpr.getType(), true);
        RelDataType origType = typeFactory.createTypeWithNullability(castOperand.getType(), true);
        if (castType.equals(origType)) {
          childColumns.set(((RexInputRef) castOperand).getIndex());
        }
      } else {
        // If the expression will not influence uniqueness of the
        // projection, then skip it.
        continue;
      }
    }

    // If no columns can affect uniqueness, then return unknown
    if (childColumns.cardinality() == 0) {
      return null;
    }

    return RelMetadataQuery.areColumnsUnique(rel.getChild(), childColumns, ignoreNulls);
  }
Esempio n. 5
0
    // implement CallConvertlet
    public void convert(RexCall call) {
      // REVIEW jvs 18-Mar-2006:  The test for variableSeen
      // here and elsewhere precludes predicates like where
      // (boolean_col AND (int_col > 10)).  Should probably
      // support bare boolean columns as predicates with
      // coordinate TRUE.

      if (variableSeen || (coordinate != null)) {
        failed = true;
      }

      if (failed) {
        return;
      }

      int nOperands = call.getOperands().size();
      assert (exprStack.size() >= nOperands);

      SargSetExpr expr = factory.newSetExpr(boundInputRef.getType(), setOp);

      // Pop the correct number of operands off the stack
      // and transfer them to the new set expression.
      ListIterator<SargExpr> iter = exprStack.listIterator(exprStack.size() - nOperands);
      while (iter.hasNext()) {
        expr.addChild(iter.next());
        iter.remove();
      }

      exprStack.add(expr);
    }
    private void analyzeCall(RexCall call, Constancy callConstancy) {
      parentCallTypeStack.add(call.getOperator());

      // visit operands, pushing their states onto stack
      super.visitCall(call);

      // look for NON_CONSTANT operands
      int nOperands = call.getOperands().length;
      List<Constancy> operandStack = stack.subList(stack.size() - nOperands, stack.size());
      for (Constancy operandConstancy : operandStack) {
        if (operandConstancy == Constancy.NON_CONSTANT) {
          callConstancy = Constancy.NON_CONSTANT;
        }
      }

      // Even if all operands are constant, the call itself may
      // be non-deterministic.
      if (!call.getOperator().isDeterministic()) {
        callConstancy = Constancy.NON_CONSTANT;
      } else if (call.getOperator().isDynamicFunction()) {
        // We can reduce the call to a constant, but we can't
        // cache the plan if the function is dynamic
        preparingStmt.disableStatementCaching();
      }

      // Row operator itself can't be reduced to a literal, but if
      // the operands are constants, we still want to reduce those
      if ((callConstancy == Constancy.REDUCIBLE_CONSTANT)
          && (call.getOperator() instanceof SqlRowOperator)) {
        callConstancy = Constancy.NON_CONSTANT;
      }

      if (callConstancy == Constancy.NON_CONSTANT) {
        // any REDUCIBLE_CONSTANT children are now known to be maximal
        // reducible subtrees, so they can be added to the result
        // list
        for (int iOperand = 0; iOperand < nOperands; ++iOperand) {
          Constancy constancy = operandStack.get(iOperand);
          if (constancy == Constancy.REDUCIBLE_CONSTANT) {
            addResult(call.getOperands()[iOperand]);
          }
        }

        // if this cast expression can't be reduced to a literal,
        // then see if we can remove the cast
        if (call.getOperator() == SqlStdOperatorTable.castFunc) {
          reduceCasts(call);
        }
      }

      // pop operands off of the stack
      operandStack.clear();

      // pop this parent call operator off the stack
      parentCallTypeStack.remove(parentCallTypeStack.size() - 1);

      // push constancy result for this call onto stack
      stack.add(callConstancy);
    }
  /**
   * 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);
  }
 // 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;
 }
Esempio n. 9
0
    public Void visitCall(RexCall call) {
      CallConvertlet convertlet = convertletMap.get(call.getOperator());
      if (convertlet == null) {
        failed = true;
        return null;
      }

      // visit operands first
      super.visitCall(call);

      convertlet.convert(call);
      return null;
    }
        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);
        }
    private void reduceCasts(RexCall outerCast) {
      RexNode[] operands = outerCast.getOperands();
      if (operands.length != 1) {
        return;
      }
      RelDataType outerCastType = outerCast.getType();
      RelDataType operandType = operands[0].getType();
      if (operandType.equals(outerCastType)) {
        removableCasts.add(outerCast);
        return;
      }

      // See if the reduction
      // CAST((CAST x AS type) AS type NOT NULL)
      // -> CAST(x AS type NOT NULL)
      // applies.  TODO jvs 15-Dec-2008:  consider
      // similar cases for precision changes.
      if (!(operands[0] instanceof RexCall)) {
        return;
      }
      RexCall innerCast = (RexCall) operands[0];
      if (innerCast.getOperator() != SqlStdOperatorTable.castFunc) {
        return;
      }
      if (innerCast.getOperands().length != 1) {
        return;
      }
      RelDataTypeFactory typeFactory = preparingStmt.getFarragoTypeFactory();
      RelDataType outerTypeNullable = typeFactory.createTypeWithNullability(outerCastType, true);
      RelDataType innerTypeNullable = typeFactory.createTypeWithNullability(operandType, true);
      if (outerTypeNullable != innerTypeNullable) {
        return;
      }
      if (operandType.isNullable()) {
        removableCasts.add(innerCast);
      }
    }
  // implement FarragoOJRexImplementor
  public Expression implementFarrago(
      FarragoRexToOJTranslator translator, RexCall call, Expression[] operands) {
    RelDataType lhsType = call.getType();
    RelDataType rhsType = call.operands[0].getType();
    Expression rhsExp = operands[0];

    SqlTypeName lhsTypeName = lhsType.getSqlTypeName();
    if ((lhsTypeName == SqlTypeName.CURSOR) || (lhsTypeName == SqlTypeName.COLUMN_LIST)) {
      // Conversion should already have been taken care of outside.
      return rhsExp;
    }

    // NOTE jvs 19-Nov-2008:  In some cases (e.g. FRG-273) a cast
    // may be illegal at the SQL level, but allowable as part of
    // implementation, so don't try to enforce
    // SqlTypeUtil.canCastFrom here.  Anything which was supposed
    // to have been prevented should already have been caught
    // by the validator.

    CastHelper helper =
        new CastHelper(translator, null, call.toString(), lhsType, rhsType, null, rhsExp);

    return helper.implement();
  }
Esempio n. 13
0
    // implement CallConvertlet
    public void convert(RexCall call) {
      if (!variableSeen) {
        failed = true;
      }

      SqlOperator op = call.getOperator();
      if ((op == SqlStdOperatorTable.isNullOperator)
          || (op == SqlStdOperatorTable.isUnknownOperator)) {
        coordinate = factory.getRexBuilder().constantNull();
      } else if (op == SqlStdOperatorTable.isTrueOperator) {
        coordinate = factory.getRexBuilder().makeLiteral(true);
      } else if (op == SqlStdOperatorTable.isFalseOperator) {
        coordinate = factory.getRexBuilder().makeLiteral(false);
      } else if (coordinate == null) {
        failed = true;
      }

      if (failed) {
        return;
      }

      SargIntervalExpr expr = factory.newIntervalExpr(boundInputRef.getType());

      if (boundType == null) {
        expr.setPoint(coordinate);
      } else {
        SargBoundType actualBound = boundType;
        if (reverse) {
          if (actualBound == SargBoundType.LOWER) {
            actualBound = SargBoundType.UPPER;
          } else {
            actualBound = SargBoundType.LOWER;
          }
        }
        if (actualBound == SargBoundType.LOWER) {
          expr.setLower(coordinate, strictness);
        } else {
          expr.setUpper(coordinate, strictness);
        }
      }
      exprStack.add(expr);

      clearLeaf();
    }
Esempio n. 14
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);
   }
 }
Esempio n. 15
0
    @Override
    public TupleFilter visitCall(RexCall call) {
      TupleFilter filter = null;
      SqlOperator op = call.getOperator();
      switch (op.getKind()) {
        case AND:
          filter = new LogicalTupleFilter(FilterOperatorEnum.AND);
          break;
        case OR:
          filter = new LogicalTupleFilter(FilterOperatorEnum.OR);
          break;
        case NOT:
          filter = new LogicalTupleFilter(FilterOperatorEnum.NOT);
          break;
        case EQUALS:
          filter = new CompareTupleFilter(FilterOperatorEnum.EQ);
          break;
        case GREATER_THAN:
          filter = new CompareTupleFilter(FilterOperatorEnum.GT);
          break;
        case LESS_THAN:
          filter = new CompareTupleFilter(FilterOperatorEnum.LT);
          break;
        case GREATER_THAN_OR_EQUAL:
          filter = new CompareTupleFilter(FilterOperatorEnum.GTE);
          break;
        case LESS_THAN_OR_EQUAL:
          filter = new CompareTupleFilter(FilterOperatorEnum.LTE);
          break;
        case NOT_EQUALS:
          filter = new CompareTupleFilter(FilterOperatorEnum.NEQ);
          break;
        case IS_NULL:
          filter = new CompareTupleFilter(FilterOperatorEnum.ISNULL);
          break;
        case IS_NOT_NULL:
          filter = new CompareTupleFilter(FilterOperatorEnum.ISNOTNULL);
          break;
        case CAST:
        case REINTERPRET:
          // NOTE: use child directly
          break;
        case CASE:
          filter = new CaseTupleFilter();
          break;
        case OTHER:
          if (op.getName().equalsIgnoreCase("extract_date")) {
            filter = new ExtractTupleFilter(FilterOperatorEnum.EXTRACT);
          } else {
            throw new UnsupportedOperationException(op.getName());
          }
          break;
        default:
          throw new UnsupportedOperationException(op.getName());
      }

      for (RexNode operand : call.operands) {
        TupleFilter childFilter = operand.accept(this);
        if (filter == null) {
          filter = childFilter;
        } else {
          filter.addChild(childFilter);
        }
      }

      if (op.getKind() == SqlKind.OR) {
        CompareTupleFilter inFilter = mergeToInClause(filter);
        if (inFilter != null) {
          filter = inFilter;
        }
      }
      return filter;
    }
  /**
   * 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;
  }