/** * Returns true if a type is a simple cast of another type. It is if the cast type is nullable and * the cast is one of the following: * <li>x TO x * <li>char(n) TO varchar(m) * <li>varchar(n) TO varchar(m) * <li>x not null TO x nullable * * @param origType original type passed into the cast operand * @param castType type the operand will be casted to * @return true if the cast is simple */ private boolean isCastSimple(RelDataType origType, RelDataType castType) { SqlTypeName origTypeName = origType.getSqlTypeName(); SqlTypeName castTypeName = castType.getSqlTypeName(); if (!(castType.isNullable())) { return false; } Charset origCharset = origType.getCharset(); Charset castCharset = castType.getCharset(); if ((origCharset != null) || (castCharset != null)) { if ((origCharset == null) || (castCharset == null)) { return false; } if (!origCharset.equals(castCharset)) { return false; } } return ((origType == castType) || ((origTypeName == SqlTypeName.CHAR) && (castTypeName == SqlTypeName.VARCHAR)) || ((origTypeName == SqlTypeName.VARCHAR) && (castTypeName == SqlTypeName.VARCHAR)) || ((origTypeName == castTypeName) && (origType.getPrecision() == castType.getPrecision()) && ((origTypeName != SqlTypeName.DECIMAL) || (origType.getScale() == castType.getScale())) && (!origType.isNullable() && castType.isNullable()))); }
/** * 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)); }