public static NumberType getNumberType(int type, long precision, int scale) { switch (type) { case Types.SQL_INTEGER: return SQL_INTEGER; case Types.SQL_SMALLINT: return SQL_SMALLINT; case Types.SQL_BIGINT: return SQL_BIGINT; case Types.TINYINT: return TINYINT; case Types.SQL_REAL: case Types.SQL_DOUBLE: case Types.SQL_FLOAT: return SQL_DOUBLE; case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: return new NumberType(type, precision, scale); default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
/** Returns decimal precision for NUMERIC/DECIMAL. Returns binary precision for other parts. */ public int getPrecision() { switch (typeCode) { case Types.TINYINT: return 1; case Types.SQL_SMALLINT: return 2; case Types.SQL_INTEGER: return 4; case Types.SQL_BIGINT: return 8; case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: return 8; case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: return (int) precision; default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
@Override public String getNameString() { switch (typeCode) { case Types.TINYINT: return Tokens.T_TINYINT; case Types.SQL_SMALLINT: return Tokens.T_SMALLINT; case Types.SQL_INTEGER: return Tokens.T_INTEGER; case Types.SQL_BIGINT: return Tokens.T_BIGINT; case Types.SQL_REAL: return Tokens.T_REAL; case Types.SQL_FLOAT: return Tokens.T_FLOAT; case Types.SQL_DOUBLE: return Tokens.T_DOUBLE; case Types.SQL_NUMERIC: return Tokens.T_NUMERIC; case Types.SQL_DECIMAL: return Tokens.T_DECIMAL; default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
/** * relaxes the SQL standard list to avoid problems with covnersion of literals and java method * parameter type issues */ public int precedenceDegree(Type other) { if (other.typeCode == typeCode) { return 0; } if (!other.isBinaryType()) { return Integer.MIN_VALUE; } switch (typeCode) { case Types.SQL_BIT: case Types.SQL_BIT_VARYING: return Integer.MIN_VALUE; case Types.SQL_BINARY: return other.typeCode == Types.SQL_BLOB ? 4 : 2; case Types.SQL_VARBINARY: return other.typeCode == Types.SQL_BLOB ? 4 : 2; case Types.SQL_BLOB: return other.typeCode == Types.SQL_BINARY ? -4 : -2; default: throw Error.runtimeError(ErrorCode.U_S0500, "CharacterType"); } }
public boolean isNegative(Object a) { if (a == null) { return false; } switch (typeCode) { case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: { double ad = ((Number) a).doubleValue(); return ad < 0; } case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: return ((BigDecimal) a).signum() < 0; case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: return ((Number) a).intValue() < 0; case Types.SQL_BIGINT: return ((Number) a).longValue() < 0; default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
public final RowIterator rowIterator() { if (indexList.length == 0 || indexList[0] == null) { throw Error.runtimeError(ErrorCode.U_S0500, "RowStoreAV"); } return indexList[0].firstRow(this); }
public CachedObject getAccessor(Index key) { int position = key.getPosition(); if (position >= accessorList.length) { throw Error.runtimeError(ErrorCode.U_S0500, "RowStoreAV"); } return accessorList[position]; }
static { try { BYTES_NULL = "NULL".getBytes("ISO-8859-1"); BYTES_TRUE = "TRUE".getBytes("ISO-8859-1"); BYTES_FALSE = "FALSE".getBytes("ISO-8859-1"); BYTES_AND = " AND ".getBytes("ISO-8859-1"); BYTES_IS = " IS ".getBytes("ISO-8859-1"); } catch (UnsupportedEncodingException e) { Error.runtimeError(ErrorCode.U_S0500, "RowOutputTextLog"); } }
@Override public Object add(Object a, Object b, Type otherType) { if (a == null || b == null) { return null; } switch (typeCode) { case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: { double ad = ((Number) a).doubleValue(); double bd = ((Number) b).doubleValue(); return ValuePool.getDouble(Double.doubleToLongBits(ad + bd)); // return new Double(ad + bd); } case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: { a = convertToDefaultType(null, a); b = convertToDefaultType(null, b); BigDecimal abd = (BigDecimal) a; BigDecimal bbd = (BigDecimal) b; return abd.add(bbd); } case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: { int ai = ((Number) a).intValue(); int bi = ((Number) b).intValue(); return ValuePool.getInt(ai + bi); } case Types.SQL_BIGINT: { long longa = ((Number) a).longValue(); long longb = ((Number) b).longValue(); return ValuePool.getLong(longa + longb); } default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
/** @todo check and adjust max precision */ public static BinaryType getBinaryType(int type, long precision) { switch (type) { case Types.SQL_BINARY: case Types.SQL_VARBINARY: return new BinaryType(type, precision); case Types.SQL_BLOB: return new BlobType(precision); default: throw Error.runtimeError(ErrorCode.U_S0500, "BinaryType"); } }
public BlobData overlay( Session session, BlobData data, BlobData overlay, long offset, long length, boolean hasLength) { if (data == null || overlay == null) { return null; } if (!hasLength) { length = ((BlobData) overlay).length(session); } switch (typeCode) { case Types.SQL_BINARY: case Types.SQL_VARBINARY: { BinaryData binary = new BinaryData(session, substring(session, data, 0, offset, true), overlay); binary = new BinaryData(session, binary, substring(session, data, offset + length, 0, false)); return binary; } case Types.SQL_BLOB: { byte[] bytes = substring(session, data, 0, offset, false).getBytes(); long blobLength = data.length(session) + overlay.length(session) - length; BlobData blob = session.createBlob(blobLength); blob.setBytes(session, 0, bytes); blob.setBytes(session, blob.length(session), overlay.getBytes()); bytes = substring(session, data, offset + length, 0, false).getBytes(); blob.setBytes(session, blob.length(session), bytes); return blob; } default: throw Error.runtimeError(ErrorCode.U_S0500, "BinaryType"); } }
private static BigDecimal convertToDecimal(Object a) { if (a instanceof BigDecimal) { return (BigDecimal) a; } else if (a instanceof Integer || a instanceof Long) { return BigDecimal.valueOf(((Number) a).longValue()); } else if (a instanceof Double) { double value = ((Number) a).doubleValue(); if (Double.isInfinite(value) || Double.isNaN(value)) { return null; } return new BigDecimal(value); } else { throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
@Override public int displaySize() { switch (typeCode) { case Types.SQL_DECIMAL: case Types.SQL_NUMERIC: if (scale == 0) { if (precision == 0) { return 646456995; // precision + "-.".length()} } return (int) precision + 1; } if (precision == scale) { return (int) precision + 3; } return (int) precision + 2; case Types.SQL_FLOAT: case Types.SQL_REAL: case Types.SQL_DOUBLE: return 23; // String.valueOf(-Double.MAX_VALUE).length(); case Types.SQL_BIGINT: return 20; // decimal precision + "-".length(); case Types.SQL_INTEGER: return 11; // decimal precision + "-".length(); case Types.SQL_SMALLINT: return 6; // decimal precision + "-".length(); case Types.TINYINT: return 4; // decimal precision + "-".length(); default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
/** @todo - review usage to see if range enforcement / java type conversion is necessary */ @Override public Object convertToTypeLimits(SessionInterface session, Object a) { if (a == null) { return null; } switch (typeCode) { case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: case Types.SQL_BIGINT: return a; case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: return a; case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: BigDecimal dec = (BigDecimal) a; if (scale != dec.scale()) { dec = dec.setScale(scale, BigDecimal.ROUND_HALF_DOWN); } int valuePrecision = JavaSystem.precision(dec); if (valuePrecision > precision) { throw Error.error(ErrorCode.X_22003); } return dec; default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
@Override public String getJDBCClassName() { switch (typeCode) { case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: case Types.SQL_BIGINT: return "java.lang.Integer"; case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: return "java.lang.Double"; case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: return "java.math.BigDecimal"; default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
public int compareToZero(Object a) { if (a == null) { return 0; } switch (typeCode) { case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: { double ad = ((Number) a).doubleValue(); return ad == 0 ? 0 : ad < 0 ? -1 : 1; } case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: return ((BigDecimal) a).signum(); case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: { int ai = ((Number) a).intValue(); return ai == 0 ? 0 : ai < 0 ? -1 : 1; } case Types.SQL_BIGINT: { long al = ((Number) a).longValue(); return al == 0 ? 0 : al < 0 ? -1 : 1; } default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
public int compare(Object a, Object b) { if (a == b) { return 0; } if (a == null) { return -1; } if (b == null) { return 1; } if (a instanceof BinaryData && b instanceof BinaryData) { byte[] data1 = ((BinaryData) a).getBytes(); byte[] data2 = ((BinaryData) b).getBytes(); int length = data1.length > data2.length ? data2.length : data1.length; for (int i = 0; i < length; i++) { if (data1[i] == data2[i]) { continue; } return (((int) data1[i]) & 0xff) > (((int) data2[i]) & 0xff) ? 1 : -1; } if (data1.length == data2.length) { return 0; } return data1.length > data2.length ? 1 : -1; } throw Error.runtimeError(ErrorCode.U_S0500, "BinaryType"); }
public NumberType(int type, long precision, int scale) { super(Types.SQL_NUMERIC, type, precision, scale); switch (type) { case Types.TINYINT: typeWidth = TINYINT_WIDTH; break; case Types.SQL_SMALLINT: typeWidth = SMALLINT_WIDTH; break; case Types.SQL_INTEGER: typeWidth = INTEGER_WIDTH; break; case Types.SQL_BIGINT: typeWidth = BIGINT_WIDTH; break; case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: typeWidth = DOUBLE_WIDTH; break; case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: typeWidth = DECIMAL_WIDTH; break; default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
@Override public int compare(Object a, Object b) { if (a == b) { return 0; } if (a == null) { return -1; } if (b == null) { return 1; } switch (typeCode) { case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: { if (b instanceof Integer) { int ai = ((Number) a).intValue(); int bi = ((Number) b).intValue(); return (ai > bi) ? 1 : (bi > ai ? -1 : 0); } else if (b instanceof Double) { double ai = ((Number) a).doubleValue(); double bi = ((Number) b).doubleValue(); return (ai > bi) ? 1 : (bi > ai ? -1 : 0); } else if (b instanceof BigDecimal) { BigDecimal ad = convertToDecimal(a); int i = ad.compareTo((BigDecimal) b); return (i == 0) ? 0 : (i < 0 ? -1 : 1); } } // fall through case Types.SQL_BIGINT: { if (b instanceof Long) { long longa = ((Number) a).longValue(); long longb = ((Number) b).longValue(); return (longa > longb) ? 1 : (longb > longa ? -1 : 0); } else if (b instanceof Double) { BigDecimal ad = BigDecimal.valueOf(((Number) a).longValue()); BigDecimal bd = new BigDecimal(((Double) b).doubleValue()); int i = ad.compareTo(bd); return (i == 0) ? 0 : (i < 0 ? -1 : 1); } else if (b instanceof BigDecimal) { BigDecimal ad = BigDecimal.valueOf(((Number) a).longValue()); int i = ad.compareTo((BigDecimal) b); return (i == 0) ? 0 : (i < 0 ? -1 : 1); } } // fall through case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: { /** @todo big-decimal etc */ double ad = ((Number) a).doubleValue(); double bd = ((Number) b).doubleValue(); return (ad > bd) ? 1 : (bd > ad ? -1 : 0); } case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: { BigDecimal bd = convertToDecimal(b); int i = ((BigDecimal) a).compareTo(bd); return (i == 0) ? 0 : (i < 0 ? -1 : 1); } default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
/** * 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); }
@Override public String convertToString(Object a) { if (a == null) { return null; } switch (this.typeCode) { case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: case Types.SQL_BIGINT: return a.toString(); case Types.SQL_REAL: case Types.SQL_DOUBLE: double value = ((Double) a).doubleValue(); /** @todo - java 5 format change */ if (value == Double.NEGATIVE_INFINITY) { return "-1E0/0"; } if (value == Double.POSITIVE_INFINITY) { return "1E0/0"; } if (Double.isNaN(value)) { return "0E0/0E0"; } // START of VoltDB patch to comply literally with the SQL standard requirement // that 0.0 be represented as a special cased "0E0" // and NOT "0.0E0" as HSQL had been giving. if (value == 0.0) { return "0E0"; } // END of VoltDB patch. String s = Double.toString(value); // ensure the engine treats the value as a DOUBLE, not DECIMAL if (s.indexOf('E') < 0) { // START of VoltDB patch to ALWAYS use proper E notation, // with a proper single-non-zero-digit integer part. // HSQL originally just had: s = s.concat("E0"); int decimalOffset = s.indexOf('.'); String optionalSign = (value < 0.0 ? "-" : ""); int leadingNonZeroOffset; String decimalPart; int exponent; if (value > -10.0 && value < 10.0) { if (value <= -1.0 || value >= 1.0) { // OK -- exactly 1 leading digit. Done. s = s.concat("E0"); return s; } // A zero leading digit, and maybe more zeros after the decimal. // Search for a significant digit past the decimal point. for (leadingNonZeroOffset = decimalOffset + 1; leadingNonZeroOffset < s.length(); ++leadingNonZeroOffset) { if (s.charAt(leadingNonZeroOffset) != '0') { break; } } // Count 1 for the leading 0 but not for the decimal point. exponent = decimalOffset - leadingNonZeroOffset; // Since exact 0.0 was eliminated earlier, // s.charAt(leadingNonZeroOffset) must be our leading non-zero digit. // Rewrite 0.[0]*nn* as n.n*E-x where x is the number of leading zeros found // BUT rewrite 0.[0]*n as n.0E-x where x is the number of leading zeros found. if (leadingNonZeroOffset + 1 == s.length()) { decimalPart = "0"; } else { decimalPart = s.substring(leadingNonZeroOffset + 1); } } else { // Too many leading digits. leadingNonZeroOffset = optionalSign.length(); // Set the exponent to how far the original decimal point was from its target // position, just after the leading digit. This is also the length of the // string of extra integer part digits that need to be moved into the decimal part. exponent = decimalOffset - (leadingNonZeroOffset + 1); decimalPart = s.substring(leadingNonZeroOffset + 1, exponent) + s.substring(decimalOffset + 1); // Trim any trailing zeros from the result. int lastIndex; for (lastIndex = decimalPart.length() - 1; lastIndex > 0; --lastIndex) { if (decimalPart.charAt(lastIndex) != '0') { break; } } if (lastIndex > 0 && decimalPart.charAt(lastIndex) == '0') { decimalPart = decimalPart.substring(lastIndex); } } s = optionalSign + s.charAt(leadingNonZeroOffset) + "." + decimalPart + "E" + exponent; // END of VoltDB patch to use proper E notation, } return s; case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: return JavaSystem.toString((BigDecimal) a); default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
@Override public Object divide(Object a, Object b) { if (a == null || b == null) { return null; } switch (typeCode) { case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: { double ad = ((Number) a).doubleValue(); double bd = ((Number) b).doubleValue(); if (bd == 0) { throw Error.error(ErrorCode.X_22012); } return ValuePool.getDouble(Double.doubleToLongBits(ad / bd)); } case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: { a = convertToDefaultType(null, a); b = convertToDefaultType(null, b); BigDecimal abd = (BigDecimal) a; BigDecimal bbd = (BigDecimal) b; int scale = abd.scale() > bbd.scale() ? abd.scale() : bbd.scale(); if (bbd.signum() == 0) { throw Error.error(ErrorCode.X_22012); } return abd.divide(bbd, scale, BigDecimal.ROUND_DOWN); } case Types.TINYINT: case Types.SQL_SMALLINT: case Types.SQL_INTEGER: { int ai = ((Number) a).intValue(); int bi = ((Number) b).intValue(); if (bi == 0) { throw Error.error(ErrorCode.X_22012); } return ValuePool.getInt(ai / bi); } case Types.SQL_BIGINT: { long al = ((Number) a).longValue(); long bl = ((Number) b).longValue(); if (bl == 0) { throw Error.error(ErrorCode.X_22012); } return ValuePool.getLong(al / bl); } default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }
@Override public Object negate(Object a) { if (a == null) { return null; } switch (typeCode) { case Types.SQL_REAL: case Types.SQL_FLOAT: case Types.SQL_DOUBLE: { double ad = -((Number) a).doubleValue(); return ValuePool.getDouble(Double.doubleToLongBits(ad)); } case Types.SQL_NUMERIC: case Types.SQL_DECIMAL: return ((BigDecimal) a).negate(); case Types.TINYINT: { int value = ((Number) a).intValue(); if (value == Byte.MIN_VALUE) { throw Error.error(ErrorCode.X_22003); } return ValuePool.getInt(-value); } case Types.SQL_SMALLINT: { int value = ((Number) a).intValue(); if (value == Short.MIN_VALUE) { throw Error.error(ErrorCode.X_22003); } return ValuePool.getInt(-value); } case Types.SQL_INTEGER: { int value = ((Number) a).intValue(); if (value == Integer.MIN_VALUE) { throw Error.error(ErrorCode.X_22003); } return ValuePool.getInt(-value); } case Types.SQL_BIGINT: { long value = ((Number) a).longValue(); if (value == Long.MIN_VALUE) { throw Error.error(ErrorCode.X_22003); } return ValuePool.getLong(-value); } default: throw Error.runtimeError(ErrorCode.U_S0500, "NumberType"); } }