0001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
0002: // Copyright (C) 2004 The jTDS Project
0003: //
0004: // This library is free software; you can redistribute it and/or
0005: // modify it under the terms of the GNU Lesser General Public
0006: // License as published by the Free Software Foundation; either
0007: // version 2.1 of the License, or (at your option) any later version.
0008: //
0009: // This library is distributed in the hope that it will be useful,
0010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: // Lesser General Public License for more details.
0013: //
0014: // You should have received a copy of the GNU Lesser General Public
0015: // License along with this library; if not, write to the Free Software
0016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: //
0018: package net.sourceforge.jtds.jdbc;
0019:
0020: import java.io.*;
0021: import java.lang.reflect.Method;
0022: import java.math.BigDecimal;
0023: import java.math.BigInteger;
0024: import java.sql.*;
0025: import java.util.Calendar;
0026: import java.util.GregorianCalendar;
0027: import java.util.HashMap;
0028:
0029: import net.sourceforge.jtds.util.Logger;
0030:
0031: /**
0032: * This class contains static utility methods designed to support the
0033: * main driver classes.
0034: * <p>
0035: * Implementation notes:
0036: * <ol>
0037: * <li>The methods in this class incorporate some code from previous versions
0038: * of jTDS to handle dates, BLobs etc.
0039: * <li>This class contains routines to generate runtime messages from the resource file.
0040: * <li>The key data conversion logic used in Statements and result sets is implemented here.
0041: * <li>There is nothing here which is TDS specific.
0042: * </ol>
0043: *
0044: * @author Mike Hutchinson
0045: * @author jTDS project
0046: * @version $Id: Support.java,v 1.56 2007/07/08 18:42:14 bheineman Exp $
0047: */
0048: public class Support {
0049: // Constants used in datatype conversions to avoid object allocations.
0050: private static final Integer INTEGER_ZERO = new Integer(0);
0051: private static final Integer INTEGER_ONE = new Integer(1);
0052: private static final Long LONG_ZERO = new Long(0L);
0053: private static final Long LONG_ONE = new Long(1L);
0054: private static final Float FLOAT_ZERO = new Float(0.0);
0055: private static final Float FLOAT_ONE = new Float(1.0);
0056: private static final Double DOUBLE_ZERO = new Double(0.0);
0057: private static final Double DOUBLE_ONE = new Double(1.0);
0058: private static final BigDecimal BIG_DECIMAL_ZERO = new BigDecimal(
0059: 0.0);
0060: private static final BigDecimal BIG_DECIMAL_ONE = new BigDecimal(
0061: 1.0);
0062: private static final java.sql.Date DATE_ZERO = new java.sql.Date(0);
0063: private static final java.sql.Time TIME_ZERO = new java.sql.Time(0);
0064: private static final BigInteger MAX_VALUE_28 = new BigInteger(
0065: "9999999999999999999999999999");
0066: private static final BigInteger MAX_VALUE_38 = new BigInteger(
0067: "99999999999999999999999999999999999999");
0068:
0069: /**
0070: * Convert java clases to java.sql.Type constant.
0071: */
0072: private static final HashMap typeMap = new HashMap();
0073:
0074: static {
0075: typeMap.put(Byte.class, new Integer(java.sql.Types.TINYINT));
0076: typeMap.put(Short.class, new Integer(java.sql.Types.SMALLINT));
0077: typeMap.put(Integer.class, new Integer(java.sql.Types.INTEGER));
0078: typeMap.put(Long.class, new Integer(java.sql.Types.BIGINT));
0079: typeMap.put(Float.class, new Integer(java.sql.Types.REAL));
0080: typeMap.put(Double.class, new Integer(java.sql.Types.DOUBLE));
0081: typeMap.put(BigDecimal.class, new Integer(
0082: java.sql.Types.DECIMAL));
0083: typeMap.put(Boolean.class, new Integer(JtdsStatement.BOOLEAN));
0084: typeMap
0085: .put(byte[].class,
0086: new Integer(java.sql.Types.VARBINARY));
0087: typeMap.put(java.sql.Date.class, new Integer(
0088: java.sql.Types.DATE));
0089: typeMap.put(java.sql.Time.class, new Integer(
0090: java.sql.Types.TIME));
0091: typeMap.put(java.sql.Timestamp.class, new Integer(
0092: java.sql.Types.TIMESTAMP));
0093: typeMap.put(BlobImpl.class, new Integer(
0094: java.sql.Types.LONGVARBINARY));
0095: typeMap.put(ClobImpl.class, new Integer(
0096: java.sql.Types.LONGVARCHAR));
0097: typeMap.put(String.class, new Integer(java.sql.Types.VARCHAR));
0098: typeMap.put(Blob.class, new Integer(
0099: java.sql.Types.LONGVARBINARY));
0100: typeMap
0101: .put(Clob.class,
0102: new Integer(java.sql.Types.LONGVARCHAR));
0103: }
0104:
0105: /**
0106: * Hex constants to use in conversion routines.
0107: */
0108: private static final char hex[] = { '0', '1', '2', '3', '4', '5',
0109: '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
0110:
0111: /**
0112: * Static utility Calendar object.
0113: */
0114: private static final GregorianCalendar cal = new GregorianCalendar();
0115:
0116: /**
0117: * Convert a byte[] object to a hex string.
0118: *
0119: * @param bytes The byte array to convert.
0120: * @return The hex equivalent as a <code>String</code>.
0121: */
0122: public static String toHex(byte[] bytes) {
0123: int len = bytes.length;
0124:
0125: if (len > 0) {
0126: StringBuffer buf = new StringBuffer(len * 2);
0127:
0128: for (int i = 0; i < len; i++) {
0129: int b1 = bytes[i] & 0xFF;
0130:
0131: buf.append(hex[b1 >> 4]);
0132: buf.append(hex[b1 & 0x0F]);
0133: }
0134:
0135: return buf.toString();
0136: }
0137:
0138: return "";
0139: }
0140:
0141: /**
0142: * Normalize a BigDecimal value so that it fits within the
0143: * available precision.
0144: *
0145: * @param value The decimal value to normalize.
0146: * @param maxPrecision The decimal precision supported by the server
0147: * (assumed to be a value of either 28 or 38).
0148: * @return The possibly normalized decimal value as a <code>BigDecimal</code>.
0149: * @throws SQLException If the number is too big.
0150: */
0151: static BigDecimal normalizeBigDecimal(BigDecimal value,
0152: int maxPrecision) throws SQLException {
0153:
0154: if (value == null) {
0155: return null;
0156: }
0157:
0158: if (value.scale() < 0) {
0159: // Java 1.5 BigDecimal allows negative scales.
0160: // jTDS cannot send these so re-scale.
0161: value = value.setScale(0);
0162: }
0163:
0164: if (value.scale() > maxPrecision) {
0165: // This is an optimization to quickly adjust the scale of a
0166: // very precise BD value. For example
0167: // BigDecimal((double)1.0/3.0) yields a BD 54 digits long!
0168: value = value.setScale(maxPrecision,
0169: BigDecimal.ROUND_HALF_UP);
0170: }
0171:
0172: BigInteger max = (maxPrecision == TdsData.DEFAULT_PRECISION_28) ? MAX_VALUE_28
0173: : MAX_VALUE_38;
0174:
0175: while (value.abs().unscaledValue().compareTo(max) > 0) {
0176: // OK we need to reduce the scale if possible to preserve
0177: // the integer part of the number and still fit within the
0178: // available precision.
0179: int scale = value.scale() - 1;
0180:
0181: if (scale < 0) {
0182: // Can't do it number just too big
0183: throw new SQLException(Messages.get(
0184: "error.normalize.numtoobig", String
0185: .valueOf(maxPrecision)), "22000");
0186: }
0187:
0188: value = value.setScale(scale, BigDecimal.ROUND_HALF_UP);
0189: }
0190:
0191: return value;
0192: }
0193:
0194: /**
0195: * Convert an existing data object to the specified JDBC type.
0196: *
0197: * @param callerReference an object reference to the caller of this method;
0198: * must be a <code>Connection</code>,
0199: * <code>Statement</code> or <code>ResultSet</code>
0200: * @param x the data object to convert
0201: * @param jdbcType the required type constant from
0202: * <code>java.sql.Types</code>
0203: * @return the converted data object
0204: * @throws SQLException if the conversion is not supported or fails
0205: */
0206: static Object convert(Object callerReference, Object x,
0207: int jdbcType, String charSet) throws SQLException {
0208: try {
0209: switch (jdbcType) {
0210: case java.sql.Types.TINYINT:
0211: case java.sql.Types.SMALLINT:
0212: case java.sql.Types.INTEGER:
0213: if (x == null) {
0214: return INTEGER_ZERO;
0215: } else if (x instanceof Integer) {
0216: return x;
0217: } else if (x instanceof Byte) {
0218: return new Integer(((Byte) x).byteValue() & 0xFF);
0219: } else if (x instanceof Number) {
0220: return new Integer(((Number) x).intValue());
0221: } else if (x instanceof String) {
0222: return new Integer(((String) x).trim());
0223: } else if (x instanceof Boolean) {
0224: return ((Boolean) x).booleanValue() ? INTEGER_ONE
0225: : INTEGER_ZERO;
0226: }
0227: break;
0228:
0229: case java.sql.Types.BIGINT:
0230: if (x == null) {
0231: return LONG_ZERO;
0232: } else if (x instanceof Long) {
0233: return x;
0234: } else if (x instanceof Byte) {
0235: return new Long(((Byte) x).byteValue() & 0xFF);
0236: } else if (x instanceof Number) {
0237: return new Long(((Number) x).longValue());
0238: } else if (x instanceof String) {
0239: return new Long(((String) x).trim());
0240: } else if (x instanceof Boolean) {
0241: return ((Boolean) x).booleanValue() ? LONG_ONE
0242: : LONG_ZERO;
0243: }
0244:
0245: break;
0246:
0247: case java.sql.Types.REAL:
0248: if (x == null) {
0249: return FLOAT_ZERO;
0250: } else if (x instanceof Float) {
0251: return x;
0252: } else if (x instanceof Byte) {
0253: return new Float(((Byte) x).byteValue() & 0xFF);
0254: } else if (x instanceof Number) {
0255: return new Float(((Number) x).floatValue());
0256: } else if (x instanceof String) {
0257: return new Float(((String) x).trim());
0258: } else if (x instanceof Boolean) {
0259: return ((Boolean) x).booleanValue() ? FLOAT_ONE
0260: : FLOAT_ZERO;
0261: }
0262:
0263: break;
0264:
0265: case java.sql.Types.FLOAT:
0266: case java.sql.Types.DOUBLE:
0267: if (x == null) {
0268: return DOUBLE_ZERO;
0269: } else if (x instanceof Double) {
0270: return x;
0271: } else if (x instanceof Byte) {
0272: return new Double(((Byte) x).byteValue() & 0xFF);
0273: } else if (x instanceof Number) {
0274: return new Double(((Number) x).doubleValue());
0275: } else if (x instanceof String) {
0276: return new Double(((String) x).trim());
0277: } else if (x instanceof Boolean) {
0278: return ((Boolean) x).booleanValue() ? DOUBLE_ONE
0279: : DOUBLE_ZERO;
0280: }
0281:
0282: break;
0283:
0284: case java.sql.Types.NUMERIC:
0285: case java.sql.Types.DECIMAL:
0286: if (x == null) {
0287: return null;
0288: } else if (x instanceof BigDecimal) {
0289: return x;
0290: } else if (x instanceof Number) {
0291: return new BigDecimal(x.toString());
0292: } else if (x instanceof String) {
0293: return new BigDecimal((String) x);
0294: } else if (x instanceof Boolean) {
0295: return ((Boolean) x).booleanValue() ? BIG_DECIMAL_ONE
0296: : BIG_DECIMAL_ZERO;
0297: }
0298:
0299: break;
0300:
0301: case java.sql.Types.VARCHAR:
0302: case java.sql.Types.CHAR:
0303: if (x == null) {
0304: return null;
0305: } else if (x instanceof String) {
0306: return x;
0307: } else if (x instanceof Number) {
0308: return x.toString();
0309: } else if (x instanceof Boolean) {
0310: return ((Boolean) x).booleanValue() ? "1" : "0";
0311: } else if (x instanceof Clob) {
0312: Clob clob = (Clob) x;
0313: long length = clob.length();
0314:
0315: if (length > Integer.MAX_VALUE) {
0316: throw new SQLException(Messages
0317: .get("error.normalize.lobtoobig"),
0318: "22000");
0319: }
0320:
0321: return clob.getSubString(1, (int) length);
0322: } else if (x instanceof Blob) {
0323: Blob blob = (Blob) x;
0324: long length = blob.length();
0325:
0326: if (length > Integer.MAX_VALUE) {
0327: throw new SQLException(Messages
0328: .get("error.normalize.lobtoobig"),
0329: "22000");
0330: }
0331:
0332: x = blob.getBytes(1, (int) length);
0333: }
0334:
0335: if (x instanceof byte[]) {
0336: return toHex((byte[]) x);
0337: }
0338:
0339: return x.toString(); // Last hope!
0340:
0341: case java.sql.Types.BIT:
0342: case JtdsStatement.BOOLEAN:
0343: if (x == null) {
0344: return Boolean.FALSE;
0345: } else if (x instanceof Boolean) {
0346: return x;
0347: } else if (x instanceof Number) {
0348: return (((Number) x).intValue() == 0) ? Boolean.FALSE
0349: : Boolean.TRUE;
0350: } else if (x instanceof String) {
0351: String tmp = ((String) x).trim();
0352:
0353: return ("1".equals(tmp) || "true"
0354: .equalsIgnoreCase(tmp)) ? Boolean.TRUE
0355: : Boolean.FALSE;
0356: }
0357:
0358: break;
0359:
0360: case java.sql.Types.VARBINARY:
0361: case java.sql.Types.BINARY:
0362: if (x == null) {
0363: return null;
0364: } else if (x instanceof byte[]) {
0365: return x;
0366: } else if (x instanceof Blob) {
0367: Blob blob = (Blob) x;
0368:
0369: return blob.getBytes(1, (int) blob.length());
0370: } else if (x instanceof Clob) {
0371: Clob clob = (Clob) x;
0372: long length = clob.length();
0373:
0374: if (length > Integer.MAX_VALUE) {
0375: throw new SQLException(Messages
0376: .get("error.normalize.lobtoobig"),
0377: "22000");
0378: }
0379:
0380: x = clob.getSubString(1, (int) length);
0381: }
0382:
0383: if (x instanceof String) {
0384: //
0385: // Strictly speaking this conversion is not required by
0386: // the JDBC standard but jTDS has always supported it.
0387: //
0388: if (charSet == null) {
0389: charSet = "ISO-8859-1";
0390: }
0391:
0392: try {
0393: return ((String) x).getBytes(charSet);
0394: } catch (UnsupportedEncodingException e) {
0395: return ((String) x).getBytes();
0396: }
0397: } else if (x instanceof UniqueIdentifier) {
0398: return ((UniqueIdentifier) x).getBytes();
0399: }
0400:
0401: break;
0402:
0403: case java.sql.Types.TIMESTAMP:
0404: if (x == null) {
0405: return null;
0406: } else if (x instanceof DateTime) {
0407: return ((DateTime) x).toTimestamp();
0408: } else if (x instanceof java.sql.Timestamp) {
0409: return x;
0410: } else if (x instanceof java.sql.Date) {
0411: return new java.sql.Timestamp(((java.sql.Date) x)
0412: .getTime());
0413: } else if (x instanceof java.sql.Time) {
0414: return new java.sql.Timestamp(((java.sql.Time) x)
0415: .getTime());
0416: } else if (x instanceof java.lang.String) {
0417: return java.sql.Timestamp.valueOf(((String) x)
0418: .trim());
0419: }
0420:
0421: break;
0422:
0423: case java.sql.Types.DATE:
0424: if (x == null) {
0425: return null;
0426: } else if (x instanceof DateTime) {
0427: return ((DateTime) x).toDate();
0428: } else if (x instanceof java.sql.Date) {
0429: return x;
0430: } else if (x instanceof java.sql.Time) {
0431: return DATE_ZERO;
0432: } else if (x instanceof java.sql.Timestamp) {
0433: synchronized (cal) {
0434: cal.setTime((java.util.Date) x);
0435: cal.set(Calendar.HOUR_OF_DAY, 0);
0436: cal.set(Calendar.MINUTE, 0);
0437: cal.set(Calendar.SECOND, 0);
0438: cal.set(Calendar.MILLISECOND, 0);
0439: // VM1.4+ only return new java.sql.Date(cal.getTimeInMillis());
0440: return new java.sql.Date(cal.getTime()
0441: .getTime());
0442: }
0443: } else if (x instanceof java.lang.String) {
0444: return java.sql.Date.valueOf(((String) x).trim());
0445: }
0446:
0447: break;
0448:
0449: case java.sql.Types.TIME:
0450: if (x == null) {
0451: return null;
0452: } else if (x instanceof DateTime) {
0453: return ((DateTime) x).toTime();
0454: } else if (x instanceof java.sql.Time) {
0455: return x;
0456: } else if (x instanceof java.sql.Date) {
0457: return TIME_ZERO;
0458: } else if (x instanceof java.sql.Timestamp) {
0459: synchronized (cal) {
0460: // VM 1.4+ only cal.setTimeInMillis(((java.sql.Timestamp)x).getTime());
0461: cal.setTime((java.util.Date) x);
0462: cal.set(Calendar.YEAR, 1970);
0463: cal.set(Calendar.MONTH, 0);
0464: cal.set(Calendar.DAY_OF_MONTH, 1);
0465: // VM 1.4+ only return new java.sql.Time(cal.getTimeInMillis());*/
0466: return new java.sql.Time(cal.getTime()
0467: .getTime());
0468: }
0469: } else if (x instanceof java.lang.String) {
0470: return java.sql.Time.valueOf(((String) x).trim());
0471: }
0472:
0473: break;
0474:
0475: case java.sql.Types.OTHER:
0476: return x;
0477:
0478: case java.sql.Types.JAVA_OBJECT:
0479: throw new SQLException(Messages.get(
0480: "error.convert.badtypes", x.getClass()
0481: .getName(), getJdbcTypeName(jdbcType)),
0482: "22005");
0483:
0484: case java.sql.Types.LONGVARBINARY:
0485: case java.sql.Types.BLOB:
0486: if (x == null) {
0487: return null;
0488: } else if (x instanceof Blob) {
0489: return x;
0490: } else if (x instanceof byte[]) {
0491: return new BlobImpl(getConnection(callerReference),
0492: (byte[]) x);
0493: } else if (x instanceof Clob) {
0494: //
0495: // Convert CLOB to BLOB. Not required by the standard but we will
0496: // do it anyway.
0497: //
0498: Clob clob = (Clob) x;
0499: try {
0500: if (charSet == null) {
0501: charSet = "ISO-8859-1";
0502: }
0503: Reader rdr = clob.getCharacterStream();
0504: BlobImpl blob = new BlobImpl(
0505: getConnection(callerReference));
0506: BufferedWriter out = new BufferedWriter(
0507: new OutputStreamWriter(blob
0508: .setBinaryStream(1), charSet));
0509: // TODO Use a buffer to improve performance
0510: int c;
0511: while ((c = rdr.read()) >= 0) {
0512: out.write(c);
0513: }
0514: out.close();
0515: rdr.close();
0516: return blob;
0517: } catch (UnsupportedEncodingException e) {
0518: // Unlikely to happen but fall back on in memory copy
0519: x = clob.getSubString(1, (int) clob.length());
0520: } catch (IOException e) {
0521: throw new SQLException(Messages
0522: .get("error.generic.ioerror", e
0523: .getMessage()), "HY000");
0524: }
0525: }
0526:
0527: if (x instanceof String) {
0528: //
0529: // Strictly speaking this conversion is also not required by
0530: // the JDBC standard but jTDS has always supported it.
0531: //
0532: BlobImpl blob = new BlobImpl(
0533: getConnection(callerReference));
0534: String data = (String) x;
0535:
0536: if (charSet == null) {
0537: charSet = "ISO-8859-1";
0538: }
0539:
0540: try {
0541: blob.setBytes(1, data.getBytes(charSet));
0542: } catch (UnsupportedEncodingException e) {
0543: blob.setBytes(1, data.getBytes());
0544: }
0545:
0546: return blob;
0547: }
0548:
0549: break;
0550:
0551: case java.sql.Types.LONGVARCHAR:
0552: case java.sql.Types.CLOB:
0553: if (x == null) {
0554: return null;
0555: } else if (x instanceof Clob) {
0556: return x;
0557: } else if (x instanceof Blob) {
0558: //
0559: // Convert BLOB to CLOB
0560: //
0561: Blob blob = (Blob) x;
0562: try {
0563: InputStream is = blob.getBinaryStream();
0564: ClobImpl clob = new ClobImpl(
0565: getConnection(callerReference));
0566: Writer out = clob.setCharacterStream(1);
0567: // TODO Use a buffer to improve performance
0568: int b;
0569: // These reads/writes are buffered by the undelying blob buffers
0570: while ((b = is.read()) >= 0) {
0571: out.write(hex[b >> 4]);
0572: out.write(hex[b & 0x0F]);
0573: }
0574: out.close();
0575: is.close();
0576: return clob;
0577: } catch (IOException e) {
0578: throw new SQLException(Messages
0579: .get("error.generic.ioerror", e
0580: .getMessage()), "HY000");
0581: }
0582: } else if (x instanceof Boolean) {
0583: x = ((Boolean) x).booleanValue() ? "1" : "0";
0584: } else if (!(x instanceof byte[])) {
0585: x = x.toString();
0586: }
0587:
0588: if (x instanceof byte[]) {
0589: ClobImpl clob = new ClobImpl(
0590: getConnection(callerReference));
0591: clob.setString(1, toHex((byte[]) x));
0592:
0593: return clob;
0594: } else if (x instanceof String) {
0595: return new ClobImpl(getConnection(callerReference),
0596: (String) x);
0597: }
0598:
0599: break;
0600:
0601: default:
0602: throw new SQLException(Messages.get(
0603: "error.convert.badtypeconst",
0604: getJdbcTypeName(jdbcType)), "HY004");
0605: }
0606:
0607: throw new SQLException(Messages.get(
0608: "error.convert.badtypes", x.getClass().getName(),
0609: getJdbcTypeName(jdbcType)), "22005");
0610: } catch (NumberFormatException nfe) {
0611: throw new SQLException(Messages.get(
0612: "error.convert.badnumber",
0613: getJdbcTypeName(jdbcType)), "22000");
0614: }
0615: }
0616:
0617: /**
0618: * Get the JDBC type constant which matches the supplied Object type.
0619: *
0620: * @param value The object to analyse.
0621: * @return The JDBC type constant as an <code>int</code>.
0622: */
0623: static int getJdbcType(Object value) {
0624: if (value == null) {
0625: return java.sql.Types.NULL;
0626: }
0627:
0628: return getJdbcType(value.getClass());
0629: }
0630:
0631: /**
0632: * Get the JDBC type constant which matches the supplied <code>Class</code>.
0633: *
0634: * @param typeClass the <code>Class</code> to analyse
0635: * @return the JDBC type constant as an <code>int</code>
0636: */
0637: static int getJdbcType(Class typeClass) {
0638: if (typeClass == null) {
0639: return java.sql.Types.JAVA_OBJECT;
0640: }
0641:
0642: Object type = typeMap.get(typeClass);
0643:
0644: if (type == null) {
0645: // not in typeMap - try recursion through superclass hierarchy
0646: return getJdbcType(typeClass.getSuperclass());
0647: }
0648:
0649: return ((Integer) type).intValue();
0650: }
0651:
0652: /**
0653: * Get a String describing the supplied JDBC type constant.
0654: *
0655: * @param jdbcType The constant to be decoded.
0656: * @return The text decode of the type constant as a <code>String</code>.
0657: */
0658: static String getJdbcTypeName(int jdbcType) {
0659: switch (jdbcType) {
0660: case java.sql.Types.ARRAY:
0661: return "ARRAY";
0662: case java.sql.Types.BIGINT:
0663: return "BIGINT";
0664: case java.sql.Types.BINARY:
0665: return "BINARY";
0666: case java.sql.Types.BIT:
0667: return "BIT";
0668: case java.sql.Types.BLOB:
0669: return "BLOB";
0670: case JtdsStatement.BOOLEAN:
0671: return "BOOLEAN";
0672: case java.sql.Types.CHAR:
0673: return "CHAR";
0674: case java.sql.Types.CLOB:
0675: return "CLOB";
0676: case JtdsStatement.DATALINK:
0677: return "DATALINK";
0678: case java.sql.Types.DATE:
0679: return "DATE";
0680: case java.sql.Types.DECIMAL:
0681: return "DECIMAL";
0682: case java.sql.Types.DISTINCT:
0683: return "DISTINCT";
0684: case java.sql.Types.DOUBLE:
0685: return "DOUBLE";
0686: case java.sql.Types.FLOAT:
0687: return "FLOAT";
0688: case java.sql.Types.INTEGER:
0689: return "INTEGER";
0690: case java.sql.Types.JAVA_OBJECT:
0691: return "JAVA_OBJECT";
0692: case java.sql.Types.LONGVARBINARY:
0693: return "LONGVARBINARY";
0694: case java.sql.Types.LONGVARCHAR:
0695: return "LONGVARCHAR";
0696: case java.sql.Types.NULL:
0697: return "NULL";
0698: case java.sql.Types.NUMERIC:
0699: return "NUMERIC";
0700: case java.sql.Types.OTHER:
0701: return "OTHER";
0702: case java.sql.Types.REAL:
0703: return "REAL";
0704: case java.sql.Types.REF:
0705: return "REF";
0706: case java.sql.Types.SMALLINT:
0707: return "SMALLINT";
0708: case java.sql.Types.STRUCT:
0709: return "STRUCT";
0710: case java.sql.Types.TIME:
0711: return "TIME";
0712: case java.sql.Types.TIMESTAMP:
0713: return "TIMESTAMP";
0714: case java.sql.Types.TINYINT:
0715: return "TINYINT";
0716: case java.sql.Types.VARBINARY:
0717: return "VARBINARY";
0718: case java.sql.Types.VARCHAR:
0719: return "VARCHAR";
0720: default:
0721: return "ERROR";
0722: }
0723: }
0724:
0725: /**
0726: * Retrieve the fully qualified java class name for the
0727: * supplied JDBC Types constant.
0728: *
0729: * @param jdbcType The JDBC Types constant.
0730: * @return The fully qualified java class name as a <code>String</code>.
0731: */
0732: static String getClassName(int jdbcType) {
0733: switch (jdbcType) {
0734: case JtdsStatement.BOOLEAN:
0735: case java.sql.Types.BIT:
0736: return "java.lang.Boolean";
0737:
0738: case java.sql.Types.TINYINT:
0739: case java.sql.Types.SMALLINT:
0740: case java.sql.Types.INTEGER:
0741: return "java.lang.Integer";
0742:
0743: case java.sql.Types.BIGINT:
0744: return "java.lang.Long";
0745:
0746: case java.sql.Types.NUMERIC:
0747: case java.sql.Types.DECIMAL:
0748: return "java.math.BigDecimal";
0749:
0750: case java.sql.Types.REAL:
0751: return "java.lang.Float";
0752:
0753: case java.sql.Types.FLOAT:
0754: case java.sql.Types.DOUBLE:
0755: return "java.lang.Double";
0756:
0757: case java.sql.Types.CHAR:
0758: case java.sql.Types.VARCHAR:
0759: return "java.lang.String";
0760:
0761: case java.sql.Types.BINARY:
0762: case java.sql.Types.VARBINARY:
0763: return "[B";
0764:
0765: case java.sql.Types.LONGVARBINARY:
0766: case java.sql.Types.BLOB:
0767: return "java.sql.Blob";
0768:
0769: case java.sql.Types.LONGVARCHAR:
0770: case java.sql.Types.CLOB:
0771: return "java.sql.Clob";
0772:
0773: case java.sql.Types.DATE:
0774: return "java.sql.Date";
0775:
0776: case java.sql.Types.TIME:
0777: return "java.sql.Time";
0778:
0779: case java.sql.Types.TIMESTAMP:
0780: return "java.sql.Timestamp";
0781: }
0782:
0783: return "java.lang.Object";
0784: }
0785:
0786: /**
0787: * Embed the data object as a string literal in the buffer supplied.
0788: *
0789: * @param buf The buffer in which the data will be embeded.
0790: * @param value The data object.
0791: * @param isUnicode Set to <code>true</code> if Unicode strings should be used, else <code>false</code>.
0792: * @param connection The {@link ConnectionJDBC2} object.
0793: */
0794: static void embedData(StringBuffer buf, Object value,
0795: boolean isUnicode, ConnectionJDBC2 connection)
0796: throws SQLException {
0797: buf.append(' ');
0798: if (value == null) {
0799: buf.append("NULL ");
0800: return;
0801: }
0802:
0803: if (value instanceof Blob) {
0804: Blob blob = (Blob) value;
0805:
0806: value = blob.getBytes(1, (int) blob.length());
0807: } else if (value instanceof Clob) {
0808: Clob clob = (Clob) value;
0809:
0810: value = clob.getSubString(1, (int) clob.length());
0811: }
0812:
0813: if (value instanceof DateTime) {
0814: buf.append('\'');
0815: buf.append(value);
0816: buf.append('\'');
0817: } else if (value instanceof byte[]) {
0818: byte[] bytes = (byte[]) value;
0819:
0820: int len = bytes.length;
0821:
0822: if (len >= 0) {
0823: buf.append('0').append('x');
0824: if (len == 0
0825: && connection.getTdsVersion() < Driver.TDS70) {
0826: // Zero length binary values are not allowed
0827: buf.append('0').append('0');
0828: } else {
0829: for (int i = 0; i < len; i++) {
0830: int b1 = bytes[i] & 0xFF;
0831:
0832: buf.append(hex[b1 >> 4]);
0833: buf.append(hex[b1 & 0x0F]);
0834: }
0835: }
0836: }
0837: } else if (value instanceof String) {
0838: String tmp = (String) value;
0839: int len = tmp.length();
0840:
0841: if (isUnicode) {
0842: buf.append('N');
0843: }
0844: buf.append('\'');
0845:
0846: for (int i = 0; i < len; i++) {
0847: char c = tmp.charAt(i);
0848:
0849: if (c == '\'') {
0850: buf.append('\'');
0851: }
0852:
0853: buf.append(c);
0854: }
0855:
0856: buf.append('\'');
0857: } else if (value instanceof java.sql.Date) {
0858: DateTime dt = new DateTime((java.sql.Date) value);
0859: buf.append('\'');
0860: buf.append(dt);
0861: buf.append('\'');
0862: } else if (value instanceof java.sql.Time) {
0863: DateTime dt = new DateTime((java.sql.Time) value);
0864: buf.append('\'');
0865: buf.append(dt);
0866: buf.append('\'');
0867: } else if (value instanceof java.sql.Timestamp) {
0868: DateTime dt = new DateTime((java.sql.Timestamp) value);
0869: buf.append('\'');
0870: buf.append(dt);
0871: buf.append('\'');
0872: } else if (value instanceof Boolean) {
0873: buf.append(((Boolean) value).booleanValue() ? '1' : '0');
0874: } else if (value instanceof BigDecimal) {
0875: //
0876: // Ensure large decimal number does not overflow the
0877: // maximum precision of the server.
0878: // Main problem is with small numbers e.g. BigDecimal(1.0).toString() =
0879: // 0.1000000000000000055511151231....
0880: //
0881: String tmp = value.toString();
0882: int maxlen = connection.getMaxPrecision();
0883: if (tmp.charAt(0) == '-') {
0884: maxlen++;
0885: }
0886: if (tmp.indexOf('.') >= 0) {
0887: maxlen++;
0888: }
0889: if (tmp.length() > maxlen) {
0890: buf.append(tmp.substring(0, maxlen));
0891: } else {
0892: buf.append(tmp);
0893: }
0894: } else {
0895: buf.append(value.toString());
0896: }
0897: buf.append(' ');
0898: }
0899:
0900: /**
0901: * Generates a unique statement key for a given SQL statement.
0902: *
0903: * @param sql the sql statment to generate the key for
0904: * @param params the statement parameters
0905: * @param serverType the type of server to generate the key for
0906: * @param catalog the catalog is required for uniqueness on Microsoft
0907: * SQL Server
0908: * @param autoCommit true if in auto commit mode
0909: * @param cursor true if this is a prepared cursor
0910: * @return the unique statement key
0911: */
0912: static String getStatementKey(String sql, ParamInfo[] params,
0913: int serverType, String catalog, boolean autoCommit,
0914: boolean cursor) {
0915: StringBuffer key;
0916:
0917: if (serverType == Driver.SQLSERVER) {
0918: key = new StringBuffer(1 + catalog.length() + sql.length()
0919: + 11 * params.length);
0920: // Need to distinguish otherwise identical SQL for cursor and
0921: // non cursor prepared statements (sp_prepare/sp_cursorprepare).
0922: key.append((cursor) ? 'C' : 'X');
0923: // Need to ensure that the current database is included in the key
0924: // as procedures and handles are database specific.
0925: key.append(catalog);
0926: // Now the actual SQL statement
0927: key.append(sql);
0928: //
0929: // Append parameter data types to key.
0930: //
0931: for (int i = 0; i < params.length; i++) {
0932: key.append(params[i].sqlType);
0933: }
0934: } else {
0935: key = new StringBuffer(sql.length() + 2);
0936: // A simple key works for Sybase just need to know if
0937: // proc created in chained mode or not.
0938: key.append((autoCommit) ? 'T' : 'F');
0939: // Now the actual SQL statement
0940: key.append(sql);
0941: }
0942:
0943: return key.toString();
0944: }
0945:
0946: /**
0947: * Constructs a parameter definition string for use with
0948: * sp_executesql, sp_prepare, sp_prepexec, sp_cursoropen,
0949: * sp_cursorprepare and sp_cursorprepexec.
0950: *
0951: * @param parameters Parameters to construct the definition for
0952: * @return a parameter definition string
0953: */
0954: static String getParameterDefinitions(ParamInfo[] parameters) {
0955: StringBuffer sql = new StringBuffer(parameters.length * 15);
0956:
0957: // Build parameter descriptor
0958: for (int i = 0; i < parameters.length; i++) {
0959: if (parameters[i].name == null) {
0960: sql.append("@P");
0961: sql.append(i);
0962: } else {
0963: sql.append(parameters[i].name);
0964: }
0965:
0966: sql.append(' ');
0967: sql.append(parameters[i].sqlType);
0968:
0969: if (i + 1 < parameters.length) {
0970: sql.append(',');
0971: }
0972: }
0973:
0974: return sql.toString();
0975: }
0976:
0977: /**
0978: * Update the SQL string and replace the ? markers with parameter names
0979: * eg @P0, @P1 etc.
0980: *
0981: * @param sql the SQL containing markers to substitute
0982: * @param list the parameter list
0983: * @return the modified SQL as a <code>String</code>
0984: */
0985: static String substituteParamMarkers(String sql, ParamInfo[] list) {
0986: // A parameter can have at most 8 characters: " @P" plus at most 4
0987: // digits plus " ". We substract the "?" placeholder, that's at most
0988: // 7 extra characters needed for each parameter.
0989: char[] buf = new char[sql.length() + list.length * 7];
0990: int bufferPtr = 0; // Output buffer pointer
0991: int start = 0; // Input string pointer
0992: StringBuffer number = new StringBuffer(4);
0993:
0994: for (int i = 0; i < list.length; i++) {
0995: int pos = list[i].markerPos;
0996:
0997: if (pos > 0) {
0998: sql.getChars(start, pos, buf, bufferPtr);
0999: bufferPtr += (pos - start);
1000: start = pos + 1;
1001:
1002: // Append " @P"
1003: buf[bufferPtr++] = ' ';
1004: buf[bufferPtr++] = '@';
1005: buf[bufferPtr++] = 'P';
1006:
1007: // Append parameter number
1008: // Rather complicated, but it's the only way in which no
1009: // unnecessary objects are created
1010: number.setLength(0);
1011: number.append(i);
1012: number.getChars(0, number.length(), buf, bufferPtr);
1013: bufferPtr += number.length();
1014:
1015: // Append " "
1016: buf[bufferPtr++] = ' ';
1017: }
1018: }
1019:
1020: if (start < sql.length()) {
1021: sql.getChars(start, sql.length(), buf, bufferPtr);
1022: bufferPtr += (sql.length() - start);
1023: }
1024:
1025: return new String(buf, 0, bufferPtr);
1026: }
1027:
1028: /**
1029: * Substitute actual data for the parameter markers to simulate
1030: * parameter substitution in a PreparedStatement.
1031: *
1032: * @param sql The SQL containing parameter markers to substitute.
1033: * @param list The parameter descriptors.
1034: * @param connection The current connection.
1035: * @return The modified SQL statement.
1036: */
1037: static String substituteParameters(String sql, ParamInfo[] list,
1038: ConnectionJDBC2 connection) throws SQLException {
1039: int len = sql.length();
1040:
1041: for (int i = 0; i < list.length; i++) {
1042: if (!list[i].isRetVal && !list[i].isSet
1043: && !list[i].isOutput) {
1044: throw new SQLException(Messages.get(
1045: "error.prepare.paramnotset", Integer
1046: .toString(i + 1)), "07000");
1047: }
1048:
1049: Object value = list[i].value;
1050:
1051: if (value instanceof java.io.InputStream
1052: || value instanceof java.io.Reader) {
1053: try {
1054: if (list[i].jdbcType == java.sql.Types.LONGVARCHAR
1055: || list[i].jdbcType == java.sql.Types.CLOB
1056: || list[i].jdbcType == java.sql.Types.VARCHAR) {
1057: // TODO: Should improve the character set handling here
1058: value = list[i].getString("US-ASCII");
1059: } else {
1060: value = list[i].getBytes("US-ASCII");
1061: }
1062: // Replace the stream/reader with the String/byte[]
1063: list[i].value = value;
1064: } catch (java.io.IOException e) {
1065: throw new SQLException(Messages.get(
1066: "error.generic.ioerror", e.getMessage()),
1067: "HY000");
1068: }
1069: }
1070:
1071: if (value instanceof String) {
1072: len += ((String) value).length() + 5;
1073: } else if (value instanceof byte[]) {
1074: len += ((byte[]) value).length * 2 + 4;
1075: } else {
1076: len += 32; // Default size
1077: }
1078: }
1079:
1080: StringBuffer buf = new StringBuffer(len + 16);
1081: int start = 0;
1082:
1083: for (int i = 0; i < list.length; i++) {
1084: int pos = list[i].markerPos;
1085:
1086: if (pos > 0) {
1087: buf.append(sql.substring(start, list[i].markerPos));
1088: start = pos + 1;
1089: final boolean isUnicode = connection.getTdsVersion() >= Driver.TDS70
1090: && list[i].isUnicode;
1091: Support.embedData(buf, list[i].value, isUnicode,
1092: connection);
1093: }
1094: }
1095:
1096: if (start < sql.length()) {
1097: buf.append(sql.substring(start));
1098: }
1099:
1100: return buf.toString();
1101: }
1102:
1103: /**
1104: * Encode a string into a byte array using the specified character set.
1105: *
1106: * @param cs The Charset name.
1107: * @param value The value to encode.
1108: * @return The value of the String as a <code>byte[]</code>.
1109: */
1110: static byte[] encodeString(String cs, String value) {
1111: try {
1112: return value.getBytes(cs);
1113: } catch (UnsupportedEncodingException e) {
1114: return value.getBytes();
1115: }
1116: }
1117:
1118: /**
1119: * Link the original cause to an <code>SQLWarning</code>.
1120: * <p>
1121: * This convenience method calls {@link #linkException(Exception, Throwable)}
1122: * and casts the result for cleaner code elsewhere.
1123: *
1124: * @param sqle The <code>SQLWarning</code> to enhance.
1125: * @param cause The <code>Throwable</code> to link.
1126: * @return The original <code>SQLWarning</code> object.
1127: */
1128: public static SQLWarning linkException(SQLWarning sqle,
1129: Throwable cause) {
1130: return (SQLWarning) linkException((Exception) sqle, cause);
1131: }
1132:
1133: /**
1134: * Link the original cause to an <code>SQLException</code>.
1135: * <p>
1136: * This convenience method calls {@link #linkException(Exception, Throwable)}
1137: * and casts the result for cleaner code elsewhere.
1138: *
1139: * @param sqle The <code>SQLException</code> to enhance.
1140: * @param cause The <code>Throwable</code> to link.
1141: * @return The original <code>SQLException</code> object.
1142: */
1143: public static SQLException linkException(SQLException sqle,
1144: Throwable cause) {
1145: return (SQLException) linkException((Exception) sqle, cause);
1146: }
1147:
1148: /**
1149: * Link the original cause to an <code>Exception</code>.
1150: * <p>
1151: * If running under JVM 1.4+ the <code>Throwable.initCause(Throwable)</code>
1152: * method will be invoked to chain the exception, else the exception is
1153: * logged via the {@link Logger} class.
1154: * Modeled after the code written by Brian Heineman.
1155: *
1156: * @param exception The <code>Exception</code> to enhance.
1157: * @param cause The <code>Throwable</code> to link.
1158: * @return The original <code>Exception</code> object.
1159: */
1160: public static Throwable linkException(Exception exception,
1161: Throwable cause) {
1162: Class exceptionClass = exception.getClass();
1163: Class[] parameterTypes = new Class[] { Throwable.class };
1164: Object[] arguments = new Object[] { cause };
1165:
1166: try {
1167: Method initCauseMethod = exceptionClass.getMethod(
1168: "initCause", parameterTypes);
1169: initCauseMethod.invoke(exception, arguments);
1170: } catch (NoSuchMethodException e) {
1171: // Best we can do; this method does not exist in older JVMs.
1172: if (Logger.isActive()) {
1173: Logger.logException((Exception) cause);
1174: }
1175: } catch (Exception e) {
1176: // Ignore all other exceptions. Do not prevent the main exception
1177: // from being returned if reflection fails for any reason.
1178: }
1179:
1180: return exception;
1181: }
1182:
1183: /**
1184: * Convert a timestamp to a different Timezone.
1185: *
1186: * @param value the timestamp value
1187: * @param target the <code>Calendar</code> containing the TimeZone
1188: * @return the new timestamp value as a <code>long</code>
1189: */
1190: public static long timeToZone(java.util.Date value, Calendar target) {
1191: synchronized (cal) {
1192: java.util.Date tmp = target.getTime();
1193: try {
1194: cal.setTime(value);
1195: if (!Driver.JDBC3 && value instanceof Timestamp) {
1196: // Not Running under 1.4 so need to add milliseconds
1197: cal.set(Calendar.MILLISECOND, ((Timestamp) value)
1198: .getNanos() / 1000000);
1199: }
1200: target.set(Calendar.HOUR_OF_DAY, cal
1201: .get(Calendar.HOUR_OF_DAY));
1202: target.set(Calendar.MINUTE, cal.get(Calendar.MINUTE));
1203: target.set(Calendar.SECOND, cal.get(Calendar.SECOND));
1204: target.set(Calendar.MILLISECOND, cal
1205: .get(Calendar.MILLISECOND));
1206: target.set(Calendar.YEAR, cal.get(Calendar.YEAR));
1207: target.set(Calendar.MONTH, cal.get(Calendar.MONTH));
1208: target.set(Calendar.DAY_OF_MONTH, cal
1209: .get(Calendar.DAY_OF_MONTH));
1210: return target.getTime().getTime();
1211: } finally {
1212: target.setTime(tmp);
1213: }
1214: }
1215: }
1216:
1217: /**
1218: * Convert a timestamp from a different Timezone.
1219: * @param value the timestamp value.
1220: * @param target the Calendar containing the TimeZone.
1221: * @return The new timestamp value as a <code>long</code>.
1222: */
1223: public static long timeFromZone(java.util.Date value,
1224: Calendar target) {
1225: synchronized (cal) {
1226: java.util.Date tmp = target.getTime();
1227: try {
1228: target.setTime(value);
1229: if (!Driver.JDBC3 && value instanceof Timestamp) {
1230: // Not Running under 1.4 so need to add milliseconds
1231: target.set(Calendar.MILLISECOND,
1232: ((Timestamp) value).getNanos() / 1000000);
1233: }
1234: cal.set(Calendar.HOUR_OF_DAY, target
1235: .get(Calendar.HOUR_OF_DAY));
1236: cal.set(Calendar.MINUTE, target.get(Calendar.MINUTE));
1237: cal.set(Calendar.SECOND, target.get(Calendar.SECOND));
1238: cal.set(Calendar.MILLISECOND, target
1239: .get(Calendar.MILLISECOND));
1240: cal.set(Calendar.YEAR, target.get(Calendar.YEAR));
1241: cal.set(Calendar.MONTH, target.get(Calendar.MONTH));
1242: cal.set(Calendar.DAY_OF_MONTH, target
1243: .get(Calendar.DAY_OF_MONTH));
1244: return cal.getTime().getTime();
1245: } finally {
1246: target.setTime(tmp);
1247: }
1248: }
1249: }
1250:
1251: /**
1252: * Converts a LOB to the equivalent Java type, i.e. <code>Clob</code> to
1253: * <code>String</code> and <code>Blob</code> to <code>byte[]</code>. If the
1254: * value passed is not a LOB object, it is left unchanged and no exception
1255: * is thrown; the idea is to transparently convert only LOBs.
1256: *
1257: * @param value an object that may be a LOB
1258: * @return if the value was a LOB, the equivalent Java object, otherwise
1259: * the original value
1260: * @throws SQLException if an error occurs while reading the LOB contents
1261: */
1262: public static Object convertLOB(Object value) throws SQLException {
1263: if (value instanceof Clob) {
1264: Clob c = (Clob) value;
1265: return c.getSubString(1, (int) c.length());
1266: }
1267:
1268: if (value instanceof Blob) {
1269: Blob b = (Blob) value;
1270: return b.getBytes(1, (int) b.length());
1271: }
1272:
1273: return value;
1274: }
1275:
1276: /**
1277: * Converts a LOB type constant to the equivalent Java type constant, i.e.
1278: * <code>Types.CLOB</code> to <code>Types.LONGVARCHAR</code> and
1279: * <code>Types.BLOB</code> to <code>Types.LONGVARBINARY</code>. If the
1280: * type passed is not that of a LOB, it is left unchanged and no exception
1281: * is thrown; the idea is to transparently convert only LOB types.
1282: *
1283: * @param type a {@link Types} constant defining a JDBC type, possibly a
1284: * LOB
1285: * @return if the type was that of a LOB, the equivalent Java object type,
1286: * otherwise the original type
1287: */
1288: public static int convertLOBType(int type) {
1289: switch (type) {
1290: case Types.BLOB:
1291: return Types.LONGVARBINARY;
1292: case Types.CLOB:
1293: return Types.LONGVARCHAR;
1294: default:
1295: return type;
1296: }
1297: }
1298:
1299: /**
1300: * Checks the <code>os.name</code> system property to see if it starts
1301: * with "windows".
1302: *
1303: * @return <code>true</code> if <code>os.name</code> starts with "windows",
1304: * else <code>false</code>.
1305: */
1306: public static boolean isWindowsOS() {
1307: return System.getProperty("os.name").toLowerCase().startsWith(
1308: "windows");
1309: }
1310:
1311: // ------------- Private methods ---------
1312:
1313: /**
1314: * Returns the connection for a given <code>ResultSet</code>,
1315: * <code>Statement</code> or <code>Connection</code> object.
1316: *
1317: * @param callerReference an object reference to the caller of this method;
1318: * must be a <code>Connection</code>, <code>Statement</code> or
1319: * <code>ResultSet</code>
1320: * @return a connection
1321: */
1322: private static ConnectionJDBC2 getConnection(Object callerReference) {
1323: if (callerReference == null) {
1324: throw new IllegalArgumentException(
1325: "callerReference cannot be null.");
1326: }
1327:
1328: Connection connection;
1329:
1330: try {
1331: if (callerReference instanceof Connection) {
1332: connection = (Connection) callerReference;
1333: } else if (callerReference instanceof Statement) {
1334: connection = ((Statement) callerReference)
1335: .getConnection();
1336: } else if (callerReference instanceof ResultSet) {
1337: connection = ((ResultSet) callerReference)
1338: .getStatement().getConnection();
1339: } else {
1340: throw new IllegalArgumentException(
1341: "callerReference is invalid.");
1342: }
1343: } catch (SQLException e) {
1344: throw new IllegalStateException(e.getMessage());
1345: }
1346:
1347: return (ConnectionJDBC2) connection;
1348: }
1349:
1350: private Support() {
1351: // Prevent an instance of this class being created.
1352: }
1353:
1354: /**
1355: * Calculate the buffer size to use when buffering the <code>InputStream</code>
1356: * for named pipes.
1357: * <p/>
1358: * The buffer size is tied directly to the packet size because each request
1359: * to the <code>SmbNamedPipe</code> will send a request for a particular
1360: * size of packet. In other words, if you only request 1 byte, the
1361: * <code>SmbNamedPipe</code> will send a request out and only ask for 1 byte
1362: * back. Buffering the expected packet size ensures that all of the data
1363: * will be returned in the buffer without wasting any space.
1364: *
1365: * @param tdsVersion the TDS version for the connection
1366: * @param packetSize requested packet size for the connection
1367: * @return minimum default packet size if <code>packetSize == 0</code>,
1368: * else <code>packetSize</code>
1369: */
1370: static int calculateNamedPipeBufferSize(final int tdsVersion,
1371: final int packetSize) {
1372:
1373: if (packetSize == 0) {
1374: if (tdsVersion >= Driver.TDS70) {
1375: return TdsCore.DEFAULT_MIN_PKT_SIZE_TDS70;
1376: }
1377:
1378: return TdsCore.MIN_PKT_SIZE;
1379: }
1380:
1381: return packetSize;
1382: }
1383: }
|