public RelDataType inferReturnType(SqlOperatorBinding opBinding) { RelDataType type1 = opBinding.getOperandType(0); RelDataType type2 = opBinding.getOperandType(1); if (SqlTypeUtil.isExactNumeric(type1) && SqlTypeUtil.isExactNumeric(type2)) { if (SqlTypeUtil.isDecimal(type1) || SqlTypeUtil.isDecimal(type2)) { int p1 = type1.getPrecision(); int p2 = type2.getPrecision(); int s1 = type1.getScale(); int s2 = type2.getScale(); int scale = Math.max(s1, s2); assert scale <= SqlTypeName.MAX_NUMERIC_SCALE; int precision = Math.max(p1 - s1, p2 - s2) + scale + 1; precision = Math.min(precision, SqlTypeName.MAX_NUMERIC_PRECISION); assert precision > 0; RelDataType ret; ret = opBinding.getTypeFactory().createSqlType(SqlTypeName.DECIMAL, precision, scale); return ret; } } return null; }
/** * 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)); }
public RelDataType inferReturnType(SqlOperatorBinding opBinding) { RelDataType type1 = opBinding.getOperandType(0); if (SqlTypeUtil.isDecimal(type1)) { if (type1.getScale() == 0) { return type1; } else { int p = type1.getPrecision(); RelDataType ret; ret = opBinding.getTypeFactory().createSqlType(SqlTypeName.DECIMAL, p, 0); if (type1.isNullable()) { ret = opBinding.getTypeFactory().createTypeWithNullability(ret, true); } return ret; } } return null; }