/** * Determines whether a {@link RexCall} requires decimal expansion. It usually requires expansion * if it has decimal operands. * * <p>Exceptions to this rule are: * * <ul> * <li>isNull doesn't require expansion * <li>It's okay to cast decimals to and from char types * <li>It's okay to cast nulls as decimals * <li>Casts require expansion if their return type is decimal * <li>Reinterpret casts can handle a decimal operand * </ul> * * @param expr expression possibly in need of expansion * @param recurse whether to check nested calls * @return whether the expression requires expansion */ public static boolean requiresDecimalExpansion(RexNode expr, boolean recurse) { if (!(expr instanceof RexCall)) { return false; } RexCall call = (RexCall) expr; boolean localCheck = true; switch (call.getKind()) { case Reinterpret: case IsNull: localCheck = false; break; case Cast: RelDataType lhsType = call.getType(); RelDataType rhsType = call.operands[0].getType(); if (rhsType.getSqlTypeName() == SqlTypeName.NULL) { return false; } if (SqlTypeUtil.inCharFamily(lhsType) || SqlTypeUtil.inCharFamily(rhsType)) { localCheck = false; } else if (SqlTypeUtil.isDecimal(lhsType) && (lhsType != rhsType)) { return true; } break; default: localCheck = call.getOperator().requiresDecimalExpansion(); } if (localCheck) { if (SqlTypeUtil.isDecimal(call.getType())) { // NOTE jvs 27-Mar-2007: Depending on the type factory, the // result of a division may be decimal, even though both inputs // are integer. return true; } for (int i = 0; i < call.operands.length; i++) { if (SqlTypeUtil.isDecimal(call.operands[i].getType())) { return true; } } } return (recurse && requiresDecimalExpansion(call.operands, recurse)); }
/** * Replaces the operands of a call. The new operands' types must match the old operands' types. */ public static RexCall replaceOperands(RexCall call, RexNode[] operands) { if (call.operands == operands) { return call; } for (int i = 0; i < operands.length; i++) { RelDataType oldType = call.operands[i].getType(); RelDataType newType = operands[i].getType(); if (!oldType.isNullable() && newType.isNullable()) { throw Util.newInternal("invalid nullability"); } assert (oldType.toString().equals(newType.toString())); } return new RexCall(call.getType(), call.getOperator(), operands); }
public RexNode visitCall(RexCall call) { List<RexNode> normalizedOperands = new ArrayList<RexNode>(); int diffCount = 0; for (RexNode operand : call.getOperands()) { operand.accept(this); final RexNode normalizedOperand = lookup(operand); normalizedOperands.add(normalizedOperand); if (normalizedOperand != operand) { ++diffCount; } } if (diffCount > 0) { call = call.clone(call.getType(), normalizedOperands); } return register(call); }
// 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(); }