Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (101)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (309)
Collections:
Other Resources:
jTDS JDBC Driver Source Code Files
jTDS JDBC Driver Source Code Files are provided in the source package file, jtds-1.3.1-fyi.zip.
You can browse jTDS JDBC Driver Source Code files below:
✍: FYIcenter.com
⏎ net/sourceforge/jtds/jdbc/TdsData.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.math.BigInteger; import java.math.BigDecimal; import java.sql.SQLException; import java.sql.Types; import net.sourceforge.jtds.util.BlobBuffer; /** * Implement TDS data types and related I/O logic. * <p> * Implementation notes: * <bl> * <li>This class encapsulates all the knowledge about reading and writing * TDS data descriptors and related application data. * <li>There are four key methods supplied here: * <ol> * <li>readType() - Reads the column and parameter meta data. * <li>readData() - Reads actual data values. * <li>writeParam() - Write parameter descriptors and data. * <li>getNativeType() - knows how to map JDBC data types to the equivalent TDS type. * </ol> * </bl> * * @author Mike Hutchinson * @author Alin Sinpalean * @author freeTDS project * @version $Id: TdsData.java,v 1.60.2.3 2009-11-05 10:42:18 ickzon Exp $ */ public class TdsData { /** * This class implements a descriptor for TDS data types; * * @author Mike Hutchinson. */ private static class TypeInfo { /** The SQL type name. */ public final String sqlType; /** * The size of this type or < 0 for variable sizes. * <p> Special values as follows: * <ol> * <li> -5 sql_variant type. * <li> -4 text, image or ntext types. * <li> -2 SQL Server 7+ long char and var binary types. * <li> -1 varchar, varbinary, null types. * </ol> */ public final int size; /** * The precision of the type. * <p>If this is -1 precision must be calculated from buffer size * eg for varchar fields. */ public final int precision; /** * The display size of the type. * <p>-1 If the display size must be calculated from the buffer size. */ public final int displaySize; /** true if type is a signed numeric. */ public final boolean isSigned; /** true if type requires TDS80 collation. */ public final boolean isCollation; /** The java.sql.Types constant for this data type. */ public final int jdbcType; /** * Construct a new TDS data type descriptor. * * @param sqlType SQL type name. * @param size Byte size for this type or < 0 for variable length types. * @param precision Decimal precision or -1 * @param displaySize Printout size for this type or special values -1,-2. * @param isSigned True if signed numeric type. * @param isCollation True if type has TDS 8 collation information. * @param jdbcType The java.sql.Type constant for this type. */ TypeInfo(String sqlType, int size, int precision, int displaySize, boolean isSigned, boolean isCollation, int jdbcType) { this.sqlType = sqlType; this.size = size; this.precision = precision; this.displaySize = displaySize; this.isSigned = isSigned; this.isCollation = isCollation; this.jdbcType = jdbcType; } } /* * Constants for TDS data types */ private static final int SYBCHAR = 47; // 0x2F private static final int SYBVARCHAR = 39; // 0x27 private static final int SYBINTN = 38; // 0x26 (MS: INTN) private static final int SYBINT1 = 48; // 0x30 (MS: INT1) private static final int SYBDATE = 49; // 0x31 Sybase 12 private static final int SYBTIME = 51; // 0x33 Sybase 12 private static final int SYBINT2 = 52; // 0x34 (MS: INT2) private static final int SYBINT4 = 56; // 0x38 (MS: INT4) private static final int SYBINT8 = 127;// 0x7F (MS: INT8) private static final int SYBFLT8 = 62; // 0x3E (MS: FLOAT8) private static final int SYBDATETIME = 61; // 0x3D (MS: DATETIME8) private static final int SYBBIT = 50; // 0x32 (MS: BIT1) private static final int SYBTEXT = 35; // 0x23 (MS: TEXT) private static final int SYBNTEXT = 99; // 0x63 (MS: NTEXT) private static final int SYBIMAGE = 34; // 0x22 (MS: IMAGE) private static final int SYBMONEY4 = 122;// 0x7A (MS: MONEY4) private static final int SYBMONEY = 60; // 0x3C (MS: MONEY8) private static final int SYBDATETIME4 = 58; // 0x3A (MS: DATETIME4) private static final int SYBREAL = 59; // 0x3B (MS: FLOAT4) private static final int SYBBINARY = 45; // 0x2D private static final int SYBVOID = 31; // 0x1F private static final int SYBVARBINARY = 37; // 0x25 private static final int SYBNVARCHAR = 103;// 0x67 private static final int SYBBITN = 104;// 0x68 (MS: BITN) private static final int SYBNUMERIC = 108;// 0x6C (MS: NUMERICN) private static final int SYBDECIMAL = 106;// 0x6A (MS: DECIMALN) private static final int SYBFLTN = 109;// 0x6D (MS: FLOATN) private static final int SYBMONEYN = 110;// 0x6E (MS: MONEYN) private static final int SYBDATETIMN = 111;// 0x6F (MS: DATETIMEN) private static final int SYBDATEN = 123;// 0x7B SYBASE 12 private static final int SYBTIMEN = 147;// 0x93 SYBASE 12 private static final int XSYBCHAR = 175;// 0xAF (MS: BIGCHAR) private static final int XSYBVARCHAR = 167;// 0xA7 (MS: BIGVARCHAR) private static final int XSYBNVARCHAR = 231;// 0xE7 (MS: NVARCHAR) private static final int XSYBNCHAR = 239;// 0xEF (MS: NCHAR) private static final int XSYBVARBINARY = 165;// 0xA5 (MS: BIGVARBINARY) private static final int XSYBBINARY = 173;// 0xAD (MS: BIGBINARY) private static final int SYBUNITEXT = 174;// 0xAE SYBASE 15 private static final int SYBLONGBINARY = 225;// 0xE1 SYBASE 12 private static final int SYBSINT1 = 64; // 0x40 private static final int SYBUINT2 = 65; // 0x41 SYBASE 15 private static final int SYBUINT4 = 66; // 0x42 SYBASE 15 private static final int SYBUINT8 = 67; // 0x43 SYBASE 15 private static final int SYBUINTN = 68; // 0x44 SYBASE 15 private static final int SYBUNIQUE = 36; // 0x24 (MS: GUID) private static final int SYBVARIANT = 98; // 0x62 (MS: SQL_VARIANT) private static final int SYBSINT8 = 191;// 0xBF SYBASE 15 // SQL Server user defined data type // private static final int UDT = 240; // XML data type introduced in SQL Server 2005 private static final int XML = 241; // time and date data types introduced in SQL Server 2008 private static final int DATEN = 40; // 0x28 MSSQL 2008 private static final int TIMEN = 41; // 0x29 MSSQL 2008 private static final int DATETIME2N = 42; // 0x2A MSSQL 2008 private static final int DATETIMEOFFSETN = 43; // 0x2B MSSQL 2008 /* * Special case for Sybase 12.5+ * This long data type is used to send text and image * data as statement parameters as a replacement for * writetext. * As far as I can tell this data type is only sent not * received. */ static final int SYBLONGDATA = 36; // 0x24 SYBASE 12 /* * Constants for Sybase User Defined data types used to * qualify the new longchar and longbinary types. */ // Common to Sybase and SQL Server private static final int UDT_CHAR = 1; // 0x01 private static final int UDT_VARCHAR = 2; // 0x02 private static final int UDT_BINARY = 3; // 0x03 private static final int UDT_VARBINARY = 4; // 0x04 private static final int UDT_SYSNAME = 18; // 0x12 // Sybase only private static final int UDT_NCHAR = 24; // 0x18 private static final int UDT_NVARCHAR = 25; // 0x19 private static final int UDT_UNICHAR = 34; // 0x22 private static final int UDT_UNIVARCHAR = 35; // 0x23 private static final int UDT_UNITEXT = 36; // 0x24 private static final int UDT_LONGSYSNAME = 42; // 0x2A private static final int UDT_TIMESTAMP = 80; // 0x50 // SQL Server 7+ private static final int UDT_NEWSYSNAME =256; // 0x100 /* * Constants for variable length data types */ private static final int VAR_MAX = 255; private static final int SYB_LONGVAR_MAX = 16384; private static final int MS_LONGVAR_MAX = 8000; private static final int SYB_CHUNK_SIZE = 8192; /** * Array of TDS data type descriptors. */ private final static TypeInfo types[] = new TypeInfo[256]; /** * Static block to initialize TDS data type descriptors. */ static { // SQL type precision signed Java type // | | | | // | | display | TDS8 | // | size | size | collation | // v v v v v v v types[SYBCHAR] = new TypeInfo( "char" , -1, -1, 1, false, false, Types.CHAR ); types[SYBVARCHAR] = new TypeInfo( "varchar" , -1, -1, 1, false, false, Types.VARCHAR ); types[SYBINTN] = new TypeInfo( "int" , -1, 10, 11, true , false, Types.INTEGER ); types[SYBINT1] = new TypeInfo( "tinyint" , 1, 3, 4, false, false, Types.TINYINT ); types[SYBINT2] = new TypeInfo( "smallint" , 2, 5, 6, true , false, Types.SMALLINT ); types[SYBINT4] = new TypeInfo( "int" , 4, 10, 11, true , false, Types.INTEGER ); types[SYBINT8] = new TypeInfo( "bigint" , 8, 19, 20, true , false, Types.BIGINT ); types[SYBFLT8] = new TypeInfo( "float" , 8, 15, 24, true , false, Types.DOUBLE ); types[SYBDATETIME] = new TypeInfo( "datetime" , 8, 23, 23, false, false, Types.TIMESTAMP ); types[SYBBIT] = new TypeInfo( "bit" , 1, 1, 1, false, false, Types.BIT ); types[SYBTEXT] = new TypeInfo( "text" , -4, -1, -1, false, true , Types.CLOB ); types[SYBNTEXT] = new TypeInfo( "ntext" , -4, -1, -1, false, true , Types.CLOB ); types[SYBUNITEXT] = new TypeInfo( "unitext" , -4, -1, -1, false, true , Types.CLOB ); types[SYBIMAGE] = new TypeInfo( "image" , -4, -1, -1, false, false, Types.BLOB ); types[SYBMONEY4] = new TypeInfo( "smallmoney" , 4, 10, 12, true , false, Types.DECIMAL ); types[SYBMONEY] = new TypeInfo( "money" , 8, 19, 21, true , false, Types.DECIMAL ); types[SYBDATETIME4] = new TypeInfo( "smalldatetime" , 4, 16, 19, false, false, Types.TIMESTAMP ); types[SYBREAL] = new TypeInfo( "real" , 4, 7, 14, true , false, Types.REAL ); types[SYBBINARY] = new TypeInfo( "binary" , -1, -1, 2, false, false, Types.BINARY ); types[SYBVOID] = new TypeInfo( "void" , -1, 1, 1, false, false, Types.NULL ); types[SYBVARBINARY] = new TypeInfo( "varbinary" , -1, -1, -1, false, false, Types.VARBINARY ); types[SYBNVARCHAR] = new TypeInfo( "nvarchar" , -1, -1, -1, false, false, Types.VARCHAR ); types[SYBBITN] = new TypeInfo( "bit" , -1, 1, 1, false, false, Types.BIT ); types[SYBNUMERIC] = new TypeInfo( "numeric" , -1, -1, -1, true , false, Types.NUMERIC ); types[SYBDECIMAL] = new TypeInfo( "decimal" , -1, -1, -1, true , false, Types.DECIMAL ); types[SYBFLTN] = new TypeInfo( "float" , -1, 15, 24, true , false, Types.DOUBLE ); types[SYBMONEYN] = new TypeInfo( "money" , -1, 19, 21, true , false, Types.DECIMAL ); types[SYBDATETIMN] = new TypeInfo( "datetime" , -1, 23, 23, false, false, Types.TIMESTAMP ); types[SYBDATE] = new TypeInfo( "date" , 4, 10, 10, false, false, Types.DATE ); types[SYBTIME] = new TypeInfo( "time" , 4, 8, 8, false, false, Types.TIME ); types[SYBDATEN] = new TypeInfo( "date" , -1, 10, 10, false, false, Types.DATE ); types[SYBTIMEN] = new TypeInfo( "time" , -1, 8, 8, false, false, Types.TIME ); types[XSYBCHAR] = new TypeInfo( "char" , -2, -1, -1, false, true , Types.CHAR ); types[XSYBVARCHAR] = new TypeInfo( "varchar" , -2, -1, -1, false, true , Types.VARCHAR ); types[XSYBNVARCHAR] = new TypeInfo( "nvarchar" , -2, -1, -1, false, true , Types.VARCHAR ); types[XSYBNCHAR] = new TypeInfo( "nchar" , -2, -1, -1, false, true , Types.CHAR ); types[XSYBVARBINARY] = new TypeInfo( "varbinary" , -2, -1, -1, false, false, Types.VARBINARY ); types[XSYBBINARY] = new TypeInfo( "binary" , -2, -1, -1, false, false, Types.BINARY ); types[SYBLONGBINARY] = new TypeInfo( "varbinary" , -5, -1, 2, false, false, Types.BINARY ); types[SYBSINT1] = new TypeInfo( "tinyint" , 1, 2, 3, false, false, Types.TINYINT ); types[SYBUINT2] = new TypeInfo( "unsigned smallint", 2, 5, 6, false, false, Types.INTEGER ); types[SYBUINT4] = new TypeInfo( "unsigned int" , 4, 10, 11, false, false, Types.BIGINT ); types[SYBUINT8] = new TypeInfo( "unsigned bigint" , 8, 20, 20, false, false, Types.DECIMAL ); types[SYBUINTN] = new TypeInfo( "unsigned int" , -1, 10, 11, true , false, Types.BIGINT ); types[SYBUNIQUE] = new TypeInfo( "uniqueidentifier" , -1, 36, 36, false, false, Types.CHAR ); types[SYBVARIANT] = new TypeInfo( "sql_variant" , -5, 0, 8000, false, false, Types.VARCHAR ); types[SYBSINT8] = new TypeInfo( "bigint" , 8, 19, 20, true , false, Types.BIGINT ); // XML data type introduced in SQL Server 2005 types[XML] = new TypeInfo( "xml" , -4, -1, -1, false, true , Types.SQLXML ); // time and date data types introduced in SQL Server 2008 types[DATEN] = new TypeInfo( "date" , 3, 10, 10, false, false, Types.DATE ); types[TIMEN] = new TypeInfo( "time" , -1, -1, -1, false, false, Types.TIME ); types[DATETIME2N] = new TypeInfo( "datetime2" , -1, -1, -1, false, false, Types.TIMESTAMP ); types[DATETIMEOFFSETN] = new TypeInfo( "datetimeoffset" , -1, -1, -1, false, false, Types.TIMESTAMP ); } /** Default Decimal Scale. */ static final int DEFAULT_SCALE = 10; /** Default precision for SQL Server 6.5 and 7. */ static final int DEFAULT_PRECISION_28 = 28; /** Default precision for Sybase and SQL Server 2000 and newer. */ static final int DEFAULT_PRECISION_38 = 38; /** * TDS 8 supplies collation information for character data types. * * @param in the server response stream * @param ci the column descriptor * @return the number of bytes read from the stream as an <code>int</code> */ static int getCollation(ResponseStream in, ColInfo ci) throws IOException { if (TdsData.isCollation(ci)) { // Read TDS8 collation info ci.collation = new byte[5]; in.read(ci.collation); return 5; } return 0; } /** * Set the <code>charsetInfo</code> field of <code>ci</code> according to * the value of its <code>collation</code> field. * <p> * The <code>Connection</code> is used to find out whether a specific * charset was requested. In this case, the column charset will be ignored. * * @param ci the <code>ColInfo</code> instance to update * @param connection a <code>Connection</code> instance to check whether it * has a fixed charset or not * @throws SQLException if a <code>CharsetInfo</code> is not found for this * particular column collation */ static void setColumnCharset(ColInfo ci, JtdsConnection connection) throws SQLException { if (connection.isCharsetSpecified()) { // If a charset was requested on connection creation, ignore the // column collation and use default ci.charsetInfo = connection.getCharsetInfo(); } else if (ci.collation != null) { // TDS version will be 8.0 or higher in this case and connection // collation will be non-null byte[] collation = ci.collation; byte[] defaultCollation = connection.getCollation(); int i; for (i = 0; i < 5; ++i) { if (collation[i] != defaultCollation[i]) { break; } } if (i == 5) { ci.charsetInfo = connection.getCharsetInfo(); } else { ci.charsetInfo = CharsetInfo.getCharset(collation); } } } /** * Read the TDS datastream and populate the ColInfo parameter with * data type and related information. * <p>The type infomation conforms to one of the following formats: * <ol> * <li> [int1 type] - eg SYBINT4. * <li> [int1 type] [int1 buffersize] - eg VARCHAR < 256 * <li> [int1 type] [int2 buffersize] - eg VARCHAR > 255. * <li> [int1 type] [int4 buffersize] [int1 tabnamelen] [int1*n tabname] - eg text. * <li> [int1 type] [int4 buffersize] - eg sql_variant. * <li> [int1 type] [int1 buffersize] [int1 precision] [int1 scale] - eg decimal. * </ol> * For TDS 8 large character types include a 5 byte collation field after the buffer size. * * @param in The server response stream. * @param ci The ColInfo column descriptor object. * @return The number of bytes read from the input stream. * @throws IOException * @throws ProtocolException */ static int readType(ResponseStream in, ColInfo ci) throws IOException, ProtocolException { int tdsVersion = in.getTdsVersion(); boolean isTds8 = tdsVersion >= Driver.TDS80; boolean isTds7 = tdsVersion >= Driver.TDS70; boolean isTds5 = tdsVersion == Driver.TDS50; boolean isTds42 = tdsVersion == Driver.TDS42; int bytesRead = 1; // Get the TDS data type code int type = in.read(); if (types[type] == null || (isTds5 && type == SYBLONGDATA)) { // Trap invalid type or 0x24 received from a Sybase server! throw new ProtocolException("Invalid TDS data type 0x" + Integer.toHexString(type & 0xFF)); } ci.tdsType = type; ci.jdbcType = types[type].jdbcType; ci.bufferSize = types[type].size; // Now get the buffersize if required if (ci.bufferSize == -5) { // sql_variant // Sybase long binary ci.bufferSize = in.readInt(); bytesRead += 4; } else if (ci.bufferSize == -4) { // text or image ci.bufferSize = in.readInt(); if (isTds8) { bytesRead += getCollation(in, ci); } int lenName = in.readShort(); ci.tableName = in.readString(lenName); bytesRead += 6 + ((in.getTdsVersion() >= Driver.TDS70) ? lenName * 2 : lenName); } else if (ci.bufferSize == -2) { // longvarchar longvarbinary if (isTds5 && ci.tdsType == XSYBCHAR) { ci.bufferSize = in.readInt(); bytesRead += 4; } else { ci.bufferSize = in.readShort(); bytesRead += 2; } if (isTds8) { bytesRead += getCollation(in, ci); } } else if (ci.bufferSize == -1) { // varchar varbinary decimal etc bytesRead += 1; ci.bufferSize = in.read(); } // Set default displaySize and precision ci.displaySize = types[type].displaySize; ci.precision = types[type].precision; ci.sqlType = types[type].sqlType; // Now fine tune sizes for specific types switch (type) { // // long datetime has scale of 3 smalldatetime has scale of 0 // case SYBDATETIME: ci.scale = 3; break; // Establish actual size of nullable datetime case SYBDATETIMN: if (ci.bufferSize == 8) { ci.displaySize = types[SYBDATETIME].displaySize; ci.precision = types[SYBDATETIME].precision; ci.scale = 3; } else { ci.displaySize = types[SYBDATETIME4].displaySize; ci.precision = types[SYBDATETIME4].precision; ci.sqlType = types[SYBDATETIME4].sqlType; ci.scale = 0; } break; // Establish actual size of nullable float case SYBFLTN: if (ci.bufferSize == 8) { ci.displaySize = types[SYBFLT8].displaySize; ci.precision = types[SYBFLT8].precision; } else { ci.displaySize = types[SYBREAL].displaySize; ci.precision = types[SYBREAL].precision; ci.jdbcType = Types.REAL; ci.sqlType = types[SYBREAL].sqlType; } break; // Establish actual size of nullable int case SYBINTN: if (ci.bufferSize == 8) { ci.displaySize = types[SYBINT8].displaySize; ci.precision = types[SYBINT8].precision; ci.jdbcType = Types.BIGINT; ci.sqlType = types[SYBINT8].sqlType; } else if (ci.bufferSize == 4) { ci.displaySize = types[SYBINT4].displaySize; ci.precision = types[SYBINT4].precision; } else if (ci.bufferSize == 2) { ci.displaySize = types[SYBINT2].displaySize; ci.precision = types[SYBINT2].precision; ci.jdbcType = Types.SMALLINT; ci.sqlType = types[SYBINT2].sqlType; } else { ci.displaySize = types[SYBINT1].displaySize; ci.precision = types[SYBINT1].precision; ci.jdbcType = Types.TINYINT; ci.sqlType = types[SYBINT1].sqlType; } break; // Establish actual size of nullable unsigned int case SYBUINTN: if (ci.bufferSize == 8) { ci.displaySize = types[SYBUINT8].displaySize; ci.precision = types[SYBUINT8].precision; ci.jdbcType = types[SYBUINT8].jdbcType; ci.sqlType = types[SYBUINT8].sqlType; } else if (ci.bufferSize == 4) { ci.displaySize = types[SYBUINT4].displaySize; ci.precision = types[SYBUINT4].precision; } else if (ci.bufferSize == 2) { ci.displaySize = types[SYBUINT2].displaySize; ci.precision = types[SYBUINT2].precision; ci.jdbcType = types[SYBUINT2].jdbcType; ci.sqlType = types[SYBUINT2].sqlType; } else { throw new ProtocolException("unsigned int null (size 1) not supported"); } break; // // Money types have a scale of 4 // case SYBMONEY: case SYBMONEY4: ci.scale = 4; break; // Establish actual size of nullable money case SYBMONEYN: if (ci.bufferSize == 8) { ci.displaySize = types[SYBMONEY].displaySize; ci.precision = types[SYBMONEY].precision; } else { ci.displaySize = types[SYBMONEY4].displaySize; ci.precision = types[SYBMONEY4].precision; ci.sqlType = types[SYBMONEY4].sqlType; } ci.scale = 4; break; // Read in scale and precision for decimal types case SYBDECIMAL: case SYBNUMERIC: ci.precision = in.read(); ci.scale = in.read(); ci.displaySize = ((ci.scale > 0) ? 2 : 1) + ci.precision; bytesRead += 2; ci.sqlType = types[type].sqlType; break; // Although a binary type force displaysize to MAXINT case SYBIMAGE: ci.precision = Integer.MAX_VALUE; ci.displaySize = Integer.MAX_VALUE; break; // Normal binaries have a display size of 2 * precision 0x0A0B etc case SYBLONGBINARY: case SYBVARBINARY: case SYBBINARY: case XSYBBINARY: case XSYBVARBINARY: ci.precision = ci.bufferSize; ci.displaySize = ci.precision * 2; break; // SQL Server unicode text can only display half as many chars case SYBNTEXT: ci.precision = Integer.MAX_VALUE / 2; ci.displaySize = Integer.MAX_VALUE / 2; break; // ASE 15+ unicode text can only display half as many chars case SYBUNITEXT: ci.precision = Integer.MAX_VALUE / 2; ci.displaySize = Integer.MAX_VALUE / 2; break; // SQL Server unicode chars can only display half as many chars case XSYBNCHAR: case XSYBNVARCHAR: ci.displaySize = ci.bufferSize / 2; ci.precision = ci.displaySize; break; // Normal characters display size = precision = buffer size. case SYBTEXT: case SYBCHAR: case XSYBCHAR: case XSYBVARCHAR: case SYBVARCHAR: case SYBNVARCHAR: ci.precision = ci.bufferSize; ci.displaySize = ci.precision; break; } // For numeric types add 'identity' for auto inc data type if (ci.isIdentity) { ci.sqlType += " identity"; } // Fine tune Sybase or SQL 6.5 data types if (isTds42 || isTds5) { switch (ci.userType) { case UDT_CHAR: ci.sqlType = "char"; ci.displaySize = ci.bufferSize; ci.jdbcType = Types.CHAR; break; case UDT_VARCHAR: ci.sqlType = "varchar"; ci.displaySize = ci.bufferSize; ci.jdbcType = Types.VARCHAR; break; case UDT_BINARY: ci.sqlType = "binary"; ci.displaySize = ci.bufferSize * 2; ci.jdbcType = Types.BINARY; break; case UDT_VARBINARY: ci.sqlType = "varbinary"; ci.displaySize = ci.bufferSize * 2; ci.jdbcType = Types.VARBINARY; break; case UDT_SYSNAME: ci.sqlType = "sysname"; ci.displaySize = ci.bufferSize; ci.jdbcType = Types.VARCHAR; break; case UDT_TIMESTAMP: ci.sqlType = "timestamp"; ci.displaySize = ci.bufferSize * 2; ci.jdbcType = Types.VARBINARY; break; } } // Fine tune Sybase data types if (isTds5) { switch (ci.userType) { case UDT_NCHAR: ci.sqlType = "nchar"; ci.displaySize = ci.bufferSize; ci.jdbcType = Types.CHAR; break; case UDT_NVARCHAR: ci.sqlType = "nvarchar"; ci.displaySize = ci.bufferSize; ci.jdbcType = Types.VARCHAR; break; case UDT_UNICHAR: ci.sqlType = "unichar"; ci.displaySize = ci.bufferSize / 2; ci.precision = ci.displaySize; ci.jdbcType = Types.CHAR; break; case UDT_UNIVARCHAR: ci.sqlType = "univarchar"; ci.displaySize = ci.bufferSize / 2; ci.precision = ci.displaySize; ci.jdbcType = Types.VARCHAR; break; case UDT_LONGSYSNAME: ci.sqlType = "longsysname"; ci.jdbcType = Types.VARCHAR; ci.displaySize = ci.bufferSize; break; } } // Fine tune SQL Server 7+ datatypes if (isTds7) { switch (ci.userType) { case UDT_TIMESTAMP: ci.sqlType = "timestamp"; ci.jdbcType = Types.BINARY; break; case UDT_NEWSYSNAME: ci.sqlType = "sysname"; ci.jdbcType = Types.VARCHAR; break; } } return bytesRead; } /** * Read the TDS data item from the Response Stream. * <p> The data size is either implicit in the type for example * fixed size integers, or a count field precedes the actual data. * The size of the count field varies with the data type. * * @param connection an object reference to the caller of this method; * must be a <code>Connection</code>, <code>Statement</code> or * <code>ResultSet</code> * @param in The server ResponseStream. * @param ci The ColInfo column descriptor object. * @return The data item Object or null. * @throws IOException * @throws ProtocolException */ static Object readData(JtdsConnection connection, ResponseStream in, ColInfo ci) throws IOException, ProtocolException { int len; switch (ci.tdsType) { case SYBINTN: switch (in.read()) { case 1: return new Integer(in.read() & 0xFF); case 2: return new Integer(in.readShort()); case 4: return new Integer(in.readInt()); case 8: return new Long(in.readLong()); } break; // Sybase ASE 15+ supports unsigned null smallint, int and bigint case SYBUINTN: switch (in.read()) { case 1: return new Integer(in.read() & 0xFF); case 2: return new Integer(in.readShort() & 0xFFFF); case 4: return new Long(in.readInt() & 0xFFFFFFFFL ); case 8: return in.readUnsignedLong(); } break; case SYBINT1: return new Integer(in.read() & 0xFF); case SYBINT2: return new Integer(in.readShort()); case SYBINT4: return new Integer(in.readInt()); // SQL Server bigint case SYBINT8: return new Long(in.readLong()); // Sybase ASE 15+ bigint case SYBSINT8: return new Long(in.readLong()); // Sybase ASE 15+ unsigned smallint case SYBUINT2: return new Integer(in.readShort() & 0xFFFF); // Sybase ASE 15+ unsigned int case SYBUINT4: return new Long(in.readInt() & 0xFFFFFFFFL); // Sybase ASE 15+ unsigned bigint case SYBUINT8: return in.readUnsignedLong(); case SYBIMAGE: len = in.read(); if (len > 0) { in.skip(24); // Skip textptr and timestamp int dataLen = in.readInt(); BlobImpl blob; if (dataLen == 0 && in.getTdsVersion() <= Driver.TDS50) { // Length of zero may indicate an initialized image // column that has been updated to null. break; } if (dataLen <= connection.getLobBuffer()) { // // OK Small enough to load into memory // byte[] data = new byte[dataLen]; in.read(data); blob = new BlobImpl(connection, data); } else { // Too big, need to write straight to disk try { blob = new BlobImpl(connection); OutputStream out = blob.setBinaryStream(1); byte[] buffer = new byte[1024]; int result; while ((result = in.read(buffer, 0, Math.min(dataLen, buffer.length))) != -1 && dataLen != 0) { out.write(buffer, 0, result); dataLen -= result; } out.close(); } catch (SQLException e) { // Transform setBinaryStream SQLException throw new IOException(e.getMessage()); } } return blob; } break; case SYBTEXT: len = in.read(); if (len > 0) { String charset; if (ci.charsetInfo != null) { charset = ci.charsetInfo.getCharset(); } else { charset = connection.getCharset(); } in.skip(24); // Skip textptr and timestamp int dataLen = in.readInt(); if (dataLen == 0 && in.getTdsVersion() <= Driver.TDS50) { // Length of zero may indicate an initialized text // column that has been updated to null. break; } ClobImpl clob = new ClobImpl(connection); BlobBuffer blobBuffer = clob.getBlobBuffer(); if (dataLen <= connection.getLobBuffer()) { // // OK Small enough to load into memory // BufferedReader rdr = new BufferedReader( new InputStreamReader(in.getInputStream(dataLen), charset), 1024); byte[] data = new byte[dataLen * 2]; int p = 0; int c; while ((c = rdr.read()) >= 0) { data[p++] = (byte)c; data[p++] = (byte)(c >> 8); } rdr.close(); blobBuffer.setBuffer(data, false); if (p == 2 && data[0] == 0x20 && data[1] == 0 && in.getTdsVersion() < Driver.TDS70) { // Single space with Sybase equates to empty string p = 0; } // Explicitly set length as multi byte character sets // may not fill array completely. blobBuffer.setLength(p); } else { // Too big, need to write straight to disk BufferedReader rdr = new BufferedReader( new InputStreamReader(in.getInputStream(dataLen), charset), 1024); try { OutputStream out = blobBuffer.setBinaryStream(1, false); int c; while ((c = rdr.read()) >= 0) { out.write(c); out.write(c >> 8); } out.close(); rdr.close(); } catch (SQLException e) { // Turn back into an IOException throw new IOException(e.getMessage()); } } return clob; } break; case SYBUNITEXT: // ASE 15+ unicode text type case SYBNTEXT: len = in.read(); if (len > 0) { in.skip(24); // Skip textptr and timestamp int dataLen = in.readInt(); if (dataLen == 0 && in.getTdsVersion() <= Driver.TDS50) { // Length of zero may indicate an initialized unitext // column that has been updated to null. break; } ClobImpl clob = new ClobImpl(connection); BlobBuffer blobBuffer = clob.getBlobBuffer(); if (dataLen <= connection.getLobBuffer()) { // // OK Small enough to load into memory // byte[] data = new byte[dataLen]; in.read(data); blobBuffer.setBuffer(data, false); if (dataLen == 2 && data[0] == 0x20 && data[1] == 0 && in.getTdsVersion() == Driver.TDS50) { // Single space with Sybase equates to empty string dataLen = 0; } // Explicitly set length as multi byte character sets // may not fill array completely. blobBuffer.setLength(dataLen); } else { // Too big, need to write straight to disk try { OutputStream out = blobBuffer.setBinaryStream(1, false); byte[] buffer = new byte[1024]; int result; while ((result = in.read(buffer, 0, Math.min(dataLen, buffer.length))) != -1 && dataLen != 0) { out.write(buffer, 0, result); dataLen -= result; } out.close(); } catch (SQLException e) { // Transform setBinaryStream SQLException throw new IOException(e.getMessage()); } } return clob; } break; case SYBCHAR: case SYBVARCHAR: len = in.read(); if (len > 0) { String value = in.readNonUnicodeString(len, ci.charsetInfo == null ? connection.getCharsetInfo() : ci.charsetInfo); if (len == 1 && ci.tdsType == SYBVARCHAR && in.getTdsVersion() < Driver.TDS70) { // In TDS 4/5 zero length varchars are stored as a // single space to distinguish them from nulls. return (" ".equals(value)) ? "" : value; } return value; } break; case SYBNVARCHAR: len = in.read(); if (len > 0) { return in.readUnicodeString(len / 2); } break; case XSYBCHAR: case XSYBVARCHAR: if (in.getTdsVersion() == Driver.TDS50) { // This is a Sybase wide table String len = in.readInt(); if (len > 0) { String tmp = in.readNonUnicodeString(len); if (" ".equals(tmp) && !"char".equals(ci.sqlType)) { tmp = ""; } return tmp; } } else { // This is a TDS 7+ long string len = in.readShort(); if (len != -1) { return in.readNonUnicodeString(len, ci.charsetInfo == null ? connection.getCharsetInfo() : ci.charsetInfo); } } break; case XSYBNCHAR: case XSYBNVARCHAR: len = in.readShort(); if (len != -1) { return in.readUnicodeString(len / 2); } break; case SYBVARBINARY: case SYBBINARY: len = in.read(); if (len > 0) { byte[] bytes = new byte[len]; in.read(bytes); return bytes; } break; case XSYBVARBINARY: case XSYBBINARY: len = in.readShort(); if (len != -1) { byte[] bytes = new byte[len]; in.read(bytes); return bytes; } break; case SYBLONGBINARY: len = in.readInt(); if (len != 0) { if ("unichar".equals(ci.sqlType) || "univarchar".equals(ci.sqlType)) { char[] buf = new char[len / 2]; in.read(buf); if ((len & 1) != 0) { // Bad length should be divisible by 2 in.skip(1); // Deal with it anyway. } if (len == 2 && buf[0] == ' ') { return ""; } else { return new String(buf); } } else { byte[] bytes = new byte[len]; in.read(bytes); return bytes; } } break; case SYBMONEY4: case SYBMONEY: case SYBMONEYN: return getMoneyValue(in, ci.tdsType); case SYBDATETIME4: case SYBDATETIMN: case SYBDATETIME: return getDatetimeValue(in, ci.tdsType); case SYBDATEN: case SYBDATE: len = (ci.tdsType == SYBDATEN)? in.read(): 4; if (len == 4) { return new DateTime(in.readInt(), DateTime.TIME_NOT_USED); } else { // Invalid length or 0 for null in.skip(len); } break; case SYBTIMEN: case SYBTIME: len = (ci.tdsType == SYBTIMEN)? in.read(): 4; if (len == 4) { return new DateTime(DateTime.DATE_NOT_USED, in.readInt()); } else { // Invalid length or 0 for null in.skip(len); } break; case SYBBIT: return (in.read() != 0) ? Boolean.TRUE : Boolean.FALSE; case SYBBITN: len = in.read(); if (len > 0) { return (in.read() != 0) ? Boolean.TRUE : Boolean.FALSE; } break; case SYBREAL: return new Float(Float.intBitsToFloat(in.readInt())); case SYBFLT8: return new Double(Double.longBitsToDouble(in.readLong())); case SYBFLTN: len = in.read(); if (len == 4) { return new Float(Float.intBitsToFloat(in.readInt())); } else if (len == 8) { return new Double(Double.longBitsToDouble(in.readLong())); } break; case SYBUNIQUE: len = in.read(); if (len > 0) { byte[] bytes = new byte[len]; in.read(bytes); return new UniqueIdentifier(bytes); } break; case SYBNUMERIC: case SYBDECIMAL: len = in.read(); if (len > 0) { int sign = in.read(); len--; byte[] bytes = new byte[len]; BigInteger bi; if (in.getServerType() == Driver.SYBASE) { // Sybase order is MSB first! for (int i = 0; i < len; i++) { bytes[i] = (byte) in.read(); } bi = new BigInteger((sign == 0) ? 1 : -1, bytes); } else { while (len-- > 0) { bytes[len] = (byte)in.read(); } bi = new BigInteger((sign == 0) ? -1 : 1, bytes); } return new BigDecimal(bi, ci.scale); } break; case SYBVARIANT: return getVariant(connection, in); default: throw new ProtocolException("Unsupported TDS data type 0x" + Integer.toHexString(ci.tdsType & 0xFF)); } return null; } /** * Retrieve the signed status of the column. * * @param ci the column meta data * @return <code>true</code> if the column is a signed numeric. */ static boolean isSigned(ColInfo ci) { int type = ci.tdsType; if (type < 0 || type > 255 || types[type] == null) { throw new IllegalArgumentException("TDS data type " + type + " invalid"); } if (type == TdsData.SYBINTN && ci.bufferSize == 1) { type = TdsData.SYBINT1; // Tiny int is not signed! } return types[type].isSigned; } /** * Retrieve the collation status of the column. * <p/> * TDS 8.0 character columns include collation information. * * @param ci the column meta data * @return <code>true</code> if the column requires collation data. */ static boolean isCollation(ColInfo ci) { int type = ci.tdsType; if (type < 0 || type > 255 || types[type] == null) { throw new IllegalArgumentException("TDS data type " + type + " invalid"); } return types[type].isCollation; } /** * Retrieve the currency status of the column. * * @param ci The column meta data. * @return <code>boolean</code> true if the column is a currency type. */ static boolean isCurrency(ColInfo ci) { int type = ci.tdsType; if (type < 0 || type > 255 || types[type] == null) { throw new IllegalArgumentException("TDS data type " + type + " invalid"); } return type == SYBMONEY || type == SYBMONEY4 || type == SYBMONEYN; } /** * Retrieve the searchable status of the column. * * @param ci the column meta data * @return <code>true</code> if the column is not a text or image type. */ static boolean isSearchable(ColInfo ci) { int type = ci.tdsType; if (type < 0 || type > 255 || types[type] == null) { throw new IllegalArgumentException("TDS data type " + type + " invalid"); } return types[type].size != -4; } /** * Determines whether the column is Unicode encoded. * * @param ci the column meta data * @return <code>true</code> if the column is Unicode encoded */ static boolean isUnicode(ColInfo ci) { int type = ci.tdsType; if (type < 0 || type > 255 || types[type] == null) { throw new IllegalArgumentException("TDS data type " + type + " invalid"); } switch (type) { case SYBNVARCHAR: case SYBNTEXT: case XSYBNCHAR: case XSYBNVARCHAR: case XSYBCHAR: // Not always case SYBVARIANT: // Not always return true; default: return false; } } /** * Fill in the TDS native type code and all other fields for a * <code>ColInfo</code> instance with the JDBC type set. * * @param ci the <code>ColInfo</code> instance */ static void fillInType(ColInfo ci) throws SQLException { switch (ci.jdbcType) { case Types.VARCHAR: ci.tdsType = SYBVARCHAR; ci.bufferSize = MS_LONGVAR_MAX; ci.displaySize = MS_LONGVAR_MAX; ci.precision = MS_LONGVAR_MAX; break; case Types.INTEGER: ci.tdsType = SYBINT4; ci.bufferSize = 4; ci.displaySize = 11; ci.precision = 10; break; case Types.SMALLINT: ci.tdsType = SYBINT2; ci.bufferSize = 2; ci.displaySize = 6; ci.precision = 5; break; case Types.BIT: ci.tdsType = SYBBIT; ci.bufferSize = 1; ci.displaySize = 1; ci.precision = 1; break; default: throw new SQLException(Messages.get( "error.baddatatype", Integer.toString(ci.jdbcType)), "HY000"); } ci.sqlType = types[ci.tdsType].sqlType; ci.scale = 0; } /** * Retrieve the TDS native type code for the parameter. * * @param connection the connectionJDBC object * @param pi the parameter descriptor */ static void getNativeType(JtdsConnection connection, ParamInfo pi) throws SQLException { int len; int jdbcType = pi.jdbcType; if (jdbcType == Types.OTHER) { jdbcType = Support.getJdbcType(pi.value); } switch (jdbcType) { case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: case Types.CLOB: if (pi.value == null) { len = 0; } else { len = pi.length; } if (connection.getTdsVersion() < Driver.TDS70) { String charset = connection.getCharset(); if (len > 0 && (len <= SYB_LONGVAR_MAX / 2 || connection.getSybaseInfo(TdsCore.SYB_UNITEXT)) && connection.getSybaseInfo(TdsCore.SYB_UNICODE) && connection.getUseUnicode() && !"UTF-8".equals(charset)) { // Sybase can send values as unicode if conversion to the // server charset fails. // One option to determine if conversion will fail is to use // the CharSetEncoder class but this is only available from // JDK 1.4. // For now we will call a local method to see if the string // should be sent as unicode. // This behaviour can be disabled by setting the connection // property sendParametersAsUnicode=false. // TODO: Find a better way of testing for convertable charset. // With ASE 15 this code will read a CLOB into memory just to // check for unicode characters. This is wasteful if no unicode // data is present and we are targetting a text column. The option // of always sending unicode does not work as the server will // complain about image to text conversions unless the target // column actually is unitext. try { String tmp = pi.getString(charset); if (!canEncode(tmp, charset)) { // Conversion fails need to send as unicode. pi.length = tmp.length(); if (pi.length > SYB_LONGVAR_MAX / 2) { pi.sqlType = "unitext"; pi.tdsType = SYBLONGDATA; } else { pi.sqlType = "univarchar("+pi.length+')'; pi.tdsType = SYBLONGBINARY; } break; } } catch (IOException e) { throw new SQLException( Messages.get("error.generic.ioerror", e.getMessage()), "HY000"); } } // // If the client character set is wide then we need to ensure that the size // is within bounds even after conversion from Unicode // if (connection.isWideChar() && len <= SYB_LONGVAR_MAX) { try { byte tmp[] = pi.getBytes(charset); len = (tmp == null) ? 0 : tmp.length; } catch (IOException e) { throw new SQLException( Messages.get("error.generic.ioerror", e.getMessage()), "HY000"); } } if (len <= VAR_MAX) { pi.tdsType = SYBVARCHAR; pi.sqlType = "varchar(255)"; } else { if (connection.getSybaseInfo(TdsCore.SYB_LONGDATA)) { if (len > SYB_LONGVAR_MAX) { // Use special Sybase long data type which // allows text data to be sent as a statement parameter // (although not as a SP parameter). pi.tdsType = SYBLONGDATA; pi.sqlType = "text"; } else { // Use Sybase 12.5+ long varchar type which // is limited to 16384 bytes. pi.tdsType = XSYBCHAR; pi.sqlType = "varchar(" + len + ')'; } } else { pi.tdsType = SYBTEXT; pi.sqlType = "text"; } } } else { if (pi.isUnicode && len <= MS_LONGVAR_MAX / 2) { pi.tdsType = XSYBNVARCHAR; pi.sqlType = "nvarchar(4000)"; } else if (!pi.isUnicode && len <= MS_LONGVAR_MAX) { CharsetInfo csi = connection.getCharsetInfo(); try { if (len > 0 && csi.isWideChars() && pi.getBytes(csi.getCharset()).length > MS_LONGVAR_MAX) { pi.tdsType = SYBTEXT; pi.sqlType = "text"; } else { pi.tdsType = XSYBVARCHAR; pi.sqlType = "varchar(8000)"; } } catch (IOException e) { throw new SQLException( Messages.get("error.generic.ioerror", e.getMessage()), "HY000"); } } else { if (pi.isOutput) { throw new SQLException( Messages.get("error.textoutparam"), "HY000"); } if (pi.isUnicode) { pi.tdsType = SYBNTEXT; pi.sqlType = "ntext"; } else { pi.tdsType = SYBTEXT; pi.sqlType = "text"; } } } break; case Types.TINYINT: case Types.SMALLINT: case Types.INTEGER: pi.tdsType = SYBINTN; pi.sqlType = "int"; break; case JtdsStatement.BOOLEAN: case Types.BIT: if (connection.getTdsVersion() >= Driver.TDS70 || connection.getSybaseInfo(TdsCore.SYB_BITNULL)) { pi.tdsType = SYBBITN; } else { pi.tdsType = SYBBIT; } pi.sqlType = "bit"; break; case Types.REAL: pi.tdsType = SYBFLTN; pi.sqlType = "real"; break; case Types.FLOAT: case Types.DOUBLE: pi.tdsType = SYBFLTN; pi.sqlType = "float"; break; case Types.DATE: if (connection.getSybaseInfo(TdsCore.SYB_DATETIME)) { pi.tdsType = SYBDATEN; pi.sqlType = "date"; } else { pi.tdsType = SYBDATETIMN; pi.sqlType = "datetime"; } break; case Types.TIME: if (connection.getSybaseInfo(TdsCore.SYB_DATETIME)) { pi.tdsType = SYBTIMEN; pi.sqlType = "time"; } else { pi.tdsType = SYBDATETIMN; pi.sqlType = "datetime"; } break; case Types.TIMESTAMP: pi.tdsType = SYBDATETIMN; pi.sqlType = "datetime"; break; case Types.BINARY: case Types.VARBINARY: case Types.BLOB: case Types.LONGVARBINARY: if (pi.value == null) { len = 0; } else { len = pi.length; } if (connection.getTdsVersion() < Driver.TDS70) { if (len <= VAR_MAX) { pi.tdsType = SYBVARBINARY; pi.sqlType = "varbinary(255)"; } else { if (connection.getSybaseInfo(TdsCore.SYB_LONGDATA)) { if (len > SYB_LONGVAR_MAX) { // Need to use special Sybase long binary type pi.tdsType = SYBLONGDATA; pi.sqlType = "image"; } else { // Sybase long binary that can be used as a SP parameter pi.tdsType = SYBLONGBINARY; pi.sqlType = "varbinary(" + len + ")"; } } else { // Sybase < 12.5 or SQL Server 6.5 pi.tdsType = SYBIMAGE; pi.sqlType = "image"; } } } else { if (len <= MS_LONGVAR_MAX) { pi.tdsType = XSYBVARBINARY; pi.sqlType = "varbinary(8000)"; } else { if (pi.isOutput) { throw new SQLException( Messages.get("error.textoutparam"), "HY000"); } pi.tdsType = SYBIMAGE; pi.sqlType = isMSSQL2005Plus(connection) ? "varbinary(max)" : "image"; } } break; case Types.BIGINT: if (connection.getTdsVersion() >= Driver.TDS80 || connection.getSybaseInfo(TdsCore.SYB_BIGINT)) { pi.tdsType = SYBINTN; pi.sqlType = "bigint"; } else { // int8 not supported send as a decimal field pi.tdsType = SYBDECIMAL; pi.sqlType = "decimal(" + connection.getMaxPrecision() + ')'; pi.scale = 0; } break; case Types.DECIMAL: case Types.NUMERIC: pi.tdsType = SYBDECIMAL; int prec = connection.getMaxPrecision(); int scale = DEFAULT_SCALE; if (pi.value instanceof BigDecimal) { scale = ((BigDecimal)pi.value).scale(); } else if (pi.scale >= 0 && pi.scale <= prec) { scale = pi.scale; } pi.sqlType = "decimal(" + prec + ',' + scale + ')'; break; case Types.OTHER: case Types.NULL: // Send a null String in the absence of anything better pi.tdsType = SYBVARCHAR; pi.sqlType = "varchar(255)"; break; case Types.SQLXML: len = pi.value == null ? 0 : pi.length; if (connection.getTdsVersion() >= Driver.TDS80 ) { pi.tdsType = XML; pi.sqlType = "xml"; } else if( connection.getTdsVersion() < Driver.TDS70 ) { if( len <= VAR_MAX ) { pi.tdsType = SYBVARBINARY; pi.sqlType = "varbinary(255)"; } else { if( connection.getSybaseInfo( TdsCore.SYB_LONGDATA ) ) { if( len > SYB_LONGVAR_MAX ) { // Need to use special Sybase long binary type pi.tdsType = SYBLONGDATA; pi.sqlType = "image"; } else { // Sybase long binary that can be used as a SP parameter pi.tdsType = SYBLONGBINARY; pi.sqlType = "varbinary(" + len + ')'; } } else { // Sybase < 12.5 or SQL Server 6.5 pi.tdsType = SYBIMAGE; pi.sqlType = "image"; } } } else { if( len <= MS_LONGVAR_MAX ) { pi.tdsType = XSYBVARBINARY; pi.sqlType = "varbinary(8000)"; } else { if( pi.isOutput ) throw new SQLException( Messages.get( "error.textoutparam" ), "HY000" ); pi.tdsType = SYBIMAGE; pi.sqlType = isMSSQL2005Plus(connection) ? "varbinary(max)" : "image"; } } break; default: throw new SQLException(Messages.get( "error.baddatatype", Integer.toString(pi.jdbcType)), "HY000"); } } /** * Calculate the size of the parameter descriptor array for TDS 5 packets. * * @param charset The encoding character set. * @param isWideChar True if multi byte encoding. * @param pi The parameter to describe. * @param useParamNames True if named parameters should be used. * @return The size of the parameter descriptor as an <code>int</code>. */ static int getTds5ParamSize(String charset, boolean isWideChar, ParamInfo pi, boolean useParamNames) { int size = 8; if (pi.name != null && useParamNames) { // Size of parameter name if (isWideChar) { byte[] buf = Support.encodeString(charset, pi.name); size += buf.length; } else { size += pi.name.length(); } } switch (pi.tdsType) { case SYBVARCHAR: case SYBVARBINARY: case SYBINTN: case SYBFLTN: case SYBDATETIMN: case SYBDATEN: case SYBTIMEN: size += 1; break; case SYBDECIMAL: case SYBLONGDATA: size += 3; break; case XSYBCHAR: case SYBLONGBINARY: size += 4; break; case SYBBIT: break; default: throw new IllegalStateException("Unsupported output TDS type 0x" + Integer.toHexString(pi.tdsType)); } return size; } /** * Write a TDS 5 parameter format descriptor. * * @param out The server RequestStream. * @param charset The encoding character set. * @param isWideChar True if multi byte encoding. * @param pi The parameter to describe. * @param useParamNames True if named parameters should be used. * @throws IOException */ static void writeTds5ParamFmt(RequestStream out, String charset, boolean isWideChar, ParamInfo pi, boolean useParamNames) throws IOException { if (pi.name != null && useParamNames) { // Output parameter name. if (isWideChar) { byte[] buf = Support.encodeString(charset, pi.name); out.write((byte) buf.length); out.write(buf); } else { out.write((byte) pi.name.length()); out.write(pi.name); } } else { out.write((byte)0); } out.write((byte) (pi.isOutput ? 1 : 0)); // Output param if (pi.sqlType.startsWith("univarchar")) { out.write(UDT_UNIVARCHAR); } else if ("unitext".equals(pi.sqlType)) { out.write(UDT_UNITEXT); } else { out.write(0); // user type } out.write((byte) pi.tdsType); // TDS data type token // Output length fields switch (pi.tdsType) { case SYBVARCHAR: case SYBVARBINARY: out.write((byte) VAR_MAX); break; case XSYBCHAR: out.write(0x7FFFFFFF); break; case SYBLONGDATA: // It appears that type 3 = send text data // and type 4 = send image or unitext data // No idea if there is a type 1/2 or what they are. out.write("text".equals(pi.sqlType) ? (byte) 3 : (byte) 4); out.write((byte)0); out.write((byte)0); break; case SYBLONGBINARY: out.write(0x7FFFFFFF); break; case SYBBIT: break; case SYBINTN: out.write("bigint".equals(pi.sqlType) ? (byte) 8: (byte) 4); break; case SYBFLTN: if (pi.value instanceof Float) { out.write((byte) 4); } else { out.write((byte) 8); } break; case SYBDATETIMN: out.write((byte) 8); break; case SYBDATEN: case SYBTIMEN: out.write((byte)4); break; case SYBDECIMAL: out.write((byte) 17); out.write((byte) 38); if (pi.jdbcType == Types.BIGINT) { out.write((byte) 0); } else { if (pi.value instanceof BigDecimal) { out.write((byte) ((BigDecimal) pi.value).scale()); } else { if (pi.scale >= 0 && pi.scale <= TdsData.DEFAULT_PRECISION_38) { out.write((byte) pi.scale); } else { out.write((byte) DEFAULT_SCALE); } } } break; default: throw new IllegalStateException( "Unsupported output TDS type " + Integer.toHexString(pi.tdsType)); } out.write((byte) 0); // Locale information } /** * Write the actual TDS 5 parameter data. * * @param out the server RequestStream * @param charsetInfo the encoding character set * @param pi the parameter to output * @throws IOException * @throws SQLException */ static void writeTds5Param(RequestStream out, CharsetInfo charsetInfo, ParamInfo pi) throws IOException, SQLException { if (pi.charsetInfo == null) { pi.charsetInfo = charsetInfo; } switch (pi.tdsType) { case SYBVARCHAR: if (pi.value == null) { out.write((byte) 0); } else { byte buf[] = pi.getBytes(pi.charsetInfo.getCharset()); if (buf.length == 0) { buf = new byte[1]; buf[0] = ' '; } if (buf.length > VAR_MAX) { throw new SQLException( Messages.get("error.generic.truncmbcs"), "HY000"); } out.write((byte) buf.length); out.write(buf); } break; case SYBVARBINARY: if (pi.value == null) { out.write((byte) 0); } else { byte buf[] = pi.getBytes(pi.charsetInfo.getCharset()); if (out.getTdsVersion() < Driver.TDS70 && buf.length == 0) { // Sybase and SQL 6.5 do not allow zero length binary out.write((byte) 1); out.write((byte) 0); } else { out.write((byte) buf.length); out.write(buf); } } break; case XSYBCHAR: if (pi.value == null) { out.write((byte) 0); } else { byte buf[] = pi.getBytes(pi.charsetInfo.getCharset()); if (buf.length == 0) { buf = new byte[1]; buf[0] = ' '; } out.write(buf.length); out.write(buf); } break; case SYBLONGDATA: // // Write a three byte prefix usage unknown // out.write((byte)0); out.write((byte)0); out.write((byte)0); // // Write BLOB direct from input stream // if (pi.value instanceof InputStream) { byte buffer[] = new byte[SYB_CHUNK_SIZE]; int len = ((InputStream) pi.value).read(buffer); while (len > 0) { out.write((byte) len); out.write((byte) (len >> 8)); out.write((byte) (len >> 16)); out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come out.write(buffer, 0, len); len = ((InputStream) pi.value).read(buffer); } } else // // Write CLOB direct from input Reader // if (pi.value instanceof Reader && !pi.charsetInfo.isWideChars()) { // For ASE 15+ the getNativeType() routine will already have // read the data from the reader so this code will not be // reached unless sendStringParametersAsUnicode=false. char buffer[] = new char[SYB_CHUNK_SIZE]; int len = ((Reader) pi.value).read(buffer); while (len > 0) { out.write((byte) len); out.write((byte) (len >> 8)); out.write((byte) (len >> 16)); out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come out.write(Support.encodeString( pi.charsetInfo.getCharset(), new String(buffer, 0, len))); len = ((Reader) pi.value).read(buffer); } } else // // Write data from memory buffer // if (pi.value != null) { // // Actual data needs to be written out in chunks of // 8192 bytes. // if ("unitext".equals(pi.sqlType)) { // Write out String as unicode bytes String buf = pi.getString(pi.charsetInfo.getCharset()); int pos = 0; while (pos < buf.length()) { int clen = (buf.length() - pos >= SYB_CHUNK_SIZE / 2)? SYB_CHUNK_SIZE / 2: buf.length() - pos; int len = clen * 2; out.write((byte) len); out.write((byte) (len >> 8)); out.write((byte) (len >> 16)); out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come // Write data out.write(buf.substring(pos, pos+clen).toCharArray(), 0, clen); pos += clen; } } else { // Write text as bytes byte buf[] = pi.getBytes(pi.charsetInfo.getCharset()); int pos = 0; while (pos < buf.length) { int len = (buf.length - pos >= SYB_CHUNK_SIZE) ? SYB_CHUNK_SIZE : buf.length - pos; out.write((byte) len); out.write((byte) (len >> 8)); out.write((byte) (len >> 16)); out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come // Write data for (int i = 0; i < len; i++) { out.write(buf[pos++]); } } } } // Write terminator out.write(0); break; case SYBLONGBINARY: // Sybase data <= 16284 bytes long if (pi.value == null) { out.write(0); } else { if (pi.sqlType.startsWith("univarchar")){ String tmp = pi.getString(pi.charsetInfo.getCharset()); if (tmp.length() == 0) { tmp = " "; } out.write(tmp.length() * 2); out.write(tmp.toCharArray(), 0, tmp.length()); } else { byte buf[] = pi.getBytes(pi.charsetInfo.getCharset()); if (buf.length > 0) { out.write(buf.length); out.write(buf); } else { out.write(1); out.write((byte) 0); } } } break; case SYBINTN: if (pi.value == null) { out.write((byte) 0); } else { if ("bigint".equals(pi.sqlType)) { out.write((byte) 8); out.write(((Number) pi.value).longValue()); } else { out.write((byte) 4); out.write(((Number) pi.value).intValue()); } } break; case SYBFLTN: if (pi.value == null) { out.write((byte) 0); } else { if (pi.value instanceof Float) { out.write((byte) 4); out.write(((Number) pi.value).floatValue()); } else { out.write((byte) 8); out.write(((Number) pi.value).doubleValue()); } } break; case SYBDATETIMN: putDateTimeValue(out, (DateTime) pi.value); break; case SYBDATEN: if (pi.value == null) { out.write((byte)0); } else { out.write((byte)4); out.write(((DateTime) pi.value).getDate()); } break; case SYBTIMEN: if (pi.value == null) { out.write((byte)0); } else { out.write((byte)4); out.write(((DateTime) pi.value).getTime()); } break; case SYBBIT: if (pi.value == null) { out.write((byte) 0); } else { out.write((byte) (((Boolean) pi.value).booleanValue() ? 1 : 0)); } break; case SYBNUMERIC: case SYBDECIMAL: BigDecimal value = null; if (pi.value != null) { if (pi.value instanceof Long) { // Long to BigDecimal conversion is buggy. It's actually // long to double to BigDecimal. value = new BigDecimal(pi.value.toString()); } else { value = (BigDecimal) pi.value; } } out.write(value); break; default: throw new IllegalStateException( "Unsupported output TDS type " + Integer.toHexString(pi.tdsType)); } } /** * TDS 8 requires collation information for char data descriptors. * * @param out The Server request stream. * @param pi The parameter descriptor. * @throws IOException */ static void putCollation(RequestStream out, ParamInfo pi) throws IOException { // // For TDS 8 write a collation string // I am assuming this can be all zero for now if none is known // if (types[pi.tdsType].isCollation) { if (pi.collation != null) { out.write(pi.collation); } else { byte collation[] = {0x00, 0x00, 0x00, 0x00, 0x00}; out.write(collation); } } } /** * Write a parameter to the server request stream. * * @param out the server request stream * @param charsetInfo the default character set * @param collation the default SQL Server 2000 collation * @param pi the parameter descriptor */ static void writeParam(RequestStream out, CharsetInfo charsetInfo, byte[] collation, ParamInfo pi) throws IOException { int len; String tmp; byte[] buf; boolean isTds8 = out.getTdsVersion() >= Driver.TDS80; if (isTds8) { if (pi.collation == null) { pi.collation = collation; } } if (pi.charsetInfo == null) { pi.charsetInfo = charsetInfo; } switch (pi.tdsType) { case XSYBVARCHAR: if (pi.value == null) { out.write((byte) pi.tdsType); out.write((short) MS_LONGVAR_MAX); if (isTds8) { putCollation(out, pi); } out.write((short) 0xFFFF); } else { buf = pi.getBytes(pi.charsetInfo.getCharset()); if (buf.length > MS_LONGVAR_MAX) { out.write((byte) SYBTEXT); out.write(buf.length); if (isTds8) { putCollation(out, pi); } out.write(buf.length); out.write(buf); } else { out.write((byte) pi.tdsType); out.write((short) MS_LONGVAR_MAX); if (isTds8) { putCollation(out, pi); } out.write((short) buf.length); out.write(buf); } } break; case SYBVARCHAR: if (pi.value == null) { out.write((byte) pi.tdsType); out.write((byte) VAR_MAX); out.write((byte) 0); } else { buf = pi.getBytes(pi.charsetInfo.getCharset()); if (buf.length > VAR_MAX) { if (buf.length <= MS_LONGVAR_MAX && out.getTdsVersion() >= Driver.TDS70) { out.write((byte) XSYBVARCHAR); out.write((short) MS_LONGVAR_MAX); if (isTds8) { putCollation(out, pi); } out.write((short) buf.length); out.write(buf); } else { out.write((byte) SYBTEXT); out.write(buf.length); if (isTds8) { putCollation(out, pi); } out.write(buf.length); out.write(buf); } } else { if (buf.length == 0) { buf = new byte[1]; buf[0] = ' '; } out.write((byte) pi.tdsType); out.write((byte) VAR_MAX); out.write((byte) buf.length); out.write(buf); } } break; case XSYBNVARCHAR: out.write((byte) pi.tdsType); out.write((short) MS_LONGVAR_MAX); if (isTds8) { putCollation(out, pi); } if (pi.value == null) { out.write((short) 0xFFFF); } else { tmp = pi.getString(pi.charsetInfo.getCharset()); out.write((short) (tmp.length() * 2)); out.write(tmp); } break; case SYBTEXT: if (pi.value == null) { len = 0; } else { len = pi.length; if (len == 0 && out.getTdsVersion() < Driver.TDS70) { pi.value = " "; len = 1; } } out.write((byte) pi.tdsType); if (len > 0) { if (pi.value instanceof InputStream) { // Write output directly from stream out.write(len); if (isTds8) { putCollation(out, pi); } out.write(len); out.writeStreamBytes((InputStream) pi.value, len); } else if (pi.value instanceof Reader && !pi.charsetInfo.isWideChars()) { // Write output directly from stream with character translation out.write(len); if (isTds8) { putCollation(out, pi); } out.write(len); out.writeReaderBytes((Reader) pi.value, len); } else { buf = pi.getBytes(pi.charsetInfo.getCharset()); out.write(buf.length); if (isTds8) { putCollation(out, pi); } out.write(buf.length); out.write(buf); } } else { out.write(len); // Zero length if (isTds8) { putCollation(out, pi); } out.write(len); } break; case SYBNTEXT: if (pi.value == null) { len = 0; } else { len = pi.length; } out.write((byte)pi.tdsType); if (len > 0) { if (pi.value instanceof Reader) { out.write(len); if (isTds8) { putCollation(out, pi); } out.write(len * 2); out.writeReaderChars((Reader) pi.value, len); } else if (pi.value instanceof InputStream && !pi.charsetInfo.isWideChars()) { out.write(len); if (isTds8) { putCollation(out, pi); } out.write(len * 2); out.writeReaderChars(new InputStreamReader( (InputStream) pi.value, pi.charsetInfo.getCharset()), len); } else { tmp = pi.getString(pi.charsetInfo.getCharset()); len = tmp.length(); out.write(len); if (isTds8) { putCollation(out, pi); } out.write(len * 2); out.write(tmp); } } else { out.write(len); if (isTds8) { putCollation(out, pi); } out.write(len); } break; case XSYBVARBINARY: out.write((byte) pi.tdsType); out.write((short) MS_LONGVAR_MAX); if (pi.value == null) { out.write((short)0xFFFF); } else { buf = pi.getBytes(pi.charsetInfo.getCharset()); out.write((short) buf.length); out.write(buf); } break; case SYBVARBINARY: out.write((byte) pi.tdsType); out.write((byte) VAR_MAX); if (pi.value == null) { out.write((byte) 0); } else { buf = pi.getBytes(pi.charsetInfo.getCharset()); if (out.getTdsVersion() < Driver.TDS70 && buf.length == 0) { // Sybase and SQL 6.5 do not allow zero length binary out.write((byte) 1); out.write((byte) 0); } else { out.write((byte) buf.length); out.write(buf); } } break; case SYBIMAGE: if (pi.value == null) { len = 0; } else { len = pi.length; } out.write((byte) pi.tdsType); if (len > 0) { if (pi.value instanceof InputStream) { out.write(len); out.write(len); out.writeStreamBytes((InputStream) pi.value, len); } else { buf = pi.getBytes(pi.charsetInfo.getCharset()); out.write(buf.length); out.write(buf.length); out.write(buf); } } else { if (out.getTdsVersion() < Driver.TDS70) { // Sybase and SQL 6.5 do not allow zero length binary out.write(1); out.write(1); out.write((byte) 0); } else { out.write(len); out.write(len); } } break; case SYBINTN: out.write((byte) pi.tdsType); if (pi.value == null) { out.write(("bigint".equals(pi.sqlType))? (byte)8: (byte)4); out.write((byte) 0); } else { if ("bigint".equals(pi.sqlType)) { out.write((byte) 8); out.write((byte) 8); out.write(((Number) pi.value).longValue()); } else { out.write((byte) 4); out.write((byte) 4); out.write(((Number) pi.value).intValue()); } } break; case SYBFLTN: out.write((byte) pi.tdsType); if (pi.value instanceof Float) { out.write((byte) 4); out.write((byte) 4); out.write(((Number) pi.value).floatValue()); } else { out.write((byte) 8); if (pi.value == null) { out.write((byte) 0); } else { out.write((byte) 8); out.write(((Number) pi.value).doubleValue()); } } break; case SYBDATETIMN: out.write((byte) SYBDATETIMN); out.write((byte) 8); putDateTimeValue(out, (DateTime) pi.value); break; case SYBBIT: out.write((byte) pi.tdsType); if (pi.value == null) { out.write((byte) 0); } else { out.write((byte) (((Boolean) pi.value).booleanValue() ? 1 : 0)); } break; case SYBBITN: out.write((byte) SYBBITN); out.write((byte) 1); if (pi.value == null) { out.write((byte) 0); } else { out.write((byte) 1); out.write((byte) (((Boolean) pi.value).booleanValue() ? 1 : 0)); } break; case SYBNUMERIC: case SYBDECIMAL: out.write((byte) pi.tdsType); BigDecimal value = null; int prec = out.getMaxPrecision(); int scale; if (pi.value == null) { if (pi.jdbcType == Types.BIGINT) { scale = 0; } else { if (pi.scale >= 0 && pi.scale <= prec) { scale = pi.scale; } else { scale = DEFAULT_SCALE; } } } else { if (pi.value instanceof Long) { value = new BigDecimal(((Long) pi.value).toString()); scale = 0; } else { value = (BigDecimal) pi.value; scale = value.scale(); } } out.write(out.getMaxDecimalBytes()); out.write((byte) prec); out.write((byte) scale); out.write(value); break; case XML: len = pi.length; out.write( (byte) pi.tdsType ); out.write( (byte) 0 ); if( pi.value == null ) { out.write( (long) -1 ); } else { out.write( (long) len ); out.write( len ); if( pi.value instanceof byte[] ) { out.write( (byte[]) pi.value ); } else if( pi.value instanceof InputStream ) { byte buffer[] = new byte[1024]; while( len > 0 ) { int res = ( (InputStream) pi.value ).read( buffer ); if (res < 0) throw new java.io.IOException( Messages.get( "error.io.outofdata" ) ); // FIXME: out.write( buffer, 0, res ); len -= res; } // FIXME: JDBC defines both to be an error, but we ignore it for now // if( len < 0 ) // throw new java.io.IOException( Messages.get( "error.io.toomuchdata" ) ); // // if( ( (InputStream) pi.value ).read() >= 0 ) // throw new java.io.IOException( Messages.get( "error.io.toofewdata" ) ); } out.write( 0 ); } break; default: throw new IllegalStateException("Unsupported output TDS type " + Integer.toHexString(pi.tdsType)); } } // // ---------------------- Private methods from here ----------------------- // /** * Private constructor to prevent users creating an * actual instance of this class. */ private TdsData() { } /** * Get a DATETIME value from the server response stream. * * @param in The server response stream. * @param type The TDS data type. * @return The java.sql.Timestamp value or null. * @throws java.io.IOException */ private static Object getDatetimeValue(ResponseStream in, final int type) throws IOException, ProtocolException { int len; int daysSince1900; int time; int minutes; if (type == SYBDATETIMN) { len = in.read(); // No need to & with 0xff } else if (type == SYBDATETIME4) { len = 4; } else { len = 8; } switch (len) { case 0: return null; case 8: // A datetime is made of of two 32 bit integers // The first one is the number of days since 1900 // The second integer is the number of seconds*300 // Negative days indicate dates earlier than 1900. // The full range is 1753-01-01 to 9999-12-31. daysSince1900 = in.readInt(); time = in.readInt(); return new DateTime(daysSince1900, time); case 4: // A smalldatetime is two 16 bit integers. // The first is the number of days past January 1, 1900, // the second smallint is the number of minutes past // midnight. // The full range is 1900-01-01 to 2079-06-06. daysSince1900 = in.readShort() & 0xFFFF; minutes = in.readShort(); return new DateTime((short) daysSince1900, (short) minutes); default: throw new ProtocolException("Invalid DATETIME value with size of " + len + " bytes."); } } /** * Output a java.sql.Date/Time/Timestamp value to the server * as a Sybase datetime value. * * @param out the server request stream * @param value the date value to write */ private static void putDateTimeValue(RequestStream out, DateTime value) throws IOException { if (value == null) { out.write((byte) 0); return; } out.write((byte) 8); out.write(value.getDate()); out.write(value.getTime()); } /** * Read a MONEY value from the server response stream. * * @param in The server response stream. * @param type The TDS data type. * @return The java.math.BigDecimal value or null. * @throws IOException * @throws ProtocolException */ private static Object getMoneyValue(ResponseStream in, final int type) throws IOException, ProtocolException { final int len; if (type == SYBMONEY) { len = 8; } else if (type == SYBMONEYN) { len = in.read(); } else { len = 4; } BigInteger x = null; if (len == 4) { x = BigInteger.valueOf(in.readInt()); } else if (len == 8) { final byte b4 = (byte) in.read(); final byte b5 = (byte) in.read(); final byte b6 = (byte) in.read(); final byte b7 = (byte) in.read(); final byte b0 = (byte) in.read(); final byte b1 = (byte) in.read(); final byte b2 = (byte) in.read(); final byte b3 = (byte) in.read(); final long l = (b0 & 0xff) + ((long) (b1 & 0xff) << 8) + ((long) (b2 & 0xff) << 16) + ((long) (b3 & 0xff) << 24) + ((long) (b4 & 0xff) << 32) + ((long) (b5 & 0xff) << 40) + ((long) (b6 & 0xff) << 48) + ((long) (b7 & 0xff) << 56); x = BigInteger.valueOf(l); } else if (len != 0) { throw new ProtocolException("Invalid money value."); } return (x == null) ? null : new BigDecimal(x, 4); } /** * Read a MSQL 2000 sql_variant data value from the input stream. * <p>SQL_VARIANT has the following structure: * <ol> * <li>INT4 total size of data * <li>INT1 TDS data type (text/image/ntext/sql_variant not allowed) * <li>INT1 Length of extra type descriptor information * <li>Optional additional type info required by some types * <li>byte[0...n] the actual data * </ol> * * @param connection used to obtain collation/charset information * @param in the server response stream * @return the SQL_VARIANT data */ private static Object getVariant(JtdsConnection connection, ResponseStream in) throws IOException, ProtocolException { byte[] bytes; int len = in.readInt(); if (len == 0) { // Length of zero means item is null return null; } ColInfo ci = new ColInfo(); len -= 2; ci.tdsType = in.read(); // TDS Type len -= in.read(); // Size of descriptor switch (ci.tdsType) { case SYBINT1: return new Integer(in.read() & 0xFF); case SYBINT2: return new Integer(in.readShort()); case SYBINT4: return new Integer(in.readInt()); case SYBINT8: return new Long(in.readLong()); case XSYBCHAR: case XSYBVARCHAR: // FIXME Use collation for reading getCollation(in, ci); try { setColumnCharset(ci, connection); } catch (SQLException ex) { // Skip the buffer size and value in.skip(2 + len); throw new ProtocolException(ex.toString() + " [SQLState: " + ex.getSQLState() + ']'); } in.skip(2); // Skip buffer size return in.readNonUnicodeString(len); case XSYBNCHAR: case XSYBNVARCHAR: // XXX Why do we need collation for Unicode strings? in.skip(7); // Skip collation and buffer size return in.readUnicodeString(len / 2); case XSYBVARBINARY: case XSYBBINARY: in.skip(2); // Skip buffer size bytes = new byte[len]; in.read(bytes); return bytes; case SYBMONEY4: case SYBMONEY: return getMoneyValue(in, ci.tdsType); case SYBDATETIME4: case SYBDATETIME: return getDatetimeValue(in, ci.tdsType); case SYBBIT: return (in.read() != 0) ? Boolean.TRUE : Boolean.FALSE; case SYBREAL: return new Float(Float.intBitsToFloat(in.readInt())); case SYBFLT8: return new Double(Double.longBitsToDouble(in.readLong())); case SYBUNIQUE: bytes = new byte[len]; in.read(bytes); return new UniqueIdentifier(bytes); case SYBNUMERIC: case SYBDECIMAL: ci.precision = in.read(); ci.scale = in.read(); int sign = in.read(); len--; bytes = new byte[len]; BigInteger bi; while (len-- > 0) { bytes[len] = (byte)in.read(); } bi = new BigInteger((sign == 0) ? -1 : 1, bytes); return new BigDecimal(bi, ci.scale); default: throw new ProtocolException("Unsupported TDS data type 0x" + Integer.toHexString(ci.tdsType) + " in sql_variant"); } // // For compatibility with the MS driver convert to String. // Change the data type for sql_variant from OTHER to VARCHAR // Without this code the actual Object type can be retrieved // by using getObject(n). // // try { // value = Support.convert(value, Types.VARCHAR, in.getCharset()); // } catch (SQLException e) { // // Conversion failed just try toString(); // value = value.toString(); // } } /** * For SQL 2005 This routine will modify the meta data to allow the * caller to distinguish between varchar(max) and text or varbinary(max) * and image or nvarchar(max) and ntext. * * @param typeName the SQL type returned by sp_columns * @param tdsType the TDS type returned by sp_columns * @return the (possibly) modified SQL type name as a <code>String</code> */ public static String getMSTypeName(String typeName, int tdsType) { if (typeName.equalsIgnoreCase("text") && tdsType != SYBTEXT) { return "varchar"; } else if (typeName.equalsIgnoreCase("ntext") && tdsType != SYBTEXT) { return "nvarchar"; } else if (typeName.equalsIgnoreCase("image") && tdsType != SYBIMAGE) { return "varbinary"; } else { return typeName; } } /** * Extract the TDS protocol version from the value returned by the server in the LOGINACK * packet. * * @param rawTdsVersion the TDS protocol version as returned by the server * @return the jTDS internal value for the protocol version (i.e one of the * <code>Driver.TDS<i>XX</i></code> values) */ public static int getTdsVersion(int rawTdsVersion) { if (rawTdsVersion >= 0x71000001) { return Driver.TDS81; } else if (rawTdsVersion >= 0x07010000) { return Driver.TDS80; } else if (rawTdsVersion >= 0x07000000) { return Driver.TDS70; } else if (rawTdsVersion >= 0x05000000) { return Driver.TDS50; } else { return Driver.TDS42; } } /** * Establish if a String can be converted to a byte based character set. * * @param value The String to test. * @param charset The server character set in force. * @return <code>boolean</code> true if string can be converted. */ private static boolean canEncode(String value, String charset) { if (value == null) { return true; } if ("UTF-8".equals(charset)) { // Should be no problem with UTF-8 return true; } if ("ISO-8859-1".equals(charset)) { // ISO_1 = lower byte of unicode for (int i = value.length() - 1; i >= 0; i--) { if (value.charAt(i) > 255) { return false; // Outside range } } return true; } if ("ISO-8859-15".equals(charset) || "Cp1252".equals(charset)) { // These will accept euro symbol for (int i = value.length() - 1; i >= 0; i--) { // FIXME This is not correct! Cp1252 also contains other characters. // No: I think it is OK the point is to ensure that all characters are either // < 256 in which case the sets are the same or the euro which is convertable. // Any other combination will cause the string to be sent as unicode. char c = value.charAt(i); if (c > 255 && c != 0x20AC) { return false; // Outside range } } return true; } if ("US-ASCII".equals(charset)) { for (int i = value.length() - 1; i >= 0; i--) { if (value.charAt(i) > 127) { return false; // Outside range } } return true; } // OK need to do an expensive check try { return new String(value.getBytes(charset), charset).equals(value); } catch (UnsupportedEncodingException e) { return false; } } static boolean isMSSQL2005Plus( JtdsConnection connection ) { return connection.getServerType() == Driver.SQLSERVER && connection.getDatabaseMajorVersion() > 8; } }
⏎ net/sourceforge/jtds/jdbc/TdsData.java
Or download all of them as a single archive file:
File name: jtds-1.3.1-fyi.zip File size: 323160 bytes Release date: 2013-06-08 Download
⇐ What Is jtds-1.3.1-dist.zip?
2016-11-26, 7830👍, 0💬
Popular Posts:
JAX-WS is an API for building web services and clients. It is the next generation Web Services API r...
Apache Axis2 is the core engine for Web services. It is a complete re-design and re-write of the wid...
jlGui is a music player for the Java platform. It is based on Java Sound 1.0 (i.e. JDK 1.3+). It sup...
How to download and install JDK (Java Development Kit) 1.4? If you want to write Java applications, ...
ASM is an all purpose Java bytecode manipulation and analysis framework. It can be used to modify ex...