com.microsoft.sqlserver.jdbc.DDC Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mssql-jdbc Show documentation
Show all versions of mssql-jdbc Show documentation
Microsoft JDBC Driver for SQL Server.
The newest version!
/*
* Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made
* available under the terms of the MIT License. See the LICENSE file in the project root for more information.
*/
package com.microsoft.sqlserver.jdbc;
import static java.nio.charset.StandardCharsets.US_ASCII;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
/**
* Utility class for all Data Dependent Conversions (DDC).
*/
final class DDC {
private DDC() {
throw new UnsupportedOperationException(SQLServerException.getErrString("R_notSupported"));
}
/**
* Convert an Integer object to desired target user type.
*
* @param intValue
* the value to convert.
* @param valueLength
* the value to convert.
* @param jdbcType
* the jdbc type required.
* @param streamType
* the type of stream required.
* @return the required object.
*/
static final Object convertIntegerToObject(int intValue, int valueLength, JDBCType jdbcType,
StreamType streamType) {
switch (jdbcType) {
case INTEGER:
return intValue;
case SMALLINT: // 2.21 small and tinyint returned as short
case TINYINT:
return (short) intValue;
case BIT:
case BOOLEAN:
return 0 != intValue;
case BIGINT:
return (long) intValue;
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return new BigDecimal(Integer.toString(intValue));
case FLOAT:
case DOUBLE:
return (double) intValue;
case REAL:
return (float) intValue;
case BINARY:
return convertIntToBytes(intValue, valueLength);
case SQL_VARIANT:
// return short or bit if the underlying datatype of sql_variant is tinyint, smallint or bit
// otherwise, return integer
// Longer datatypes such as double and float are handled by convertLongToObject instead.
if (valueLength == 1) {
return 0 != intValue;
} else if (valueLength == 3 || valueLength == 4) {
return (short) intValue;
} else {
return intValue;
}
default:
return Integer.toString(intValue);
}
}
/**
* Convert a Long object to desired target user type.
*
* @param longVal
* the value to convert.
* @param jdbcType
* the jdbc type required.
* @param baseSSType
* the base SQLServer type.
* @param streamType
* the stream type.
* @return the required object.
*/
static final Object convertLongToObject(long longVal, JDBCType jdbcType, SSType baseSSType, StreamType streamType) {
switch (jdbcType) {
case BIGINT:
case SQL_VARIANT:
return longVal;
case INTEGER:
return (int) longVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
return (short) longVal;
case BIT:
case BOOLEAN:
return 0 != longVal;
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return new BigDecimal(Long.toString(longVal));
case FLOAT:
case DOUBLE:
return (double) longVal;
case REAL:
return (float) longVal;
case BINARY:
byte[] convertedBytes = convertLongToBytes(longVal);
int bytesToReturnLength;
byte[] bytesToReturn;
switch (baseSSType) {
case BIT:
case TINYINT:
bytesToReturnLength = 1;
bytesToReturn = new byte[bytesToReturnLength];
System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0,
bytesToReturnLength);
return bytesToReturn;
case SMALLINT:
bytesToReturnLength = 2;
bytesToReturn = new byte[bytesToReturnLength];
System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0,
bytesToReturnLength);
return bytesToReturn;
case INTEGER:
bytesToReturnLength = 4;
bytesToReturn = new byte[bytesToReturnLength];
System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0,
bytesToReturnLength);
return bytesToReturn;
case BIGINT:
bytesToReturnLength = 8;
bytesToReturn = new byte[bytesToReturnLength];
System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0,
bytesToReturnLength);
return bytesToReturn;
default:
return convertedBytes;
}
case VARBINARY:
switch (baseSSType) {
case BIGINT:
return longVal;
case INTEGER:
return (int) longVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
return (short) longVal;
case BIT:
return 0 != longVal;
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return new BigDecimal(Long.toString(longVal));
case FLOAT:
return (double) longVal;
case REAL:
return (float) longVal;
case BINARY:
return convertLongToBytes(longVal);
default:
return Long.toString(longVal);
}
default:
return Long.toString(longVal);
}
}
/**
* Encodes an integer value to a byte array in big-endian order.
*
* @param intValue
* the integer value to encode.
* @param valueLength
* the number of bytes to encode.
* @return the byte array containing the big-endian encoded value.
*/
static final byte[] convertIntToBytes(int intValue, int valueLength) {
byte[] bytes = new byte[valueLength];
for (int i = valueLength; i-- > 0;) {
bytes[i] = (byte) (intValue & 0xFF);
intValue >>= 8;
}
return bytes;
}
/**
* Convert a Float object to desired target user type.
*
* @param floatVal
* the value to convert.
* @param jdbcType
* the jdbc type required.
* @param streamType
* the stream type.
* @return the required object.
*/
static final Object convertFloatToObject(float floatVal, JDBCType jdbcType, StreamType streamType) {
switch (jdbcType) {
case REAL:
case SQL_VARIANT:
return floatVal;
case INTEGER:
return (int) floatVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
return (short) floatVal;
case BIT:
case BOOLEAN:
return 0 != Float.compare(0.0f, floatVal);
case BIGINT:
return (long) floatVal;
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return new BigDecimal(Float.toString(floatVal));
case FLOAT:
case DOUBLE:
return (Float.valueOf(floatVal)).doubleValue();
case BINARY:
return convertIntToBytes(Float.floatToRawIntBits(floatVal), 4);
default:
return Float.toString(floatVal);
}
}
/**
* Encodes a long value to a byte array in big-endian order.
*
* @param longValue
* the long value to encode.
* @return the byte array containing the big-endian encoded value.
*/
static final byte[] convertLongToBytes(long longValue) {
byte[] bytes = new byte[8];
for (int i = 8; i-- > 0;) {
bytes[i] = (byte) (longValue & 0xFF);
longValue >>= 8;
}
return bytes;
}
/**
* Convert a Double object to desired target user type.
*
* @param doubleVal
* the value to convert.
* @param jdbcType
* the jdbc type required.
* @param streamType
* the stream type.
* @return the required object.
*/
static final Object convertDoubleToObject(double doubleVal, JDBCType jdbcType, StreamType streamType) {
switch (jdbcType) {
case FLOAT:
case DOUBLE:
case SQL_VARIANT:
return doubleVal;
case REAL:
return (Double.valueOf(doubleVal)).floatValue();
case INTEGER:
return (int) doubleVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
return (short) doubleVal;
case BIT:
case BOOLEAN:
return 0 != Double.compare(0.0d, doubleVal);
case BIGINT:
return (long) doubleVal;
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return new BigDecimal(Double.toString(doubleVal));
case BINARY:
return convertLongToBytes(Double.doubleToRawLongBits(doubleVal));
default:
return Double.toString(doubleVal);
}
}
static final byte[] convertBigDecimalToBytes(BigDecimal bigDecimalVal, int scale) {
byte[] valueBytes;
if (bigDecimalVal == null) {
valueBytes = new byte[2];
valueBytes[0] = (byte) scale;
valueBytes[1] = 0; // data length
} else {
boolean isNegative = (bigDecimalVal.signum() < 0);
// NOTE: Handle negative scale as a special case for JDK 1.5 and later VMs.
if (bigDecimalVal.scale() < 0)
bigDecimalVal = bigDecimalVal.setScale(0);
BigInteger bi = bigDecimalVal.unscaledValue();
if (isNegative)
bi = bi.negate();
byte[] unscaledBytes = bi.toByteArray();
valueBytes = new byte[unscaledBytes.length + 3];
int j = 0;
valueBytes[j++] = (byte) bigDecimalVal.scale();
valueBytes[j++] = (byte) (unscaledBytes.length + 1); // data length + sign
valueBytes[j++] = (byte) (isNegative ? 0 : 1); // 1 = +ve, 0 = -ve
for (int i = unscaledBytes.length - 1; i >= 0; i--)
valueBytes[j++] = unscaledBytes[i];
}
return valueBytes;
}
static final byte[] convertMoneyToBytes(BigDecimal bigDecimalVal, int bLength) throws SQLServerException {
byte[] valueBytes = new byte[bLength];
BigInteger bi = bigDecimalVal.unscaledValue();
if (bLength == 8) {
// money
Util.validateMoneyRange(bigDecimalVal, JDBCType.MONEY);
byte[] longbArray = new byte[bLength];
Util.writeLong(bi.longValue(), longbArray, 0);
/*
* TDS 2.2.5.5.1.4 Fixed-Point Numbers Money is represented as a 8 byte signed integer, with one 4-byte
* integer that represents the more significant half, and one 4-byte integer that represents the less
* significant half.
*/
System.arraycopy(longbArray, 0, valueBytes, 4, 4);
System.arraycopy(longbArray, 4, valueBytes, 0, 4);
} else {
// smallmoney
Util.validateMoneyRange(bigDecimalVal, JDBCType.SMALLMONEY);
Util.writeInt(bi.intValue(), valueBytes, 0);
}
return valueBytes;
}
/**
* Convert a BigDecimal object to desired target user type.
*
* @param bigDecimalVal
* the value to convert.
* @param jdbcType
* the jdbc type required.
* @param streamType
* the stream type.
* @return the required object.
*/
static final Object convertBigDecimalToObject(BigDecimal bigDecimalVal, JDBCType jdbcType, StreamType streamType) {
switch (jdbcType) {
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
case SQL_VARIANT:
return bigDecimalVal;
case FLOAT:
case DOUBLE:
return bigDecimalVal.doubleValue();
case REAL:
return bigDecimalVal.floatValue();
case INTEGER:
return bigDecimalVal.intValue();
case SMALLINT: // small and tinyint returned as short
case TINYINT:
return bigDecimalVal.shortValue();
case BIT:
case BOOLEAN:
return 0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0));
case BIGINT:
return bigDecimalVal.longValue();
case BINARY:
return convertBigDecimalToBytes(bigDecimalVal, bigDecimalVal.scale());
default:
return bigDecimalVal.toString();
}
}
/**
* Convert a Money object to desired target user type.
*
* @param bigDecimalVal
* the value to convert.
* @param jdbcType
* the jdbc type required.
* @param streamType
* the stream type.
* @param numberOfBytes
* the number of bytes to convert
* @return the required object.
*/
static final Object convertMoneyToObject(BigDecimal bigDecimalVal, JDBCType jdbcType, StreamType streamType,
int numberOfBytes) {
switch (jdbcType) {
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return bigDecimalVal;
case FLOAT:
case DOUBLE:
return bigDecimalVal.doubleValue();
case REAL:
return bigDecimalVal.floatValue();
case INTEGER:
return bigDecimalVal.intValue();
case SMALLINT: // small and tinyint returned as short
case TINYINT:
return bigDecimalVal.shortValue();
case BIT:
case BOOLEAN:
return 0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0));
case BIGINT:
return bigDecimalVal.longValue();
case BINARY:
return convertToBytes(bigDecimalVal, bigDecimalVal.scale(), numberOfBytes);
default:
return bigDecimalVal.toString();
}
}
// converts big decimal to money and smallmoney
private static byte[] convertToBytes(BigDecimal value, int scale, int numBytes) {
boolean isNeg = value.signum() < 0;
value = value.setScale(scale);
BigInteger bigInt = value.unscaledValue();
byte[] unscaledBytes = bigInt.toByteArray();
byte[] ret = new byte[numBytes];
if (unscaledBytes.length < numBytes) {
for (int i = 0; i < numBytes - unscaledBytes.length; ++i) {
ret[i] = (byte) (isNeg ? -1 : 0);
}
}
int offset = numBytes - unscaledBytes.length;
System.arraycopy(unscaledBytes, 0, ret, offset, numBytes - offset);
return ret;
}
/**
* Convert a byte array to desired target user type.
*
* @param bytesValue
* the value to convert.
* @param jdbcType
* the jdbc type required.
* @param baseTypeInfo
* the type information associated with bytesValue.
* @return the required object.
* @throws SQLServerException
* when an error occurs.
*/
static final Object convertBytesToObject(byte[] bytesValue, JDBCType jdbcType,
TypeInfo baseTypeInfo) throws SQLServerException {
switch (jdbcType) {
case CHAR:
String str = Util.bytesToHexString(bytesValue, bytesValue.length);
if ((SSType.BINARY == baseTypeInfo.getSSType()) && (str.length() < (baseTypeInfo.getPrecision() * 2))) {
StringBuilder strbuf = new StringBuilder(str);
while (strbuf.length() < (baseTypeInfo.getPrecision() * 2)) {
strbuf.append('0');
}
return strbuf.toString();
}
return str;
case BINARY:
case VARBINARY:
case LONGVARBINARY:
if ((SSType.BINARY == baseTypeInfo.getSSType()) && (bytesValue.length < baseTypeInfo.getPrecision())) {
byte[] newBytes = new byte[baseTypeInfo.getPrecision()];
System.arraycopy(bytesValue, 0, newBytes, 0, bytesValue.length);
return newBytes;
}
return bytesValue;
default:
MessageFormat form = new MessageFormat(
SQLServerException.getErrString("R_unsupportedConversionFromTo"));
throw new SQLServerException(form.format(new Object[] {baseTypeInfo.getSSType().name(), jdbcType}),
null, 0, null);
}
}
/**
* Convert a String object to desired target user type.
*
* @param stringVal
* the value to convert.
* @param charset
* the character set.
* @param jdbcType
* the jdbc type required.
* @return the required object.
*/
static final Object convertStringToObject(String stringVal, Charset charset, JDBCType jdbcType,
StreamType streamType) throws UnsupportedEncodingException {
switch (jdbcType) {
// Convert String to Numeric types.
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return new BigDecimal(stringVal.trim());
case FLOAT:
case DOUBLE:
return Double.valueOf(stringVal.trim());
case REAL:
return Float.valueOf(stringVal.trim());
case INTEGER:
return Integer.valueOf(stringVal.trim());
case SMALLINT: // small and tinyint returned as short
case TINYINT:
return Short.valueOf(stringVal.trim());
case BIT:
case BOOLEAN:
String trimmedString = stringVal.trim();
return (1 == trimmedString.length()) ? Boolean.valueOf('1' == trimmedString.charAt(0))
: Boolean.valueOf(trimmedString);
case BIGINT:
return Long.valueOf(stringVal.trim());
// Convert String to Temporal types.
case TIMESTAMP:
return java.sql.Timestamp.valueOf(stringVal.trim());
case LOCALDATETIME:
return parseStringIntoLDT(stringVal.trim());
case DATE:
return java.sql.Date.valueOf(getDatePart(stringVal.trim()));
case TIME:
// Accepted character formats for conversion to java.sql.Time are:
// hh:mm:ss[.nnnnnnnnn]
// YYYY-MM-DD hh:mm:ss[.nnnnnnnnn]
//
// To handle either of these formats:
// 1) Normalize and parse as a Timestamp
// 2) Round fractional seconds up to the nearest millisecond (max resolution of java.sql.Time)
// 3) Renormalize (as rounding may have changed the date) to a java.sql.Time
java.sql.Timestamp ts = java.sql.Timestamp
.valueOf(TDS.BASE_DATE_1970 + " " + getTimePart(stringVal.trim()));
GregorianCalendar cal = new GregorianCalendar(Locale.US);
cal.clear();
cal.setTimeInMillis(ts.getTime());
if (ts.getNanos() % Nanos.PER_MILLISECOND >= Nanos.PER_MILLISECOND / 2)
cal.add(Calendar.MILLISECOND, 1);
cal.set(TDS.BASE_YEAR_1970, Calendar.JANUARY, 1);
return new java.sql.Time(cal.getTimeInMillis());
case BINARY:
return stringVal.getBytes(charset);
default:
// For everything else, just return either a string or appropriate stream.
switch (streamType) {
case CHARACTER:
return new StringReader(stringVal);
case ASCII:
return new ByteArrayInputStream(stringVal.getBytes(US_ASCII));
case BINARY:
return new ByteArrayInputStream(stringVal.getBytes());
default:
return stringVal;
}
}
}
/**
* Taken from java.sql.Timestamp implementation
*
* @param s
* String to be parsed
* @return LocalDateTime
*/
private static LocalDateTime parseStringIntoLDT(String s) {
final int YEAR_LENGTH = 4;
final int MONTH_LENGTH = 2;
final int DAY_LENGTH = 2;
final int MAX_MONTH = 12;
final int MAX_DAY = 31;
int year = 0;
int month = 0;
int day = 0;
int hour;
int minute;
int second;
int nanos = 0;
int firstDash;
int secondDash;
int dividingSpace;
int firstColon;
int secondColon;
int period;
String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]";
if (s == null)
throw new java.lang.IllegalArgumentException("null string");
// Split the string into date and time components
s = s.trim();
dividingSpace = s.indexOf(' ');
if (dividingSpace < 0) {
throw new java.lang.IllegalArgumentException(formatError);
}
// Parse the date
firstDash = s.indexOf('-');
secondDash = s.indexOf('-', firstDash + 1);
// Parse the time
firstColon = s.indexOf(':', dividingSpace + 1);
secondColon = s.indexOf(':', firstColon + 1);
period = s.indexOf('.', secondColon + 1);
// Convert the date
boolean parsedDate = false;
if (firstDash > 0 && secondDash > 0 && secondDash < dividingSpace - 1 && firstDash == YEAR_LENGTH
&& (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1)
&& (dividingSpace - secondDash > 1 && dividingSpace - secondDash <= DAY_LENGTH + 1)) {
year = Integer.parseInt(s.substring(0, firstDash));
month = Integer.parseInt(s.substring(firstDash + 1, secondDash));
day = Integer.parseInt(s.substring(secondDash + 1, dividingSpace));
if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
parsedDate = true;
}
}
if (!parsedDate) {
throw new java.lang.IllegalArgumentException(formatError);
}
// Convert the time; default missing nanos
int len = s.length();
if (firstColon > 0 && secondColon > 0 && secondColon < len - 1) {
hour = Integer.parseInt(s.substring(dividingSpace + 1, firstColon));
minute = Integer.parseInt(s.substring(firstColon + 1, secondColon));
if (period > 0 && period < len - 1) {
second = Integer.parseInt(s.substring(secondColon + 1, period));
int nanoPrecision = len - (period + 1);
if (nanoPrecision > 9)
throw new java.lang.IllegalArgumentException(formatError);
if (!Character.isDigit(s.charAt(period + 1)))
throw new java.lang.IllegalArgumentException(formatError);
int tmpNanos = Integer.parseInt(s.substring(period + 1, len));
while (nanoPrecision < 9) {
tmpNanos *= 10;
nanoPrecision++;
}
nanos = tmpNanos;
} else if (period > 0) {
throw new java.lang.IllegalArgumentException(formatError);
} else {
second = Integer.parseInt(s.substring(secondColon + 1, len));
}
} else {
throw new java.lang.IllegalArgumentException(formatError);
}
return LocalDateTime.of(year, month, day, hour, minute, second, nanos);
}
static final Object convertStreamToObject(BaseInputStream stream, TypeInfo typeInfo, JDBCType jdbcType,
InputStreamGetterArgs getterArgs) throws SQLServerException {
// Need to handle the simple case of a null value here, as it is not done
// outside this function.
if (null == stream)
return null;
assert null != typeInfo;
assert null != getterArgs;
SSType ssType = typeInfo.getSSType();
try {
switch (jdbcType) {
case CLOB:
return new SQLServerClob(stream, typeInfo);
case NCLOB:
return new SQLServerNClob(stream, typeInfo);
case SQLXML:
return new SQLServerSQLXML(stream, getterArgs, typeInfo);
case BINARY:
case VARBINARY:
case LONGVARBINARY:
case BLOB:
// Where allowed, streams convert directly to binary representation
if (StreamType.BINARY == getterArgs.streamType)
return stream;
if (JDBCType.BLOB == jdbcType)
return new SQLServerBlob(stream);
return stream.getBytes();
case CHAR:
case VARCHAR:
case LONGVARCHAR:
case NCHAR:
case NVARCHAR:
case LONGNVARCHAR:
default:
// Binary streams to character types:
// - Direct conversion to ASCII stream
// - Convert as hexized value to other character types
if (SSType.BINARY == ssType || SSType.VARBINARY == ssType || SSType.VARBINARYMAX == ssType
|| SSType.TIMESTAMP == ssType || SSType.IMAGE == ssType || SSType.UDT == ssType) {
if (StreamType.ASCII == getterArgs.streamType) {
return stream;
} else {
assert StreamType.CHARACTER == getterArgs.streamType
|| StreamType.NONE == getterArgs.streamType;
byte[] byteValue = stream.getBytes();
if (JDBCType.GUID == jdbcType) {
return Util.readGUID(byteValue);
} else if (JDBCType.GEOMETRY == jdbcType) {
if (!typeInfo.getSSTypeName().equalsIgnoreCase(jdbcType.toString())) {
DataTypes.throwConversionError(typeInfo.getSSTypeName().toUpperCase(),
jdbcType.toString());
}
return Geometry.STGeomFromWKB(byteValue);
} else if (JDBCType.GEOGRAPHY == jdbcType) {
if (!typeInfo.getSSTypeName().equalsIgnoreCase(jdbcType.toString())) {
DataTypes.throwConversionError(typeInfo.getSSTypeName().toUpperCase(),
jdbcType.toString());
}
return Geography.STGeomFromWKB(byteValue);
} else {
String hexString = Util.bytesToHexString(byteValue, byteValue.length);
if (StreamType.NONE == getterArgs.streamType)
return hexString;
return new StringReader(hexString);
}
}
}
// Handle streams converting to ASCII
if (StreamType.ASCII == getterArgs.streamType) {
// Fast path for SBCS data that converts directly/easily to ASCII
if (typeInfo.supportsFastAsciiConversion())
return new AsciiFilteredInputStream(stream);
// Slightly less fast path for MBCS data that converts directly/easily to ASCII
if (getterArgs.isAdaptive) {
return AsciiFilteredUnicodeInputStream.makeAsciiFilteredUnicodeInputStream(stream,
new BufferedReader(new InputStreamReader(stream, typeInfo.getCharset())));
} else {
return new ByteArrayInputStream(
(new String(stream.getBytes(), typeInfo.getCharset())).getBytes(US_ASCII));
}
} else if (StreamType.CHARACTER == getterArgs.streamType
|| StreamType.NCHARACTER == getterArgs.streamType) {
if (getterArgs.isAdaptive)
return new BufferedReader(new InputStreamReader(stream, typeInfo.getCharset()));
else
return new StringReader(new String(stream.getBytes(), typeInfo.getCharset()));
}
// None of the special/fast textual conversion cases applied. Just go the normal route of converting
// via String.
return convertStringToObject(new String(stream.getBytes(), typeInfo.getCharset()),
typeInfo.getCharset(), jdbcType, getterArgs.streamType);
}
}
// Conversion can throw either of these exceptions:
//
// UnsupportedEncodingException (binary conversions)
// IllegalArgumentException (any conversion - note: numerics throw NumberFormatException subclass)
//
// Catch them and translate them to a SQLException so that we don't propagate an unexpected exception
// type all the way up to the app, which may not catch it either...
catch (IllegalArgumentException | UnsupportedEncodingException e) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue"));
throw new SQLServerException(form.format(new Object[] {typeInfo.getSSType(), jdbcType}), null, 0, e);
}
}
// Returns date portion of string.
// Expects one of "" or "