📄 support.java
字号:
// jTDS JDBC Driver for Microsoft SQL Server and Sybase
// Copyright (C) 2004 The jTDS Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
package net.sourceforge.jtds.jdbc;
import java.io.*;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.*;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import net.sourceforge.jtds.util.Logger;
/**
* This class contains static utility methods designed to support the
* main driver classes.
* <p>
* Implementation notes:
* <ol>
* <li>The methods in this class incorporate some code from previous versions
* of jTDS to handle dates, BLobs etc.
* <li>This class contains routines to generate runtime messages from the resource file.
* <li>The key data conversion logic used in Statements and result sets is implemented here.
* <li>There is nothing here which is TDS specific.
* </ol>
*
* @author Mike Hutchinson
* @author jTDS project
* @version $Id: Support.java,v 1.56 2007/07/08 18:42:14 bheineman Exp $
*/
public class Support {
// Constants used in datatype conversions to avoid object allocations.
private static final Integer INTEGER_ZERO = new Integer(0);
private static final Integer INTEGER_ONE = new Integer(1);
private static final Long LONG_ZERO = new Long(0L);
private static final Long LONG_ONE = new Long(1L);
private static final Float FLOAT_ZERO = new Float(0.0);
private static final Float FLOAT_ONE = new Float(1.0);
private static final Double DOUBLE_ZERO = new Double(0.0);
private static final Double DOUBLE_ONE = new Double(1.0);
private static final BigDecimal BIG_DECIMAL_ZERO = new BigDecimal(0.0);
private static final BigDecimal BIG_DECIMAL_ONE = new BigDecimal(1.0);
private static final java.sql.Date DATE_ZERO = new java.sql.Date(0);
private static final java.sql.Time TIME_ZERO = new java.sql.Time(0);
private static final BigInteger MAX_VALUE_28 = new BigInteger("9999999999999999999999999999");
private static final BigInteger MAX_VALUE_38 = new BigInteger("99999999999999999999999999999999999999");
/**
* Convert java clases to java.sql.Type constant.
*/
private static final HashMap typeMap = new HashMap();
static {
typeMap.put(Byte.class, new Integer(java.sql.Types.TINYINT));
typeMap.put(Short.class, new Integer(java.sql.Types.SMALLINT));
typeMap.put(Integer.class, new Integer(java.sql.Types.INTEGER));
typeMap.put(Long.class, new Integer(java.sql.Types.BIGINT));
typeMap.put(Float.class, new Integer(java.sql.Types.REAL));
typeMap.put(Double.class, new Integer(java.sql.Types.DOUBLE));
typeMap.put(BigDecimal.class, new Integer(java.sql.Types.DECIMAL));
typeMap.put(Boolean.class, new Integer(JtdsStatement.BOOLEAN));
typeMap.put(byte[].class, new Integer(java.sql.Types.VARBINARY));
typeMap.put(java.sql.Date.class, new Integer(java.sql.Types.DATE));
typeMap.put(java.sql.Time.class, new Integer(java.sql.Types.TIME));
typeMap.put(java.sql.Timestamp.class, new Integer(java.sql.Types.TIMESTAMP));
typeMap.put(BlobImpl.class, new Integer(java.sql.Types.LONGVARBINARY));
typeMap.put(ClobImpl.class, new Integer(java.sql.Types.LONGVARCHAR));
typeMap.put(String.class, new Integer(java.sql.Types.VARCHAR));
typeMap.put(Blob.class, new Integer(java.sql.Types.LONGVARBINARY));
typeMap.put(Clob.class, new Integer(java.sql.Types.LONGVARCHAR));
}
/**
* Hex constants to use in conversion routines.
*/
private static final char hex[] = {'0', '1', '2', '3', '4', '5', '6','7',
'8', '9', 'A', 'B', 'C', 'D', 'E','F'
};
/**
* Static utility Calendar object.
*/
private static final GregorianCalendar cal = new GregorianCalendar();
/**
* Convert a byte[] object to a hex string.
*
* @param bytes The byte array to convert.
* @return The hex equivalent as a <code>String</code>.
*/
public static String toHex(byte[] bytes) {
int len = bytes.length;
if (len > 0) {
StringBuffer buf = new StringBuffer(len * 2);
for (int i = 0; i < len; i++) {
int b1 = bytes[i] & 0xFF;
buf.append(hex[b1 >> 4]);
buf.append(hex[b1 & 0x0F]);
}
return buf.toString();
}
return "";
}
/**
* Normalize a BigDecimal value so that it fits within the
* available precision.
*
* @param value The decimal value to normalize.
* @param maxPrecision The decimal precision supported by the server
* (assumed to be a value of either 28 or 38).
* @return The possibly normalized decimal value as a <code>BigDecimal</code>.
* @throws SQLException If the number is too big.
*/
static BigDecimal normalizeBigDecimal(BigDecimal value, int maxPrecision)
throws SQLException {
if (value == null) {
return null;
}
if (value.scale() < 0) {
// Java 1.5 BigDecimal allows negative scales.
// jTDS cannot send these so re-scale.
value = value.setScale(0);
}
if (value.scale() > maxPrecision) {
// This is an optimization to quickly adjust the scale of a
// very precise BD value. For example
// BigDecimal((double)1.0/3.0) yields a BD 54 digits long!
value = value.setScale(maxPrecision, BigDecimal.ROUND_HALF_UP);
}
BigInteger max = (maxPrecision == TdsData.DEFAULT_PRECISION_28) ? MAX_VALUE_28 : MAX_VALUE_38;
while (value.abs().unscaledValue().compareTo(max) > 0) {
// OK we need to reduce the scale if possible to preserve
// the integer part of the number and still fit within the
// available precision.
int scale = value.scale() - 1;
if (scale < 0) {
// Can't do it number just too big
throw new SQLException(Messages.get("error.normalize.numtoobig",
String.valueOf(maxPrecision)), "22000");
}
value = value.setScale(scale, BigDecimal.ROUND_HALF_UP);
}
return value;
}
/**
* 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 {
try {
switch (jdbcType) {
case java.sql.Types.TINYINT:
case java.sql.Types.SMALLINT:
case java.sql.Types.INTEGER:
if (x == null) {
return INTEGER_ZERO;
} else if (x instanceof Integer) {
return x;
} else if (x instanceof Byte) {
return new Integer(((Byte)x).byteValue() & 0xFF);
} else if (x instanceof Number) {
return new Integer(((Number) x).intValue());
} else if (x instanceof String) {
return new Integer(((String) x).trim());
} else if (x instanceof Boolean) {
return ((Boolean) x).booleanValue() ? INTEGER_ONE : INTEGER_ZERO;
}
break;
case java.sql.Types.BIGINT:
if (x == null) {
return LONG_ZERO;
} else if (x instanceof Long) {
return x;
} else if (x instanceof Byte) {
return new Long(((Byte)x).byteValue() & 0xFF);
} else if (x instanceof Number) {
return new Long(((Number) x).longValue());
} else if (x instanceof String) {
return new Long(((String) x).trim());
} else if (x instanceof Boolean) {
return ((Boolean) x).booleanValue() ? LONG_ONE : LONG_ZERO;
}
break;
case java.sql.Types.REAL:
if (x == null) {
return FLOAT_ZERO;
} else 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 == null) {
return DOUBLE_ZERO;
} else 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 == null) {
return null;
} else 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 == null) {
return null;
} else 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 == null) {
return Boolean.FALSE;
} else if (x instanceof Boolean) {
return x;
} else if (x instanceof Number) {
return(((Number) x).intValue() == 0) ? Boolean.FALSE : Boolean.TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -