Source Code Cross Referenced for TdsData.java in  » Database-JDBC-Connection-Pool » jTDS » net » sourceforge » jtds » jdbc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » jTDS » net.sourceforge.jtds.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.math.BigInteger;
0022:        import java.math.BigDecimal;
0023:        import java.sql.SQLException;
0024:
0025:        import net.sourceforge.jtds.util.BlobBuffer;
0026:
0027:        /**
0028:         * Implement TDS data types and related I/O logic.
0029:         * <p>
0030:         * Implementation notes:
0031:         * <bl>
0032:         * <li>This class encapsulates all the knowledge about reading and writing
0033:         *     TDS data descriptors and related application data.
0034:         * <li>There are four key methods supplied here:
0035:         * <ol>
0036:         * <li>readType() - Reads the column and parameter meta data.
0037:         * <li>readData() - Reads actual data values.
0038:         * <li>writeParam() - Write parameter descriptors and data.
0039:         * <li>getNativeType() - knows how to map JDBC data types to the equivalent TDS type.
0040:         * </ol>
0041:         * </bl>
0042:         *
0043:         * @author Mike Hutchinson
0044:         * @author Alin Sinpalean
0045:         * @author freeTDS project
0046:         * @version $Id: TdsData.java,v 1.60 2007/08/19 02:25:28 bheineman Exp $
0047:         */
0048:        public class TdsData {
0049:            /**
0050:             * This class implements a descriptor for TDS data types;
0051:             *
0052:             * @author Mike Hutchinson.
0053:             */
0054:            private static class TypeInfo {
0055:                /** The SQL type name. */
0056:                public final String sqlType;
0057:                /**
0058:                 * The size of this type or &lt; 0 for variable sizes.
0059:                 * <p> Special values as follows:
0060:                 * <ol>
0061:                 * <li> -5 sql_variant type.
0062:                 * <li> -4 text, image or ntext types.
0063:                 * <li> -2 SQL Server 7+ long char and var binary types.
0064:                 * <li> -1 varchar, varbinary, null types.
0065:                 * </ol>
0066:                 */
0067:                public final int size;
0068:                /**
0069:                 * The precision of the type.
0070:                 * <p>If this is -1 precision must be calculated from buffer size
0071:                 * eg for varchar fields.
0072:                 */
0073:                public final int precision;
0074:                /**
0075:                 * The display size of the type.
0076:                 * <p>-1 If the display size must be calculated from the buffer size.
0077:                 */
0078:                public final int displaySize;
0079:                /** true if type is a signed numeric. */
0080:                public final boolean isSigned;
0081:                /** true if type requires TDS80 collation. */
0082:                public final boolean isCollation;
0083:                /** The java.sql.Types constant for this data type. */
0084:                public final int jdbcType;
0085:
0086:                /**
0087:                 * Construct a new TDS data type descriptor.
0088:                 *
0089:                 * @param sqlType   SQL type name.
0090:                 * @param size Byte size for this type or &lt; 0 for variable length types.
0091:                 * @param precision Decimal precision or -1
0092:                 * @param displaySize Printout size for this type or special values -1,-2.
0093:                 * @param isSigned True if signed numeric type.
0094:                 * @param isCollation True if type has TDS 8 collation information.
0095:                 * @param jdbcType The java.sql.Type constant for this type.
0096:                 */
0097:                TypeInfo(String sqlType, int size, int precision,
0098:                        int displaySize, boolean isSigned, boolean isCollation,
0099:                        int jdbcType) {
0100:                    this .sqlType = sqlType;
0101:                    this .size = size;
0102:                    this .precision = precision;
0103:                    this .displaySize = displaySize;
0104:                    this .isSigned = isSigned;
0105:                    this .isCollation = isCollation;
0106:                    this .jdbcType = jdbcType;
0107:                }
0108:
0109:            }
0110:
0111:            /*
0112:             * Constants for TDS data types
0113:             */
0114:            private static final int SYBCHAR = 47; // 0x2F
0115:            private static final int SYBVARCHAR = 39; // 0x27
0116:            private static final int SYBINTN = 38; // 0x26
0117:            private static final int SYBINT1 = 48; // 0x30
0118:            private static final int SYBDATE = 49; // 0x31 Sybase 12
0119:            private static final int SYBTIME = 51; // 0x33 Sybase 12
0120:            private static final int SYBINT2 = 52; // 0x34
0121:            private static final int SYBINT4 = 56; // 0x38
0122:            private static final int SYBINT8 = 127;// 0x7F
0123:            private static final int SYBFLT8 = 62; // 0x3E
0124:            private static final int SYBDATETIME = 61; // 0x3D
0125:            private static final int SYBBIT = 50; // 0x32
0126:            private static final int SYBTEXT = 35; // 0x23
0127:            private static final int SYBNTEXT = 99; // 0x63
0128:            private static final int SYBIMAGE = 34; // 0x22
0129:            private static final int SYBMONEY4 = 122;// 0x7A
0130:            private static final int SYBMONEY = 60; // 0x3C
0131:            private static final int SYBDATETIME4 = 58; // 0x3A
0132:            private static final int SYBREAL = 59; // 0x3B
0133:            private static final int SYBBINARY = 45; // 0x2D
0134:            private static final int SYBVOID = 31; // 0x1F
0135:            private static final int SYBVARBINARY = 37; // 0x25
0136:            private static final int SYBNVARCHAR = 103;// 0x67
0137:            private static final int SYBBITN = 104;// 0x68
0138:            private static final int SYBNUMERIC = 108;// 0x6C
0139:            private static final int SYBDECIMAL = 106;// 0x6A
0140:            private static final int SYBFLTN = 109;// 0x6D
0141:            private static final int SYBMONEYN = 110;// 0x6E
0142:            private static final int SYBDATETIMN = 111;// 0x6F
0143:            private static final int SYBDATEN = 123;// 0x7B SYBASE 12
0144:            private static final int SYBTIMEN = 147;// 0x93 SYBASE 12
0145:            private static final int XSYBCHAR = 175;// 0xAF
0146:            private static final int XSYBVARCHAR = 167;// 0xA7
0147:            private static final int XSYBNVARCHAR = 231;// 0xE7
0148:            private static final int XSYBNCHAR = 239;// 0xEF
0149:            private static final int XSYBVARBINARY = 165;// 0xA5
0150:            private static final int XSYBBINARY = 173;// 0xAD
0151:            private static final int SYBUNITEXT = 174;// 0xAE SYBASE 15
0152:            private static final int SYBLONGBINARY = 225;// 0xE1 SYBASE 12
0153:            private static final int SYBSINT1 = 64; // 0x40
0154:            private static final int SYBUINT2 = 65; // 0x41 SYBASE 15
0155:            private static final int SYBUINT4 = 66; // 0x42 SYBASE 15
0156:            private static final int SYBUINT8 = 67; // 0x43 SYBASE 15
0157:            private static final int SYBUINTN = 68; // 0x44 SYBASE 15
0158:            private static final int SYBUNIQUE = 36; // 0x24
0159:            private static final int SYBVARIANT = 98; // 0x62
0160:            private static final int SYBSINT8 = 191;// 0xBF SYBASE 15
0161:
0162:            /*
0163:             * Special case for Sybase 12.5+
0164:             * This long data type is used to send text and image
0165:             * data as statement parameters as a replacement for
0166:             * writetext.
0167:             * As far as I can tell this data type is only sent not
0168:             * received.
0169:             */
0170:            static final int SYBLONGDATA = 36; // 0x24 SYBASE 12
0171:
0172:            /*
0173:             * Constants for Sybase User Defined data types used to
0174:             * qualify the new longchar and longbinary types.
0175:             */
0176:            // Common to Sybase and SQL Server
0177:            private static final int UDT_CHAR = 1; // 0x01
0178:            private static final int UDT_VARCHAR = 2; // 0x02
0179:            private static final int UDT_BINARY = 3; // 0x03
0180:            private static final int UDT_VARBINARY = 4; // 0x04
0181:            private static final int UDT_SYSNAME = 18; // 0x12
0182:            // Sybase only
0183:            private static final int UDT_NCHAR = 24; // 0x18
0184:            private static final int UDT_NVARCHAR = 25; // 0x19
0185:            private static final int UDT_UNICHAR = 34; // 0x22
0186:            private static final int UDT_UNIVARCHAR = 35; // 0x23
0187:            private static final int UDT_UNITEXT = 36; // 0x24
0188:            private static final int UDT_LONGSYSNAME = 42; // 0x2A
0189:            private static final int UDT_TIMESTAMP = 80; // 0x50
0190:            // SQL Server 7+
0191:            private static final int UDT_NEWSYSNAME = 256; // 0x100
0192:
0193:            /*
0194:             * Constants for variable length data types
0195:             */
0196:            private static final int VAR_MAX = 255;
0197:            private static final int SYB_LONGVAR_MAX = 16384;
0198:            private static final int MS_LONGVAR_MAX = 8000;
0199:            private static final int SYB_CHUNK_SIZE = 8192;
0200:
0201:            /**
0202:             * Array of TDS data type descriptors.
0203:             */
0204:            private final static TypeInfo types[] = new TypeInfo[256];
0205:
0206:            /**
0207:             * Static block to initialise TDS data type descriptors.
0208:             */
0209:            static {//                             SQL Type       Size Prec  DS signed TDS8 Col java Type
0210:                types[SYBCHAR] = new TypeInfo("char", -1, -1, 1, false, false,
0211:                        java.sql.Types.CHAR);
0212:                types[SYBVARCHAR] = new TypeInfo("varchar", -1, -1, 1, false,
0213:                        false, java.sql.Types.VARCHAR);
0214:                types[SYBINTN] = new TypeInfo("int", -1, 10, 11, true, false,
0215:                        java.sql.Types.INTEGER);
0216:                types[SYBINT1] = new TypeInfo("tinyint", 1, 3, 4, false, false,
0217:                        java.sql.Types.TINYINT);
0218:                types[SYBINT2] = new TypeInfo("smallint", 2, 5, 6, true, false,
0219:                        java.sql.Types.SMALLINT);
0220:                types[SYBINT4] = new TypeInfo("int", 4, 10, 11, true, false,
0221:                        java.sql.Types.INTEGER);
0222:                types[SYBINT8] = new TypeInfo("bigint", 8, 19, 20, true, false,
0223:                        java.sql.Types.BIGINT);
0224:                types[SYBFLT8] = new TypeInfo("float", 8, 15, 24, true, false,
0225:                        java.sql.Types.DOUBLE);
0226:                types[SYBDATETIME] = new TypeInfo("datetime", 8, 23, 23, false,
0227:                        false, java.sql.Types.TIMESTAMP);
0228:                types[SYBBIT] = new TypeInfo("bit", 1, 1, 1, false, false,
0229:                        java.sql.Types.BIT);
0230:                types[SYBTEXT] = new TypeInfo("text", -4, -1, -1, false, true,
0231:                        java.sql.Types.CLOB);
0232:                types[SYBNTEXT] = new TypeInfo("ntext", -4, -1, -1, false,
0233:                        true, java.sql.Types.CLOB);
0234:                types[SYBUNITEXT] = new TypeInfo("unitext", -4, -1, -1, false,
0235:                        true, java.sql.Types.CLOB);
0236:                types[SYBIMAGE] = new TypeInfo("image", -4, -1, -1, false,
0237:                        false, java.sql.Types.BLOB);
0238:                types[SYBMONEY4] = new TypeInfo("smallmoney", 4, 10, 12, true,
0239:                        false, java.sql.Types.DECIMAL);
0240:                types[SYBMONEY] = new TypeInfo("money", 8, 19, 21, true, false,
0241:                        java.sql.Types.DECIMAL);
0242:                types[SYBDATETIME4] = new TypeInfo("smalldatetime", 4, 16, 19,
0243:                        false, false, java.sql.Types.TIMESTAMP);
0244:                types[SYBREAL] = new TypeInfo("real", 4, 7, 14, true, false,
0245:                        java.sql.Types.REAL);
0246:                types[SYBBINARY] = new TypeInfo("binary", -1, -1, 2, false,
0247:                        false, java.sql.Types.BINARY);
0248:                types[SYBVOID] = new TypeInfo("void", -1, 1, 1, false, false, 0);
0249:                types[SYBVARBINARY] = new TypeInfo("varbinary", -1, -1, -1,
0250:                        false, false, java.sql.Types.VARBINARY);
0251:                types[SYBNVARCHAR] = new TypeInfo("nvarchar", -1, -1, -1,
0252:                        false, false, java.sql.Types.VARCHAR);
0253:                types[SYBBITN] = new TypeInfo("bit", -1, 1, 1, false, false,
0254:                        java.sql.Types.BIT);
0255:                types[SYBNUMERIC] = new TypeInfo("numeric", -1, -1, -1, true,
0256:                        false, java.sql.Types.NUMERIC);
0257:                types[SYBDECIMAL] = new TypeInfo("decimal", -1, -1, -1, true,
0258:                        false, java.sql.Types.DECIMAL);
0259:                types[SYBFLTN] = new TypeInfo("float", -1, 15, 24, true, false,
0260:                        java.sql.Types.DOUBLE);
0261:                types[SYBMONEYN] = new TypeInfo("money", -1, 19, 21, true,
0262:                        false, java.sql.Types.DECIMAL);
0263:                types[SYBDATETIMN] = new TypeInfo("datetime", -1, 23, 23,
0264:                        false, false, java.sql.Types.TIMESTAMP);
0265:                types[SYBDATE] = new TypeInfo("date", 4, 10, 10, false, false,
0266:                        java.sql.Types.DATE);
0267:                types[SYBTIME] = new TypeInfo("time", 4, 8, 8, false, false,
0268:                        java.sql.Types.TIME);
0269:                types[SYBDATEN] = new TypeInfo("date", -1, 10, 10, false,
0270:                        false, java.sql.Types.DATE);
0271:                types[SYBTIMEN] = new TypeInfo("time", -1, 8, 8, false, false,
0272:                        java.sql.Types.TIME);
0273:                types[XSYBCHAR] = new TypeInfo("char", -2, -1, -1, false, true,
0274:                        java.sql.Types.CHAR);
0275:                types[XSYBVARCHAR] = new TypeInfo("varchar", -2, -1, -1, false,
0276:                        true, java.sql.Types.VARCHAR);
0277:                types[XSYBNVARCHAR] = new TypeInfo("nvarchar", -2, -1, -1,
0278:                        false, true, java.sql.Types.VARCHAR);
0279:                types[XSYBNCHAR] = new TypeInfo("nchar", -2, -1, -1, false,
0280:                        true, java.sql.Types.CHAR);
0281:                types[XSYBVARBINARY] = new TypeInfo("varbinary", -2, -1, -1,
0282:                        false, false, java.sql.Types.VARBINARY);
0283:                types[XSYBBINARY] = new TypeInfo("binary", -2, -1, -1, false,
0284:                        false, java.sql.Types.BINARY);
0285:                types[SYBLONGBINARY] = new TypeInfo("varbinary", -5, -1, 2,
0286:                        false, false, java.sql.Types.BINARY);
0287:                types[SYBSINT1] = new TypeInfo("tinyint", 1, 2, 3, false,
0288:                        false, java.sql.Types.TINYINT);
0289:                types[SYBUINT2] = new TypeInfo("unsigned smallint", 2, 5, 6,
0290:                        false, false, java.sql.Types.INTEGER);
0291:                types[SYBUINT4] = new TypeInfo("unsigned int", 4, 10, 11,
0292:                        false, false, java.sql.Types.BIGINT);
0293:                types[SYBUINT8] = new TypeInfo("unsigned bigint", 8, 20, 20,
0294:                        false, false, java.sql.Types.DECIMAL);
0295:                types[SYBUINTN] = new TypeInfo("unsigned int", -1, 10, 11,
0296:                        true, false, java.sql.Types.BIGINT);
0297:                types[SYBUNIQUE] = new TypeInfo("uniqueidentifier", -1, 36, 36,
0298:                        false, false, java.sql.Types.CHAR);
0299:                types[SYBVARIANT] = new TypeInfo("sql_variant", -5, 0, 8000,
0300:                        false, false, java.sql.Types.VARCHAR);
0301:                types[SYBSINT8] = new TypeInfo("bigint", 8, 19, 20, true,
0302:                        false, java.sql.Types.BIGINT);
0303:            }
0304:
0305:            /** Default Decimal Scale. */
0306:            static final int DEFAULT_SCALE = 10;
0307:            /** Default precision for SQL Server 6.5 and 7. */
0308:            static final int DEFAULT_PRECISION_28 = 28;
0309:            /** Default precision for Sybase and SQL Server 2000 and newer. */
0310:            static final int DEFAULT_PRECISION_38 = 38;
0311:
0312:            /**
0313:             * TDS 8 supplies collation information for character data types.
0314:             *
0315:             * @param in the server response stream
0316:             * @param ci the column descriptor
0317:             * @return the number of bytes read from the stream as an <code>int</code>
0318:             */
0319:            static int getCollation(ResponseStream in, ColInfo ci)
0320:                    throws IOException {
0321:                if (TdsData.isCollation(ci)) {
0322:                    // Read TDS8 collation info
0323:                    ci.collation = new byte[5];
0324:                    in.read(ci.collation);
0325:
0326:                    return 5;
0327:                }
0328:
0329:                return 0;
0330:            }
0331:
0332:            /**
0333:             * Set the <code>charsetInfo</code> field of <code>ci</code> according to
0334:             * the value of its <code>collation</code> field.
0335:             * <p>
0336:             * The <code>Connection</code> is used to find out whether a specific
0337:             * charset was requested. In this case, the column charset will be ignored.
0338:             *
0339:             * @param ci         the <code>ColInfo</code> instance to update
0340:             * @param connection a <code>Connection</code> instance to check whether it
0341:             *                   has a fixed charset or not
0342:             * @throws SQLException if a <code>CharsetInfo</code> is not found for this
0343:             *                      particular column collation
0344:             */
0345:            static void setColumnCharset(ColInfo ci, ConnectionJDBC2 connection)
0346:                    throws SQLException {
0347:                if (connection.isCharsetSpecified()) {
0348:                    // If a charset was requested on connection creation, ignore the
0349:                    // column collation and use default
0350:                    ci.charsetInfo = connection.getCharsetInfo();
0351:                } else if (ci.collation != null) {
0352:                    // TDS version will be 8.0 or higher in this case and connection
0353:                    // collation will be non-null
0354:                    byte[] collation = ci.collation;
0355:                    byte[] defaultCollation = connection.getCollation();
0356:                    int i;
0357:
0358:                    for (i = 0; i < 5; ++i) {
0359:                        if (collation[i] != defaultCollation[i]) {
0360:                            break;
0361:                        }
0362:                    }
0363:
0364:                    if (i == 5) {
0365:                        ci.charsetInfo = connection.getCharsetInfo();
0366:                    } else {
0367:                        ci.charsetInfo = CharsetInfo.getCharset(collation);
0368:                    }
0369:                }
0370:            }
0371:
0372:            /**
0373:             * Read the TDS datastream and populate the ColInfo parameter with
0374:             * data type and related information.
0375:             * <p>The type infomation conforms to one of the following formats:
0376:             * <ol>
0377:             * <li> [int1 type]  - eg SYBINT4.
0378:             * <li> [int1 type] [int1 buffersize]  - eg VARCHAR &lt; 256
0379:             * <li> [int1 type] [int2 buffersize]  - eg VARCHAR &gt; 255.
0380:             * <li> [int1 type] [int4 buffersize] [int1 tabnamelen] [int1*n tabname] - eg text.
0381:             * <li> [int1 type] [int4 buffersize] - eg sql_variant.
0382:             * <li> [int1 type] [int1 buffersize] [int1 precision] [int1 scale] - eg decimal.
0383:             * </ol>
0384:             * For TDS 8 large character types include a 5 byte collation field after the buffer size.
0385:             *
0386:             * @param in The server response stream.
0387:             * @param ci The ColInfo column descriptor object.
0388:             * @return The number of bytes read from the input stream.
0389:             * @throws IOException
0390:             * @throws ProtocolException
0391:             */
0392:            static int readType(ResponseStream in, ColInfo ci)
0393:                    throws IOException, ProtocolException {
0394:                int tdsVersion = in.getTdsVersion();
0395:                boolean isTds8 = tdsVersion >= Driver.TDS80;
0396:                boolean isTds7 = tdsVersion >= Driver.TDS70;
0397:                boolean isTds5 = tdsVersion == Driver.TDS50;
0398:                boolean isTds42 = tdsVersion == Driver.TDS42;
0399:                int bytesRead = 1;
0400:                // Get the TDS data type code
0401:                int type = in.read();
0402:
0403:                if (types[type] == null || (isTds5 && type == SYBLONGDATA)) {
0404:                    // Trap invalid type or 0x24 received from a Sybase server!
0405:                    throw new ProtocolException("Invalid TDS data type 0x"
0406:                            + Integer.toHexString(type & 0xFF));
0407:                }
0408:
0409:                ci.tdsType = type;
0410:                ci.jdbcType = types[type].jdbcType;
0411:                ci.bufferSize = types[type].size;
0412:
0413:                // Now get the buffersize if required
0414:                if (ci.bufferSize == -5) {
0415:                    // sql_variant
0416:                    // Sybase long binary
0417:                    ci.bufferSize = in.readInt();
0418:                    bytesRead += 4;
0419:                } else if (ci.bufferSize == -4) {
0420:                    // text or image
0421:                    ci.bufferSize = in.readInt();
0422:
0423:                    if (isTds8) {
0424:                        bytesRead += getCollation(in, ci);
0425:                    }
0426:
0427:                    int lenName = in.readShort();
0428:
0429:                    ci.tableName = in.readString(lenName);
0430:                    bytesRead += 6 + ((in.getTdsVersion() >= Driver.TDS70) ? lenName * 2
0431:                            : lenName);
0432:                } else if (ci.bufferSize == -2) {
0433:                    // longvarchar longvarbinary
0434:                    if (isTds5 && ci.tdsType == XSYBCHAR) {
0435:                        ci.bufferSize = in.readInt();
0436:                        bytesRead += 4;
0437:                    } else {
0438:                        ci.bufferSize = in.readShort();
0439:                        bytesRead += 2;
0440:                    }
0441:
0442:                    if (isTds8) {
0443:                        bytesRead += getCollation(in, ci);
0444:                    }
0445:
0446:                } else if (ci.bufferSize == -1) {
0447:                    // varchar varbinary decimal etc
0448:                    bytesRead += 1;
0449:                    ci.bufferSize = in.read();
0450:                }
0451:
0452:                // Set default displaySize and precision
0453:                ci.displaySize = types[type].displaySize;
0454:                ci.precision = types[type].precision;
0455:                ci.sqlType = types[type].sqlType;
0456:
0457:                // Now fine tune sizes for specific types
0458:                switch (type) {
0459:                //
0460:                // long datetime has scale of 3 smalldatetime has scale of 0
0461:                //
0462:                case SYBDATETIME:
0463:                    ci.scale = 3;
0464:                    break;
0465:                // Establish actual size of nullable datetime
0466:                case SYBDATETIMN:
0467:                    if (ci.bufferSize == 8) {
0468:                        ci.displaySize = types[SYBDATETIME].displaySize;
0469:                        ci.precision = types[SYBDATETIME].precision;
0470:                        ci.scale = 3;
0471:                    } else {
0472:                        ci.displaySize = types[SYBDATETIME4].displaySize;
0473:                        ci.precision = types[SYBDATETIME4].precision;
0474:                        ci.sqlType = types[SYBDATETIME4].sqlType;
0475:                        ci.scale = 0;
0476:                    }
0477:                    break;
0478:                // Establish actual size of nullable float
0479:                case SYBFLTN:
0480:                    if (ci.bufferSize == 8) {
0481:                        ci.displaySize = types[SYBFLT8].displaySize;
0482:                        ci.precision = types[SYBFLT8].precision;
0483:                    } else {
0484:                        ci.displaySize = types[SYBREAL].displaySize;
0485:                        ci.precision = types[SYBREAL].precision;
0486:                        ci.jdbcType = java.sql.Types.REAL;
0487:                        ci.sqlType = types[SYBREAL].sqlType;
0488:                    }
0489:                    break;
0490:                // Establish actual size of nullable int
0491:                case SYBINTN:
0492:                    if (ci.bufferSize == 8) {
0493:                        ci.displaySize = types[SYBINT8].displaySize;
0494:                        ci.precision = types[SYBINT8].precision;
0495:                        ci.jdbcType = java.sql.Types.BIGINT;
0496:                        ci.sqlType = types[SYBINT8].sqlType;
0497:                    } else if (ci.bufferSize == 4) {
0498:                        ci.displaySize = types[SYBINT4].displaySize;
0499:                        ci.precision = types[SYBINT4].precision;
0500:                    } else if (ci.bufferSize == 2) {
0501:                        ci.displaySize = types[SYBINT2].displaySize;
0502:                        ci.precision = types[SYBINT2].precision;
0503:                        ci.jdbcType = java.sql.Types.SMALLINT;
0504:                        ci.sqlType = types[SYBINT2].sqlType;
0505:                    } else {
0506:                        ci.displaySize = types[SYBINT1].displaySize;
0507:                        ci.precision = types[SYBINT1].precision;
0508:                        ci.jdbcType = java.sql.Types.TINYINT;
0509:                        ci.sqlType = types[SYBINT1].sqlType;
0510:                    }
0511:                    break;
0512:                // Establish actual size of nullable unsigned int
0513:                case SYBUINTN:
0514:                    if (ci.bufferSize == 8) {
0515:                        ci.displaySize = types[SYBUINT8].displaySize;
0516:                        ci.precision = types[SYBUINT8].precision;
0517:                        ci.jdbcType = types[SYBUINT8].jdbcType;
0518:                        ci.sqlType = types[SYBUINT8].sqlType;
0519:                    } else if (ci.bufferSize == 4) {
0520:                        ci.displaySize = types[SYBUINT4].displaySize;
0521:                        ci.precision = types[SYBUINT4].precision;
0522:                    } else if (ci.bufferSize == 2) {
0523:                        ci.displaySize = types[SYBUINT2].displaySize;
0524:                        ci.precision = types[SYBUINT2].precision;
0525:                        ci.jdbcType = types[SYBUINT2].jdbcType;
0526:                        ci.sqlType = types[SYBUINT2].sqlType;
0527:                    } else {
0528:                        throw new ProtocolException(
0529:                                "unsigned int null (size 1) not supported");
0530:                    }
0531:                    break;
0532:                //
0533:                // Money types have a scale of 4
0534:                //
0535:                case SYBMONEY:
0536:                case SYBMONEY4:
0537:                    ci.scale = 4;
0538:                    break;
0539:                // Establish actual size of nullable money
0540:                case SYBMONEYN:
0541:                    if (ci.bufferSize == 8) {
0542:                        ci.displaySize = types[SYBMONEY].displaySize;
0543:                        ci.precision = types[SYBMONEY].precision;
0544:                    } else {
0545:                        ci.displaySize = types[SYBMONEY4].displaySize;
0546:                        ci.precision = types[SYBMONEY4].precision;
0547:                        ci.sqlType = types[SYBMONEY4].sqlType;
0548:                    }
0549:                    ci.scale = 4;
0550:                    break;
0551:
0552:                // Read in scale and precision for decimal types
0553:                case SYBDECIMAL:
0554:                case SYBNUMERIC:
0555:                    ci.precision = in.read();
0556:                    ci.scale = in.read();
0557:                    ci.displaySize = ((ci.scale > 0) ? 2 : 1) + ci.precision;
0558:                    bytesRead += 2;
0559:                    ci.sqlType = types[type].sqlType;
0560:                    break;
0561:
0562:                // Although a binary type force displaysize to MAXINT
0563:                case SYBIMAGE:
0564:                    ci.precision = Integer.MAX_VALUE;
0565:                    ci.displaySize = Integer.MAX_VALUE;
0566:                    break;
0567:                // Normal binaries have a display size of 2 * precision 0x0A0B etc
0568:                case SYBLONGBINARY:
0569:                case SYBVARBINARY:
0570:                case SYBBINARY:
0571:                case XSYBBINARY:
0572:                case XSYBVARBINARY:
0573:                    ci.precision = ci.bufferSize;
0574:                    ci.displaySize = ci.precision * 2;
0575:                    break;
0576:
0577:                // SQL Server unicode text can only display half as many chars
0578:                case SYBNTEXT:
0579:                    ci.precision = Integer.MAX_VALUE / 2;
0580:                    ci.displaySize = Integer.MAX_VALUE / 2;
0581:                    break;
0582:
0583:                // ASE 15+ unicode text can only display half as many chars
0584:                case SYBUNITEXT:
0585:                    ci.precision = Integer.MAX_VALUE / 2;
0586:                    ci.displaySize = Integer.MAX_VALUE / 2;
0587:                    break;
0588:
0589:                // SQL Server unicode chars can only display half as many chars
0590:                case XSYBNCHAR:
0591:                case XSYBNVARCHAR:
0592:                    ci.displaySize = ci.bufferSize / 2;
0593:                    ci.precision = ci.displaySize;
0594:                    break;
0595:
0596:                // Normal characters display size = precision = buffer size.
0597:                case SYBTEXT:
0598:                case SYBCHAR:
0599:                case XSYBCHAR:
0600:                case XSYBVARCHAR:
0601:                case SYBVARCHAR:
0602:                case SYBNVARCHAR:
0603:                    ci.precision = ci.bufferSize;
0604:                    ci.displaySize = ci.precision;
0605:                    break;
0606:                }
0607:
0608:                // For numeric types add 'identity' for auto inc data type
0609:                if (ci.isIdentity) {
0610:                    ci.sqlType += " identity";
0611:                }
0612:
0613:                // Fine tune Sybase or SQL 6.5 data types
0614:                if (isTds42 || isTds5) {
0615:                    switch (ci.userType) {
0616:                    case UDT_CHAR:
0617:                        ci.sqlType = "char";
0618:                        ci.displaySize = ci.bufferSize;
0619:                        ci.jdbcType = java.sql.Types.CHAR;
0620:                        break;
0621:                    case UDT_VARCHAR:
0622:                        ci.sqlType = "varchar";
0623:                        ci.displaySize = ci.bufferSize;
0624:                        ci.jdbcType = java.sql.Types.VARCHAR;
0625:                        break;
0626:                    case UDT_BINARY:
0627:                        ci.sqlType = "binary";
0628:                        ci.displaySize = ci.bufferSize * 2;
0629:                        ci.jdbcType = java.sql.Types.BINARY;
0630:                        break;
0631:                    case UDT_VARBINARY:
0632:                        ci.sqlType = "varbinary";
0633:                        ci.displaySize = ci.bufferSize * 2;
0634:                        ci.jdbcType = java.sql.Types.VARBINARY;
0635:                        break;
0636:                    case UDT_SYSNAME:
0637:                        ci.sqlType = "sysname";
0638:                        ci.displaySize = ci.bufferSize;
0639:                        ci.jdbcType = java.sql.Types.VARCHAR;
0640:                        break;
0641:                    case UDT_TIMESTAMP:
0642:                        ci.sqlType = "timestamp";
0643:                        ci.displaySize = ci.bufferSize * 2;
0644:                        ci.jdbcType = java.sql.Types.VARBINARY;
0645:                        break;
0646:                    }
0647:                }
0648:
0649:                // Fine tune Sybase data types
0650:                if (isTds5) {
0651:                    switch (ci.userType) {
0652:                    case UDT_NCHAR:
0653:                        ci.sqlType = "nchar";
0654:                        ci.displaySize = ci.bufferSize;
0655:                        ci.jdbcType = java.sql.Types.CHAR;
0656:                        break;
0657:                    case UDT_NVARCHAR:
0658:                        ci.sqlType = "nvarchar";
0659:                        ci.displaySize = ci.bufferSize;
0660:                        ci.jdbcType = java.sql.Types.VARCHAR;
0661:                        break;
0662:                    case UDT_UNICHAR:
0663:                        ci.sqlType = "unichar";
0664:                        ci.displaySize = ci.bufferSize / 2;
0665:                        ci.precision = ci.displaySize;
0666:                        ci.jdbcType = java.sql.Types.CHAR;
0667:                        break;
0668:                    case UDT_UNIVARCHAR:
0669:                        ci.sqlType = "univarchar";
0670:                        ci.displaySize = ci.bufferSize / 2;
0671:                        ci.precision = ci.displaySize;
0672:                        ci.jdbcType = java.sql.Types.VARCHAR;
0673:                        break;
0674:                    case UDT_LONGSYSNAME:
0675:                        ci.sqlType = "longsysname";
0676:                        ci.jdbcType = java.sql.Types.VARCHAR;
0677:                        ci.displaySize = ci.bufferSize;
0678:                        break;
0679:                    }
0680:                }
0681:                // Fine tune SQL Server 7+ datatypes
0682:                if (isTds7) {
0683:                    switch (ci.userType) {
0684:                    case UDT_TIMESTAMP:
0685:                        ci.sqlType = "timestamp";
0686:                        ci.jdbcType = java.sql.Types.BINARY;
0687:                        break;
0688:                    case UDT_NEWSYSNAME:
0689:                        ci.sqlType = "sysname";
0690:                        ci.jdbcType = java.sql.Types.VARCHAR;
0691:                        break;
0692:                    }
0693:                }
0694:
0695:                return bytesRead;
0696:            }
0697:
0698:            /**
0699:             * Read the TDS data item from the Response Stream.
0700:             * <p> The data size is either implicit in the type for example
0701:             * fixed size integers, or a count field precedes the actual data.
0702:             * The size of the count field varies with the data type.
0703:             *
0704:             * @param connection an object reference to the caller of this method;
0705:             *        must be a <code>Connection</code>, <code>Statement</code> or
0706:             *        <code>ResultSet</code>
0707:             * @param in The server ResponseStream.
0708:             * @param ci The ColInfo column descriptor object.
0709:             * @return The data item Object or null.
0710:             * @throws IOException
0711:             * @throws ProtocolException
0712:             */
0713:            static Object readData(ConnectionJDBC2 connection,
0714:                    ResponseStream in, ColInfo ci) throws IOException,
0715:                    ProtocolException {
0716:                int len;
0717:
0718:                switch (ci.tdsType) {
0719:                case SYBINTN:
0720:                    switch (in.read()) {
0721:                    case 1:
0722:                        return new Integer(in.read() & 0xFF);
0723:                    case 2:
0724:                        return new Integer(in.readShort());
0725:                    case 4:
0726:                        return new Integer(in.readInt());
0727:                    case 8:
0728:                        return new Long(in.readLong());
0729:                    }
0730:
0731:                    break;
0732:
0733:                // Sybase ASE 15+ supports unsigned null smallint, int and bigint
0734:                case SYBUINTN:
0735:                    switch (in.read()) {
0736:                    case 1:
0737:                        return new Integer(in.read() & 0xFF);
0738:                    case 2:
0739:                        return new Integer((int) in.readShort() & 0xFFFF);
0740:                    case 4:
0741:                        return new Long((long) in.readInt() & 0xFFFFFFFFL);
0742:                    case 8:
0743:                        return in.readUnsignedLong();
0744:                    }
0745:                    break;
0746:
0747:                case SYBINT1:
0748:                    return new Integer(in.read() & 0xFF);
0749:
0750:                case SYBINT2:
0751:                    return new Integer(in.readShort());
0752:
0753:                case SYBINT4:
0754:                    return new Integer(in.readInt());
0755:
0756:                    // SQL Server bigint
0757:                case SYBINT8:
0758:                    return new Long(in.readLong());
0759:
0760:                    // Sybase ASE 15+ bigint
0761:                case SYBSINT8:
0762:                    return new Long(in.readLong());
0763:
0764:                    // Sybase ASE 15+ unsigned smallint
0765:                case SYBUINT2:
0766:                    return new Integer((int) in.readShort() & 0xFFFF);
0767:
0768:                    // Sybase ASE 15+ unsigned int
0769:                case SYBUINT4:
0770:                    return new Long((long) in.readInt() & 0xFFFFFFFFL);
0771:
0772:                    // Sybase ASE 15+ unsigned bigint
0773:                case SYBUINT8:
0774:                    return in.readUnsignedLong();
0775:
0776:                case SYBIMAGE:
0777:                    len = in.read();
0778:
0779:                    if (len > 0) {
0780:                        in.skip(24); // Skip textptr and timestamp
0781:                        int dataLen = in.readInt();
0782:                        BlobImpl blob;
0783:                        if (dataLen == 0 && in.getTdsVersion() <= Driver.TDS50) {
0784:                            // Length of zero may indicate an initialized image 
0785:                            // column that has been updated to null.
0786:                            break;
0787:                        }
0788:                        if (dataLen <= connection.getLobBuffer()) {
0789:                            //
0790:                            // OK Small enough to load into memory
0791:                            //
0792:                            byte[] data = new byte[dataLen];
0793:                            in.read(data);
0794:                            blob = new BlobImpl(connection, data);
0795:                        } else {
0796:                            // Too big, need to write straight to disk
0797:                            try {
0798:                                blob = new BlobImpl(connection);
0799:                                OutputStream out = blob.setBinaryStream(1);
0800:                                byte[] buffer = new byte[1024];
0801:                                int result;
0802:                                while ((result = in.read(buffer, 0, Math.min(
0803:                                        dataLen, buffer.length))) != -1
0804:                                        && dataLen != 0) {
0805:                                    out.write(buffer, 0, result);
0806:                                    dataLen -= result;
0807:                                }
0808:                                out.close();
0809:                            } catch (SQLException e) {
0810:                                // Transform setBinaryStream SQLException
0811:                                throw new IOException(e.getMessage());
0812:                            }
0813:                        }
0814:                        return blob;
0815:                    }
0816:
0817:                    break;
0818:
0819:                case SYBTEXT:
0820:                    len = in.read();
0821:
0822:                    if (len > 0) {
0823:                        String charset;
0824:                        if (ci.charsetInfo != null) {
0825:                            charset = ci.charsetInfo.getCharset();
0826:                        } else {
0827:                            charset = connection.getCharset();
0828:                        }
0829:                        in.skip(24); // Skip textptr and timestamp
0830:                        int dataLen = in.readInt();
0831:                        if (dataLen == 0 && in.getTdsVersion() <= Driver.TDS50) {
0832:                            // Length of zero may indicate an initialized text 
0833:                            // column that has been updated to null.
0834:                            break;
0835:                        }
0836:                        ClobImpl clob = new ClobImpl(connection);
0837:                        BlobBuffer blobBuffer = clob.getBlobBuffer();
0838:                        if (dataLen <= connection.getLobBuffer()) {
0839:                            //
0840:                            // OK Small enough to load into memory
0841:                            //
0842:                            BufferedReader rdr = new BufferedReader(
0843:                                    new InputStreamReader(in
0844:                                            .getInputStream(dataLen), charset),
0845:                                    1024);
0846:                            byte[] data = new byte[dataLen * 2];
0847:                            int p = 0;
0848:                            int c;
0849:                            while ((c = rdr.read()) >= 0) {
0850:                                data[p++] = (byte) c;
0851:                                data[p++] = (byte) (c >> 8);
0852:                            }
0853:                            rdr.close();
0854:                            blobBuffer.setBuffer(data, false);
0855:                            if (p == 2 && data[0] == 0x20 && data[1] == 0
0856:                                    && in.getTdsVersion() < Driver.TDS70) {
0857:                                // Single space with Sybase equates to empty string
0858:                                p = 0;
0859:                            }
0860:                            // Explicitly set length as multi byte character sets
0861:                            // may not fill array completely.
0862:                            blobBuffer.setLength(p);
0863:                        } else {
0864:                            // Too big, need to write straight to disk
0865:                            BufferedReader rdr = new BufferedReader(
0866:                                    new InputStreamReader(in
0867:                                            .getInputStream(dataLen), charset),
0868:                                    1024);
0869:                            try {
0870:                                OutputStream out = blobBuffer.setBinaryStream(
0871:                                        1, false);
0872:                                int c;
0873:                                while ((c = rdr.read()) >= 0) {
0874:                                    out.write(c);
0875:                                    out.write(c >> 8);
0876:                                }
0877:                                out.close();
0878:                                rdr.close();
0879:                            } catch (SQLException e) {
0880:                                // Turn back into an IOException
0881:                                throw new IOException(e.getMessage());
0882:                            }
0883:                        }
0884:                        return clob;
0885:                    }
0886:
0887:                    break;
0888:
0889:                case SYBUNITEXT: // ASE 15+ unicode text type
0890:                case SYBNTEXT:
0891:                    len = in.read();
0892:
0893:                    if (len > 0) {
0894:                        in.skip(24); // Skip textptr and timestamp
0895:                        int dataLen = in.readInt();
0896:                        if (dataLen == 0 && in.getTdsVersion() <= Driver.TDS50) {
0897:                            // Length of zero may indicate an initialized unitext 
0898:                            // column that has been updated to null.
0899:                            break;
0900:                        }
0901:                        ClobImpl clob = new ClobImpl(connection);
0902:                        BlobBuffer blobBuffer = clob.getBlobBuffer();
0903:                        if (dataLen <= connection.getLobBuffer()) {
0904:                            //
0905:                            // OK Small enough to load into memory
0906:                            //
0907:                            byte[] data = new byte[dataLen];
0908:                            in.read(data);
0909:                            blobBuffer.setBuffer(data, false);
0910:                            if (dataLen == 2 && data[0] == 0x20 && data[1] == 0
0911:                                    && in.getTdsVersion() == Driver.TDS50) {
0912:                                // Single space with Sybase equates to empty string
0913:                                dataLen = 0;
0914:                            }
0915:                            // Explicitly set length as multi byte character sets
0916:                            // may not fill array completely.
0917:                            blobBuffer.setLength(dataLen);
0918:                        } else {
0919:                            // Too big, need to write straight to disk
0920:                            try {
0921:                                OutputStream out = blobBuffer.setBinaryStream(
0922:                                        1, false);
0923:                                byte[] buffer = new byte[1024];
0924:                                int result;
0925:                                while ((result = in.read(buffer, 0, Math.min(
0926:                                        dataLen, buffer.length))) != -1
0927:                                        && dataLen != 0) {
0928:                                    out.write(buffer, 0, result);
0929:                                    dataLen -= result;
0930:                                }
0931:                                out.close();
0932:                            } catch (SQLException e) {
0933:                                // Transform setBinaryStream SQLException
0934:                                throw new IOException(e.getMessage());
0935:                            }
0936:                        }
0937:                        return clob;
0938:                    }
0939:
0940:                    break;
0941:
0942:                case SYBCHAR:
0943:                case SYBVARCHAR:
0944:                    len = in.read();
0945:
0946:                    if (len > 0) {
0947:                        String value = in.readNonUnicodeString(len,
0948:                                ci.charsetInfo == null ? connection
0949:                                        .getCharsetInfo() : ci.charsetInfo);
0950:
0951:                        if (len == 1 && ci.tdsType == SYBVARCHAR
0952:                                && in.getTdsVersion() < Driver.TDS70) {
0953:                            // In TDS 4/5 zero length varchars are stored as a
0954:                            // single space to distinguish them from nulls.
0955:                            return (" ".equals(value)) ? "" : value;
0956:                        }
0957:
0958:                        return value;
0959:                    }
0960:
0961:                    break;
0962:
0963:                case SYBNVARCHAR:
0964:                    len = in.read();
0965:
0966:                    if (len > 0) {
0967:                        return in.readUnicodeString(len / 2);
0968:                    }
0969:
0970:                    break;
0971:
0972:                case XSYBCHAR:
0973:                case XSYBVARCHAR:
0974:                    if (in.getTdsVersion() == Driver.TDS50) {
0975:                        // This is a Sybase wide table String
0976:                        len = in.readInt();
0977:                        if (len > 0) {
0978:                            String tmp = in.readNonUnicodeString(len);
0979:                            if (" ".equals(tmp) && !"char".equals(ci.sqlType)) {
0980:                                tmp = "";
0981:                            }
0982:                            return tmp;
0983:                        }
0984:                    } else {
0985:                        // This is a TDS 7+ long string
0986:                        len = in.readShort();
0987:                        if (len != -1) {
0988:                            return in.readNonUnicodeString(len,
0989:                                    ci.charsetInfo == null ? connection
0990:                                            .getCharsetInfo() : ci.charsetInfo);
0991:                        }
0992:                    }
0993:
0994:                    break;
0995:
0996:                case XSYBNCHAR:
0997:                case XSYBNVARCHAR:
0998:                    len = in.readShort();
0999:
1000:                    if (len != -1) {
1001:                        return in.readUnicodeString(len / 2);
1002:                    }
1003:
1004:                    break;
1005:
1006:                case SYBVARBINARY:
1007:                case SYBBINARY:
1008:                    len = in.read();
1009:
1010:                    if (len > 0) {
1011:                        byte[] bytes = new byte[len];
1012:
1013:                        in.read(bytes);
1014:
1015:                        return bytes;
1016:                    }
1017:
1018:                    break;
1019:
1020:                case XSYBVARBINARY:
1021:                case XSYBBINARY:
1022:                    len = in.readShort();
1023:
1024:                    if (len != -1) {
1025:                        byte[] bytes = new byte[len];
1026:
1027:                        in.read(bytes);
1028:
1029:                        return bytes;
1030:                    }
1031:
1032:                    break;
1033:
1034:                case SYBLONGBINARY:
1035:                    len = in.readInt();
1036:                    if (len != 0) {
1037:                        if ("unichar".equals(ci.sqlType)
1038:                                || "univarchar".equals(ci.sqlType)) {
1039:                            char[] buf = new char[len / 2];
1040:                            in.read(buf);
1041:                            if ((len & 1) != 0) {
1042:                                // Bad length should be divisible by 2
1043:                                in.skip(1); // Deal with it anyway.
1044:                            }
1045:                            if (len == 2 && buf[0] == ' ') {
1046:                                return "";
1047:                            } else {
1048:                                return new String(buf);
1049:                            }
1050:                        } else {
1051:                            byte[] bytes = new byte[len];
1052:                            in.read(bytes);
1053:                            return bytes;
1054:                        }
1055:                    }
1056:                    break;
1057:
1058:                case SYBMONEY4:
1059:                case SYBMONEY:
1060:                case SYBMONEYN:
1061:                    return getMoneyValue(in, ci.tdsType);
1062:
1063:                case SYBDATETIME4:
1064:                case SYBDATETIMN:
1065:                case SYBDATETIME:
1066:                    return getDatetimeValue(in, ci.tdsType);
1067:
1068:                case SYBDATEN:
1069:                case SYBDATE:
1070:                    len = (ci.tdsType == SYBDATEN) ? in.read() : 4;
1071:                    if (len == 4) {
1072:                        return new DateTime(in.readInt(), -1);
1073:                    } else {
1074:                        // Invalid length or 0 for null
1075:                        in.skip(len);
1076:                    }
1077:                    break;
1078:
1079:                case SYBTIMEN:
1080:                case SYBTIME:
1081:                    len = (ci.tdsType == SYBTIMEN) ? in.read() : 4;
1082:                    if (len == 4) {
1083:                        return new DateTime(-1, in.readInt());
1084:                    } else {
1085:                        // Invalid length or 0 for null
1086:                        in.skip(len);
1087:                    }
1088:                    break;
1089:
1090:                case SYBBIT:
1091:                    return (in.read() != 0) ? Boolean.TRUE : Boolean.FALSE;
1092:
1093:                case SYBBITN:
1094:                    len = in.read();
1095:
1096:                    if (len > 0) {
1097:                        return (in.read() != 0) ? Boolean.TRUE : Boolean.FALSE;
1098:                    }
1099:
1100:                    break;
1101:
1102:                case SYBREAL:
1103:                    return new Float(Float.intBitsToFloat(in.readInt()));
1104:
1105:                case SYBFLT8:
1106:                    return new Double(Double.longBitsToDouble(in.readLong()));
1107:
1108:                case SYBFLTN:
1109:                    len = in.read();
1110:
1111:                    if (len == 4) {
1112:                        return new Float(Float.intBitsToFloat(in.readInt()));
1113:                    } else if (len == 8) {
1114:                        return new Double(Double
1115:                                .longBitsToDouble(in.readLong()));
1116:                    }
1117:
1118:                    break;
1119:
1120:                case SYBUNIQUE:
1121:                    len = in.read();
1122:
1123:                    if (len > 0) {
1124:                        byte[] bytes = new byte[len];
1125:
1126:                        in.read(bytes);
1127:
1128:                        return new UniqueIdentifier(bytes);
1129:                    }
1130:
1131:                    break;
1132:
1133:                case SYBNUMERIC:
1134:                case SYBDECIMAL:
1135:                    len = in.read();
1136:
1137:                    if (len > 0) {
1138:                        int sign = in.read();
1139:
1140:                        len--;
1141:                        byte[] bytes = new byte[len];
1142:                        BigInteger bi;
1143:
1144:                        if (in.getServerType() == Driver.SYBASE) {
1145:                            // Sybase order is MSB first!
1146:                            for (int i = 0; i < len; i++) {
1147:                                bytes[i] = (byte) in.read();
1148:                            }
1149:
1150:                            bi = new BigInteger((sign == 0) ? 1 : -1, bytes);
1151:                        } else {
1152:                            while (len-- > 0) {
1153:                                bytes[len] = (byte) in.read();
1154:                            }
1155:
1156:                            bi = new BigInteger((sign == 0) ? -1 : 1, bytes);
1157:                        }
1158:
1159:                        return new BigDecimal(bi, ci.scale);
1160:                    }
1161:
1162:                    break;
1163:
1164:                case SYBVARIANT:
1165:                    return getVariant(connection, in);
1166:
1167:                default:
1168:                    throw new ProtocolException("Unsupported TDS data type 0x"
1169:                            + Integer.toHexString(ci.tdsType & 0xFF));
1170:                }
1171:
1172:                return null;
1173:            }
1174:
1175:            /**
1176:             * Retrieve the signed status of the column.
1177:             *
1178:             * @param ci the column meta data
1179:             * @return <code>true</code> if the column is a signed numeric.
1180:             */
1181:            static boolean isSigned(ColInfo ci) {
1182:                int type = ci.tdsType;
1183:
1184:                if (type < 0 || type > 255 || types[type] == null) {
1185:                    throw new IllegalArgumentException("TDS data type " + type
1186:                            + " invalid");
1187:                }
1188:                if (type == TdsData.SYBINTN && ci.bufferSize == 1) {
1189:                    type = TdsData.SYBINT1; // Tiny int is not signed!
1190:                }
1191:                return types[type].isSigned;
1192:            }
1193:
1194:            /**
1195:             * Retrieve the collation status of the column.
1196:             * <p/>
1197:             * TDS 8.0 character columns include collation information.
1198:             *
1199:             * @param ci the column meta data
1200:             * @return <code>true</code> if the column requires collation data.
1201:             */
1202:            static boolean isCollation(ColInfo ci) {
1203:                int type = ci.tdsType;
1204:
1205:                if (type < 0 || type > 255 || types[type] == null) {
1206:                    throw new IllegalArgumentException("TDS data type " + type
1207:                            + " invalid");
1208:                }
1209:
1210:                return types[type].isCollation;
1211:            }
1212:
1213:            /**
1214:             * Retrieve the currency status of the column.
1215:             *
1216:             * @param ci The column meta data.
1217:             * @return <code>boolean</code> true if the column is a currency type.
1218:             */
1219:            static boolean isCurrency(ColInfo ci) {
1220:                int type = ci.tdsType;
1221:
1222:                if (type < 0 || type > 255 || types[type] == null) {
1223:                    throw new IllegalArgumentException("TDS data type " + type
1224:                            + " invalid");
1225:                }
1226:
1227:                return type == SYBMONEY || type == SYBMONEY4
1228:                        || type == SYBMONEYN;
1229:            }
1230:
1231:            /**
1232:             * Retrieve the searchable status of the column.
1233:             *
1234:             * @param ci the column meta data
1235:             * @return <code>true</code> if the column is not a text or image type.
1236:             */
1237:            static boolean isSearchable(ColInfo ci) {
1238:                int type = ci.tdsType;
1239:
1240:                if (type < 0 || type > 255 || types[type] == null) {
1241:                    throw new IllegalArgumentException("TDS data type " + type
1242:                            + " invalid");
1243:                }
1244:
1245:                return types[type].size != -4;
1246:            }
1247:
1248:            /**
1249:             * Determines whether the column is Unicode encoded.
1250:             *
1251:             * @param ci the column meta data
1252:             * @return <code>true</code> if the column is Unicode encoded
1253:             */
1254:            static boolean isUnicode(ColInfo ci) {
1255:                int type = ci.tdsType;
1256:
1257:                if (type < 0 || type > 255 || types[type] == null) {
1258:                    throw new IllegalArgumentException("TDS data type " + type
1259:                            + " invalid");
1260:                }
1261:
1262:                switch (type) {
1263:                case SYBNVARCHAR:
1264:                case SYBNTEXT:
1265:                case XSYBNCHAR:
1266:                case XSYBNVARCHAR:
1267:                case XSYBCHAR: // Not always
1268:                case SYBVARIANT: // Not always
1269:                    return true;
1270:
1271:                default:
1272:                    return false;
1273:                }
1274:            }
1275:
1276:            /**
1277:             * Fill in the TDS native type code and all other fields for a
1278:             * <code>ColInfo</code> instance with the JDBC type set.
1279:             *
1280:             * @param ci the <code>ColInfo</code> instance
1281:             */
1282:            static void fillInType(ColInfo ci) throws SQLException {
1283:                switch (ci.jdbcType) {
1284:                case java.sql.Types.VARCHAR:
1285:                    ci.tdsType = SYBVARCHAR;
1286:                    ci.bufferSize = MS_LONGVAR_MAX;
1287:                    ci.displaySize = MS_LONGVAR_MAX;
1288:                    ci.precision = MS_LONGVAR_MAX;
1289:                    break;
1290:                case java.sql.Types.INTEGER:
1291:                    ci.tdsType = SYBINT4;
1292:                    ci.bufferSize = 4;
1293:                    ci.displaySize = 11;
1294:                    ci.precision = 10;
1295:                    break;
1296:                case java.sql.Types.SMALLINT:
1297:                    ci.tdsType = SYBINT2;
1298:                    ci.bufferSize = 2;
1299:                    ci.displaySize = 6;
1300:                    ci.precision = 5;
1301:                    break;
1302:                case java.sql.Types.BIT:
1303:                    ci.tdsType = SYBBIT;
1304:                    ci.bufferSize = 1;
1305:                    ci.displaySize = 1;
1306:                    ci.precision = 1;
1307:                    break;
1308:                default:
1309:                    throw new SQLException(Messages.get("error.baddatatype",
1310:                            Integer.toString(ci.jdbcType)), "HY000");
1311:                }
1312:                ci.sqlType = types[ci.tdsType].sqlType;
1313:                ci.scale = 0;
1314:            }
1315:
1316:            /**
1317:             * Retrieve the TDS native type code for the parameter.
1318:             *
1319:             * @param connection the connectionJDBC object
1320:             * @param pi         the parameter descriptor
1321:             */
1322:            static void getNativeType(ConnectionJDBC2 connection, ParamInfo pi)
1323:                    throws SQLException {
1324:                int len;
1325:                int jdbcType = pi.jdbcType;
1326:
1327:                if (jdbcType == java.sql.Types.OTHER) {
1328:                    jdbcType = Support.getJdbcType(pi.value);
1329:                }
1330:
1331:                switch (jdbcType) {
1332:                case java.sql.Types.CHAR:
1333:                case java.sql.Types.VARCHAR:
1334:                case java.sql.Types.LONGVARCHAR:
1335:                case java.sql.Types.CLOB:
1336:                    if (pi.value == null) {
1337:                        len = 0;
1338:                    } else {
1339:                        len = pi.length;
1340:                    }
1341:                    if (connection.getTdsVersion() < Driver.TDS70) {
1342:                        String charset = connection.getCharset();
1343:                        if (len > 0
1344:                                && (len <= SYB_LONGVAR_MAX / 2 || connection
1345:                                        .getSybaseInfo(TdsCore.SYB_UNITEXT))
1346:                                && connection
1347:                                        .getSybaseInfo(TdsCore.SYB_UNICODE)
1348:                                && connection.getUseUnicode()
1349:                                && !"UTF-8".equals(charset)) {
1350:                            // Sybase can send values as unicode if conversion to the
1351:                            // server charset fails.
1352:                            // One option to determine if conversion will fail is to use
1353:                            // the CharSetEncoder class but this is only available from
1354:                            // JDK 1.4.
1355:                            // For now we will call a local method to see if the string
1356:                            // should be sent as unicode.
1357:                            // This behaviour can be disabled by setting the connection
1358:                            // property sendParametersAsUnicode=false.
1359:                            // TODO: Find a better way of testing for convertable charset.
1360:                            // With ASE 15 this code will read a CLOB into memory just to
1361:                            // check for unicode characters. This is wasteful if no unicode
1362:                            // data is present and we are targetting a text column. The option
1363:                            // of always sending unicode does not work as the server will
1364:                            // complain about image to text conversions unless the target
1365:                            // column actually is unitext.
1366:                            try {
1367:                                String tmp = pi.getString(charset);
1368:                                if (!canEncode(tmp, charset)) {
1369:                                    // Conversion fails need to send as unicode.
1370:                                    pi.length = tmp.length();
1371:                                    if (pi.length > SYB_LONGVAR_MAX / 2) {
1372:                                        pi.sqlType = "unitext";
1373:                                        pi.tdsType = SYBLONGDATA;
1374:                                    } else {
1375:                                        pi.sqlType = "univarchar(" + pi.length
1376:                                                + ')';
1377:                                        pi.tdsType = SYBLONGBINARY;
1378:                                    }
1379:                                    break;
1380:                                }
1381:                            } catch (IOException e) {
1382:                                throw new SQLException(Messages
1383:                                        .get("error.generic.ioerror", e
1384:                                                .getMessage()), "HY000");
1385:                            }
1386:                        }
1387:                        //
1388:                        // If the client character set is wide then we need to ensure that the size
1389:                        // is within bounds even after conversion from Unicode
1390:                        //
1391:                        if (connection.isWideChar() && len <= SYB_LONGVAR_MAX) {
1392:                            try {
1393:                                byte tmp[] = pi.getBytes(charset);
1394:                                len = (tmp == null) ? 0 : tmp.length;
1395:                            } catch (IOException e) {
1396:                                throw new SQLException(Messages
1397:                                        .get("error.generic.ioerror", e
1398:                                                .getMessage()), "HY000");
1399:                            }
1400:                        }
1401:                        if (len <= VAR_MAX) {
1402:                            pi.tdsType = SYBVARCHAR;
1403:                            pi.sqlType = "varchar(255)";
1404:                        } else {
1405:                            if (connection.getSybaseInfo(TdsCore.SYB_LONGDATA)) {
1406:                                if (len > SYB_LONGVAR_MAX) {
1407:                                    // Use special Sybase long data type which
1408:                                    // allows text data to be sent as a statement parameter
1409:                                    // (although not as a SP parameter).
1410:                                    pi.tdsType = SYBLONGDATA;
1411:                                    pi.sqlType = "text";
1412:                                } else {
1413:                                    // Use Sybase 12.5+ long varchar type which
1414:                                    // is limited to 16384 bytes.
1415:                                    pi.tdsType = XSYBCHAR;
1416:                                    pi.sqlType = "varchar(" + len + ')';
1417:                                }
1418:                            } else {
1419:                                pi.tdsType = SYBTEXT;
1420:                                pi.sqlType = "text";
1421:                            }
1422:                        }
1423:                    } else {
1424:                        if (pi.isUnicode && len <= MS_LONGVAR_MAX / 2) {
1425:                            pi.tdsType = XSYBNVARCHAR;
1426:                            pi.sqlType = "nvarchar(4000)";
1427:                        } else if (!pi.isUnicode && len <= MS_LONGVAR_MAX) {
1428:                            pi.tdsType = XSYBVARCHAR;
1429:                            pi.sqlType = "varchar(8000)";
1430:                        } else {
1431:                            if (pi.isOutput) {
1432:                                throw new SQLException(Messages
1433:                                        .get("error.textoutparam"), "HY000");
1434:                            }
1435:
1436:                            if (pi.isUnicode) {
1437:                                pi.tdsType = SYBNTEXT;
1438:                                pi.sqlType = "ntext";
1439:                            } else {
1440:                                pi.tdsType = SYBTEXT;
1441:                                pi.sqlType = "text";
1442:                            }
1443:                        }
1444:                    }
1445:                    break;
1446:
1447:                case java.sql.Types.TINYINT:
1448:                case java.sql.Types.SMALLINT:
1449:                case java.sql.Types.INTEGER:
1450:                    pi.tdsType = SYBINTN;
1451:                    pi.sqlType = "int";
1452:                    break;
1453:
1454:                case JtdsStatement.BOOLEAN:
1455:                case java.sql.Types.BIT:
1456:                    if (connection.getTdsVersion() >= Driver.TDS70
1457:                            || connection.getSybaseInfo(TdsCore.SYB_BITNULL)) {
1458:                        pi.tdsType = SYBBITN;
1459:                    } else {
1460:                        pi.tdsType = SYBBIT;
1461:                    }
1462:
1463:                    pi.sqlType = "bit";
1464:                    break;
1465:
1466:                case java.sql.Types.REAL:
1467:                    pi.tdsType = SYBFLTN;
1468:                    pi.sqlType = "real";
1469:                    break;
1470:
1471:                case java.sql.Types.FLOAT:
1472:                case java.sql.Types.DOUBLE:
1473:                    pi.tdsType = SYBFLTN;
1474:                    pi.sqlType = "float";
1475:                    break;
1476:
1477:                case java.sql.Types.DATE:
1478:                    if (connection.getSybaseInfo(TdsCore.SYB_DATETIME)) {
1479:                        pi.tdsType = SYBDATEN;
1480:                        pi.sqlType = "date";
1481:                    } else {
1482:                        pi.tdsType = SYBDATETIMN;
1483:                        pi.sqlType = "datetime";
1484:                    }
1485:                    break;
1486:                case java.sql.Types.TIME:
1487:                    if (connection.getSybaseInfo(TdsCore.SYB_DATETIME)) {
1488:                        pi.tdsType = SYBTIMEN;
1489:                        pi.sqlType = "time";
1490:                    } else {
1491:                        pi.tdsType = SYBDATETIMN;
1492:                        pi.sqlType = "datetime";
1493:                    }
1494:                    break;
1495:                case java.sql.Types.TIMESTAMP:
1496:                    pi.tdsType = SYBDATETIMN;
1497:                    pi.sqlType = "datetime";
1498:                    break;
1499:
1500:                case java.sql.Types.BINARY:
1501:                case java.sql.Types.VARBINARY:
1502:                case java.sql.Types.BLOB:
1503:                case java.sql.Types.LONGVARBINARY:
1504:                    if (pi.value == null) {
1505:                        len = 0;
1506:                    } else {
1507:                        len = pi.length;
1508:                    }
1509:
1510:                    if (connection.getTdsVersion() < Driver.TDS70) {
1511:                        if (len <= VAR_MAX) {
1512:                            pi.tdsType = SYBVARBINARY;
1513:                            pi.sqlType = "varbinary(255)";
1514:                        } else {
1515:                            if (connection.getSybaseInfo(TdsCore.SYB_LONGDATA)) {
1516:                                if (len > SYB_LONGVAR_MAX) {
1517:                                    // Need to use special Sybase long binary type
1518:                                    pi.tdsType = SYBLONGDATA;
1519:                                    pi.sqlType = "image";
1520:                                } else {
1521:                                    // Sybase long binary that can be used as a SP parameter
1522:                                    pi.tdsType = SYBLONGBINARY;
1523:                                    pi.sqlType = "varbinary(" + len + ')';
1524:                                }
1525:                            } else {
1526:                                // Sybase < 12.5 or SQL Server 6.5
1527:                                pi.tdsType = SYBIMAGE;
1528:                                pi.sqlType = "image";
1529:                            }
1530:                        }
1531:                    } else {
1532:                        if (len <= MS_LONGVAR_MAX) {
1533:                            pi.tdsType = XSYBVARBINARY;
1534:                            pi.sqlType = "varbinary(8000)";
1535:                        } else {
1536:                            if (pi.isOutput) {
1537:                                throw new SQLException(Messages
1538:                                        .get("error.textoutparam"), "HY000");
1539:                            }
1540:
1541:                            pi.tdsType = SYBIMAGE;
1542:                            pi.sqlType = "image";
1543:                        }
1544:                    }
1545:
1546:                    break;
1547:
1548:                case java.sql.Types.BIGINT:
1549:                    if (connection.getTdsVersion() >= Driver.TDS80
1550:                            || connection.getSybaseInfo(TdsCore.SYB_BIGINT)) {
1551:                        pi.tdsType = SYBINTN;
1552:                        pi.sqlType = "bigint";
1553:                    } else {
1554:                        // int8 not supported send as a decimal field
1555:                        pi.tdsType = SYBDECIMAL;
1556:                        pi.sqlType = "decimal(" + connection.getMaxPrecision()
1557:                                + ')';
1558:                        pi.scale = 0;
1559:                    }
1560:
1561:                    break;
1562:
1563:                case java.sql.Types.DECIMAL:
1564:                case java.sql.Types.NUMERIC:
1565:                    pi.tdsType = SYBDECIMAL;
1566:                    int prec = connection.getMaxPrecision();
1567:                    int scale = DEFAULT_SCALE;
1568:                    if (pi.value instanceof  BigDecimal) {
1569:                        scale = ((BigDecimal) pi.value).scale();
1570:                    } else if (pi.scale >= 0 && pi.scale <= prec) {
1571:                        scale = pi.scale;
1572:                    }
1573:                    pi.sqlType = "decimal(" + prec + ',' + scale + ')';
1574:
1575:                    break;
1576:
1577:                case java.sql.Types.OTHER:
1578:                case java.sql.Types.NULL:
1579:                    // Send a null String in the absence of anything better
1580:                    pi.tdsType = SYBVARCHAR;
1581:                    pi.sqlType = "varchar(255)";
1582:                    break;
1583:
1584:                default:
1585:                    throw new SQLException(Messages.get("error.baddatatype",
1586:                            Integer.toString(pi.jdbcType)), "HY000");
1587:                }
1588:            }
1589:
1590:            /**
1591:             * Calculate the size of the parameter descriptor array for TDS 5 packets.
1592:             *
1593:             * @param charset The encoding character set.
1594:             * @param isWideChar True if multi byte encoding.
1595:             * @param pi The parameter to describe.
1596:             * @param useParamNames True if named parameters should be used.
1597:             * @return The size of the parameter descriptor as an <code>int</code>.
1598:             */
1599:            static int getTds5ParamSize(String charset, boolean isWideChar,
1600:                    ParamInfo pi, boolean useParamNames) {
1601:                int size = 8;
1602:                if (pi.name != null && useParamNames) {
1603:                    // Size of parameter name
1604:                    if (isWideChar) {
1605:                        byte[] buf = Support.encodeString(charset, pi.name);
1606:
1607:                        size += buf.length;
1608:                    } else {
1609:                        size += pi.name.length();
1610:                    }
1611:                }
1612:
1613:                switch (pi.tdsType) {
1614:                case SYBVARCHAR:
1615:                case SYBVARBINARY:
1616:                case SYBINTN:
1617:                case SYBFLTN:
1618:                case SYBDATETIMN:
1619:                case SYBDATEN:
1620:                case SYBTIMEN:
1621:                    size += 1;
1622:                    break;
1623:                case SYBDECIMAL:
1624:                case SYBLONGDATA:
1625:                    size += 3;
1626:                    break;
1627:                case XSYBCHAR:
1628:                case SYBLONGBINARY:
1629:                    size += 4;
1630:                    break;
1631:                case SYBBIT:
1632:                    break;
1633:                default:
1634:                    throw new IllegalStateException(
1635:                            "Unsupported output TDS type 0x"
1636:                                    + Integer.toHexString(pi.tdsType));
1637:                }
1638:
1639:                return size;
1640:            }
1641:
1642:            /**
1643:             * Write a TDS 5 parameter format descriptor.
1644:             *
1645:             * @param out The server RequestStream.
1646:             * @param charset The encoding character set.
1647:             * @param isWideChar True if multi byte encoding.
1648:             * @param pi The parameter to describe.
1649:             * @param useParamNames True if named parameters should be used.
1650:             * @throws IOException
1651:             */
1652:            static void writeTds5ParamFmt(RequestStream out, String charset,
1653:                    boolean isWideChar, ParamInfo pi, boolean useParamNames)
1654:                    throws IOException {
1655:                if (pi.name != null && useParamNames) {
1656:                    // Output parameter name.
1657:                    if (isWideChar) {
1658:                        byte[] buf = Support.encodeString(charset, pi.name);
1659:
1660:                        out.write((byte) buf.length);
1661:                        out.write(buf);
1662:                    } else {
1663:                        out.write((byte) pi.name.length());
1664:                        out.write(pi.name);
1665:                    }
1666:                } else {
1667:                    out.write((byte) 0);
1668:                }
1669:
1670:                out.write((byte) (pi.isOutput ? 1 : 0)); // Output param
1671:                if (pi.sqlType.startsWith("univarchar")) {
1672:                    out.write((int) UDT_UNIVARCHAR);
1673:                } else if ("unitext".equals(pi.sqlType)) {
1674:                    out.write((int) UDT_UNITEXT);
1675:                } else {
1676:                    out.write((int) 0); // user type
1677:                }
1678:                out.write((byte) pi.tdsType); // TDS data type token
1679:
1680:                // Output length fields
1681:                switch (pi.tdsType) {
1682:                case SYBVARCHAR:
1683:                case SYBVARBINARY:
1684:                    out.write((byte) VAR_MAX);
1685:                    break;
1686:                case XSYBCHAR:
1687:                    out.write((int) 0x7FFFFFFF);
1688:                    break;
1689:                case SYBLONGDATA:
1690:                    // It appears that type 3 = send text data
1691:                    // and type 4 = send image or unitext data
1692:                    // No idea if there is a type 1/2 or what they are.
1693:                    out.write("text".equals(pi.sqlType) ? (byte) 3 : (byte) 4);
1694:                    out.write((byte) 0);
1695:                    out.write((byte) 0);
1696:                    break;
1697:                case SYBLONGBINARY:
1698:                    out.write((int) 0x7FFFFFFF);
1699:                    break;
1700:                case SYBBIT:
1701:                    break;
1702:                case SYBINTN:
1703:                    out
1704:                            .write("bigint".equals(pi.sqlType) ? (byte) 8
1705:                                    : (byte) 4);
1706:                    break;
1707:                case SYBFLTN:
1708:                    if (pi.value instanceof  Float) {
1709:                        out.write((byte) 4);
1710:                    } else {
1711:                        out.write((byte) 8);
1712:                    }
1713:                    break;
1714:                case SYBDATETIMN:
1715:                    out.write((byte) 8);
1716:                    break;
1717:                case SYBDATEN:
1718:                case SYBTIMEN:
1719:                    out.write((byte) 4);
1720:                    break;
1721:                case SYBDECIMAL:
1722:                    out.write((byte) 17);
1723:                    out.write((byte) 38);
1724:
1725:                    if (pi.jdbcType == java.sql.Types.BIGINT) {
1726:                        out.write((byte) 0);
1727:                    } else {
1728:                        if (pi.value instanceof  BigDecimal) {
1729:                            out.write((byte) ((BigDecimal) pi.value).scale());
1730:                        } else {
1731:                            if (pi.scale >= 0
1732:                                    && pi.scale <= TdsData.DEFAULT_PRECISION_38) {
1733:                                out.write((byte) pi.scale);
1734:                            } else {
1735:                                out.write((byte) DEFAULT_SCALE);
1736:                            }
1737:                        }
1738:                    }
1739:
1740:                    break;
1741:                default:
1742:                    throw new IllegalStateException(
1743:                            "Unsupported output TDS type "
1744:                                    + Integer.toHexString(pi.tdsType));
1745:                }
1746:
1747:                out.write((byte) 0); // Locale information
1748:            }
1749:
1750:            /**
1751:             * Write the actual TDS 5 parameter data.
1752:             *
1753:             * @param out         the server RequestStream
1754:             * @param charsetInfo the encoding character set
1755:             * @param pi          the parameter to output
1756:             * @throws IOException
1757:             * @throws SQLException
1758:             */
1759:            static void writeTds5Param(RequestStream out,
1760:                    CharsetInfo charsetInfo, ParamInfo pi) throws IOException,
1761:                    SQLException {
1762:
1763:                if (pi.charsetInfo == null) {
1764:                    pi.charsetInfo = charsetInfo;
1765:                }
1766:                switch (pi.tdsType) {
1767:
1768:                case SYBVARCHAR:
1769:                    if (pi.value == null) {
1770:                        out.write((byte) 0);
1771:                    } else {
1772:                        byte buf[] = pi.getBytes(pi.charsetInfo.getCharset());
1773:
1774:                        if (buf.length == 0) {
1775:                            buf = new byte[1];
1776:                            buf[0] = ' ';
1777:                        }
1778:
1779:                        if (buf.length > VAR_MAX) {
1780:                            throw new SQLException(Messages
1781:                                    .get("error.generic.truncmbcs"), "HY000");
1782:                        }
1783:
1784:                        out.write((byte) buf.length);
1785:                        out.write(buf);
1786:                    }
1787:
1788:                    break;
1789:
1790:                case SYBVARBINARY:
1791:                    if (pi.value == null) {
1792:                        out.write((byte) 0);
1793:                    } else {
1794:                        byte buf[] = pi.getBytes(pi.charsetInfo.getCharset());
1795:                        if (out.getTdsVersion() < Driver.TDS70
1796:                                && buf.length == 0) {
1797:                            // Sybase and SQL 6.5 do not allow zero length binary
1798:                            out.write((byte) 1);
1799:                            out.write((byte) 0);
1800:                        } else {
1801:                            out.write((byte) buf.length);
1802:                            out.write(buf);
1803:                        }
1804:                    }
1805:
1806:                    break;
1807:
1808:                case XSYBCHAR:
1809:                    if (pi.value == null) {
1810:                        out.write((byte) 0);
1811:                    } else {
1812:                        byte buf[] = pi.getBytes(pi.charsetInfo.getCharset());
1813:
1814:                        if (buf.length == 0) {
1815:                            buf = new byte[1];
1816:                            buf[0] = ' ';
1817:                        }
1818:                        out.write((int) buf.length);
1819:                        out.write(buf);
1820:                    }
1821:                    break;
1822:
1823:                case SYBLONGDATA:
1824:                    //
1825:                    // Write a three byte prefix usage unknown
1826:                    //
1827:                    out.write((byte) 0);
1828:                    out.write((byte) 0);
1829:                    out.write((byte) 0);
1830:                    //
1831:                    // Write BLOB direct from input stream
1832:                    //
1833:                    if (pi.value instanceof  InputStream) {
1834:                        byte buffer[] = new byte[SYB_CHUNK_SIZE];
1835:                        int len = ((InputStream) pi.value).read(buffer);
1836:                        while (len > 0) {
1837:                            out.write((byte) len);
1838:                            out.write((byte) (len >> 8));
1839:                            out.write((byte) (len >> 16));
1840:                            out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come
1841:                            out.write(buffer, 0, len);
1842:                            len = ((InputStream) pi.value).read(buffer);
1843:                        }
1844:                    } else
1845:                    //
1846:                    // Write CLOB direct from input Reader
1847:                    //
1848:                    if (pi.value instanceof  Reader
1849:                            && !pi.charsetInfo.isWideChars()) {
1850:                        // For ASE 15+ the getNativeType() routine will already have
1851:                        // read the data from the reader so this code will not be
1852:                        // reached unless sendStringParametersAsUnicode=false.
1853:                        char buffer[] = new char[SYB_CHUNK_SIZE];
1854:                        int len = ((Reader) pi.value).read(buffer);
1855:                        while (len > 0) {
1856:                            out.write((byte) len);
1857:                            out.write((byte) (len >> 8));
1858:                            out.write((byte) (len >> 16));
1859:                            out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come
1860:                            out.write(Support.encodeString(pi.charsetInfo
1861:                                    .getCharset(), new String(buffer, 0, len)));
1862:                            len = ((Reader) pi.value).read(buffer);
1863:                        }
1864:                    } else
1865:                    //
1866:                    // Write data from memory buffer
1867:                    //
1868:                    if (pi.value != null) {
1869:                        //
1870:                        // Actual data needs to be written out in chunks of
1871:                        // 8192 bytes.
1872:                        //
1873:                        if ("unitext".equals(pi.sqlType)) {
1874:                            // Write out String as unicode bytes
1875:                            String buf = pi.getString(pi.charsetInfo
1876:                                    .getCharset());
1877:                            int pos = 0;
1878:                            while (pos < buf.length()) {
1879:                                int clen = (buf.length() - pos >= SYB_CHUNK_SIZE / 2) ? SYB_CHUNK_SIZE / 2
1880:                                        : buf.length() - pos;
1881:                                int len = clen * 2;
1882:                                out.write((byte) len);
1883:                                out.write((byte) (len >> 8));
1884:                                out.write((byte) (len >> 16));
1885:                                out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come
1886:                                // Write data
1887:                                out.write(buf.substring(pos, pos + clen)
1888:                                        .toCharArray(), 0, clen);
1889:                                pos += clen;
1890:                            }
1891:                        } else {
1892:                            // Write text as bytes
1893:                            byte buf[] = pi.getBytes(pi.charsetInfo
1894:                                    .getCharset());
1895:                            int pos = 0;
1896:                            while (pos < buf.length) {
1897:                                int len = (buf.length - pos >= SYB_CHUNK_SIZE) ? SYB_CHUNK_SIZE
1898:                                        : buf.length - pos;
1899:                                out.write((byte) len);
1900:                                out.write((byte) (len >> 8));
1901:                                out.write((byte) (len >> 16));
1902:                                out.write((byte) ((len >> 24) | 0x80)); // 0x80 means more to come
1903:                                // Write data
1904:                                for (int i = 0; i < len; i++) {
1905:                                    out.write(buf[pos++]);
1906:                                }
1907:                            }
1908:                        }
1909:                    }
1910:                    // Write terminator
1911:                    out.write((int) 0);
1912:                    break;
1913:
1914:                case SYBLONGBINARY:
1915:                    // Sybase data <= 16284 bytes long
1916:                    if (pi.value == null) {
1917:                        out.write((int) 0);
1918:                    } else {
1919:                        if (pi.sqlType.startsWith("univarchar")) {
1920:                            String tmp = pi.getString(pi.charsetInfo
1921:                                    .getCharset());
1922:                            if (tmp.length() == 0) {
1923:                                tmp = " ";
1924:                            }
1925:                            out.write((int) tmp.length() * 2);
1926:                            out.write(tmp.toCharArray(), 0, tmp.length());
1927:                        } else {
1928:                            byte buf[] = pi.getBytes(pi.charsetInfo
1929:                                    .getCharset());
1930:                            if (buf.length > 0) {
1931:                                out.write((int) buf.length);
1932:                                out.write(buf);
1933:                            } else {
1934:                                out.write((int) 1);
1935:                                out.write((byte) 0);
1936:                            }
1937:                        }
1938:                    }
1939:                    break;
1940:
1941:                case SYBINTN:
1942:                    if (pi.value == null) {
1943:                        out.write((byte) 0);
1944:                    } else {
1945:                        if ("bigint".equals(pi.sqlType)) {
1946:                            out.write((byte) 8);
1947:                            out.write((long) ((Number) pi.value).longValue());
1948:                        } else {
1949:                            out.write((byte) 4);
1950:                            out.write((int) ((Number) pi.value).intValue());
1951:                        }
1952:                    }
1953:
1954:                    break;
1955:
1956:                case SYBFLTN:
1957:                    if (pi.value == null) {
1958:                        out.write((byte) 0);
1959:                    } else {
1960:                        if (pi.value instanceof  Float) {
1961:                            out.write((byte) 4);
1962:                            out.write(((Number) pi.value).floatValue());
1963:                        } else {
1964:                            out.write((byte) 8);
1965:                            out.write(((Number) pi.value).doubleValue());
1966:                        }
1967:                    }
1968:
1969:                    break;
1970:
1971:                case SYBDATETIMN:
1972:                    putDateTimeValue(out, (DateTime) pi.value);
1973:                    break;
1974:
1975:                case SYBDATEN:
1976:                    if (pi.value == null) {
1977:                        out.write((byte) 0);
1978:                    } else {
1979:                        out.write((byte) 4);
1980:                        out.write((int) ((DateTime) pi.value).getDate());
1981:                    }
1982:                    break;
1983:
1984:                case SYBTIMEN:
1985:                    if (pi.value == null) {
1986:                        out.write((byte) 0);
1987:                    } else {
1988:                        out.write((byte) 4);
1989:                        out.write((int) ((DateTime) pi.value).getTime());
1990:                    }
1991:                    break;
1992:
1993:                case SYBBIT:
1994:                    if (pi.value == null) {
1995:                        out.write((byte) 0);
1996:                    } else {
1997:                        out
1998:                                .write((byte) (((Boolean) pi.value)
1999:                                        .booleanValue() ? 1 : 0));
2000:                    }
2001:
2002:                    break;
2003:
2004:                case SYBNUMERIC:
2005:                case SYBDECIMAL:
2006:                    BigDecimal value = null;
2007:
2008:                    if (pi.value != null) {
2009:                        if (pi.value instanceof  Long) {
2010:                            // Long to BigDecimal conversion is buggy. It's actually
2011:                            // long to double to BigDecimal.
2012:                            value = new BigDecimal(pi.value.toString());
2013:                        } else {
2014:                            value = (BigDecimal) pi.value;
2015:                        }
2016:                    }
2017:
2018:                    out.write(value);
2019:                    break;
2020:
2021:                default:
2022:                    throw new IllegalStateException(
2023:                            "Unsupported output TDS type "
2024:                                    + Integer.toHexString(pi.tdsType));
2025:                }
2026:            }
2027:
2028:            /**
2029:             * TDS 8 requires collation information for char data descriptors.
2030:             *
2031:             * @param out The Server request stream.
2032:             * @param pi The parameter descriptor.
2033:             * @throws IOException
2034:             */
2035:            static void putCollation(RequestStream out, ParamInfo pi)
2036:                    throws IOException {
2037:                //
2038:                // For TDS 8 write a collation string
2039:                // I am assuming this can be all zero for now if none is known
2040:                //
2041:                if (types[pi.tdsType].isCollation) {
2042:                    if (pi.collation != null) {
2043:                        out.write(pi.collation);
2044:                    } else {
2045:                        byte collation[] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
2046:
2047:                        out.write(collation);
2048:                    }
2049:                }
2050:            }
2051:
2052:            /**
2053:             * Write a parameter to the server request stream.
2054:             *
2055:             * @param out         the server request stream
2056:             * @param charsetInfo the default character set
2057:             * @param collation   the default SQL Server 2000 collation
2058:             * @param pi          the parameter descriptor
2059:             */
2060:            static void writeParam(RequestStream out, CharsetInfo charsetInfo,
2061:                    byte[] collation, ParamInfo pi) throws IOException {
2062:                int len;
2063:                String tmp;
2064:                byte[] buf;
2065:                boolean isTds8 = out.getTdsVersion() >= Driver.TDS80;
2066:
2067:                if (isTds8) {
2068:                    if (pi.collation == null) {
2069:                        pi.collation = collation;
2070:                    }
2071:                }
2072:                if (pi.charsetInfo == null) {
2073:                    pi.charsetInfo = charsetInfo;
2074:                }
2075:
2076:                switch (pi.tdsType) {
2077:
2078:                case XSYBVARCHAR:
2079:                    if (pi.value == null) {
2080:                        out.write((byte) pi.tdsType);
2081:                        out.write((short) MS_LONGVAR_MAX);
2082:
2083:                        if (isTds8) {
2084:                            putCollation(out, pi);
2085:                        }
2086:
2087:                        out.write((short) 0xFFFF);
2088:                    } else {
2089:                        buf = pi.getBytes(pi.charsetInfo.getCharset());
2090:
2091:                        if (buf.length > MS_LONGVAR_MAX) {
2092:                            out.write((byte) SYBTEXT);
2093:                            out.write((int) buf.length);
2094:
2095:                            if (isTds8) {
2096:                                putCollation(out, pi);
2097:                            }
2098:
2099:                            out.write((int) buf.length);
2100:                            out.write(buf);
2101:                        } else {
2102:                            out.write((byte) pi.tdsType);
2103:                            out.write((short) MS_LONGVAR_MAX);
2104:
2105:                            if (isTds8) {
2106:                                putCollation(out, pi);
2107:                            }
2108:
2109:                            out.write((short) buf.length);
2110:                            out.write(buf);
2111:                        }
2112:                    }
2113:
2114:                    break;
2115:
2116:                case SYBVARCHAR:
2117:                    if (pi.value == null) {
2118:                        out.write((byte) pi.tdsType);
2119:                        out.write((byte) VAR_MAX);
2120:                        out.write((byte) 0);
2121:                    } else {
2122:                        buf = pi.getBytes(pi.charsetInfo.getCharset());
2123:
2124:                        if (buf.length > VAR_MAX) {
2125:                            if (buf.length <= MS_LONGVAR_MAX
2126:                                    && out.getTdsVersion() >= Driver.TDS70) {
2127:                                out.write((byte) XSYBVARCHAR);
2128:                                out.write((short) MS_LONGVAR_MAX);
2129:
2130:                                if (isTds8) {
2131:                                    putCollation(out, pi);
2132:                                }
2133:
2134:                                out.write((short) buf.length);
2135:                                out.write(buf);
2136:                            } else {
2137:                                out.write((byte) SYBTEXT);
2138:                                out.write((int) buf.length);
2139:
2140:                                if (isTds8) {
2141:                                    putCollation(out, pi);
2142:                                }
2143:
2144:                                out.write((int) buf.length);
2145:                                out.write(buf);
2146:                            }
2147:                        } else {
2148:                            if (buf.length == 0) {
2149:                                buf = new byte[1];
2150:                                buf[0] = ' ';
2151:                            }
2152:
2153:                            out.write((byte) pi.tdsType);
2154:                            out.write((byte) VAR_MAX);
2155:                            out.write((byte) buf.length);
2156:                            out.write(buf);
2157:                        }
2158:                    }
2159:
2160:                    break;
2161:
2162:                case XSYBNVARCHAR:
2163:                    out.write((byte) pi.tdsType);
2164:                    out.write((short) MS_LONGVAR_MAX);
2165:
2166:                    if (isTds8) {
2167:                        putCollation(out, pi);
2168:                    }
2169:
2170:                    if (pi.value == null) {
2171:                        out.write((short) 0xFFFF);
2172:                    } else {
2173:                        tmp = pi.getString(pi.charsetInfo.getCharset());
2174:                        out.write((short) (tmp.length() * 2));
2175:                        out.write(tmp);
2176:                    }
2177:
2178:                    break;
2179:
2180:                case SYBTEXT:
2181:                    if (pi.value == null) {
2182:                        len = 0;
2183:                    } else {
2184:                        len = pi.length;
2185:
2186:                        if (len == 0 && out.getTdsVersion() < Driver.TDS70) {
2187:                            pi.value = " ";
2188:                            len = 1;
2189:                        }
2190:                    }
2191:
2192:                    out.write((byte) pi.tdsType);
2193:
2194:                    if (len > 0) {
2195:                        if (pi.value instanceof  InputStream) {
2196:                            // Write output directly from stream
2197:                            out.write((int) len);
2198:
2199:                            if (isTds8) {
2200:                                putCollation(out, pi);
2201:                            }
2202:
2203:                            out.write((int) len);
2204:                            out.writeStreamBytes((InputStream) pi.value, len);
2205:                        } else if (pi.value instanceof  Reader
2206:                                && !pi.charsetInfo.isWideChars()) {
2207:                            // Write output directly from stream with character translation
2208:                            out.write((int) len);
2209:
2210:                            if (isTds8) {
2211:                                putCollation(out, pi);
2212:                            }
2213:
2214:                            out.write((int) len);
2215:                            out.writeReaderBytes((Reader) pi.value, len);
2216:                        } else {
2217:                            buf = pi.getBytes(pi.charsetInfo.getCharset());
2218:                            out.write((int) buf.length);
2219:
2220:                            if (isTds8) {
2221:                                putCollation(out, pi);
2222:                            }
2223:
2224:                            out.write((int) buf.length);
2225:                            out.write(buf);
2226:                        }
2227:                    } else {
2228:                        out.write((int) len); // Zero length
2229:
2230:                        if (isTds8) {
2231:                            putCollation(out, pi);
2232:                        }
2233:
2234:                        out.write((int) len);
2235:                    }
2236:
2237:                    break;
2238:
2239:                case SYBNTEXT:
2240:                    if (pi.value == null) {
2241:                        len = 0;
2242:                    } else {
2243:                        len = pi.length;
2244:                    }
2245:
2246:                    out.write((byte) pi.tdsType);
2247:
2248:                    if (len > 0) {
2249:                        if (pi.value instanceof  Reader) {
2250:                            out.write((int) len);
2251:
2252:                            if (isTds8) {
2253:                                putCollation(out, pi);
2254:                            }
2255:
2256:                            out.write((int) len * 2);
2257:                            out.writeReaderChars((Reader) pi.value, len);
2258:                        } else if (pi.value instanceof  InputStream
2259:                                && !pi.charsetInfo.isWideChars()) {
2260:                            out.write((int) len);
2261:
2262:                            if (isTds8) {
2263:                                putCollation(out, pi);
2264:                            }
2265:
2266:                            out.write((int) len * 2);
2267:                            out.writeReaderChars(new InputStreamReader(
2268:                                    (InputStream) pi.value, pi.charsetInfo
2269:                                            .getCharset()), len);
2270:                        } else {
2271:                            tmp = pi.getString(pi.charsetInfo.getCharset());
2272:                            len = tmp.length();
2273:                            out.write((int) len);
2274:
2275:                            if (isTds8) {
2276:                                putCollation(out, pi);
2277:                            }
2278:
2279:                            out.write((int) len * 2);
2280:                            out.write(tmp);
2281:                        }
2282:                    } else {
2283:                        out.write((int) len);
2284:
2285:                        if (isTds8) {
2286:                            putCollation(out, pi);
2287:                        }
2288:
2289:                        out.write((int) len);
2290:                    }
2291:
2292:                    break;
2293:
2294:                case XSYBVARBINARY:
2295:                    out.write((byte) pi.tdsType);
2296:                    out.write((short) MS_LONGVAR_MAX);
2297:
2298:                    if (pi.value == null) {
2299:                        out.write((short) 0xFFFF);
2300:                    } else {
2301:                        buf = pi.getBytes(pi.charsetInfo.getCharset());
2302:                        out.write((short) buf.length);
2303:                        out.write(buf);
2304:                    }
2305:
2306:                    break;
2307:
2308:                case SYBVARBINARY:
2309:                    out.write((byte) pi.tdsType);
2310:                    out.write((byte) VAR_MAX);
2311:
2312:                    if (pi.value == null) {
2313:                        out.write((byte) 0);
2314:                    } else {
2315:                        buf = pi.getBytes(pi.charsetInfo.getCharset());
2316:                        if (out.getTdsVersion() < Driver.TDS70
2317:                                && buf.length == 0) {
2318:                            // Sybase and SQL 6.5 do not allow zero length binary
2319:                            out.write((byte) 1);
2320:                            out.write((byte) 0);
2321:                        } else {
2322:                            out.write((byte) buf.length);
2323:                            out.write(buf);
2324:                        }
2325:                    }
2326:
2327:                    break;
2328:
2329:                case SYBIMAGE:
2330:                    if (pi.value == null) {
2331:                        len = 0;
2332:                    } else {
2333:                        len = pi.length;
2334:                    }
2335:
2336:                    out.write((byte) pi.tdsType);
2337:
2338:                    if (len > 0) {
2339:                        if (pi.value instanceof  InputStream) {
2340:                            out.write((int) len);
2341:                            out.write((int) len);
2342:                            out.writeStreamBytes((InputStream) pi.value, len);
2343:                        } else {
2344:                            buf = pi.getBytes(pi.charsetInfo.getCharset());
2345:                            out.write((int) buf.length);
2346:                            out.write((int) buf.length);
2347:                            out.write(buf);
2348:                        }
2349:                    } else {
2350:                        if (out.getTdsVersion() < Driver.TDS70) {
2351:                            // Sybase and SQL 6.5 do not allow zero length binary
2352:                            out.write((int) 1);
2353:                            out.write((int) 1);
2354:                            out.write((byte) 0);
2355:                        } else {
2356:                            out.write((int) len);
2357:                            out.write((int) len);
2358:                        }
2359:                    }
2360:
2361:                    break;
2362:
2363:                case SYBINTN:
2364:                    out.write((byte) pi.tdsType);
2365:
2366:                    if (pi.value == null) {
2367:                        out.write(("bigint".equals(pi.sqlType)) ? (byte) 8
2368:                                : (byte) 4);
2369:                        out.write((byte) 0);
2370:                    } else {
2371:                        if ("bigint".equals(pi.sqlType)) {
2372:                            out.write((byte) 8);
2373:                            out.write((byte) 8);
2374:                            out.write((long) ((Number) pi.value).longValue());
2375:                        } else {
2376:                            out.write((byte) 4);
2377:                            out.write((byte) 4);
2378:                            out.write((int) ((Number) pi.value).intValue());
2379:                        }
2380:                    }
2381:
2382:                    break;
2383:
2384:                case SYBFLTN:
2385:                    out.write((byte) pi.tdsType);
2386:                    if (pi.value instanceof  Float) {
2387:                        out.write((byte) 4);
2388:                        out.write((byte) 4);
2389:                        out.write(((Number) pi.value).floatValue());
2390:                    } else {
2391:                        out.write((byte) 8);
2392:                        if (pi.value == null) {
2393:                            out.write((byte) 0);
2394:                        } else {
2395:                            out.write((byte) 8);
2396:                            out.write(((Number) pi.value).doubleValue());
2397:                        }
2398:                    }
2399:
2400:                    break;
2401:
2402:                case SYBDATETIMN:
2403:                    out.write((byte) SYBDATETIMN);
2404:                    out.write((byte) 8);
2405:                    putDateTimeValue(out, (DateTime) pi.value);
2406:                    break;
2407:
2408:                case SYBBIT:
2409:                    out.write((byte) pi.tdsType);
2410:
2411:                    if (pi.value == null) {
2412:                        out.write((byte) 0);
2413:                    } else {
2414:                        out
2415:                                .write((byte) (((Boolean) pi.value)
2416:                                        .booleanValue() ? 1 : 0));
2417:                    }
2418:
2419:                    break;
2420:
2421:                case SYBBITN:
2422:                    out.write((byte) SYBBITN);
2423:                    out.write((byte) 1);
2424:
2425:                    if (pi.value == null) {
2426:                        out.write((byte) 0);
2427:                    } else {
2428:                        out.write((byte) 1);
2429:                        out
2430:                                .write((byte) (((Boolean) pi.value)
2431:                                        .booleanValue() ? 1 : 0));
2432:                    }
2433:
2434:                    break;
2435:
2436:                case SYBNUMERIC:
2437:                case SYBDECIMAL:
2438:                    out.write((byte) pi.tdsType);
2439:                    BigDecimal value = null;
2440:                    int prec = out.getMaxPrecision();
2441:                    int scale;
2442:
2443:                    if (pi.value == null) {
2444:                        if (pi.jdbcType == java.sql.Types.BIGINT) {
2445:                            scale = 0;
2446:                        } else {
2447:                            if (pi.scale >= 0 && pi.scale <= prec) {
2448:                                scale = pi.scale;
2449:                            } else {
2450:                                scale = DEFAULT_SCALE;
2451:                            }
2452:                        }
2453:                    } else {
2454:                        if (pi.value instanceof  Long) {
2455:                            value = new BigDecimal(((Long) pi.value).toString());
2456:                            scale = 0;
2457:                        } else {
2458:                            value = (BigDecimal) pi.value;
2459:                            scale = value.scale();
2460:                        }
2461:                    }
2462:
2463:                    out.write((byte) out.getMaxDecimalBytes());
2464:                    out.write((byte) prec);
2465:                    out.write((byte) scale);
2466:                    out.write(value);
2467:                    break;
2468:
2469:                default:
2470:                    throw new IllegalStateException(
2471:                            "Unsupported output TDS type "
2472:                                    + Integer.toHexString(pi.tdsType));
2473:                }
2474:            }
2475:
2476:            //
2477:            // ---------------------- Private methods from here -----------------------
2478:            //
2479:
2480:            /**
2481:             * Private constructor to prevent users creating an
2482:             * actual instance of this class.
2483:             */
2484:            private TdsData() {
2485:            }
2486:
2487:            /**
2488:             * Get a DATETIME value from the server response stream.
2489:             *
2490:             * @param in The server response stream.
2491:             * @param type The TDS data type.
2492:             * @return The java.sql.Timestamp value or null.
2493:             * @throws java.io.IOException
2494:             */
2495:            private static Object getDatetimeValue(ResponseStream in,
2496:                    final int type) throws IOException, ProtocolException {
2497:                int len;
2498:                int daysSince1900;
2499:                int time;
2500:                int minutes;
2501:
2502:                if (type == SYBDATETIMN) {
2503:                    len = in.read(); // No need to & with 0xff
2504:                } else if (type == SYBDATETIME4) {
2505:                    len = 4;
2506:                } else {
2507:                    len = 8;
2508:                }
2509:
2510:                switch (len) {
2511:                case 0:
2512:                    return null;
2513:
2514:                case 8:
2515:                    // A datetime is made of of two 32 bit integers
2516:                    // The first one is the number of days since 1900
2517:                    // The second integer is the number of seconds*300
2518:                    // Negative days indicate dates earlier than 1900.
2519:                    // The full range is 1753-01-01 to 9999-12-31.
2520:                    daysSince1900 = in.readInt();
2521:                    time = in.readInt();
2522:                    return new DateTime(daysSince1900, time);
2523:                case 4:
2524:                    // A smalldatetime is two 16 bit integers.
2525:                    // The first is the number of days past January 1, 1900,
2526:                    // the second smallint is the number of minutes past
2527:                    // midnight.
2528:                    // The full range is 1900-01-01 to 2079-06-06.
2529:                    daysSince1900 = ((int) in.readShort()) & 0xFFFF;
2530:                    minutes = in.readShort();
2531:                    return new DateTime((short) daysSince1900, (short) minutes);
2532:                default:
2533:                    throw new ProtocolException(
2534:                            "Invalid DATETIME value with size of " + len
2535:                                    + " bytes.");
2536:                }
2537:            }
2538:
2539:            /**
2540:             * Output a java.sql.Date/Time/Timestamp value to the server
2541:             * as a Sybase datetime value.
2542:             *
2543:             * @param out   the server request stream
2544:             * @param value the date value to write
2545:             */
2546:            private static void putDateTimeValue(RequestStream out,
2547:                    DateTime value) throws IOException {
2548:                if (value == null) {
2549:                    out.write((byte) 0);
2550:                    return;
2551:                }
2552:                out.write((byte) 8);
2553:                out.write((int) value.getDate());
2554:                out.write((int) value.getTime());
2555:            }
2556:
2557:            /**
2558:             * Read a MONEY value from the server response stream.
2559:             *
2560:             * @param in The server response stream.
2561:             * @param type The TDS data type.
2562:             * @return The java.math.BigDecimal value or null.
2563:             * @throws IOException
2564:             * @throws ProtocolException
2565:             */
2566:            private static Object getMoneyValue(ResponseStream in,
2567:                    final int type) throws IOException, ProtocolException {
2568:                final int len;
2569:
2570:                if (type == SYBMONEY) {
2571:                    len = 8;
2572:                } else if (type == SYBMONEYN) {
2573:                    len = in.read();
2574:                } else {
2575:                    len = 4;
2576:                }
2577:
2578:                BigInteger x = null;
2579:
2580:                if (len == 4) {
2581:                    x = BigInteger.valueOf(in.readInt());
2582:                } else if (len == 8) {
2583:                    final byte b4 = (byte) in.read();
2584:                    final byte b5 = (byte) in.read();
2585:                    final byte b6 = (byte) in.read();
2586:                    final byte b7 = (byte) in.read();
2587:                    final byte b0 = (byte) in.read();
2588:                    final byte b1 = (byte) in.read();
2589:                    final byte b2 = (byte) in.read();
2590:                    final byte b3 = (byte) in.read();
2591:                    final long l = (long) (b0 & 0xff)
2592:                            + ((long) (b1 & 0xff) << 8)
2593:                            + ((long) (b2 & 0xff) << 16)
2594:                            + ((long) (b3 & 0xff) << 24)
2595:                            + ((long) (b4 & 0xff) << 32)
2596:                            + ((long) (b5 & 0xff) << 40)
2597:                            + ((long) (b6 & 0xff) << 48)
2598:                            + ((long) (b7 & 0xff) << 56);
2599:
2600:                    x = BigInteger.valueOf(l);
2601:                } else if (len != 0) {
2602:                    throw new ProtocolException("Invalid money value.");
2603:                }
2604:
2605:                return (x == null) ? null : new BigDecimal(x, 4);
2606:            }
2607:
2608:            /**
2609:             * Read a MSQL 2000 sql_variant data value from the input stream.
2610:             * <p>SQL_VARIANT has the following structure:
2611:             * <ol>
2612:             * <li>INT4 total size of data
2613:             * <li>INT1 TDS data type (text/image/ntext/sql_variant not allowed)
2614:             * <li>INT1 Length of extra type descriptor information
2615:             * <li>Optional additional type info required by some types
2616:             * <li>byte[0...n] the actual data
2617:             * </ol>
2618:             *
2619:             * @param connection used to obtain collation/charset information
2620:             * @param in         the server response stream
2621:             * @return the SQL_VARIANT data
2622:             */
2623:            private static Object getVariant(ConnectionJDBC2 connection,
2624:                    ResponseStream in) throws IOException, ProtocolException {
2625:                byte[] bytes;
2626:                int len = in.readInt();
2627:
2628:                if (len == 0) {
2629:                    // Length of zero means item is null
2630:                    return null;
2631:                }
2632:
2633:                ColInfo ci = new ColInfo();
2634:                len -= 2;
2635:                ci.tdsType = in.read(); // TDS Type
2636:                len -= in.read(); // Size of descriptor
2637:
2638:                switch (ci.tdsType) {
2639:                case SYBINT1:
2640:                    return new Integer(in.read() & 0xFF);
2641:
2642:                case SYBINT2:
2643:                    return new Integer(in.readShort());
2644:
2645:                case SYBINT4:
2646:                    return new Integer(in.readInt());
2647:
2648:                case SYBINT8:
2649:                    return new Long(in.readLong());
2650:
2651:                case XSYBCHAR:
2652:                case XSYBVARCHAR:
2653:                    // FIXME Use collation for reading
2654:                    getCollation(in, ci);
2655:                    try {
2656:                        setColumnCharset(ci, connection);
2657:                    } catch (SQLException ex) {
2658:                        // Skip the buffer size and value
2659:                        in.skip(2 + len);
2660:                        throw new ProtocolException(ex.toString()
2661:                                + " [SQLState: " + ex.getSQLState() + ']');
2662:                    }
2663:
2664:                    in.skip(2); // Skip buffer size
2665:                    return in.readNonUnicodeString(len);
2666:
2667:                case XSYBNCHAR:
2668:                case XSYBNVARCHAR:
2669:                    // XXX Why do we need collation for Unicode strings?
2670:                    in.skip(7); // Skip collation and buffer size
2671:
2672:                    return in.readUnicodeString(len / 2);
2673:
2674:                case XSYBVARBINARY:
2675:                case XSYBBINARY:
2676:                    in.skip(2); // Skip buffer size
2677:                    bytes = new byte[len];
2678:                    in.read(bytes);
2679:
2680:                    return bytes;
2681:
2682:                case SYBMONEY4:
2683:                case SYBMONEY:
2684:                    return getMoneyValue(in, ci.tdsType);
2685:
2686:                case SYBDATETIME4:
2687:                case SYBDATETIME:
2688:                    return getDatetimeValue(in, ci.tdsType);
2689:
2690:                case SYBBIT:
2691:                    return (in.read() != 0) ? Boolean.TRUE : Boolean.FALSE;
2692:
2693:                case SYBREAL:
2694:                    return new Float(Float.intBitsToFloat(in.readInt()));
2695:
2696:                case SYBFLT8:
2697:                    return new Double(Double.longBitsToDouble(in.readLong()));
2698:
2699:                case SYBUNIQUE:
2700:                    bytes = new byte[len];
2701:                    in.read(bytes);
2702:
2703:                    return new UniqueIdentifier(bytes);
2704:
2705:                case SYBNUMERIC:
2706:                case SYBDECIMAL:
2707:                    ci.precision = in.read();
2708:                    ci.scale = in.read();
2709:                    int sign = in.read();
2710:                    len--;
2711:                    bytes = new byte[len];
2712:                    BigInteger bi;
2713:
2714:                    while (len-- > 0) {
2715:                        bytes[len] = (byte) in.read();
2716:                    }
2717:
2718:                    bi = new BigInteger((sign == 0) ? -1 : 1, bytes);
2719:
2720:                    return new BigDecimal(bi, ci.scale);
2721:
2722:                default:
2723:                    throw new ProtocolException("Unsupported TDS data type 0x"
2724:                            + Integer.toHexString(ci.tdsType)
2725:                            + " in sql_variant");
2726:                }
2727:                //
2728:                // For compatibility with the MS driver convert to String.
2729:                // Change the data type for sql_variant from OTHER to VARCHAR
2730:                // Without this code the actual Object type can be retrieved
2731:                // by using getObject(n).
2732:                //
2733:                //        try {
2734:                //            value = Support.convert(value, java.sql.Types.VARCHAR, in.getCharset());
2735:                //        } catch (SQLException e) {
2736:                //            // Conversion failed just try toString();
2737:                //            value = value.toString();
2738:                //        }
2739:            }
2740:
2741:            /**
2742:             * For SQL 2005 This routine will modify the meta data to allow the
2743:             * caller to distinguish between varchar(max) and text or varbinary(max)
2744:             * and image or nvarchar(max) and ntext.
2745:             *
2746:             * @param typeName the SQL type returned by sp_columns
2747:             * @param tdsType the TDS type returned by sp_columns
2748:             * @return the (possibly) modified SQL type name as a <code>String</code>
2749:             */
2750:            public static String getMSTypeName(String typeName, int tdsType) {
2751:                if (typeName.equalsIgnoreCase("text") && tdsType != SYBTEXT) {
2752:                    return "varchar";
2753:                } else if (typeName.equalsIgnoreCase("ntext")
2754:                        && tdsType != SYBTEXT) {
2755:                    return "nvarchar";
2756:                } else if (typeName.equalsIgnoreCase("image")
2757:                        && tdsType != SYBIMAGE) {
2758:                    return "varbinary";
2759:                } else {
2760:                    return typeName;
2761:                }
2762:            }
2763:
2764:            /**
2765:             * Extract the TDS protocol version from the value returned by the server in the LOGINACK
2766:             * packet.
2767:             *
2768:             * @param rawTdsVersion the TDS protocol version as returned by the server
2769:             * @return the jTDS internal value for the protocol version (i.e one of the
2770:             *         <code>Driver.TDS<i>XX</i></code> values)
2771:             */
2772:            public static int getTdsVersion(int rawTdsVersion) {
2773:                if (rawTdsVersion >= 0x71000001) {
2774:                    return Driver.TDS81;
2775:                } else if (rawTdsVersion >= 0x07010000) {
2776:                    return Driver.TDS80;
2777:                } else if (rawTdsVersion >= 0x07000000) {
2778:                    return Driver.TDS70;
2779:                } else if (rawTdsVersion >= 0x05000000) {
2780:                    return Driver.TDS50;
2781:                } else {
2782:                    return Driver.TDS42;
2783:                }
2784:            }
2785:
2786:            /**
2787:             * Establish if a String can be converted to a byte based character set.
2788:             *
2789:             * @param value The String to test.
2790:             * @param charset The server character set in force.
2791:             * @return <code>boolean</code> true if string can be converted.
2792:             */
2793:            private static boolean canEncode(String value, String charset) {
2794:                if (value == null) {
2795:                    return true;
2796:                }
2797:                if ("UTF-8".equals(charset)) {
2798:                    // Should be no problem with UTF-8
2799:                    return true;
2800:                }
2801:                if ("ISO-8859-1".equals(charset)) {
2802:                    // ISO_1 = lower byte of unicode
2803:                    for (int i = value.length() - 1; i >= 0; i--) {
2804:                        if (value.charAt(i) > 255) {
2805:                            return false; // Outside range
2806:                        }
2807:                    }
2808:                    return true;
2809:                }
2810:                if ("ISO-8859-15".equals(charset) || "Cp1252".equals(charset)) {
2811:                    // These will accept euro symbol
2812:                    for (int i = value.length() - 1; i >= 0; i--) {
2813:                        // FIXME This is not correct! Cp1252 also contains other characters.
2814:                        // No: I think it is OK the point is to ensure that all characters are either
2815:                        // < 256 in which case the sets are the same or the euro which is convertable.
2816:                        // Any other combination will cause the string to be sent as unicode.
2817:                        char c = value.charAt(i);
2818:                        if (c > 255 && c != 0x20AC) {
2819:                            return false; // Outside range
2820:                        }
2821:                    }
2822:                    return true;
2823:                }
2824:                if ("US-ASCII".equals(charset)) {
2825:                    for (int i = value.length() - 1; i >= 0; i--) {
2826:                        if (value.charAt(i) > 127) {
2827:                            return false; // Outside range
2828:                        }
2829:                    }
2830:                    return true;
2831:                }
2832:                // OK need to do an expensive check
2833:                try {
2834:                    return new String(value.getBytes(charset), charset)
2835:                            .equals(value);
2836:                } catch (UnsupportedEncodingException e) {
2837:                    return false;
2838:                }
2839:            }
2840:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.