@Override public boolean canConvertFrom(Type otherType) { if (otherType.typeCode == Types.SQL_ALL_TYPES) { return true; } if (otherType.isNumberType()) { return true; } if (otherType.isIntervalType()) { return true; } if (otherType.isCharacterType()) { return true; } return false; }
@Override public Object convertToType(SessionInterface session, Object a, Type otherType) { if (a == null) { return a; } if (otherType.typeCode == typeCode) { switch (typeCode) { case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: if (otherType.scale == scale && otherType.precision <= precision) { return a; } break; default: return a; } } if (otherType.isIntervalType()) { int endType = ((IntervalType) otherType).endIntervalType; switch (endType) { case Types.SQL_INTERVAL_YEAR: case Types.SQL_INTERVAL_MONTH: case Types.SQL_INTERVAL_DAY: case Types.SQL_INTERVAL_HOUR: case Types.SQL_INTERVAL_MINUTE: { Long value = ValuePool.getLong(((IntervalType) otherType).convertToLong(a)); return convertToType(session, value, Type.SQL_BIGINT); } case Types.SQL_INTERVAL_SECOND: { long seconds = ((IntervalSecondData) a).units; long nanos = ((IntervalSecondData) a).nanos; BigDecimal value = ((DTIType) otherType).getSecondPart(seconds, nanos); return value; } } } switch (otherType.typeCode) { case Types.SQL_CLOB: a = ((ClobData) a).getSubString(session, 0L, (int) ((ClobData) a).length(session)); // fall through case Types.SQL_CHAR: case Types.SQL_VARCHAR: case Types.VARCHAR_IGNORECASE: { a = session.getScanner().convertToNumber((String) a, this); return convertToDefaultType(session, a); } case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: case Types.SQL_BIGINT: case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: break; default: throw Error.error(ErrorCode.X_42561); } switch (this.typeCode) { case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: return convertToInt(a, this.typeCode); case Types.SQL_BIGINT: return convertToLong(a); case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: return convertToDouble(a); case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: BigDecimal value = convertToDecimal(a); return convertToTypeLimits(session, value); default: throw Error.error(ErrorCode.X_42561); } }
/** * Returns a SQL type "wide" enough to represent the result of the expression.<br> * A type is "wider" than the other if it can represent all its numeric values.<br> * Arithmetic operation terms are promoted to a type that can represent the resulting values and * avoid incorrect results. * * <p>FLOAT/REAL/DOUBLE used in an operation results in the same type, regardless of the type of * the other operand. When the result or the expression is converted to the type of the target * column for storage, an exception is thrown if the resulting value cannot be stored in the * column * * <p>Types narrower than INTEGER (int) are promoted to INTEGER. The order of promotion is as * follows * * <p>INTEGER, BIGINT, NUMERIC/DECIMAL * * <p>TINYINT and SMALLINT in any combination return INTEGER<br> * TINYINT/SMALLINT/INTEGER and INTEGER return BIGINT<br> * TINYINT/SMALLINT/INTEGER and BIGINT return NUMERIC/DECIMAL<br> * BIGINT and BIGINT return NUMERIC/DECIMAL<br> * REAL/FLOAT/DOUBLE and any type return REAL/FLOAT/DOUBLE<br> * NUMERIC/DECIMAL any type other than REAL/FLOAT/DOUBLE returns NUMERIC/DECIMAL<br> * In the case of NUMERIC/DECIMAL returned, the result precision is always large enough to express * any value result, while the scale depends on the operation:<br> * For ADD/SUBTRACT/DIVIDE, the scale is the larger of the two<br> * For MULTIPLY, the scale is the sum of the two scales<br> */ @Override public Type getCombinedType(Type other, int operation) { if (other.typeCode == Types.SQL_ALL_TYPES) { other = this; } switch (operation) { case OpTypes.ADD: break; case OpTypes.MULTIPLY: if (other.isIntervalType()) { return other.getCombinedType(this, OpTypes.MULTIPLY); } break; case OpTypes.DIVIDE: case OpTypes.SUBTRACT: default: // all derivatives of equality ops or comparison ops return getAggregateType(other); } // resolution for ADD and MULTIPLY only if (!other.isNumberType()) { throw Error.error(ErrorCode.X_42562); } if (typeWidth == DOUBLE_WIDTH || ((NumberType) other).typeWidth == DOUBLE_WIDTH) { return Type.SQL_DOUBLE; } int sum = typeWidth + ((NumberType) other).typeWidth; if (sum <= INTEGER_WIDTH) { return Type.SQL_INTEGER; } if (sum <= BIGINT_WIDTH) { return Type.SQL_BIGINT; } int newScale; long newDigits; switch (operation) { // case OpCodes.DIVIDE : // case OpCodes.SUBTRACT : case OpTypes.ADD: newScale = scale > other.scale ? scale : other.scale; newDigits = precision - scale > other.precision - other.scale ? precision - scale : other.precision - other.scale; newDigits++; break; case OpTypes.MULTIPLY: newDigits = precision - scale + other.precision - other.scale; newScale = scale + other.scale; break; default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } return getNumberType(Types.SQL_DECIMAL, newScale + newDigits, newScale); }