/** * Converts a LOB to the equivalent Java type, i.e. <code>Clob</code> to <code>String</code> and * <code>Blob</code> to <code>byte[]</code>. If the value passed is not a LOB object, it is left * unchanged and no exception is thrown; the idea is to transparently convert only LOBs. * * @param value an object that may be a LOB * @return if the value was a LOB, the equivalent Java object, otherwise the original value * @throws SQLException if an error occurs while reading the LOB contents */ public static Object convertLOB(Object value) throws SQLException { if (value instanceof Clob) { Clob c = (Clob) value; return c.getSubString(1, (int) c.length()); } if (value instanceof Blob) { Blob b = (Blob) value; return b.getBytes(1, (int) b.length()); } return value; }
/** * {@collect.stats} Constructs a <code>SerialBlob</code> object that is a serialized version of * the given <code>Blob</code> object. * * <p>The new <code>SerialBlob</code> object is initialized with the data from the <code>Blob * </code> object; therefore, the <code>Blob</code> object should have previously brought the SQL * <code>BLOB</code> value's data over to the client from the database. Otherwise, the new <code> * SerialBlob</code> object will contain no data. * * @param blob the <code>Blob</code> object from which this <code>SerialBlob</code> object is to * be constructed; cannot be null. * @throws SerialException if an error occurs during serialization * @throws SQLException if the <code>Blob</code> passed to this to this constructor is a <code> * null</code>. * @see java.sql.Blob */ public SerialBlob(Blob blob) throws SerialException, SQLException { if (blob == null) { throw new SQLException("Cannot instantiate a SerialBlob " + "object with a null Blob object"); } len = blob.length(); buf = blob.getBytes(1, (int) len); this.blob = blob; // if ( len < 10240000) // len = 10240000; origLen = len; }
/** * {@collect.stats} Returns the position in this <code>SerialBlob</code> object where the given * <code>Blob</code> object begins, starting the search at the specified position. * * @param pattern the <code>Blob</code> object for which to search; * @param start the position of the byte in this <code>SerialBlob</code> object from which to * begin the search; the first position is <code>1</code>; must not be less than <code>1 * </code> nor greater than the length of this <code>SerialBlob</code> object * @return the position in this <code>SerialBlob</code> object where the given <code>Blob</code> * object begins, starting at the specified position; <code>-1</code> if the pattern is not * found or the given starting position is out of bounds; position numbering for the return * value starts at <code>1</code> * @throws SerialException if an error occurs when serializing the blob * @throws SQLException if there is an error accessing the <code>BLOB</code> value from the * database */ public long position(Blob pattern, long start) throws SerialException, SQLException { return position(pattern.getBytes(1, (int) (pattern.length())), start); }
/** * Embed the data object as a string literal in the buffer supplied. * * @param buf The buffer in which the data will be embedded. * @param value The data object. * @param isUnicode Set to <code>true</code> if Unicode strings should be used, else <code>false * </code>. * @param connection The {@link ConnectionJDBC2} object. */ static void embedData( StringBuffer buf, Object value, boolean isUnicode, ConnectionJDBC2 connection) throws SQLException { buf.append(' '); if (value == null) { buf.append("NULL "); return; } if (value instanceof Blob) { Blob blob = (Blob) value; value = blob.getBytes(1, (int) blob.length()); } else if (value instanceof Clob) { Clob clob = (Clob) value; value = clob.getSubString(1, (int) clob.length()); } if (value instanceof DateTime) { buf.append('\''); buf.append(value); buf.append('\''); } else if (value instanceof byte[]) { byte[] bytes = (byte[]) value; int len = bytes.length; if (len >= 0) { buf.append('0').append('x'); if (len == 0 && connection.getTdsVersion() < Driver.TDS70) { // Zero length binary values are not allowed buf.append('0').append('0'); } else { for (int i = 0; i < len; i++) { int b1 = bytes[i] & 0xFF; buf.append(hex[b1 >> 4]); buf.append(hex[b1 & 0x0F]); } } } } else if (value instanceof String) { String tmp = (String) value; int len = tmp.length(); if (isUnicode) { buf.append('N'); } buf.append('\''); for (int i = 0; i < len; i++) { char c = tmp.charAt(i); if (c == '\'') { buf.append('\''); } buf.append(c); } buf.append('\''); } else if (value instanceof java.sql.Date) { DateTime dt = new DateTime((java.sql.Date) value); buf.append('\''); buf.append(dt); buf.append('\''); } else if (value instanceof java.sql.Time) { DateTime dt = new DateTime((java.sql.Time) value); buf.append('\''); buf.append(dt); buf.append('\''); } else if (value instanceof java.sql.Timestamp) { DateTime dt = new DateTime((java.sql.Timestamp) value); buf.append('\''); buf.append(dt); buf.append('\''); } else if (value instanceof Boolean) { buf.append(((Boolean) value).booleanValue() ? '1' : '0'); } else if (value instanceof BigDecimal) { // // Ensure large decimal number does not overflow the // maximum precision of the server. // Main problem is with small numbers e.g. BigDecimal(1.0).toString() = // 0.1000000000000000055511151231.... // String tmp = value.toString(); int maxlen = connection.getMaxPrecision(); if (tmp.charAt(0) == '-') { maxlen++; } if (tmp.indexOf('.') >= 0) { maxlen++; } if (tmp.length() > maxlen) { buf.append(tmp.substring(0, maxlen)); } else { buf.append(tmp); } } else { buf.append(value.toString()); } buf.append(' '); }
/** * Convert an existing data object to the specified JDBC type. * * @param callerReference an object reference to the caller of this method; must be a <code> * Connection</code>, <code>Statement</code> or <code>ResultSet</code> * @param x the data object to convert * @param jdbcType the required type constant from <code>java.sql.Types</code> * @return the converted data object * @throws SQLException if the conversion is not supported or fails */ static Object convert(Object callerReference, Object x, int jdbcType, String charSet) throws SQLException { // handle null value if (x == null) { switch (jdbcType) { case java.sql.Types.BIT: case JtdsStatement.BOOLEAN: return Boolean.FALSE; case java.sql.Types.TINYINT: case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: return INTEGER_ZERO; case java.sql.Types.BIGINT: return LONG_ZERO; case java.sql.Types.REAL: return FLOAT_ZERO; case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: return DOUBLE_ZERO; default: return null; } } try { switch (jdbcType) { case java.sql.Types.TINYINT: if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? INTEGER_ONE : INTEGER_ZERO; } else if (x instanceof Byte) { return new Integer(((Byte) x).byteValue() & 0xFF); } else { long val; if (x instanceof Number) { val = ((Number) x).longValue(); } else if (x instanceof String) { val = new Long(((String) x).trim()).longValue(); } else { break; } if (val < Byte.MIN_VALUE || val > Byte.MAX_VALUE) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Integer(new Long(val).intValue()); } } case java.sql.Types.SMALLINT: if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? INTEGER_ONE : INTEGER_ZERO; } else if (x instanceof Short) { return new Integer(((Short) x).shortValue()); } else if (x instanceof Byte) { return new Integer(((Byte) x).byteValue() & 0xFF); } else { long val; if (x instanceof Number) { val = ((Number) x).longValue(); } else if (x instanceof String) { val = new Long(((String) x).trim()).longValue(); } else { break; } if (val < Short.MIN_VALUE || val > Short.MAX_VALUE) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Integer(new Long(val).intValue()); } } case java.sql.Types.INTEGER: if (x instanceof Integer) { return x; } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? INTEGER_ONE : INTEGER_ZERO; } else if (x instanceof Short) { return new Integer(((Short) x).shortValue()); } else if (x instanceof Byte) { return new Integer(((Byte) x).byteValue() & 0xFF); } else { long val; if (x instanceof Number) { val = ((Number) x).longValue(); } else if (x instanceof String) { val = new Long(((String) x).trim()).longValue(); } else { break; } if (val < Integer.MIN_VALUE || val > Integer.MAX_VALUE) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Integer(new Long(val).intValue()); } } case java.sql.Types.BIGINT: if (x instanceof BigDecimal) { BigDecimal val = (BigDecimal) x; if (val.compareTo(MIN_VALUE_LONG_BD) < 0 || val.compareTo(MAX_VALUE_LONG_BD) > 0) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Long(val.longValue()); } } else if (x instanceof Long) { return x; } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? LONG_ONE : LONG_ZERO; } else if (x instanceof Byte) { return new Long(((Byte) x).byteValue() & 0xFF); } else if (x instanceof BigInteger) { BigInteger val = (BigInteger) x; if (val.compareTo(MIN_VALUE_LONG_BI) < 0 || val.compareTo(MAX_VALUE_LONG_BI) > 0) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Long(val.longValue()); } } else if (x instanceof Number) { return new Long(((Number) x).longValue()); } else if (x instanceof String) { return new Long(((String) x).trim()); } else { break; } case java.sql.Types.REAL: if (x instanceof Float) { return x; } else if (x instanceof Byte) { return new Float(((Byte) x).byteValue() & 0xFF); } else if (x instanceof Number) { return new Float(((Number) x).floatValue()); } else if (x instanceof String) { return new Float(((String) x).trim()); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? FLOAT_ONE : FLOAT_ZERO; } break; case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: if (x instanceof Double) { return x; } else if (x instanceof Byte) { return new Double(((Byte) x).byteValue() & 0xFF); } else if (x instanceof Number) { return new Double(((Number) x).doubleValue()); } else if (x instanceof String) { return new Double(((String) x).trim()); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? DOUBLE_ONE : DOUBLE_ZERO; } break; case java.sql.Types.NUMERIC: case java.sql.Types.DECIMAL: if (x instanceof BigDecimal) { return x; } else if (x instanceof Number) { return new BigDecimal(x.toString()); } else if (x instanceof String) { return new BigDecimal((String) x); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? BIG_DECIMAL_ONE : BIG_DECIMAL_ZERO; } break; case java.sql.Types.VARCHAR: case java.sql.Types.CHAR: if (x instanceof String) { return x; } else if (x instanceof Number) { return x.toString(); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? "1" : "0"; } else if (x instanceof Clob) { Clob clob = (Clob) x; long length = clob.length(); if (length > Integer.MAX_VALUE) { throw new SQLException(Messages.get("error.normalize.lobtoobig"), "22000"); } return clob.getSubString(1, (int) length); } else if (x instanceof Blob) { Blob blob = (Blob) x; long length = blob.length(); if (length > Integer.MAX_VALUE) { throw new SQLException(Messages.get("error.normalize.lobtoobig"), "22000"); } x = blob.getBytes(1, (int) length); } if (x instanceof byte[]) { return toHex((byte[]) x); } return x.toString(); // Last hope! case java.sql.Types.BIT: case JtdsStatement.BOOLEAN: if (x instanceof Boolean) { return x; } else if (x instanceof Number) { return (((Number) x).intValue() == 0) ? Boolean.FALSE : Boolean.TRUE; } else if (x instanceof String) { String tmp = ((String) x).trim(); return ("1".equals(tmp) || "true".equalsIgnoreCase(tmp)) ? Boolean.TRUE : Boolean.FALSE; } break; case java.sql.Types.VARBINARY: case java.sql.Types.BINARY: if (x instanceof byte[]) { return x; } else if (x instanceof Blob) { Blob blob = (Blob) x; return blob.getBytes(1, (int) blob.length()); } else if (x instanceof Clob) { Clob clob = (Clob) x; long length = clob.length(); if (length > Integer.MAX_VALUE) { throw new SQLException(Messages.get("error.normalize.lobtoobig"), "22000"); } x = clob.getSubString(1, (int) length); } if (x instanceof String) { // // Strictly speaking this conversion is not required by // the JDBC standard but jTDS has always supported it. // if (charSet == null) { charSet = "ISO-8859-1"; } try { return ((String) x).getBytes(charSet); } catch (UnsupportedEncodingException e) { return ((String) x).getBytes(); } } else if (x instanceof UniqueIdentifier) { return ((UniqueIdentifier) x).getBytes(); } break; case java.sql.Types.TIMESTAMP: if (x instanceof DateTime) { return ((DateTime) x).toTimestamp(); } else if (x instanceof java.sql.Timestamp) { return x; } else if (x instanceof java.sql.Date) { return new java.sql.Timestamp(((java.sql.Date) x).getTime()); } else if (x instanceof java.sql.Time) { return new java.sql.Timestamp(((java.sql.Time) x).getTime()); } else if (x instanceof java.lang.String) { return java.sql.Timestamp.valueOf(((String) x).trim()); } break; case java.sql.Types.DATE: if (x instanceof DateTime) { return ((DateTime) x).toDate(); } else if (x instanceof java.sql.Date) { return x; } else if (x instanceof java.sql.Time) { return DATE_ZERO; } else if (x instanceof java.sql.Timestamp) { GregorianCalendar cal = (GregorianCalendar) calendar.get(); cal.setTime((java.util.Date) x); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); // VM1.4+ only return new java.sql.Date(cal.getTimeInMillis()); return new java.sql.Date(cal.getTime().getTime()); } else if (x instanceof java.lang.String) { return java.sql.Date.valueOf(((String) x).trim()); } break; case java.sql.Types.TIME: if (x instanceof DateTime) { return ((DateTime) x).toTime(); } else if (x instanceof java.sql.Time) { return x; } else if (x instanceof java.sql.Date) { return TIME_ZERO; } else if (x instanceof java.sql.Timestamp) { GregorianCalendar cal = (GregorianCalendar) calendar.get(); // VM 1.4+ only cal.setTimeInMillis(((java.sql.Timestamp)x).getTime()); cal.setTime((java.util.Date) x); cal.set(Calendar.YEAR, 1970); cal.set(Calendar.MONTH, 0); cal.set(Calendar.DAY_OF_MONTH, 1); // VM 1.4+ only return new java.sql.Time(cal.getTimeInMillis());*/ return new java.sql.Time(cal.getTime().getTime()); } else if (x instanceof java.lang.String) { return java.sql.Time.valueOf(((String) x).trim()); } break; case java.sql.Types.OTHER: return x; case java.sql.Types.JAVA_OBJECT: throw new SQLException( Messages.get( "error.convert.badtypes", x.getClass().getName(), getJdbcTypeName(jdbcType)), "22005"); case java.sql.Types.LONGVARBINARY: case java.sql.Types.BLOB: if (x instanceof Blob) { return x; } else if (x instanceof byte[]) { return new BlobImpl(getConnection(callerReference), (byte[]) x); } else if (x instanceof Clob) { // // Convert CLOB to BLOB. Not required by the standard but we will // do it anyway. // Clob clob = (Clob) x; try { if (charSet == null) { charSet = "ISO-8859-1"; } Reader rdr = clob.getCharacterStream(); BlobImpl blob = new BlobImpl(getConnection(callerReference)); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(blob.setBinaryStream(1), charSet)); // TODO Use a buffer to improve performance int c; while ((c = rdr.read()) >= 0) { out.write(c); } out.close(); rdr.close(); return blob; } catch (UnsupportedEncodingException e) { // Unlikely to happen but fall back on in memory copy x = clob.getSubString(1, (int) clob.length()); } catch (IOException e) { throw new SQLException( Messages.get("error.generic.ioerror", e.getMessage()), "HY000"); } } if (x instanceof String) { // // Strictly speaking this conversion is also not required by // the JDBC standard but jTDS has always supported it. // BlobImpl blob = new BlobImpl(getConnection(callerReference)); String data = (String) x; if (charSet == null) { charSet = "ISO-8859-1"; } try { blob.setBytes(1, data.getBytes(charSet)); } catch (UnsupportedEncodingException e) { blob.setBytes(1, data.getBytes()); } return blob; } break; case java.sql.Types.LONGVARCHAR: case java.sql.Types.CLOB: if (x instanceof Clob) { return x; } else if (x instanceof Blob) { // // Convert BLOB to CLOB // Blob blob = (Blob) x; try { InputStream is = blob.getBinaryStream(); ClobImpl clob = new ClobImpl(getConnection(callerReference)); Writer out = clob.setCharacterStream(1); // TODO Use a buffer to improve performance int b; // These reads/writes are buffered by the underlying blob buffers while ((b = is.read()) >= 0) { out.write(hex[b >> 4]); out.write(hex[b & 0x0F]); } out.close(); is.close(); return clob; } catch (IOException e) { throw new SQLException( Messages.get("error.generic.ioerror", e.getMessage()), "HY000"); } } else if (x instanceof Boolean) { x = ((Boolean) x).booleanValue() ? "1" : "0"; } else if (!(x instanceof byte[])) { x = x.toString(); } if (x instanceof byte[]) { ClobImpl clob = new ClobImpl(getConnection(callerReference)); clob.setString(1, toHex((byte[]) x)); return clob; } else if (x instanceof String) { return new ClobImpl(getConnection(callerReference), (String) x); } break; default: throw new SQLException( Messages.get("error.convert.badtypeconst", getJdbcTypeName(jdbcType)), "HY004"); } throw new SQLException( Messages.get("error.convert.badtypes", x.getClass().getName(), getJdbcTypeName(jdbcType)), "22005"); } catch (NumberFormatException nfe) { throw new SQLException( Messages.get("error.convert.badnumber", getJdbcTypeName(jdbcType)), "22000"); } }