Source Code Cross Referenced for Tds.java in  » Database-JDBC-Connection-Pool » octopus » com » internetcds » jdbc » tds » 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 » octopus » com.internetcds.jdbc.tds 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        //
0002:        // Copyright 1998, 1999 CDS Networks, Inc., Medford Oregon
0003:        //
0004:        // All rights reserved.
0005:        //
0006:        // Redistribution and use in source and binary forms, with or without
0007:        // modification, are permitted provided that the following conditions are met:
0008:        // 1. Redistributions of source code must retain the above copyright
0009:        //    notice, this list of conditions and the following disclaimer.
0010:        // 2. Redistributions in binary form must reproduce the above copyright
0011:        //    notice, this list of conditions and the following disclaimer in the
0012:        //    documentation and/or other materials provided with the distribution.
0013:        // 3. All advertising materials mentioning features or use of this software
0014:        //    must display the following acknowledgement:
0015:        //      This product includes software developed by CDS Networks, Inc.
0016:        // 4. The name of CDS Networks, Inc.  may not be used to endorse or promote
0017:        //    products derived from this software without specific prior
0018:        //    written permission.
0019:        //
0020:        // THIS SOFTWARE IS PROVIDED BY CDS NETWORKS, INC. ``AS IS'' AND
0021:        // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0022:        // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0023:        // ARE DISCLAIMED.  IN NO EVENT SHALL CDS NETWORKS, INC. BE LIABLE
0024:        // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0025:        // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0026:        // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0027:        // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0028:        // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0029:        // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0030:        // SUCH DAMAGE.
0031:        //
0032:
0033:        package com.internetcds.jdbc.tds;
0034:
0035:        import java.net.Socket;
0036:        import java.util.Vector;
0037:        import java.lang.Thread;
0038:        import java.util.StringTokenizer;
0039:        import java.sql.*;
0040:        import com.internetcds.jdbc.tds.TdsComm;
0041:        import com.internetcds.util.Logger;
0042:        import java.math.BigInteger;
0043:        import java.math.BigDecimal;
0044:        import java.util.Calendar;
0045:        import java.util.Properties;
0046:        import java.util.TimeZone;
0047:        import java.util.Locale;
0048:
0049:        /**
0050:         * Cancel the current SQL if the timeout expires.
0051:         *
0052:         * @version  $Id: Tds.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $
0053:         * @author Craig Spannring
0054:         */
0055:        class TimeoutHandler extends Thread {
0056:            public static final String cvsVersion = "$Id: Tds.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $";
0057:
0058:            java.sql.Statement stmt;
0059:            int timeout;
0060:
0061:            public TimeoutHandler(java.sql.Statement stmt_, int timeout_) {
0062:                stmt = stmt_;
0063:                timeout = timeout_;
0064:            }
0065:
0066:            public void run() {
0067:                try {
0068:                    sleep(timeout * 1000);
0069:                    stmt.cancel();
0070:                } catch (SQLException e) {
0071:                    // nop
0072:                } catch (java.lang.InterruptedException e) {
0073:                    // nop
0074:                }
0075:            }
0076:        }
0077:
0078:        /**
0079:         * Implement the TDS protocol.
0080:         *
0081:         * @version  $Id: Tds.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $
0082:         * @author Craig Spannring
0083:         * @author Igor Petrovski
0084:         * @author The FreeTDS project
0085:         */
0086:        public class Tds implements  TdsDefinitions {
0087:            public static final String cvsVersion = "$Id: Tds.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $";
0088:
0089:            // 
0090:            // If the following variable is false we will consider calling 
0091:            // unimplemented methods to be an error and will raise an exception.
0092:            // If you want to ignore any unimplemented methods, set it to 
0093:            // true.  Only do this if you know what you are doing and can tolerate
0094:            // bogus results from the unimplemented methods.
0095:            //
0096:            static boolean ignoreNotImplemented = false;
0097:
0098:            Socket sock = null;
0099:            TdsComm comm = null;
0100:
0101:            String databaseProductName;
0102:            String databaseProductVersion;
0103:
0104:            java.sql.Connection connection;
0105:            String host;
0106:            int serverType = -1; // either Tds.SYBASE or Tds.SQLSERVER
0107:            int port; // Port numbers are _unsigned_ 16 bit, short is too small
0108:            String database;
0109:            String user;
0110:            String password;
0111:            String appName;
0112:            String serverName;
0113:            String progName;
0114:            byte progMajorVersion;
0115:            byte progMinorVersion;
0116:
0117:            boolean haveProcNameTable = false;
0118:            String procNameGeneratorName = null;
0119:            String procNameTableName = null;
0120:
0121:            String initialSettings = null;
0122:
0123:            private Properties initialProps = null;
0124:            private EncodingHelper encoder = null;
0125:            private String charset = null;
0126:
0127:            // int          rowCount    = -1;    // number of rows selected or updated
0128:            private boolean moreResults = false; // Is there another result set?
0129:
0130:            // Jens Jakobsen 1999-01-10
0131:            // Until TDS_END_TOKEN is reached we assume that there are outstanding
0132:            // UpdateCounts or ResultSets
0133:            private boolean moreResults2 = true;
0134:
0135:            CancelController cancelController = null;
0136:
0137:            SqlMessage lastServerMessage = null;
0138:
0139:            // Added 2000-06-07.  Used to control TDS version-specific behavior.
0140:            private int tdsVer = Tds.TDS42;
0141:
0142:            // RMK 2000-06-08.
0143:            private boolean showWarnings = false;
0144:
0145:            // RMK 2000-06-12.  Time zone offset on client (disregarding DST).
0146:            private int zoneOffset = Calendar.getInstance().get(
0147:                    Calendar.ZONE_OFFSET);
0148:
0149:            public Tds(java.sql.Connection connection_, Properties props_,
0150:                    String initialSettings) throws java.io.IOException,
0151:                    java.net.UnknownHostException, java.sql.SQLException,
0152:                    com.internetcds.jdbc.tds.TdsException {
0153:                connection = (java.sql.Connection) connection_;
0154:                initialProps = props_;
0155:
0156:                host = props_.getProperty("HOST");
0157:                serverType = Integer.parseInt(props_.getProperty("SERVERTYPE"));
0158:                port = Integer.parseInt(props_.getProperty("PORT"));
0159:                database = props_.getProperty("DBNAME");
0160:                user = props_.getProperty("user");
0161:                password = props_.getProperty("password");
0162:                appName = props_.getProperty("APPNAME", "jdbclib");
0163:                serverName = props_.getProperty("SERVERNAME", host);
0164:                progName = props_.getProperty("PROGNAME", "java_app");
0165:                progMajorVersion = (byte) DriverVersion.getDriverMajorVersion();
0166:                progMinorVersion = (byte) DriverVersion.getDriverMinorVersion();
0167:                //      String verString = props_.getProperty("TDS", "42");
0168:                String verString = props_.getProperty("TDS", "7.0");
0169:
0170:                // XXX This driver doesn't properly support TDS 5.0, AFAIK.
0171:                // Added 2000-06-07.
0172:
0173:                tdsVer = TDS42;
0174:                if (verString.equals("5.0")) {
0175:                    tdsVer = Tds.TDS50;
0176:                } else if (verString.equals("7.0")) {
0177:                    tdsVer = Tds.TDS70;
0178:                }
0179:                // RMK 2000-06-08
0180:                if (System.getProperty("TDS_SHOW_WARNINGS") != null
0181:                        || props_.getProperty("TDS_SHOW_WARNINGS") != null) {
0182:                    showWarnings = true;
0183:                }
0184:
0185:                cancelController = new CancelController();
0186:
0187:                // Send the logon packet to the server
0188:                sock = new Socket(host, port);
0189:                sock.setTcpNoDelay(true);
0190:                comm = new TdsComm(sock, tdsVer);
0191:
0192:                setCharset(props_.getProperty("CHARSET"));
0193:
0194:                if (logon()) {
0195:                    // everything is hunky-dory.
0196:                } else {
0197:                    throw new SQLException("Logon failed.  "
0198:                            + lastServerMessage);
0199:                }
0200:            }
0201:
0202:            private void setCharset(String charset) {
0203:                try {
0204:                    Logger.println("Trying to change charset to " + charset);
0205:                } catch (java.io.IOException e) {
0206:                    // nop
0207:                }
0208:
0209:                if (charset == null || charset.length() > 30) {
0210:                    charset = "iso_1";
0211:                }
0212:
0213:                if (!charset.equals(this .charset)) {
0214:                    encoder = EncodingHelper.getHelper(charset);
0215:                    if (encoder == null) {
0216:                        charset = "iso_1";
0217:                        encoder = EncodingHelper.getHelper(charset);
0218:                    }
0219:                    this .charset = charset;
0220:                }
0221:            }
0222:
0223:            EncodingHelper getEncoder() {
0224:                return encoder;
0225:            }
0226:
0227:            public void close() {
0228:                comm.close();
0229:                try {
0230:                    sock.close();
0231:                } catch (java.io.IOException e) {
0232:                    // XXX should do something here
0233:                }
0234:            }
0235:
0236:            static private int toUInt(byte b) {
0237:                int result = ((int) b) & 0x00ff;
0238:                return result;
0239:            }
0240:
0241:            public String toString() {
0242:                return "" + database + ", " + sock.getLocalAddress() + ":"
0243:                        + sock.getLocalPort() + " -> " + sock.getInetAddress()
0244:                        + ":" + sock.getPort();
0245:            }
0246:
0247:            /**
0248:             * Convert a JDBC escaped SQL string into the native SQL
0249:             *
0250:             * @param input   escaped string to convert
0251:             *
0252:             * @return native SQL string
0253:             */
0254:            static public String toNativeSql(String input, int serverType)
0255:                    throws SQLException {
0256:                EscapeProcessor escape;
0257:                if (serverType == TdsDefinitions.SYBASE) {
0258:                    escape = new SybaseEscapeProcessor(input);
0259:                } else {
0260:                    escape = new MSSqlServerEscapeProcessor(input);
0261:                }
0262:
0263:                return escape.nativeString();
0264:            }
0265:
0266:            /**
0267:             * Convert a JDBC java.sql.Types identifier to a SQLServer type identifier
0268:             *
0269:             * @author Craig Spannring
0270:             *
0271:             * @param jdbcType   JDBC type to convert.  Should be one of the
0272:             *                   constants from java.sql.Types.
0273:             *
0274:             * @return The corresponding SQLServer type identifier.
0275:             */
0276:            public static byte cvtJdbcTypeToNativeType(int jdbcType)
0277:                    throws TdsNotImplemented {
0278:                // This function is thread safe.
0279:                byte result = 0;
0280:                switch (jdbcType) {
0281:                case java.sql.Types.CHAR:
0282:                    //         case java.sql.Types.VARCHAR:
0283:                    //         case java.sql.Types.LONGVARCHAR:
0284:                {
0285:                    result = SYBCHAR;
0286:                    break;
0287:                }
0288:                    //Sinisa 
0289:                    //Add java.sql.types VARCHAR & LONGVARCHAR as a native type SYBVARCHAR 
0290:                case java.sql.Types.VARCHAR:
0291:                case java.sql.Types.LONGVARCHAR: {
0292:                    result = SYBVARCHAR;
0293:                    break;
0294:                }
0295:                    //Sinisa
0296:                    //Add java.sql.types VARCHAR & LONGVARCHAR as a native type SYBFLT8 
0297:                case java.sql.Types.DECIMAL: {
0298:                    result = SYBFLT8;
0299:                    break;
0300:                }
0301:                case java.sql.Types.INTEGER:
0302:                case java.sql.Types.SMALLINT:
0303:                case java.sql.Types.BIGINT: {
0304:                    result = SYBINT4;
0305:                    break;
0306:                }
0307:                case java.sql.Types.REAL:
0308:                case java.sql.Types.DOUBLE: {
0309:                    result = SYBFLT8;
0310:                    break;
0311:                }
0312:                case java.sql.Types.DATE:
0313:                case java.sql.Types.TIMESTAMP:
0314:                case java.sql.Types.TIME: {
0315:                    result = SYBDATETIMN;
0316:                    break;
0317:                }
0318:                case java.sql.Types.VARBINARY:
0319:                case java.sql.Types.LONGVARBINARY: {
0320:                    result = SYBIMAGE;
0321:                    break;
0322:                }
0323:                    //Dusan
0324:                case java.sql.Types.BIT: {
0325:                    result = SYBBIT;
0326:                    break;
0327:                }
0328:                default: {
0329:                    throw new TdsNotImplemented("cvtJdbcTypeToNativeType ("
0330:                            + TdsUtil.javaSqlTypeToString(jdbcType) + ")");
0331:                }
0332:                }
0333:
0334:                return result;
0335:            }
0336:
0337:            /**
0338:             * Convert a JDBC java.sql.Types identifier to a
0339:             * SQLServer type identifier
0340:             *
0341:             * @author Craig Spannring
0342:             *
0343:             * @param nativeType   SQLServer type to convert.
0344:             * @param size         Maximum size of data coming back from server.
0345:             *
0346:             * @return The corresponding JDBC type identifier.
0347:             */
0348:            public static int cvtNativeTypeToJdbcType(int nativeType, int size)
0349:                    throws TdsException {
0350:
0351:                // This function is thread safe.
0352:
0353:                int result = java.sql.Types.OTHER;
0354:                switch (nativeType) {
0355:                // XXX We need to figure out how to map _all_ of these types
0356:                case SYBBINARY:
0357:                    result = java.sql.Types.BINARY;
0358:                    break;
0359:                case SYBBIT:
0360:                    result = java.sql.Types.BIT;
0361:                    break;
0362:                case SYBBITN:
0363:                    result = java.sql.Types.BIT;
0364:                    break;
0365:                case SYBCHAR:
0366:                    result = java.sql.Types.CHAR;
0367:                    break;
0368:                case SYBNCHAR:
0369:                    result = java.sql.Types.CHAR;
0370:                    break;
0371:                case SYBDATETIME4:
0372:                    result = java.sql.Types.TIMESTAMP;
0373:                    break;
0374:                case SYBDATETIME:
0375:                    result = java.sql.Types.TIMESTAMP;
0376:                    break;
0377:                case SYBDATETIMN:
0378:                    result = java.sql.Types.TIMESTAMP;
0379:                    break;
0380:                case SYBDECIMAL:
0381:                    result = java.sql.Types.DECIMAL;
0382:                    break;
0383:                case SYBNUMERIC:
0384:                    result = java.sql.Types.NUMERIC;
0385:                    break;
0386:                case SYBFLT8:
0387:                    result = java.sql.Types.DOUBLE;
0388:                    break;
0389:                case SYBFLTN:
0390:                    result = java.sql.Types.DOUBLE;
0391:                    break;
0392:                case SYBINT1:
0393:                    result = java.sql.Types.TINYINT;
0394:                    break;
0395:                case SYBINT2:
0396:                    result = java.sql.Types.SMALLINT;
0397:                    break;
0398:                case SYBINT4:
0399:                    result = java.sql.Types.INTEGER;
0400:                    break;
0401:                case SYBINTN: {
0402:                    switch (size) {
0403:                    case 1:
0404:                        result = java.sql.Types.TINYINT;
0405:                        break;
0406:                    case 2:
0407:                        result = java.sql.Types.SMALLINT;
0408:                        break;
0409:                    case 4:
0410:                        result = java.sql.Types.INTEGER;
0411:                        break;
0412:                    default:
0413:                        throw new TdsException("Bad size of SYBINTN");
0414:                    }
0415:                    break;
0416:                }
0417:                    // XXX Should money types by NUMERIC or OTHER?
0418:                case SYBSMALLMONEY:
0419:                    result = java.sql.Types.NUMERIC;
0420:                    break;
0421:                case SYBMONEY4:
0422:                    result = java.sql.Types.NUMERIC;
0423:                    break;
0424:                case SYBMONEY:
0425:                    result = java.sql.Types.NUMERIC;
0426:                    break;
0427:                case SYBMONEYN:
0428:                    result = java.sql.Types.NUMERIC;
0429:                    break;
0430:                //         case SYBNUMERIC:      result = java.sql.Types.NUMERIC;     break;
0431:                case SYBREAL:
0432:                    result = java.sql.Types.REAL;
0433:                    break;
0434:                case SYBTEXT:
0435:                    result = java.sql.Types.LONGVARCHAR;
0436:                    break;
0437:                case SYBNTEXT:
0438:                    result = java.sql.Types.LONGVARCHAR;
0439:                    break;
0440:                case SYBIMAGE:
0441:                    result = java.sql.Types.VARBINARY;
0442:                    break;
0443:                case SYBVARBINARY:
0444:                    result = java.sql.Types.VARBINARY;
0445:                    break;
0446:                case SYBVARCHAR:
0447:                    result = java.sql.Types.VARCHAR;
0448:                    break;
0449:                case SYBNVARCHAR:
0450:                    result = java.sql.Types.VARCHAR;
0451:                    break;
0452:                //         case SYBVOID:         result = java.sql.Types. ; break;
0453:                default:
0454:                    throw new TdsException("Unknown native data type "
0455:                            + Integer.toHexString(nativeType & 0xff));
0456:                }
0457:                return result;
0458:            } /* cvtNativeTypeToJdbcType()  */
0459:
0460:            /**
0461:             * Return the type of server that we attempted to connect to.
0462:             * 
0463:             * @return TdsDefinitions.SYBASE or TdsDefinitions.SQLSERVER
0464:             */
0465:            public int getServerType() {
0466:                return serverType;
0467:            }
0468:
0469:            /**
0470:             * Try to figure out what client name we should identify
0471:             * ourselves as.  Get the hostname of this machine,
0472:             *
0473:             * @return name we will use as the client.
0474:             */
0475:            private String getClientName() {
0476:                // This method is thread safe.
0477:                String tmp;
0478:                try {
0479:                    tmp = java.net.InetAddress.getLocalHost().getHostName();
0480:                } catch (java.net.UnknownHostException e) {
0481:                    tmp = "";
0482:                }
0483:                StringTokenizer st = new StringTokenizer(tmp, ".");
0484:
0485:                if (!st.hasMoreTokens()) {
0486:                    // This means hostname wasn't found for this machine.
0487:                    return "JOHNDOE";
0488:                }
0489:
0490:                // Look at the first (and possibly only) word in the name.
0491:                tmp = st.nextToken();
0492:                if (tmp.length() == 0) {
0493:                    // This means the hostname had no leading component.
0494:                    // (This case would be strange.)
0495:                    return "JANEDOE";
0496:                } else if (Character.isDigit(tmp.charAt(0))) {
0497:                    // This probably means that the name was a quad-decimal
0498:                    // number.  We don't want to send that as our name,
0499:                    // so make one up.
0500:                    return "BABYDOE";
0501:                } else {
0502:                    // Ah, Life is good.  We have a name.  All other
0503:                    // applications I've seen have upper case client names,
0504:                    // and so shall we.
0505:                    return tmp.toUpperCase();
0506:                }
0507:            }
0508:
0509:            /**
0510:             * Log onto the SQLServer
0511:             * <p>
0512:             *
0513:             * This method is not synchronized and does not need to be so long
0514:             * as it can only be called from the constructor.
0515:             *
0516:             * <p>
0517:             *  <U>Login Packet</U>
0518:             *  <P>
0519:             *  Packet type (first byte) is 2.  The following is from tds.h the numbers
0520:             *  on the left are offsets <I>not including</I> the packet header.
0521:             * <br>
0522:             *  Note:  The logical logon packet is split into two physical
0523:             *  packets.  Each physical packet has its own header.
0524:             *  <br>
0525:             *  <PRE>
0526:             * -- 0 -- DBCHAR host_name[30];
0527:             * -- 30 -- DBTINYINT host_name_length;
0528:             * -- 31 -- DBCHAR user_name[30];
0529:             * -- 61 -- DBTINYINT user_name_length;
0530:             * -- 62 -- DBCHAR password[30];
0531:             * -- 92 -- DBTINYINT password_length;
0532:             * -- 93 -- DBCHAR host_process[30];
0533:             * -- 123 -- DBTINYINT host_process_length;
0534:             * -- 124 -- DBCHAR magic1[6]; -- here were most of the mystery stuff is --
0535:             * -- 130 -- DBTINYINT bulk_copy;
0536:             * -- 131 -- DBCHAR magic2[9]; -- here were most of the mystery stuff is --
0537:             * -- 140 -- DBCHAR app_name[30];
0538:             * -- 170 -- DBTINYINT app_name_length;
0539:             * -- 171 -- DBCHAR server_name[30];
0540:             * -- 201 -- DBTINYINT server_name_length;
0541:             * -- 202 -- DBCHAR magic3; -- 0, dont know this one either --
0542:             * -- 203 -- DBTINYINT password2_length;
0543:             * -- 204 -- DBCHAR password2[30];
0544:             * -- 234 -- DBCHAR magic4[223];
0545:             * -- 457 -- DBTINYINT password2_length_plus2;
0546:             * -- 458 -- DBSMALLINT major_version; -- TDS version --
0547:             * -- 460 -- DBSMALLINT minor_version; -- TDS version --
0548:             * -- 462 -- DBCHAR library_name[10]; -- Ct-Library or DB-Library --
0549:             * -- 472 -- DBTINYINT library_length; -- Ct-Library or DB-Library --
0550:             * -- 473 -- DBSMALLINT major_version2; -- program version --
0551:             * -- 475 -- DBSMALLINT minor_version2; -- program version --
0552:             * -- 477 -- DBCHAR magic6[3]; -- ? last two octets are 13 and 17 --
0553:             *                              -- bdw reports last two as 12 and 16 here --
0554:             *                              -- possibly a bitset flag --
0555:             * -- 480 -- DBCHAR language[30]; -- ie us-english --
0556:             *  -- second packet --
0557:             * -- 524 -- DBTINYINT language_length; -- 10 in this case --
0558:             * -- 525 -- DBCHAR magic7; -- no clue... has 1 in the first octet --
0559:             *                           --  bdw reports 0x0 --
0560:             * -- 526 -- DBSMALLINT old_secure; -- explaination? --
0561:             * -- 528 -- DBTINYINT encrypted; -- 1 means encrypted all password fields blank --
0562:             * -- 529 -- DBCHAR magic8; -- no clue... zeros --
0563:             * -- 530 -- DBCHAR sec_spare[9]; -- explaination --
0564:             * -- 539 -- DBCHAR char_set[30]; -- ie iso_1 --
0565:             * -- 569 -- DBTINYINT char_set_length; -- 5 --
0566:             * -- 570 -- DBTINYINT magic9; -- 1 --
0567:             * -- 571 -- DBCHAR block_size[6]; -- in text --
0568:             * -- 577 -- DBTINYINT block_size_length;
0569:             * -- 578 -- DBCHAR magic10[25]; -- lots of stuff here...no clue --
0570:             *
0571:             *  </PRE>
0572:             *
0573:             * This routine will basically eat all of the data returned from the
0574:             * SQLServer.
0575:             *
0576:             * @author Craig Spannring
0577:             *
0578:             * @exception TdsUnknownPacketSubType
0579:             * @exception com.internetcds.jdbc.tds.TdsException
0580:             * @exception java.io.IOException
0581:             * @exception java.sql.SQLException
0582:             */
0583:            private boolean logon() throws java.sql.SQLException,
0584:                    TdsUnknownPacketSubType, java.io.IOException,
0585:                    com.internetcds.jdbc.tds.TdsException {
0586:                boolean isOkay = true;
0587:                byte pad = (byte) 0;
0588:                byte[] empty = new byte[0];
0589:
0590:                // Added 2000-06-07.
0591:                if (tdsVer == Tds.TDS70)
0592:                    send70Login();
0593:                else {
0594:
0595:                    comm.startPacket(TdsComm.LOGON);
0596:
0597:                    // hostname  (offset0)
0598:                    // comm.appendString("TOLEDO", 30, (byte)0);
0599:                    byte[] tmp = encoder.getBytes(getClientName());
0600:                    comm.appendBytes(tmp, 30, pad);
0601:                    comm.appendByte((byte) (tmp.length < 30 ? tmp.length : 30));
0602:
0603:                    // username (offset 31 0x1f)
0604:                    tmp = encoder.getBytes(user);
0605:                    comm.appendBytes(tmp, 30, pad);
0606:                    comm.appendByte((byte) (tmp.length < 30 ? tmp.length : 30));
0607:
0608:                    // password (offset 62 0x3e)
0609:                    tmp = encoder.getBytes(password);
0610:                    comm.appendBytes(tmp, 30, pad);
0611:                    comm.appendByte((byte) (tmp.length < 30 ? tmp.length : 30));
0612:
0613:                    // hostproc (offset 93 0x5d)
0614:                    tmp = encoder.getBytes("00000116");
0615:                    comm.appendBytes(tmp, 8, pad);
0616:
0617:                    // unused (offset 109 0x6d)
0618:                    comm.appendBytes(empty, (30 - 14), pad);
0619:
0620:                    // apptype (offset )
0621:                    comm.appendByte((byte) 0x0);
0622:                    comm.appendByte((byte) 0xA0);
0623:                    comm.appendByte((byte) 0x24);
0624:                    comm.appendByte((byte) 0xCC);
0625:                    comm.appendByte((byte) 0x50);
0626:                    comm.appendByte((byte) 0x12);
0627:
0628:                    // hostproc length (offset )
0629:                    comm.appendByte((byte) 8);
0630:
0631:                    // type of int2
0632:                    comm.appendByte((byte) 3);
0633:
0634:                    // type of int4
0635:                    comm.appendByte((byte) 1);
0636:
0637:                    // type of char
0638:                    comm.appendByte((byte) 6);
0639:
0640:                    // type of flt
0641:                    comm.appendByte((byte) 10);
0642:
0643:                    // type of date
0644:                    comm.appendByte((byte) 9);
0645:
0646:                    // notify of use db
0647:                    comm.appendByte((byte) 1);
0648:
0649:                    // disallow dump/load and bulk insert
0650:                    comm.appendByte((byte) 1);
0651:
0652:                    // sql interface type
0653:                    comm.appendByte((byte) 0);
0654:
0655:                    // type of network connection
0656:                    comm.appendByte((byte) 0);
0657:
0658:                    // spare[7]
0659:                    comm.appendBytes(empty, 7, pad);
0660:
0661:                    // appname
0662:                    tmp = encoder.getBytes(appName);
0663:                    comm.appendBytes(tmp, 30, pad);
0664:                    comm.appendByte((byte) (tmp.length < 30 ? tmp.length : 30));
0665:
0666:                    // server name
0667:                    tmp = encoder.getBytes(serverName);
0668:                    comm.appendBytes(tmp, 30, pad);
0669:                    comm.appendByte((byte) (tmp.length < 30 ? tmp.length : 30));
0670:
0671:                    // remote passwords
0672:                    comm.appendBytes(empty, 2, pad);
0673:                    tmp = encoder.getBytes(password);
0674:                    comm.appendBytes(tmp, 253, pad);
0675:                    comm.appendByte((byte) (tmp.length < 253 ? tmp.length + 2
0676:                            : 253 + 2));
0677:
0678:                    // tds version
0679:                    comm.appendByte((byte) 4);
0680:                    comm.appendByte((byte) 2);
0681:                    comm.appendByte((byte) 0);
0682:                    comm.appendByte((byte) 0);
0683:
0684:                    // prog name
0685:                    tmp = encoder.getBytes(progName);
0686:                    comm.appendBytes(tmp, 10, pad);
0687:                    comm.appendByte((byte) (tmp.length < 10 ? tmp.length : 10));
0688:
0689:                    // prog version
0690:                    comm.appendByte((byte) 6); // Tell the server we can handle SQLServer version 6
0691:                    comm.appendByte((byte) 0); // Send zero to tell the server we can't handle any other version
0692:                    comm.appendByte((byte) 0);
0693:                    comm.appendByte((byte) 0);
0694:
0695:                    // auto convert short
0696:                    comm.appendByte((byte) 0);
0697:
0698:                    // type of flt4
0699:                    comm.appendByte((byte) 0x0D);
0700:
0701:                    // type of date4
0702:                    comm.appendByte((byte) 0x11);
0703:
0704:                    // language
0705:                    tmp = encoder.getBytes("us_english");
0706:                    comm.appendBytes(tmp, 30, pad);
0707:                    comm.appendByte((byte) (tmp.length < 30 ? tmp.length : 30));
0708:
0709:                    // notify on lang change
0710:                    comm.appendByte((byte) 1);
0711:
0712:                    // security label hierachy
0713:                    comm.appendShort((short) 0);
0714:
0715:                    // security components
0716:                    comm.appendBytes(empty, 8, pad);
0717:
0718:                    // security spare
0719:                    comm.appendShort((short) 0);
0720:
0721:                    // security login role
0722:                    comm.appendByte((byte) 0);
0723:
0724:                    // charset
0725:                    tmp = encoder.getBytes(charset);
0726:                    comm.appendBytes(tmp, 30, pad);
0727:                    comm.appendByte((byte) (tmp.length < 30 ? tmp.length : 30));
0728:
0729:                    // notify on charset change
0730:                    comm.appendByte((byte) 1);
0731:
0732:                    // length of tds packets
0733:                    tmp = encoder.getBytes("512");
0734:                    comm.appendBytes(tmp, 6, pad);
0735:                    comm.appendByte((byte) 3);
0736:
0737:                    // pad out to a longword
0738:                    comm.appendBytes(empty, 8, pad);
0739:
0740:                    moreResults2 = true; //JJ 1999-01-10
0741:                }
0742:
0743:                comm.sendPacket();
0744:
0745:                // Get the reply to the logon packet.
0746:                PacketResult result;
0747:
0748:                while (!((result = processSubPacket()) instanceof  PacketEndTokenResult)) {
0749:                    if (result instanceof  PacketErrorResult) {
0750:                        isOkay = false;
0751:                    }
0752:                    // XXX Should really process some more types of packets.
0753:                }
0754:
0755:                if (isOkay) {
0756:                    // XXX Should we move this to the Connection class?
0757:                    isOkay = changeSettings(database, initialSettings);
0758:                }
0759:
0760:                // XXX Possible bug.  What happend if this is cancelled before the logon
0761:                // takes place?  Should isOkay be false?
0762:                return isOkay;
0763:            }
0764:
0765:            /*
0766:             * New code added to handle TDS 7.0 login, which uses a completely
0767:             * different packet layout.  Logic taken directly from freetds C
0768:             * code in tds/login.c.  Lots of magic values: I don't pretend
0769:             * to have any idea what most of this means.
0770:             *
0771:             * Added 2000-06-05.
0772:             */
0773:            private void send70Login() throws java.io.IOException {
0774:
0775:                byte[] magic1 = { (byte) 0006, (byte) 0203, (byte) 0362,
0776:                        (byte) 0370, (byte) 0377, (byte) 0000, (byte) 0000,
0777:                        (byte) 0000, (byte) 0000, (byte) 0340, (byte) 0003,
0778:                        (byte) 0000, (byte) 0000, (byte) 0210, (byte) 0377,
0779:                        (byte) 0377, (byte) 0377, (byte) 0066, (byte) 0004,
0780:                        (byte) 0000, (byte) 0000 };
0781:                byte[] magic2 = { (byte) 0000, (byte) 0100, (byte) 0063,
0782:                        (byte) 0232, (byte) 0153, (byte) 0120 };
0783:                byte[] magic3 = encoder.getBytes("NTLMSSP");
0784:                String libName = "DB-Library";
0785:                byte pad = (byte) 0;
0786:                byte[] empty = new byte[0];
0787:                String appName = "CDR";
0788:                short len = (short) (86 + 2 * (user.length()
0789:                        + password.length() + appName.length()
0790:                        + serverName.length() + libName.length()));
0791:                short packSize = (short) (len + 48);
0792:                comm.startPacket(TdsComm.LOGON70);
0793:                comm.appendTdsShort(packSize);
0794:                comm.appendBytes(empty, 5, pad);
0795:                comm.appendByte((byte) 0x70);
0796:                comm.appendBytes(empty, 7, pad);
0797:                comm.appendBytes(magic1, 21, pad);
0798:
0799:                // Pack up value lengths, positions.
0800:                short curPos = 86;
0801:
0802:                // Unknown
0803:                comm.appendTdsShort(curPos);
0804:                comm.appendTdsShort((short) 0);
0805:
0806:                // Username
0807:                comm.appendTdsShort(curPos);
0808:                comm.appendTdsShort((short) user.length());
0809:                curPos += user.length() * 2;
0810:
0811:                // Password
0812:                comm.appendTdsShort(curPos);
0813:                comm.appendTdsShort((short) password.length());
0814:                curPos += password.length() * 2;
0815:
0816:                // App name
0817:                comm.appendTdsShort(curPos);
0818:                comm.appendTdsShort((short) appName.length());
0819:                curPos += appName.length() * 2;
0820:
0821:                // Server name
0822:                comm.appendTdsShort(curPos);
0823:                comm.appendTdsShort((short) serverName.length());
0824:                curPos += serverName.length() * 2;
0825:
0826:                // Another unknown value
0827:                comm.appendTdsShort((short) 0);
0828:                comm.appendTdsShort((short) 0);
0829:
0830:                // Library name
0831:                comm.appendTdsShort(curPos);
0832:                comm.appendTdsShort((short) libName.length());
0833:                curPos += libName.length() * 2;
0834:
0835:                // Two more unknowns
0836:                comm.appendTdsShort(curPos);
0837:                comm.appendTdsShort((short) 0);
0838:                comm.appendTdsShort(curPos);
0839:                comm.appendTdsShort((short) 0);
0840:
0841:                // More magic.
0842:                comm.appendBytes(magic2, 6, pad);
0843:                comm.appendTdsShort(len);
0844:                comm.appendTdsShort((short) 0x30);
0845:                comm.appendTdsShort(packSize);
0846:                comm.appendTdsShort((short) 0);
0847:
0848:                // Pack up the login values.
0849:                String scrambledPw = tds7CryptPass(password);
0850:                comm.appendChars(user);
0851:                comm.appendChars(scrambledPw);
0852:                comm.appendChars(appName);
0853:                comm.appendChars(serverName);
0854:                comm.appendChars(libName);
0855:
0856:                // Still more magic!
0857:                comm.appendBytes(magic3, 7, pad);
0858:                comm.appendByte((byte) 0);
0859:                comm.appendByte((byte) 1);
0860:                comm.appendBytes(empty, 3, pad);
0861:                comm.appendByte((byte) 6);
0862:                comm.appendByte((byte) 130);
0863:                comm.appendBytes(empty, 22, pad);
0864:                comm.appendByte((byte) 48);
0865:                comm.appendBytes(empty, 7, pad);
0866:                comm.appendByte((byte) 48);
0867:                comm.appendBytes(empty, 3, pad);
0868:            }
0869:
0870:            /**
0871:             * This is a <B>very</B> poor man's "encryption."
0872:             */
0873:            private static String tds7CryptPass(String pw) {
0874:                int xormask = 0x5A5A;
0875:                int len = pw.length();
0876:                char[] chars = new char[len];
0877:                for (int i = 0; i < len; ++i) {
0878:                    int c = (int) (pw.charAt(i)) ^ xormask;
0879:                    int m1 = (c >> 4) & 0x0F0F;
0880:                    int m2 = (c << 4) & 0xF0F0;
0881:                    chars[i] = (char) (m1 | m2);
0882:                }
0883:                return new String(chars);
0884:            }
0885:
0886:            /**
0887:             * change the connection level settings for this connection
0888:             * stream to the database.
0889:             *
0890:             * @return true if the database accepted the changes, false if rejected.
0891:             */
0892:            synchronized public boolean changeSettings(String database,
0893:                    String settings) throws java.sql.SQLException {
0894:                boolean isOkay = true;
0895:                try {
0896:                    PacketResult result;
0897:
0898:                    if (database != null) {
0899:                        isOkay = changeDB(database);
0900:                    }
0901:
0902:                    if (isOkay && (settings != null && settings.length() > 0)) {
0903:                        String query = settings;
0904:                        comm.startPacket(TdsComm.QUERY);
0905:                        if (tdsVer == Tds.TDS70)
0906:                            comm.appendChars(query);
0907:                        else {
0908:                            byte[] queryBytes = encoder.getBytes(query);
0909:                            comm.appendBytes(queryBytes, queryBytes.length,
0910:                                    (byte) 0);
0911:                        }
0912:                        moreResults2 = true; //JJ 1999-01-10
0913:                        comm.sendPacket();
0914:
0915:                        boolean done = false;
0916:                        while (!done) {
0917:                            result = processSubPacket();
0918:                            done = (result instanceof  PacketEndTokenResult)
0919:                                    && !((PacketEndTokenResult) result)
0920:                                            .moreResults();
0921:                            if (result instanceof  PacketErrorResult) {
0922:                                isOkay = false;
0923:                            }
0924:                            // XXX Should really process some more types of packets.
0925:                        }
0926:                    }
0927:                } catch (com.internetcds.jdbc.tds.TdsUnknownPacketSubType e) {
0928:                    throw new SQLException("Unknown response. "
0929:                            + e.getMessage());
0930:                } catch (java.io.IOException e) {
0931:                    throw new SQLException("Network problem. " + e.getMessage());
0932:                } catch (com.internetcds.jdbc.tds.TdsException e) {
0933:                    throw new SQLException(e.getMessage());
0934:                }
0935:                return isOkay;
0936:            } // changeSettings
0937:
0938:            /**
0939:             * Select a new database to use.
0940:             *
0941:             * @param database Name of the database to use.
0942:             *
0943:             * @return true if the change was accepted, false otherwise
0944:             */
0945:            synchronized private boolean changeDB(String database)
0946:                    throws java.sql.SQLException {
0947:                boolean isOkay = true;
0948:                ;
0949:
0950:                try {
0951:                    PacketResult result;
0952:                    int i;
0953:
0954:                    // XXX Check to make sure the database name
0955:                    // doesn't have funny characters.
0956:
0957:                    //      if (database name has funny characters)
0958:                    if (database.length() > 32) {
0959:                        throw new SQLException("Name too long " + database);
0960:                    }
0961:
0962:                    for (i = 0; i < database.length(); i++) {
0963:                        char ch;
0964:                        ch = database.charAt(i);
0965:                        if (!((ch == '_' && i != 0) || (ch >= 'a' && ch <= 'z')
0966:                                || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) {
0967:                            throw new SQLException("Bad database name- "
0968:                                    + database);
0969:                        }
0970:                    }
0971:
0972:                    String query = "use " + database;
0973:                    comm.startPacket(TdsComm.QUERY);
0974:                    if (tdsVer == Tds.TDS70)
0975:                        comm.appendChars(query);
0976:                    else {
0977:                        byte[] queryBytes = encoder.getBytes(query);
0978:                        comm.appendBytes(queryBytes, queryBytes.length,
0979:                                (byte) 0);
0980:                    }
0981:                    moreResults2 = true; //JJ 1999-01-10
0982:                    comm.sendPacket();
0983:
0984:                    // XXX Should we check that the change actual was okay
0985:                    // and throw some sort of exception if it wasn't?
0986:                    // Get the reply to the change database request.
0987:                    while (!((result = processSubPacket()) instanceof  PacketEndTokenResult)) {
0988:                        if (result instanceof  PacketErrorResult) {
0989:                            isOkay = false;
0990:                        }
0991:                        // XXX Should really process some more types of packets.
0992:                    }
0993:                } catch (com.internetcds.jdbc.tds.TdsUnknownPacketSubType e) {
0994:                    throw new SQLException("Unknown response. "
0995:                            + e.getMessage());
0996:                } catch (java.io.IOException e) {
0997:                    throw new SQLException("Network problem. " + e.getMessage());
0998:                } catch (com.internetcds.jdbc.tds.TdsException e) {
0999:                    throw new SQLException(e.getMessage());
1000:                }
1001:
1002:                return isOkay;
1003:            } // changeDB()
1004:
1005:            public void cancel() throws java.io.IOException,
1006:                    com.internetcds.jdbc.tds.TdsException {
1007:                // XXX How should this be synchronized?  What sort of deadlock
1008:                // conditions do we need to consider?
1009:
1010:                cancelController.doCancel(comm);
1011:            }
1012:
1013:            public boolean moreResults() {
1014:                return moreResults2;
1015:            }
1016:
1017:            /**
1018:             * Get the length of the current subpacket.
1019:             * <p>
1020:             * This will eat two bytes from the input socket.
1021:             *
1022:             * @return length of the current subpacket.
1023:             */
1024:            private int getSubPacketLength() throws java.io.IOException,
1025:                    com.internetcds.jdbc.tds.TdsException {
1026:                return comm.getTdsShort();
1027:            }
1028:
1029:            /**
1030:             * This will read a error (or warning) message from the SQLServer and
1031:             * create a SqlMessage object from that message.
1032:             * <p>
1033:             * <b> Warning! </b>  This is not synchronized because it assumes
1034:             * it will only be called by processSubPacket() which is synchronized.
1035:             *
1036:             * @param packetSubType type of the current subpacket
1037:             *
1038:             * @return The message returned by the SQLServer.
1039:             *
1040:             */
1041:            private PacketMsgResult processMsg(byte packetSubType)
1042:                    throws java.io.IOException,
1043:                    com.internetcds.jdbc.tds.TdsException {
1044:                SqlMessage msg = new SqlMessage();
1045:
1046:                int len = getSubPacketLength();
1047:
1048:                msg.number = comm.getTdsInt();
1049:
1050:                msg.state = comm.getByte();
1051:
1052:                msg.level = comm.getByte(); // ?class?
1053:
1054:                int msgLen = comm.getTdsShort();
1055:                msg.message = comm.getString(msgLen);
1056:
1057:                // RMK 2000-06-08: the getWarnings() methods aren't implemented, so we
1058:                //                 need to do something with these.
1059:                if (showWarnings && msg.message != null) {
1060:                    String warn = msg.message.trim();
1061:                    if (warn.length() > 0)
1062:                        System.err.println("Server message: " + warn);
1063:                }
1064:
1065:                int srvNameLen = comm.getByte() & 0xFF;
1066:                msg.server = comm.getString(srvNameLen);
1067:
1068:                if (packetSubType == TDS_MSG_TOKEN
1069:                        || packetSubType == TDS_ERR_TOKEN) {
1070:                    // nop
1071:                    int procNameLen = comm.getByte() & 0xFF;
1072:                    msg.procName = comm.getString(procNameLen);
1073:                } else {
1074:                    throw new TdsConfused(
1075:                            "Was expecting a msg or error token.  "
1076:                                    + "Found 0x"
1077:                                    + Integer.toHexString(packetSubType & 0xff));
1078:                }
1079:
1080:                msg.line = comm.getByte();
1081:
1082:                // unknonw byte
1083:                comm.getByte();
1084:
1085:                lastServerMessage = msg;
1086:
1087:                if (packetSubType == TDS_ERR_TOKEN) {
1088:                    return new PacketErrorResult(packetSubType, msg);
1089:                } else {
1090:                    return new PacketMsgResult(packetSubType, msg);
1091:                }
1092:            }
1093:
1094:            /**
1095:             * Process an env change message (TDS_ENV_CHG_TOKEN)
1096:             * <p>
1097:             * <b> Warning! </b>  This is not synchronized because it assumes
1098:             * it will only be called by processSubPacket() which is synchronized.
1099:             *
1100:             * @exception java.io.IOException
1101:             * @exception com.internetcds.jdbc.tds.TdsException
1102:             */
1103:            private PacketResult processEnvChange() throws java.io.IOException,
1104:                    com.internetcds.jdbc.tds.TdsException {
1105:                final byte CHARSET_CHANGE = (byte) 3;
1106:
1107:                int len = getSubPacketLength();
1108:                int type = comm.getByte();
1109:                switch (type) {
1110:                case CHARSET_CHANGE: {
1111:                    int clen = comm.getByte() & 0xFF;
1112:                    String charset;
1113:                    if (tdsVer == TDS70) {
1114:                        charset = comm.getString(clen);
1115:                        comm.skip(len - 2 - clen * 2);
1116:                    } else {
1117:                        charset = encoder.getString(comm.getBytes(clen));
1118:                        comm.skip(len - 2 - clen);
1119:                    }
1120:                    setCharset(charset);
1121:                    break;
1122:                }
1123:                default: {
1124:                    // XXX Should actually look at the env change
1125:                    // instead of ignoring it.
1126:                    comm.skip(len - 1);
1127:                    break;
1128:                }
1129:                }
1130:
1131:                return new PacketResult(TDS_ENV_CHG_TOKEN);
1132:            }
1133:
1134:            /**
1135:             * Process an column name subpacket.
1136:             * <p>
1137:             * <p>
1138:             * <b> Warning! </b>  This is not synchronized because it assumes
1139:             * it will only be called by processSubPacket() which is synchronized.
1140:             *
1141:             */
1142:            private PacketColumnNamesResult processColumnNames()
1143:                    throws java.io.IOException,
1144:                    com.internetcds.jdbc.tds.TdsException {
1145:                Columns columns = new Columns();
1146:
1147:                int totalLen = comm.getTdsShort();
1148:
1149:                int bytesRead = 0;
1150:                int i = 0;
1151:                while (bytesRead < totalLen) {
1152:                    int colNameLen = comm.getByte();
1153:                    String colName = encoder.getString(comm
1154:                            .getBytes(colNameLen));
1155:                    bytesRead = bytesRead + 1 + colNameLen;
1156:                    i++;
1157:                    columns.setName(i, colName);
1158:                    columns.setLabel(i, colName);
1159:                }
1160:
1161:                return new PacketColumnNamesResult(columns);
1162:            } // processColumnNames()
1163:
1164:            /**
1165:             * Process the columns information subpacket.
1166:             * <p>
1167:             * <b> Warning! </b>  This is not synchronized because it assumes
1168:             * it will only be called by processSubPacket() which is synchronized.
1169:             *
1170:             */
1171:            private PacketColumnInfoResult processColumnInfo()
1172:                    throws java.io.IOException,
1173:                    com.internetcds.jdbc.tds.TdsException {
1174:                Columns columns = new Columns();
1175:                int precision;
1176:                int scale;
1177:
1178:                int totalLen = comm.getTdsShort();
1179:
1180:                int bytesRead = 0;
1181:                int numColumns = 0;
1182:                while (bytesRead < totalLen) {
1183:                    scale = -1;
1184:                    precision = -1;
1185:
1186:                    int sizeOfColumn = -1;
1187:
1188:                    byte flagData[] = new byte[4];
1189:                    for (int i = 0; i < 4; i++) {
1190:                        flagData[i] = comm.getByte();
1191:                        bytesRead++;
1192:                    }
1193:                    boolean nullable = (flagData[2] & 0x01) > 0;
1194:                    boolean writeable = (flagData[2] & 0x08) > 0;
1195:                    boolean autoIncrement = (flagData[2] & 0x10) > 0;
1196:
1197:                    // Get the type of column
1198:                    byte columnType = comm.getByte();
1199:                    bytesRead++;
1200:
1201:                    if (columnType == SYBTEXT || columnType == SYBIMAGE) {
1202:                        int i;
1203:                        int tmpByte;
1204:
1205:                        // XXX Need to find out what these next 4 bytes are
1206:                        //     Could they be the column size?
1207:                        comm.skip(4);
1208:                        bytesRead += 4;
1209:
1210:                        int tableNameLen = comm.getTdsShort();
1211:                        bytesRead += 2;
1212:                        String tableName = encoder.getString(comm
1213:                                .getBytes(tableNameLen));
1214:                        bytesRead += tableNameLen;
1215:
1216:                        sizeOfColumn = 2 << 31 - 1;
1217:                    } else if (columnType == SYBDECIMAL
1218:                            || columnType == SYBNUMERIC) {
1219:                        int tmp;
1220:                        sizeOfColumn = comm.getByte();
1221:                        bytesRead++;
1222:                        precision = comm.getByte(); // Total number of digits
1223:                        bytesRead++;
1224:                        scale = comm.getByte(); // # of digits after the decimal point
1225:                        bytesRead++;
1226:                    } else if (isFixedSizeColumn(columnType)) {
1227:                        sizeOfColumn = lookupColumnSize(columnType);
1228:                    } else {
1229:                        sizeOfColumn = ((int) comm.getByte() & 0xff);
1230:                        bytesRead++;
1231:                    }
1232:                    numColumns++;
1233:
1234:                    if (scale != -1) {
1235:                        columns.setScale(numColumns, scale);
1236:                    }
1237:                    if (precision != -1) {
1238:                        columns.setPrecision(numColumns, precision);
1239:                    }
1240:                    columns.setType(numColumns, columnType);
1241:                    columns.setDisplaySize(numColumns, sizeOfColumn);
1242:                    columns.setNullable(numColumns,
1243:                            (nullable ? ResultSetMetaData.columnNullable
1244:                                    : ResultSetMetaData.columnNoNulls));
1245:                    columns.setAutoIncrement(numColumns, autoIncrement);
1246:                    columns.setReadOnly(numColumns, !writeable);
1247:                }
1248:
1249:                // Don't know what the rest is except that the
1250:                int skipLen = totalLen - bytesRead;
1251:                if (skipLen != 0) {
1252:                    throw new TdsException("skipping " + skipLen + " bytes");
1253:                }
1254:
1255:                return new PacketColumnInfoResult(columns);
1256:            } // processColumnInfo
1257:
1258:            private PacketTabNameResult processTabName()
1259:                    throws java.io.IOException,
1260:                    com.internetcds.jdbc.tds.TdsException {
1261:                int totalLen = comm.getTdsShort();
1262:
1263:                // RMK 2000-06-11.  Not sure why the original code is bothering
1264:                // to extract the bytes with such meticulous care if it isn't
1265:                // going to use the extracted strings for creating the returned
1266:                // object.  At any rate, this approach doesn't work under TDS 7.0,
1267:                // because (1) the name length is a short, not a byte under 7.0,
1268:                // and (2) the name string is nameLen wide characters for 7.0, 
1269:                // not 8-bit characters.  So I'm commenting the wasted effort
1270:                // and replacing it with a simple call to TdsComm.skip().
1271:                //int bytesRead   = 0;
1272:                //int nameLen     = 0;
1273:                //String  tabName = null;
1274:
1275:                //while(bytesRead < totalLen)
1276:                //{
1277:                //   nameLen = comm.getByte();
1278:                //   bytesRead++;
1279:                //   tabName = new String(comm.getBytes(nameLen));
1280:                //   bytesRead += nameLen;
1281:                //}
1282:
1283:                comm.skip(totalLen);
1284:
1285:                return new PacketTabNameResult();
1286:            } // processTabName()
1287:
1288:            /**
1289:             * Process an end subpacket.
1290:             * <p>
1291:             * This routine assumes that the TDS_END_TOKEN byte has already
1292:             * been read.
1293:             *
1294:             * @return
1295:             *
1296:             * @exception com.internetcds.jdbc.tds.TdsException
1297:             *
1298:             * @exception java.io.IOException
1299:             * Thrown if some sort of error occured reading bytes from the network.
1300:             */
1301:            private PacketEndTokenResult processEndToken(byte packetType)
1302:                    throws com.internetcds.jdbc.tds.TdsException,
1303:                    java.io.IOException {
1304:                byte status = comm.getByte();
1305:                comm.skip(3);
1306:                int rowCount = comm.getTdsInt();
1307:
1308:                if (packetType == TdsDefinitions.TDS_DONEINPROC) {
1309:                    throw new TdsException("Internal error.  TDS_DONEINPROC "
1310:                            + " is no longer considered an end token");
1311:                }
1312:
1313:                PacketEndTokenResult result = new PacketEndTokenResult(
1314:                        packetType, status, rowCount);
1315:
1316:                moreResults = result.moreResults();
1317:
1318:                // XXX If we executed something that returns multiple result
1319:                // sets then we don't want to clear the query in progress flag.
1320:                // See the CancelController class for details.
1321:                cancelController.finishQuery(result.wasCanceled(), result
1322:                        .moreResults());
1323:
1324:                // XXX Problem handling cancels that were sent after the server
1325:                //     send the endToken packet
1326:                return result;
1327:            }
1328:
1329:            private PacketDoneInProcResult processDoneInProc(byte packetType)
1330:                    throws TdsException, java.io.IOException {
1331:                byte status = comm.getByte();
1332:                comm.skip(3);
1333:                int rowCount = comm.getTdsInt();
1334:                PacketDoneInProcResult result = new PacketDoneInProcResult(
1335:                        packetType, status, rowCount);
1336:                if (!result.moreResults()) {
1337:                    throw new TdsException(
1338:                            "What? No more results with a DONEINPROC!");
1339:                }
1340:
1341:                if (result.moreResults()
1342:                        && peek() == TdsDefinitions.TDS_DONEINPROC) {
1343:                    result = (PacketDoneInProcResult) processSubPacket();
1344:                }
1345:
1346:                while (result.moreResults()
1347:                        && (peek() == TdsDefinitions.TDS_PROCID || peek() == TdsDefinitions.TDS_RET_STAT_TOKEN)) {
1348:                    if (peek() == TDS_PROCID) {
1349:                        PacketResult tmp = processSubPacket();
1350:                    } else if (peek() == TDS_RET_STAT_TOKEN) {
1351:                        PacketRetStatResult tmp = (PacketRetStatResult) processSubPacket();
1352:                        result.setRetStat(tmp.getRetStat());
1353:                    }
1354:                }
1355:                // XXX If we executed something that returns multiple result
1356:                // sets then we don't want to clear the query in progress flag.
1357:                // See the CancelController class for details.
1358:                cancelController.finishQuery(result.wasCanceled(), result
1359:                        .moreResults());
1360:                return result;
1361:            }
1362:
1363:            /**
1364:             * Process a subpacket reply
1365:             * <p>
1366:             * <b>Note-</b> All subpackets must be processed through here.
1367:             * This is the only routine has the proper locking to support
1368:             * the cancel method in the Statement class.
1369:             * <br>
1370:             *
1371:             * @return packet subtype the was processed.
1372:             */
1373:            PacketResult processSubPacket() throws TdsUnknownPacketSubType,
1374:                    java.io.IOException, com.internetcds.jdbc.tds.TdsException {
1375:                return processSubPacket(null);
1376:            }
1377:
1378:            /**
1379:             * Process a subpacket reply
1380:             * <p>
1381:             * <b>Note-</b> All subpackets must be processed through here.  Only this
1382:             * routine has the proper locking to support the cancel method in the
1383:             * Statement class.
1384:             * <br>
1385:             *
1386:             *
1387:             * @return packet subtype the was processed.
1388:             */
1389:            synchronized PacketResult processSubPacket(Context context)
1390:                    throws TdsUnknownPacketSubType, java.io.IOException,
1391:                    com.internetcds.jdbc.tds.TdsException {
1392:                // NOTE!!! Before adding anything to this list you must
1393:                // consider the ramifications to the the handling of cancels
1394:                // as implemented by the CancelController class.
1395:                //
1396:                // The CancelController class might implicitly assume it can call
1397:                // processSubPacket() whenever it is looking for a cancel
1398:                // acknowledgment.  It assumes that any results of the call
1399:                // can be discarded.
1400:
1401:                PacketResult result = null;
1402:                moreResults = false;
1403:
1404:                byte packetSubType = comm.getByte();
1405:                Logger.println("processSubPacket: "
1406:                        + Integer.toHexString(packetSubType & 0xFF) + " "
1407:                        + "moreResults: " + moreResults());
1408:
1409:                switch (packetSubType) {
1410:                case TDS_ENV_CHG_TOKEN: {
1411:                    result = processEnvChange();
1412:                    break;
1413:                }
1414:                case TDS_ERR_TOKEN:
1415:                case TDS_MSG_TOKEN:
1416:                case TDS_MSG50_TOKEN: {
1417:                    result = processMsg(packetSubType);
1418:                    break;
1419:                }
1420:                case TDS_TEXT_UPD_TOKEN: {
1421:                    int len = getSubPacketLength();
1422:                    comm.skip(len);
1423:                    result = new PacketResult(TDS_TEXT_UPD_TOKEN);
1424:                    break;
1425:                }
1426:                case TDS_LOGIN_ACK_TOKEN: {
1427:                    result = processLoginAck();
1428:                    break;
1429:                }
1430:                case TDS_RET_STAT_TOKEN: {
1431:                    result = processRetStat();
1432:                    break;
1433:                }
1434:                case TDS_PROCID: {
1435:                    result = processProcId();
1436:                    break;
1437:                }
1438:                case TDS_DONEINPROC: {
1439:                    result = processDoneInProc(packetSubType);
1440:                    break;
1441:                }
1442:                case TDS_DONEPROC:
1443:                case TDS_END_TOKEN: {
1444:                    result = processEndToken(packetSubType);
1445:                    moreResults2 = ((PacketEndTokenResult) result)
1446:                            .moreResults();
1447:                    break;
1448:                }
1449:                case TDS_COL_NAME_TOKEN: {
1450:                    result = processColumnNames();
1451:                    break;
1452:                }
1453:                case TDS_COL_INFO_TOKEN: {
1454:                    result = processColumnInfo();
1455:                    break;
1456:                }
1457:                case TDS_UNKNOWN_0xA5:
1458:                case TDS_UNKNOWN_0xA7:
1459:                case TDS_UNKNOWN_0xA8: {
1460:                    // XXX Need to figure out what this packet is
1461:                    comm.skip(comm.getTdsShort());
1462:                    result = new PacketUnknown(packetSubType);
1463:                    break;
1464:                }
1465:                case TDS_TABNAME: {
1466:                    result = processTabName();
1467:                    break;
1468:                }
1469:                case TDS_ORDER: {
1470:                    int len = comm.getTdsShort();
1471:                    comm.skip(len);
1472:
1473:                    result = new PacketColumnOrderResult();
1474:                    break;
1475:                }
1476:                case TDS_CONTROL: {
1477:                    int len = comm.getTdsShort();
1478:                    comm.skip(len);
1479:                    // FIXME - I'm just ignoring this
1480:                    result = new PacketControlResult();
1481:                    break;
1482:                }
1483:                case TDS_ROW_TOKEN: {
1484:                    result = getRow(context.getColumnInfo());
1485:                    break;
1486:                }
1487:                case TDS7_RESULT_TOKEN: {
1488:
1489:                    result = processTds7Result();
1490:                    break;
1491:                }
1492:                default: {
1493:                    throw new TdsUnknownPacketSubType(packetSubType);
1494:                }
1495:                }
1496:                return result;
1497:            }
1498:
1499:            /**
1500:             * Find out how many bytes a particular SQLServer data type takes.
1501:             *
1502:             * @param nativeColumnType
1503:             *
1504:             * @return number of bytes required by the given type
1505:             *
1506:             * @exception com.internetcds.jdbc.tds.TdsException
1507:             * Thrown if the given type either doesn't exist or is a variable
1508:             * sized data type.
1509:             */
1510:            private int lookupColumnSize(byte nativeColumnType)
1511:                    throws com.internetcds.jdbc.tds.TdsException {
1512:                switch (nativeColumnType) {
1513:                case SYBINT1: {
1514:                    return 1;
1515:                }
1516:                case SYBINT2: {
1517:                    return 2;
1518:                }
1519:                case SYBINT4: {
1520:                    return 4;
1521:                }
1522:                case SYBREAL: {
1523:                    return 4;
1524:                }
1525:                case SYBFLT8: {
1526:                    return 8;
1527:                }
1528:                case SYBDATETIME: {
1529:                    return 8;
1530:                }
1531:                case SYBDATETIME4: {
1532:                    return 8;
1533:                }
1534:                case SYBBIT: {
1535:                    return 1;
1536:                }
1537:                case SYBMONEY: {
1538:                    return 8;
1539:                }
1540:                case SYBMONEY4:
1541:                case SYBSMALLMONEY: {
1542:                    return 4;
1543:                }
1544:                default: {
1545:                    throw new TdsException("Not fixed size column "
1546:                            + nativeColumnType);
1547:                }
1548:                }
1549:            } // lookupColumnSize()
1550:
1551:            /**
1552:             * determine if a given datatype is a fixed size
1553:             *
1554:             * @param nativeColumnType  The SQLServer datatype to check
1555:             *
1556:             * @return <code>true</code> if the datatype is a fixed size,
1557:             * <code>false</code> if the datatype is a variable size
1558:             *
1559:             * @exception com.internetcds.jdbc.tds.TdsException
1560:             * If the <code>nativeColumnType</code> is not a knowm datatype.
1561:             *
1562:             */
1563:            private boolean isFixedSizeColumn(byte nativeColumnType)
1564:                    throws com.internetcds.jdbc.tds.TdsException {
1565:                switch (nativeColumnType) {
1566:                case SYBINT1:
1567:                case SYBINT2:
1568:                case SYBINT4:
1569:                case SYBFLT8:
1570:                case SYBDATETIME:
1571:                case SYBBIT:
1572:                case SYBMONEY:
1573:                case SYBMONEY4:
1574:                case SYBSMALLMONEY:
1575:                case SYBREAL:
1576:                case SYBDATETIME4: {
1577:                    return true;
1578:                }
1579:                case SYBINTN:
1580:                case SYBMONEYN:
1581:                case SYBVARCHAR:
1582:                case SYBNVARCHAR:
1583:                case SYBDATETIMN:
1584:                case SYBFLTN:
1585:                case SYBCHAR:
1586:                case SYBNCHAR:
1587:                case SYBNTEXT:
1588:                case SYBIMAGE:
1589:                case SYBVARBINARY:
1590:                case SYBBINARY:
1591:                case SYBDECIMAL:
1592:                case SYBNUMERIC:
1593:                case SYBBITN: {
1594:                    return false;
1595:                }
1596:                default: {
1597:                    throw new TdsException("Unrecognized column type 0x"
1598:                            + Integer.toHexString(nativeColumnType));
1599:                }
1600:                }
1601:            }
1602:
1603:            private Object readFloatN(int len) throws TdsException,
1604:                    java.io.IOException {
1605:                Object tmp;
1606:
1607:                switch (len) {
1608:                case 8: {
1609:                    long l = comm.getTdsInt64();
1610:                    tmp = new Double(Double.longBitsToDouble(l));
1611:                    break;
1612:                }
1613:                case 4: {
1614:                    int i = comm.getTdsInt();
1615:                    tmp = new Float(Float.intBitsToFloat(i));
1616:                    break;
1617:                }
1618:                case 0: {
1619:                    tmp = null;
1620:                    break;
1621:                }
1622:                default: {
1623:                    throw new TdsNotImplemented("Don't now how to handle "
1624:                            + "float with size of " + len + "(0x"
1625:                            + Integer.toHexString(len & 0xff) + ")");
1626:                }
1627:                }
1628:                return tmp;
1629:            }
1630:
1631:            private Object getMoneyValue(int type) throws java.io.IOException,
1632:                    TdsException {
1633:                int len;
1634:                Object result;
1635:
1636:                if (type == SYBMONEYN) {
1637:                    len = comm.getByte();
1638:                } else {
1639:                    len = lookupColumnSize((byte) type);
1640:                }
1641:
1642:                if (len == 0) {
1643:                    result = null;
1644:                } else {
1645:                    BigInteger x = null;
1646:
1647:                    if (len == 4) {
1648:                        x = BigInteger.valueOf(comm.getTdsInt());
1649:                    } else if (len == 8) {
1650:                        byte b4 = comm.getByte();
1651:                        byte b5 = comm.getByte();
1652:                        byte b6 = comm.getByte();
1653:                        byte b7 = comm.getByte();
1654:                        byte b0 = comm.getByte();
1655:                        byte b1 = comm.getByte();
1656:                        byte b2 = comm.getByte();
1657:                        byte b3 = comm.getByte();
1658:                        long l = (long) (b0 & 0xff) + ((long) (b1 & 0xff) << 8)
1659:                                + ((long) (b2 & 0xff) << 16)
1660:                                + ((long) (b3 & 0xff) << 24)
1661:                                + ((long) (b4 & 0xff) << 32)
1662:                                + ((long) (b5 & 0xff) << 40)
1663:                                + ((long) (b6 & 0xff) << 48)
1664:                                + ((long) (b7 & 0xff) << 56);
1665:                        x = BigInteger.valueOf(l);
1666:                    } else {
1667:                        throw new TdsConfused(
1668:                                "Don't know what to do with len of " + len);
1669:                    }
1670:                    x = x.divide(BigInteger.valueOf(100));
1671:                    result = new BigDecimal(x, 2);
1672:                }
1673:                return result;
1674:            } // getMoneyValue
1675:
1676:            /**
1677:             * Extracts decimal value from the server's results packet.  Takes 
1678:             * advantage of Java's superb handling of large numbers, which does
1679:             * all the heavy lifting for us.  Format is:
1680:             * <UL>
1681:             *  <LI>Length byte <code>len</code>; count includes sign byte.</LI>
1682:             *  <LI>Sign byte (0=negative; 1=positive).</LI>
1683:             *  <LI>Magnitude bytes (array of <code>len</code> - 1 bytes,
1684:             *      in little-endian order.</LI>
1685:             * </UL>
1686:             *
1687:             *   @param  scale       number of decimal digits after the decimal 
1688:             *                       point.
1689:             *   @return             <code>BigDecimal</code> for extracted value
1690:             *                       (or (<code>null</code> if appropriate).
1691:             */
1692:            private Object getDecimalValue(int scale) throws TdsException,
1693:                    java.io.IOException, NumberFormatException {
1694:                int len = comm.getByte() & 0xff;
1695:                if (--len < 1)
1696:                    return null;
1697:
1698:                // RMK 2000-06-10.  Deduced from some testing/packet sniffing.
1699:                byte[] bytes = new byte[len];
1700:                int signum = comm.getByte() == 0 ? -1 : 1;
1701:                while (len > 0)
1702:                    bytes[--len] = comm.getByte();
1703:                BigInteger bigInt = new BigInteger(signum, bytes);
1704:                return new BigDecimal(bigInt, scale);
1705:            }
1706:
1707:            private Object getDatetimeValue(int type)
1708:                    throws java.io.IOException, TdsException {
1709:                // Some useful constants
1710:                final long SECONDS_PER_DAY = 24L * 60L * 60L;
1711:                final long DAYS_BETWEEN_1900_AND_1970 = 25567L;
1712:
1713:                int len;
1714:                Object result;
1715:
1716:                if (type == SYBDATETIMN) {
1717:                    len = comm.getByte();
1718:                } else if (type == SYBDATETIME4) {
1719:                    len = 4;
1720:                } else {
1721:                    len = 8; // XXX shouldn't this be an error?
1722:                }
1723:
1724:                switch (len) {
1725:                case 0: {
1726:                    result = null;
1727:                    break;
1728:                }
1729:                case 8: {
1730:                    // It appears that a datetime is made of of 2 32bit ints
1731:                    // The first one is the number of days since 1900
1732:                    // The second integer is the number of seconds*300
1733:                    // The reason the calculations below are sliced up into
1734:                    // such small baby steps is to avoid a bug in JDK1.2.2's
1735:                    // runtime, which got confused by the original complexity.
1736:                    long tdsDays = (long) comm.getTdsInt();
1737:                    long tdsTime = (long) comm.getTdsInt();
1738:                    long sqlDays = tdsDays - DAYS_BETWEEN_1900_AND_1970;
1739:                    long seconds = sqlDays * SECONDS_PER_DAY + tdsTime / 300L;
1740:                    long micros = ((tdsTime % 300L) * 1000000L) / 300L;
1741:                    long millis = seconds * 1000L + micros / 1000L - zoneOffset;
1742:
1743:                    // Round up if appropriate.
1744:                    if (micros % 1000L >= 500L)
1745:                        millis++;
1746:
1747:                    result = new Timestamp(millis - getDstOffset(millis));
1748:                    break;
1749:                }
1750:                case 4: {
1751:                    // Accroding to Transact SQL Reference
1752:                    // a smalldatetime is two small integers.
1753:                    // The first is the number of days past January 1, 1900,
1754:                    // the second smallint is the number of minutes past
1755:                    // midnight.
1756:
1757:                    long tdsDays = (long) comm.getTdsShort();
1758:                    long minutes = (long) comm.getTdsShort();
1759:                    long sqlDays = tdsDays - DAYS_BETWEEN_1900_AND_1970;
1760:                    long seconds = sqlDays * SECONDS_PER_DAY + minutes * 60L;
1761:                    long millis = seconds * 1000L - zoneOffset;
1762:
1763:                    result = new Timestamp(millis - getDstOffset(millis));
1764:                    break;
1765:
1766:                }
1767:                default: {
1768:                    result = null;
1769:                    throw new TdsNotImplemented("Don't now how to handle "
1770:                            + "date with size of " + len);
1771:                }
1772:                }
1773:                return result;
1774:            } // getDatetimeValue()
1775:
1776:            /**
1777:             * Determines the number of milliseconds needed to adjust for daylight
1778:             * savings time for a given date/time value.  Note that there is a problem
1779:             * with the way SQL Server sends a DATETIME value, since it is constructed
1780:             * to represent the local time for the server.  This means that each fall
1781:             * there is a window of approximately one hour during which a single value
1782:             * can represent two different times.
1783:             */
1784:            private long getDstOffset(long time) {
1785:                Calendar cal = Calendar.getInstance();
1786:                cal.setTime(new java.util.Date(time));
1787:                return cal.get(Calendar.DST_OFFSET);
1788:            }
1789:
1790:            private Object getIntValue(int type) throws java.io.IOException,
1791:                    TdsException {
1792:                Object result;
1793:                int len;
1794:
1795:                switch (type) {
1796:                case SYBINTN: {
1797:                    len = comm.getByte();
1798:                    break;
1799:                }
1800:                case SYBINT4: {
1801:                    len = 4;
1802:                    break;
1803:                }
1804:                case SYBINT2: {
1805:                    len = 2;
1806:                    break;
1807:                }
1808:                case SYBINT1: {
1809:                    len = 1;
1810:                    break;
1811:                }
1812:                default: {
1813:                    result = null;
1814:                    throw new TdsNotImplemented("can't handle integer of type "
1815:                            + Integer.toHexString(type));
1816:                }
1817:                }
1818:
1819:                switch (len) {
1820:                case 4: {
1821:                    result = new Long(comm.getTdsInt());
1822:                    break;
1823:                }
1824:                case 2: {
1825:                    result = new Long(comm.getTdsShort());
1826:                    break;
1827:                }
1828:                case 1: {
1829:                    int tmp = toUInt(comm.getByte()); // XXX Are we sure this should be unsigned?
1830:                    result = new Long(tmp);
1831:                    break;
1832:                }
1833:                case 0: {
1834:                    result = null;
1835:                    break;
1836:                }
1837:                default: {
1838:                    result = null;
1839:                    throw new TdsConfused("Bad SYBINTN length of " + len);
1840:                }
1841:                }
1842:                return result;
1843:            } // getIntValue()
1844:
1845:            private Object getCharValue(boolean wideChars) throws TdsException,
1846:                    java.io.IOException {
1847:                Object result;
1848:                int len = tdsVer == Tds.TDS70 ? comm.getTdsShort() : comm
1849:                        .getByte() & 0xFF;
1850:
1851:                if (len == 0 || tdsVer == Tds.TDS70 && len == 0xFFFF) {
1852:                    result = null;
1853:                } else if (len > 0) {
1854:                    if (wideChars)
1855:                        result = comm.getString(len / 2);
1856:                    else
1857:                        result = encoder.getString(comm.getBytes(len));
1858:
1859:                    if (result.equals(" ")) {
1860:                        // In SQL trailing spaces are stripped from strings
1861:                        // MS SQLServer denotes a zero length string
1862:                        // as a single space.
1863:                        result = "";
1864:                    }
1865:                } else {
1866:                    throw new TdsConfused("String with length<0");
1867:                }
1868:                return result;
1869:            } // getCharValue()
1870:
1871:            private Object getTextValue(boolean wideChars) throws TdsException,
1872:                    java.io.IOException {
1873:                String result;
1874:
1875:                byte hasValue = comm.getByte();
1876:
1877:                if (hasValue == 0) {
1878:                    result = null;
1879:                } else {
1880:                    // XXX Have no idea what these 24 bytes are
1881:                    // 2000-06-06 RMK They are the TEXTPTR (16 bytes) and the TIMESTAMP.
1882:                    comm.skip(24);
1883:
1884:                    int len = comm.getTdsInt();
1885:
1886:                    // RMK 2000-06-11
1887:                    // The logic immediately below does not agree with test t0031, 
1888:                    // so I'm commenting it out.  On the other hand, it's a bit
1889:                    // puzzling that a column defined as TEXT NOT NULL needs the 
1890:                    // hasValue byte read just above, but apparently it does.
1891:                    //if (len == 0)
1892:                    //{
1893:                    //   result = null;
1894:                    //}
1895:                    //else
1896:                    if (len >= 0) {
1897:                        if (wideChars) {
1898:                            result = comm.getString(len / 2);
1899:                        } else {
1900:                            result = encoder.getString(comm.getBytes(len));
1901:                        }
1902:
1903:                        if (" ".equals(result)) {
1904:                            // In SQL trailing spaces are stripped from strings
1905:                            // MS SQLServer denotes a zero length string
1906:                            // as a single space.
1907:                            result = "";
1908:                        }
1909:                    } else {
1910:                        throw new TdsConfused("String with length<0");
1911:                    }
1912:                }
1913:                return result;
1914:            } // getTextValue()
1915:
1916:            private Object getImageValue() throws TdsException,
1917:                    java.io.IOException {
1918:                byte[] result;
1919:
1920:                byte hasValue = comm.getByte();
1921:
1922:                if (hasValue == 0) {
1923:                    result = null;
1924:                } else {
1925:                    // XXX Have no idea what these 24 bytes are
1926:                    // 2000-06-06 RMK They are the TEXTPTR (16 bytes) and the TIMESTAMP.
1927:                    comm.skip(24);
1928:
1929:                    int len = comm.getTdsInt();
1930:
1931:                    // RMK 2000-06-11
1932:                    // The logic immediately below does not agree with test t0031, 
1933:                    // so I'm commenting it out.  On the other hand, it's a bit
1934:                    // puzzling that a column defined as TEXT NOT NULL needs the 
1935:                    // hasValue byte read just above, but apparently it does.
1936:                    //if (len == 0)
1937:                    //{
1938:                    //   result = null;
1939:                    //}
1940:                    //else
1941:                    if (len >= 0) {
1942:                        result = comm.getBytes(len);
1943:                    } else {
1944:                        throw new TdsConfused("String with length<0");
1945:                    }
1946:                }
1947:                return result;
1948:            } // getImageValue()
1949:
1950:            /**
1951:             * get one result row from the TDS stream
1952:             * <p>
1953:             * This will read a full row from the TDS stream and store it in
1954:             * a PacketRowResult object.
1955:             *
1956:             */
1957:            synchronized private PacketRowResult getRow(Columns columnsInfo)
1958:                    throws TdsException, java.io.IOException {
1959:                PacketRowResult result = null;
1960:
1961:                int i;
1962:
1963:                result = new PacketRowResult(columnsInfo.getColumnCount());
1964:
1965:                for (i = 1; i <= columnsInfo.getColumnCount(); i++) {
1966:                    Object element;
1967:                    int colType = columnsInfo.getType(i);
1968:
1969:                    Logger.println("colno=" + i + " type=" + colType
1970:                            + " offset="
1971:                            + Integer.toHexString(comm.inBufferIndex));
1972:                    switch (colType) {
1973:                    case SYBINTN:
1974:                    case SYBINT1:
1975:                    case SYBINT2:
1976:                    case SYBINT4: {
1977:                        element = getIntValue(colType);
1978:                        break;
1979:                    }
1980:                    case SYBIMAGE: {
1981:                        element = getImageValue();
1982:                        break;
1983:                    }
1984:                    case SYBTEXT: {
1985:                        element = getTextValue(false);
1986:                        break;
1987:                    }
1988:                    case SYBNTEXT: {
1989:                        element = getTextValue(true);
1990:                        break;
1991:                    }
1992:                    case SYBCHAR:
1993:                    case SYBVARCHAR: {
1994:                        element = getCharValue(false);
1995:                        break;
1996:                    }
1997:                    case SYBNCHAR:
1998:                    case SYBNVARCHAR: {
1999:                        element = getCharValue(true);
2000:                        break;
2001:                    }
2002:                    case SYBREAL: {
2003:                        element = readFloatN(4);
2004:                        break;
2005:                    }
2006:                    case SYBFLT8: {
2007:                        element = readFloatN(8);
2008:                        break;
2009:                    }
2010:                    case SYBFLTN: {
2011:                        int len;
2012:
2013:                        len = comm.getByte();
2014:
2015:                        element = readFloatN(len);
2016:                        break;
2017:                    }
2018:                    case SYBSMALLMONEY:
2019:                    case SYBMONEY:
2020:                    case SYBMONEYN: {
2021:                        element = getMoneyValue(colType);
2022:                        break;
2023:                    }
2024:                    case SYBNUMERIC:
2025:                    case SYBDECIMAL: {
2026:                        element = getDecimalValue(columnsInfo.getScale(i));
2027:                        break;
2028:                    }
2029:                    case SYBDATETIME4:
2030:                    case SYBDATETIMN:
2031:                    case SYBDATETIME: {
2032:                        element = getDatetimeValue(colType);
2033:                        break;
2034:                    }
2035:                    case SYBVARBINARY:
2036:                    case SYBBINARY: {
2037:                        int len = tdsVer == Tds.TDS70 ? comm.getTdsShort()
2038:                                : (comm.getByte() & 0xff);
2039:                        if (tdsVer == Tds.TDS70 && len == 0xffff)
2040:                            element = null;
2041:                        else
2042:                            element = comm.getBytes(len);
2043:                        break;
2044:                    }
2045:                    case SYBBITN:
2046:                    case SYBBIT: {
2047:                        if (colType == SYBBITN && comm.getByte() == 0)
2048:                            element = null;
2049:                        else
2050:                            element = new Boolean((comm.getByte() != 0) ? true
2051:                                    : false);
2052:                        break;
2053:                    }
2054:                    default: {
2055:                        element = null;
2056:                        throw new TdsNotImplemented("Don't now how to handle "
2057:                                + "column type 0x"
2058:                                + Integer.toHexString(colType));
2059:                    }
2060:                    }
2061:                    result.setElementAt(element, i);
2062:                }
2063:
2064:                return result;
2065:            } // getRow()
2066:
2067:            private boolean createStoredProcedureNameTable() {
2068:                boolean result = false;
2069:                String sql = null;
2070:
2071:                try {
2072:                    java.sql.Statement stmt = connection.createStatement();
2073:
2074:                    // ignore any of the exceptions thrown because they either 
2075:                    // don't matter or they will make themselves known when we try 
2076:                    // to use the name generator stored procedure.
2077:                    try {
2078:                        sql = "" + "create table " + procNameTableName
2079:                                + "(                                       "
2080:                                + "     id        NUMERIC(10, 0) IDENTITY, "
2081:                                + "     session   int not null,            "
2082:                                + "     name      char(29) not null        "
2083:                                + ")                                       ";
2084:                        stmt.executeUpdate(sql);
2085:                    } catch (java.sql.SQLException e) {
2086:                        // don't care
2087:                    }
2088:
2089:                    try {
2090:                        sql = "" + "create procedure "
2091:                                + procNameGeneratorName
2092:                                + "        "
2093:                                + "as                                                    "
2094:                                + "begin tran                                            "
2095:                                + "insert into "
2096:                                + procNameTableName
2097:                                + "                 "
2098:                                + "    (session, name)                                   "
2099:                                + " values                                               "
2100:                                + "    (@@spid, '')                                      "
2101:                                + "                                                      "
2102:                                + "update "
2103:                                + procNameTableName
2104:                                + "                      "
2105:                                + "  set name=('"
2106:                                + user
2107:                                + ".jdbctmpsp' +                "
2108:                                + "            convert(varchar, @@IDENTITY))             "
2109:                                + "  where id = @@IDENTITY                               "
2110:                                + "                                                      "
2111:                                + "select name from "
2112:                                + procNameTableName
2113:                                + "            "
2114:                                + "   where id=@@IDENTITY                                "
2115:                                + "                                                      "
2116:                                + "commit tran                                           "
2117:                                + "";
2118:
2119:                        stmt.execute(sql);
2120:                        stmt.execute("sp_procxmode " + procNameGeneratorName
2121:                                + ", 'anymode' ");
2122:                    } catch (java.sql.SQLException e) {
2123:                        // don't care
2124:                    }
2125:
2126:                    stmt = null;
2127:                } catch (java.sql.SQLException e) {
2128:                    // don't care
2129:                }
2130:                return result;
2131:            }
2132:
2133:            private String generateUniqueProcName()
2134:                    throws java.sql.SQLException {
2135:                java.sql.Statement stmt = connection.createStatement();
2136:
2137:                boolean wasRs;
2138:
2139:                wasRs = stmt.execute("exec " + procNameGeneratorName);
2140:                if (!wasRs) {
2141:                    throw new java.sql.SQLException(
2142:                            "Confused.  Was expecting a result set.");
2143:                }
2144:
2145:                java.sql.ResultSet rs;
2146:                rs = stmt.getResultSet();
2147:                if (!rs.next()) {
2148:                    throw new java.sql.SQLException(
2149:                            "Couldn't get stored proc name");
2150:                }
2151:                return rs.getString(1);
2152:            }
2153:
2154:            /**
2155:             * Create a new and unique name for a store procedure.
2156:             *
2157:             * This routine will return a unique name for a stored procedure
2158:             * that will be associated with a PreparedStatement().
2159:             * <p>
2160:             * Since SQLServer supports temporary procedure names we can just 
2161:             * use UniqueId.getUniqueId() to generate a unique (for the connection)
2162:             * name.
2163:             * <p>
2164:             * Sybase does not support temporary procedure names so we will have 
2165:             * to have a per user table devoted to storing user specific stored 
2166:             * procedures.  The table name will be of the form 
2167:             * database.user.jdbc_temp_stored_proc_names.  The table will be defined
2168:             * as 
2169:             * <code>
2170:             * CREATE TABLE database.user.jdbc_temp_stored_proc_names (
2171:             *     id        NUMERIC(10, 0) IDENTITY;
2172:             *     session   int not null;
2173:             *     name      char(29)
2174:             * )
2175:             * <code>
2176:             * This routine will use that table to track names that are being 
2177:             * used.
2178:             */
2179:            public String getUniqueProcedureName() throws java.sql.SQLException {
2180:                String result = null;
2181:
2182:                if (serverType == SYBASE) {
2183:                    if (null == procNameTableName) {
2184:                        procNameTableName = database + "." + user
2185:                                + ".jdbc_temp_stored_proc_names";
2186:                        procNameGeneratorName = user
2187:                                + ".jdbc_gen_temp_sp_names";
2188:                    }
2189:
2190:                    // 
2191:                    // Attempt to create the table for the stored procedure names
2192:                    // If it already exists we'll get an error, but we don't care.
2193:                    // Also create a stored procedure for generating the unique 
2194:                    // names.
2195:                    // 
2196:                    haveProcNameTable = createStoredProcedureNameTable();
2197:
2198:                    result = generateUniqueProcName();
2199:                } else {
2200:                    result = "#jdbc#" + UniqueId.getUniqueId();
2201:                }
2202:                return result;
2203:            } // getUniqueProcedureName()
2204:
2205:            /**
2206:             *
2207:             */
2208:            synchronized public PacketResult submitProcedure(String sql,
2209:                    SQLWarningChain chain) throws SQLException {
2210:
2211:                PacketResult result = null;
2212:                PacketResult tmp = null;
2213:                boolean okay = true;
2214:                byte tmpByte;
2215:                SQLException exception = null;
2216:
2217:                try {
2218:                    executeQuery(sql, null, 0);
2219:
2220:                    tmpByte = (byte) (comm.peek() & 0xff);
2221:
2222:                    while (!((tmp = processSubPacket()) instanceof  PacketEndTokenResult)) {
2223:                        if (tmp instanceof  PacketErrorResult) {
2224:                            result = tmp;
2225:                            okay = false;
2226:                            // XXX I'm sure we need to do more here.
2227:
2228:                            //     how about throwing an Exception? --SB
2229:                            exception = ((PacketErrorResult) tmp).getMsg()
2230:                                    .toSQLException();
2231:                        } else if (tmp instanceof  PacketMsgResult) {
2232:                            chain.addOrReturn((PacketMsgResult) tmp);
2233:                        } else {
2234:                            throw new SQLException(
2235:                                    "Confused.  Was expecting the "
2236:                                            + "end of result, found a "
2237:                                            + tmp.getClass().getName());
2238:                        }
2239:                    }
2240:                    if (result == null) {
2241:                        result = tmp;
2242:                    }
2243:                } catch (java.io.IOException e) {
2244:                    throw new SQLException("Network error" + e.getMessage());
2245:                } catch (com.internetcds.jdbc.tds.TdsUnknownPacketSubType e) {
2246:                    throw new SQLException(e.getMessage());
2247:                } catch (com.internetcds.jdbc.tds.TdsException e) {
2248:                    throw new SQLException(e.getMessage());
2249:                }
2250:
2251:                if (!okay) {
2252:                    throw exception;
2253:                }
2254:                return result;
2255:            }
2256:
2257:            /**
2258:             * Execute a stored procedure on the SQLServer
2259:             * <p>
2260:             *
2261:             * @param procedure      the stored procedure to execute.
2262:             * @param parameterList  the parameter to pass to the stored procedure
2263:             *
2264:             * @exception java.sql.SQLException
2265:             * @exception com.internetcds.jdbc.tds.TdsException
2266:             */
2267:            synchronized public void executeProcedure(String procedureName,
2268:                    ParameterListItem[] formalParameterList,
2269:                    ParameterListItem[] actualParameterList,
2270:                    java.sql.Statement stmt, int timeout)
2271:                    throws java.sql.SQLException,
2272:                    com.internetcds.jdbc.tds.TdsException {
2273:
2274:                // A stored procedure has a packet type of 0x03 in the header packet.
2275:                // for non-image date the packets consists of
2276:                // offset         length        desc.
2277:                // 0                1           The length of the name of the stored proc
2278:                // 1                N1          The name of the stored proc
2279:                // N1 + 1           2           unknown (filled with zeros?)
2280:                // N1 + 3           2           unknown prefix for param 1 (zero filled?)
2281:                // N1 + 5           1           datatype for param 1
2282:                // N1 + 6           1           max length of param 1
2283:                // N1 + 7           N2          parameter 1 data
2284:                // ...
2285:                //
2286:                // For image data (datatype 0x22) the packet consists of
2287:                // 0                1           The length of the name of the stored proc
2288:                // 1                N1          The name of the stored proc
2289:                // N1 + 1           2           unknown (filled with zeros?)
2290:                // N1 + 3           2           unknown prefix for param 1 (zero filled?)
2291:                // N1 + 5           1           datatype for param 1
2292:                // N1 + 6           4           length of param 1
2293:                // N1 + 10          4           length of param 1 (duplicated?)
2294:                // N1 + 7           N2          parameter 1 data
2295:                // ...
2296:
2297:                int i;
2298:
2299:                try {
2300:                    // mark that we are performing a query
2301:                    cancelController.setQueryInProgressFlag();
2302:
2303:                    // Start sending the procedure execute packet.
2304:                    comm.startPacket(TdsComm.PROC);
2305:
2306:                    if (tdsVer == Tds.TDS70) {
2307:                        comm.appendTdsShort((short) (procedureName.length()));
2308:                        comm.appendChars(procedureName);
2309:                    } else {
2310:                        byte[] nameBytes = encoder.getBytes(procedureName);
2311:                        comm.appendByte((byte) nameBytes.length);
2312:                        comm.appendBytes(nameBytes, nameBytes.length, (byte) 0);
2313:                    }
2314:                    comm.appendByte((byte) 0);
2315:                    comm.appendByte((byte) 0);
2316:                    // Now handle the parameters
2317:                    for (i = 0; i < formalParameterList.length; i++) {
2318:                        byte nativeType = cvtJdbcTypeToNativeType(formalParameterList[i].type);
2319:
2320:                        comm.appendByte((byte) 0);
2321:                        comm.appendByte((byte) 0);
2322:
2323:                        switch (nativeType) {
2324:                        case SYBCHAR:
2325:                        case SYBVARCHAR: {
2326:                            String val = (String) actualParameterList[i].value;
2327:                            int len = val != null ? val.length() : 0;
2328:                            int max = formalParameterList[i].maxLength;
2329:                            //Sinisa
2330:                            //using actualParameters caused problems
2331:                            //                   if (actualParameterList[i].formalType.startsWith("n")) {
2332:                            if (formalParameterList[i].formalType
2333:                                    .startsWith("n")) {
2334:                                /*
2335:                                 * This is a Unicode column, save to assume TDS 7.0
2336:                                 */
2337:                                if (max > 4000) {
2338:                                    comm.appendByte(SYBNTEXT);
2339:                                    comm.appendTdsInt(max * 2);
2340:                                    if (val == null)
2341:                                        comm.appendTdsInt(0xFFFFFFFF);
2342:                                    else {
2343:                                        comm.appendTdsInt(len * 2);
2344:                                        comm.appendChars(val);
2345:                                    }
2346:                                } else {
2347:                                    comm
2348:                                            .appendByte((byte) (SYBNVARCHAR | 0x80));
2349:                                    comm.appendTdsShort((short) (max * 2));
2350:                                    if (val == null)
2351:                                        comm.appendTdsShort((short) 0xFFFF);
2352:                                    else {
2353:                                        comm.appendTdsShort((short) (len * 2));
2354:                                        comm.appendChars(val);
2355:                                    }
2356:                                }
2357:
2358:                            } else {
2359:                                /*
2360:                                 * Either VARCHAR or TEXT, TEXT can not happen 
2361:                                 * with TDS 7.0 as we would always use NTEXT there
2362:                                 */
2363:                                if (tdsVer != TDS70 && max > 255) {
2364:                                    // TEXT
2365:                                    comm.appendByte((byte) SYBTEXT);
2366:                                    sendSybImage(encoder
2367:                                            .getBytes((String) actualParameterList[i].value));
2368:                                } else {
2369:                                    // VARCHAR
2370:                                    sendSybChar(
2371:                                            ((String) actualParameterList[i].value),
2372:                                            formalParameterList[i].maxLength);
2373:                                }
2374:                            }
2375:                            break;
2376:
2377:                        }
2378:
2379:                        case SYBINT4:
2380:                        case SYBINTN: {
2381:                            if (nativeType == SYBINTN) {
2382:                                comm.appendByte(nativeType);
2383:                                // set the maximum length of the field,
2384:                                comm.appendByte((byte) 4);
2385:
2386:                                // set the actual length, and the data
2387:                                if (actualParameterList[i].value == null) {
2388:                                    comm.appendByte((byte) 0);
2389:                                    //                        comm.appendTdsInt((byte)0);
2390:                                } else {
2391:                                    comm.appendByte((byte) 4);
2392:                                    comm
2393:                                            .appendTdsInt(((Number) (actualParameterList[i].value))
2394:                                                    .intValue());
2395:                                }
2396:                            } else if (actualParameterList[i].value == null) {
2397:                                comm.appendByte(SYBINTN);
2398:                                comm.appendByte((byte) 4);
2399:                                comm.appendByte((byte) 0);
2400:                            } else {
2401:                                comm.appendByte(nativeType);
2402:                                comm
2403:                                        .appendTdsInt(((Number) (actualParameterList[i].value))
2404:                                                .intValue());
2405:                            }
2406:                            break;
2407:                        }
2408:                        case SYBFLT8: {
2409:                            //sinisa
2410:                            //Add possibility with NULL value as a SYBFLT8 parameter
2411:                            if (actualParameterList[i].value != null) {
2412:                                Number n = (Number) (actualParameterList[i].value);
2413:                                Double d = new Double(n.doubleValue());
2414:                                comm.appendByte((byte) nativeType);
2415:                                comm.appendFlt8(d);
2416:                            }
2417:                            //sinisa
2418:                            //If parameter value is NULL send INTEGER value for NULL value to database
2419:                            else {
2420:                                comm.appendByte(SYBINTN);
2421:                                comm.appendByte((byte) 4);
2422:                                comm.appendByte((byte) 0);
2423:                            }
2424:                            break;
2425:                        }
2426:                        case SYBDATETIMN: {
2427:                            comm.appendByte((byte) nativeType);
2428:
2429:                            comm.appendByte((byte) 8);
2430:                            if (actualParameterList[i].value == null) {
2431:                                comm.appendByte((byte) 0);
2432:                            } else {
2433:                                Timestamp value;
2434:                                if (actualParameterList[i].value instanceof  java.sql.Timestamp) {
2435:                                    value = (Timestamp) actualParameterList[i].value;
2436:                                } else {
2437:                                    value = new Timestamp(
2438:                                            ((java.util.Date) actualParameterList[i].value)
2439:                                                    .getTime());
2440:                                }
2441:
2442:                                comm.appendByte((byte) 8);
2443:
2444:                                final int secondsPerDay = 24 * 60 * 60;
2445:                                final int msPerDay = secondsPerDay * 1000;
2446:                                final int nsPerMs = 1000 * 1000;
2447:                                // epochsDifference is the number of days between unix
2448:                                // epoch (1970 based) and the sybase epoch (1900 based)
2449:                                final int epochsDifference = 25567;
2450:
2451:                                long nanoseconds = value.getNanos();
2452:
2453:                                // ms is the number of milliseconds into unix epoch
2454:
2455:                                long ms = ((value.getTime() + (nanoseconds / nsPerMs)) + zoneOffset);
2456:                                ms -= getDstOffset(ms);
2457:                                long msIntoCurrentDay = ms % msPerDay;
2458:
2459:                                long daysIntoUnixEpoch = (ms - msIntoCurrentDay)
2460:                                        / msPerDay;
2461:
2462:                                int jiffies = (int) ((msIntoCurrentDay * 300) / 1000);
2463:                                int daysIntoSybaseEpoch = (int) daysIntoUnixEpoch
2464:                                        + epochsDifference;
2465:
2466:                                comm.appendTdsInt(daysIntoSybaseEpoch);
2467:                                comm.appendTdsInt(jiffies);
2468:                            }
2469:                            break;
2470:                        }
2471:                        case SYBIMAGE: {
2472:                            comm.appendByte((byte) nativeType);
2473:
2474:                            sendSybImage((byte[]) actualParameterList[i].value);
2475:                            break;
2476:                        }
2477:                        case SYBTEXT: {
2478:                            comm.appendByte((byte) SYBTEXT);
2479:                            sendSybImage(encoder
2480:                                    .getBytes((String) actualParameterList[i].value));
2481:                            break;
2482:                        }
2483:                            //Sinisa 
2484:                            //Add implementation of SYBBIT native type
2485:
2486:                        case SYBBIT: {
2487:                            if (actualParameterList[i].value == null) {
2488:                                comm.appendByte(SYBINTN);
2489:                                comm.appendByte((byte) 1);
2490:                                comm.appendByte((byte) 0);
2491:                            } else {
2492:                                comm.appendByte(nativeType);
2493:                                if (((Byte) (actualParameterList[i].value))
2494:                                        .intValue() == 1)
2495:                                    comm.appendByte((byte) 1);
2496:                                else
2497:                                    comm.appendByte((byte) 0);
2498:                            }
2499:                            break;
2500:
2501:                            //                  comm.appendByte((byte)nativeType);
2502:                            //sendSybImage(byte[])actualParameterList[i].value);
2503:                            //                  sendSybChar(((String)actualParameterList[i].value),1);
2504:                            //                  break;
2505:
2506:                        }
2507:                        case SYBVOID:
2508:                        case SYBVARBINARY:
2509:                            //Sinisa
2510:                            //               case SYBVARCHAR:
2511:                        case SYBBINARY:
2512:                        case SYBINT1:
2513:                            //case SYBBIT:
2514:                        case SYBINT2:
2515:                        case SYBDATETIME4:
2516:                        case SYBREAL:
2517:                        case SYBMONEY:
2518:                        case SYBDATETIME:
2519:                        case SYBDECIMAL:
2520:                        case SYBNUMERIC:
2521:                        case SYBFLTN:
2522:                        case SYBMONEYN:
2523:                        case SYBMONEY4:
2524:                        default: {
2525:                            throw new SQLException(
2526:                                    "Not implemented for nativeType 0x"
2527:                                            + Integer.toHexString(nativeType));
2528:                        }
2529:                        }
2530:                    }
2531:                    //sinisa
2532:                    //			moreResults2=true;
2533:                    comm.sendPacket();
2534:                    waitForDataOrTimeout(stmt, timeout);
2535:                } catch (java.io.IOException e) {
2536:                    throw new SQLException("Network error-  " + e.getMessage());
2537:                }
2538:            } /* executeProcedure()  */
2539:
2540:            private void sendSybImage(byte[] value) throws java.io.IOException {
2541:                int i;
2542:                int length = (value == null ? 0 : value.length);
2543:
2544:                // send the lenght of this piece of data
2545:                comm.appendTdsInt(length);
2546:
2547:                // send the length of this piece of data again
2548:                comm.appendTdsInt(length);
2549:
2550:                // send the data
2551:                for (i = 0; i < length; i++) {
2552:                    comm.appendByte(value[i]);
2553:                }
2554:            }
2555:
2556:            private void sendSybChar(String value, int maxLength)
2557:                    throws java.io.IOException {
2558:
2559:                byte[] converted;
2560:                if (value == null) {
2561:                    converted = new byte[0];
2562:                } else {
2563:                    converted = encoder.getBytes(value);
2564:                }
2565:
2566:                if (converted.length > 255 && tdsVer != TDS70) {
2567:                    throw new java.io.IOException("String too long");
2568:                }
2569:
2570:                // set the type of the column
2571:                // set the maximum length of the field
2572:                // set the actual lenght of the field.
2573:                if (converted.length > 256) {
2574:                    comm.appendByte((byte) (SYBVARCHAR | 0x80));
2575:                    comm.appendTdsShort((short) (maxLength));
2576:                    comm.appendTdsShort((short) (converted.length));
2577:                } else {
2578:                    comm.appendByte(SYBVARCHAR);
2579:                    comm.appendByte((byte) (maxLength));
2580:                    comm.appendByte((byte) (converted.length));
2581:                }
2582:
2583:                comm.appendBytes(converted);
2584:            }
2585:
2586:            /**
2587:             * Process a login ack supacket
2588:             */
2589:            private PacketResult processLoginAck()
2590:                    throws com.internetcds.jdbc.tds.TdsException,
2591:                    java.io.IOException {
2592:                int len = getSubPacketLength();
2593:                int bytesRead = 0;
2594:
2595:                if (tdsVer == Tds.TDS70) {
2596:                    comm.skip(5);
2597:                    int nameLen = comm.getByte();
2598:                    databaseProductName = comm.getString(nameLen);
2599:                    databaseProductVersion = ("" + comm.getByte() + "."
2600:                            + comm.getByte() + "." + ((256 * comm.getByte()) + comm
2601:                            .getByte()));
2602:                } else {
2603:                    comm.skip(5);
2604:                    short nameLen = comm.getByte();
2605:                    databaseProductName = comm.getString(nameLen);
2606:                    comm.skip(1);
2607:                    databaseProductVersion = ("" + comm.getByte() + "." + comm
2608:                            .getByte());
2609:                    comm.skip(1);
2610:                }
2611:
2612:                if (databaseProductName.length() > 1
2613:                        && -1 != databaseProductName.indexOf('\0')) {
2614:                    int last = databaseProductName.indexOf('\0');
2615:                    databaseProductName = databaseProductName
2616:                            .substring(0, last);
2617:                }
2618:
2619:                return new PacketResult(TDS_LOGIN_ACK_TOKEN);
2620:            }
2621:
2622:            /**
2623:             * Process an proc id subpacket.
2624:             * <p>
2625:             * This routine assumes that the TDS_PROCID byte has already
2626:             * been read.
2627:             *
2628:             * @exception com.internetcds.jdbc.tds.TdsException
2629:             *
2630:             * @exception java.io.IOException
2631:             * Thrown if some sort of error occured reading bytes from the network.
2632:             */
2633:            private PacketResult processProcId() throws java.io.IOException,
2634:                    com.internetcds.jdbc.tds.TdsException {
2635:                // XXX Try to find out what meaning this subpacket has.
2636:                int i;
2637:                byte tmp;
2638:
2639:                for (i = 0; i < 8; i++) {
2640:                    tmp = comm.getByte();
2641:                }
2642:                return new PacketResult(TDS_PROCID);
2643:            }
2644:
2645:            /**
2646:             * Process a TDS_RET_STAT_TOKEN subpacket.
2647:             * <p>
2648:             * This routine assumes that the TDS_RET_STAT_TOKEN
2649:             * byte has already been read.
2650:             *
2651:             * @exception com.internetcds.jdbc.tds.TdsException
2652:             *
2653:             * @exception java.io.IOException
2654:             * Thrown if some sort of error occured reading bytes from the network.
2655:             */
2656:            private PacketRetStatResult processRetStat()
2657:                    throws java.io.IOException,
2658:                    com.internetcds.jdbc.tds.TdsException {
2659:                // XXX Not completely sure of this.
2660:                return new PacketRetStatResult(comm.getTdsInt());
2661:            }
2662:
2663:            /**
2664:             * Processes a TDS 7.0-style result packet, extracting column information
2665:             * for the result set.
2666:             *
2667:             * Added 2000-06-05.
2668:             */
2669:            private PacketResult processTds7Result()
2670:                    throws java.io.IOException,
2671:                    com.internetcds.jdbc.tds.TdsException {
2672:                int numColumns = comm.getTdsShort();
2673:                Columns columns = new Columns();
2674:
2675:                //try {
2676:                //throw new Exception();
2677:                //}
2678:                //catch (Exception e) {
2679:                //e.printStackTrace();
2680:                //}
2681:                for (int colNum = 1; colNum <= numColumns; ++colNum) {
2682:
2683:                    /*
2684:                     * The freetds C code didn't know what to do with these four
2685:                     * bytes, but initial inspection appears to tentatively confirm
2686:                     * that they serve the same purpose as the flag bytes read by the 
2687:                     * Java code for 4.2 column information.
2688:                     */
2689:                    byte flagData[] = new byte[4];
2690:                    for (int i = 0; i < 4; i++)
2691:                        flagData[i] = comm.getByte();
2692:                    boolean nullable = (flagData[2] & 0x01) > 0;
2693:                    boolean writeable = (flagData[2] & 0x08) > 0;
2694:                    boolean autoIncrement = (flagData[2] & 0x10) > 0;
2695:
2696:                    /*
2697:                     * Get the type of column.  Large types have 2-byte size fields and
2698:                     * type codes OR'd with 0x80.  Except SYBNCHAR, whose type code
2699:                     * is already above 0x80.
2700:                     */
2701:                    int columnType = comm.getByte() & 0xFF;
2702:                    if (columnType == 0xEF)
2703:                        columnType = SYBNCHAR;
2704:                    int xColType = -1;
2705:                    if (isLargeType(columnType)) {
2706:                        xColType = columnType;
2707:                        if (columnType != SYBNCHAR)
2708:                            columnType -= 128;
2709:                    }
2710:                    // Determine the column size.
2711:                    int colSize;
2712:                    if (isBlobType(columnType)) {
2713:
2714:                        // Text and image columns have 4-byte size fields.
2715:                        colSize = comm.getTdsInt();
2716:
2717:                        // Swallow table name.
2718:                        comm.getString(comm.getTdsShort());
2719:                    }
2720:
2721:                    // Fixed types have no size field in the packet.
2722:                    else if (isFixedSizeColumn((byte) columnType))
2723:                        colSize = lookupColumnSize((byte) columnType);
2724:
2725:                    else if (isLargeType(xColType))
2726:                        colSize = comm.getTdsShort();
2727:
2728:                    else
2729:                        colSize = comm.getByte();
2730:
2731:                    // Get precision, scale for decimal types.
2732:                    int precision = -1;
2733:                    int scale = -1;
2734:                    if (columnType == SYBDECIMAL || columnType == SYBNUMERIC) {
2735:                        precision = comm.getByte();
2736:                        scale = comm.getByte();
2737:                    }
2738:
2739:                    /*
2740:                     * NB: under 7.0 lengths are number of characters, not number of
2741:                     * bytes.  The getString() method handles this.
2742:                     */
2743:                    int colNameLen = comm.getByte();
2744:                    String columnName = comm.getString(colNameLen);
2745:
2746:                    // Populate the Column object.
2747:                    columns.setType(colNum, columnType);
2748:                    columns.setName(colNum, columnName);
2749:                    columns.setLabel(colNum, columnName);
2750:                    columns.setDisplaySize(colNum, colSize);
2751:                    columns.setNullable(colNum,
2752:                            (nullable ? ResultSetMetaData.columnNullable
2753:                                    : ResultSetMetaData.columnNoNulls));
2754:                    columns.setAutoIncrement(colNum, autoIncrement);
2755:                    columns.setReadOnly(colNum, !writeable);
2756:                    if (precision != -1)
2757:                        columns.setPrecision(colNum, precision);
2758:                    if (scale != -1)
2759:                        columns.setScale(colNum, scale);
2760:                }
2761:                return new PacketColumnNamesResult(columns);
2762:
2763:            } // processTds7Result()
2764:
2765:            /**
2766:             * Reports whether the type is for a large object.  Name is a bit of a
2767:             * misnomer, since it returns true for large text types, not just binary
2768:             * objects (took it over from the freetds C code).
2769:             */
2770:            private static boolean isBlobType(int type) {
2771:                return type == SYBTEXT || type == SYBIMAGE || type == SYBNTEXT;
2772:            }
2773:
2774:            /**
2775:             * Reports whether the type uses a 2-byte size value.
2776:             */
2777:            private static boolean isLargeType(int type) {
2778:                return type == SYBNCHAR || type > 128;
2779:            }
2780:
2781:            private void waitForDataOrTimeout(java.sql.Statement stmt,
2782:                    int timeout) throws java.io.IOException,
2783:                    com.internetcds.jdbc.tds.TdsException {
2784:
2785:                // XXX How should this be syncrhonized?
2786:                if (timeout == 0 || stmt == null) {
2787:                    comm.peek();
2788:                } else {
2789:                    // start the timeout thread
2790:                    TimeoutHandler t = new TimeoutHandler(stmt, timeout);
2791:
2792:                    t.start();
2793:
2794:                    // wait until there is at least one byte of data
2795:                    comm.peek();
2796:
2797:                    // kill the timeout thread
2798:                    t.stop();
2799:                    t = null;
2800:                }
2801:            }
2802:
2803:            /**
2804:             * send a query to the SQLServer for execution.
2805:             * <p>
2806:             *
2807:             * @param sql  sql statement to execute.
2808:             * @param stmt
2809:             * @param timeout
2810:             *
2811:             * @exception com.internetcds.jdbc.tds.TdsException
2812:             * @exception java.io.IOException
2813:             */
2814:            synchronized public void executeQuery(String sql,
2815:                    java.sql.Statement stmt, int timeout)
2816:                    throws java.io.IOException, java.sql.SQLException,
2817:                    TdsException {
2818:                {
2819:                    cancelController.setQueryInProgressFlag();
2820:                    comm.startPacket(TdsComm.QUERY);
2821:
2822:                    if (tdsVer == Tds.TDS70) {
2823:                        comm.appendChars(sql);
2824:                    } else {
2825:                        byte[] sqlBytes = encoder.getBytes(sql);
2826:                        comm.appendBytes(sqlBytes, sqlBytes.length, (byte) 0);
2827:                    }
2828:                    moreResults2 = true; //JJ 1999-01-10
2829:                    comm.sendPacket();
2830:
2831:                    waitForDataOrTimeout(stmt, timeout);
2832:                }
2833:            }
2834:
2835:            /**
2836:             * skip over and discard any remaining data from a result set.
2837:             *
2838:             * @exception com.internetcds.jdbc.tds.TdsException
2839:             * @exception java.io.IOException
2840:             */
2841:            synchronized public void discardResultSet(Columns columnsInfo)
2842:                    throws java.io.IOException,
2843:                    com.internetcds.jdbc.tds.TdsException {
2844:                while (isResultRow()) {
2845:                    if (columnsInfo == null) {
2846:                        throw new com.internetcds.jdbc.tds.TdsConfused();
2847:                    }
2848:                    comm.skip(1);
2849:                    getRow(columnsInfo);
2850:                }
2851:
2852:                if (comm.peek() == TDS_DONEINPROC) {
2853:                    PacketResult tmp = processSubPacket();
2854:                }
2855:
2856:                // XXX Is there ever going to be a situation where the
2857:                // TDS_DONEINPROC is the real end of data?  If so then the
2858:                // next section of code will hang forever waiting for more data
2859:                // from the socket.
2860:                if (isEndOfResults()) {
2861:                    processSubPacket();
2862:                }
2863:
2864:                // RMK 2000-06-08 Don't choke on additional result sets.
2865:                else if (!isResultSet()) {
2866:                    throw new TdsConfused(
2867:                            "Was expecting an end of results token.  "
2868:                                    + "Found a 0x"
2869:                                    + Integer.toHexString(comm.peek() & 0xff));
2870:                }
2871:            }
2872:
2873:            synchronized public byte peek() throws java.io.IOException,
2874:                    com.internetcds.jdbc.tds.TdsException {
2875:                return comm.peek();
2876:            } // peek()
2877:
2878:            /**
2879:             * Determine if the next subpacket is a result set.
2880:             * <p>
2881:             * This does not eat any input.
2882:             *
2883:             * @return true if the next piece of data to read is a result set.
2884:             *
2885:             * @exception com.internetcds.jdbc.tds.TdsException
2886:             * @exception java.io.IOException
2887:             */
2888:            synchronized public boolean isResultSet()
2889:                    throws com.internetcds.jdbc.tds.TdsException,
2890:                    java.io.IOException {
2891:                byte type = comm.peek();
2892:
2893:                /*
2894:                 * XXX to support 5.0 we need to expand our view of what a result
2895:                 * set is.
2896:                 */
2897:                return type == TDS_COL_NAME_TOKEN || type == TDS7_RESULT_TOKEN;
2898:            }
2899:
2900:            /**
2901:             * Determine if the next subpacket is a ret stat
2902:             * <p>
2903:             * This does not eat any input.
2904:             *
2905:             * @return true if the next piece of data to read is a result row.
2906:             *
2907:             * @exception com.internetcds.jdbc.tds.TdsException
2908:             * @exception java.io.IOException
2909:             */
2910:            synchronized public boolean isRetStat()
2911:                    throws com.internetcds.jdbc.tds.TdsException,
2912:                    java.io.IOException {
2913:                byte type = comm.peek();
2914:
2915:                return type == TDS_RET_STAT_TOKEN;
2916:            }
2917:
2918:            /**
2919:             * Determine if the next subpacket is a result row.
2920:             * <p>
2921:             * This does not eat any input.
2922:             *
2923:             * @return true if the next piece of data to read is a result row.
2924:             *
2925:             * @exception com.internetcds.jdbc.tds.TdsException
2926:             * @exception java.io.IOException
2927:             */
2928:            synchronized public boolean isResultRow()
2929:                    throws com.internetcds.jdbc.tds.TdsException,
2930:                    java.io.IOException {
2931:                byte type = comm.peek();
2932:
2933:                return type == TDS_ROW_TOKEN;
2934:            }
2935:
2936:            /**
2937:             * Determine if the next subpacket is an end of result set marker.
2938:             * <p>
2939:             * This does not eat any input.
2940:             *
2941:             * @return true if the next piece of data to read is end of result set
2942:             * marker.
2943:             *
2944:             * @exception com.internetcds.jdbc.tds.TdsException
2945:             * @exception java.io.IOException
2946:             */
2947:            synchronized public boolean isEndOfResults()
2948:                    throws com.internetcds.jdbc.tds.TdsException,
2949:                    java.io.IOException {
2950:                byte type = comm.peek();
2951:
2952:                return type == TDS_END_TOKEN || type == TDS_DONEPROC;
2953:            }
2954:
2955:            /**
2956:             * Determine if the next subpacket is a DONEINPROC marker
2957:             * <p>
2958:             * This does not eat any input.
2959:             *
2960:             * @return
2961:             *
2962:             * @exception com.internetcds.jdbc.tds.TdsException
2963:             * @exception java.io.IOException
2964:             */
2965:            synchronized public boolean isDoneInProc()
2966:                    throws com.internetcds.jdbc.tds.TdsException,
2967:                    java.io.IOException {
2968:                byte type = comm.peek();
2969:
2970:                return type == TDS_DONEINPROC;
2971:            }
2972:
2973:            /**
2974:             * Determine if the next subpacket is a message packet
2975:             * <p>
2976:             * This does not eat any input.
2977:             *
2978:             * @return true if the next piece of data to read is message
2979:             *
2980:             * @exception com.internetcds.jdbc.tds.TdsException
2981:             * @exception java.io.IOException
2982:             */
2983:            synchronized public boolean isMessagePacket()
2984:                    throws com.internetcds.jdbc.tds.TdsException,
2985:                    java.io.IOException {
2986:                byte type = comm.peek();
2987:                return type == TDS_MSG_TOKEN;
2988:            }
2989:
2990:            /**
2991:             * Determine if the next subpacket is a text update packet
2992:             * <p>
2993:             * This does not eat any input.
2994:             *
2995:             * @return true if the next piece of data to read is text update
2996:             *
2997:             * @exception com.internetcds.jdbc.tds.TdsException
2998:             * @exception java.io.IOException
2999:             */
3000:            synchronized public boolean isTextUpdate()
3001:                    throws com.internetcds.jdbc.tds.TdsException,
3002:                    java.io.IOException {
3003:                byte type = comm.peek();
3004:                return type == TDS_TEXT_UPD_TOKEN;
3005:            }
3006:
3007:            /**
3008:             * Determine if the next subpacket is an error packet
3009:             * <p>
3010:             * This does not eat any input.
3011:             *
3012:             * @return true if the next piece of data to read is an error
3013:             *
3014:             * @exception com.internetcds.jdbc.tds.TdsException
3015:             * @exception java.io.IOException
3016:             */
3017:            synchronized public boolean isErrorPacket()
3018:                    throws com.internetcds.jdbc.tds.TdsException,
3019:                    java.io.IOException {
3020:                byte type = comm.peek();
3021:                return type == TDS_ERR_TOKEN;
3022:            }
3023:
3024:            //sinisa
3025:            /**
3026:             * Determine if the next subpacket is an return status packet
3027:             * <p>
3028:             * This does not eat any input.
3029:             *
3030:             * @return true if the next piece of data to read is an return status
3031:             *
3032:             * @exception com.internetcds.jdbc.tds.TdsException
3033:             * @exception java.io.IOException
3034:             */
3035:            synchronized public boolean isReturnStatus()
3036:                    throws com.internetcds.jdbc.tds.TdsException,
3037:                    java.io.IOException {
3038:                byte type = comm.peek();
3039:                return type == TDS_RET_STAT_TOKEN;
3040:            }
3041:
3042:            /**
3043:             * Determine if the next subpacket is an procid subpacket
3044:             * <p>
3045:             * This does not eat any input.
3046:             *
3047:             * @return true if the next piece of data to read is end of result set
3048:             * marker.
3049:             *
3050:             * @exception com.internetcds.jdbc.tds.TdsException
3051:             * @exception java.io.IOException
3052:             */
3053:            synchronized public boolean isProcId()
3054:                    throws com.internetcds.jdbc.tds.TdsException,
3055:                    java.io.IOException {
3056:
3057:                byte type = comm.peek();
3058:                return type == TDS_PROCID;
3059:            }
3060:
3061:            /**
3062:             * Accessor method to determine the TDS level used.
3063:             *
3064:             * @return TDS42, TDS50, or TDS70.
3065:             */
3066:            int getTdsVer() {
3067:                return tdsVer;
3068:            }
3069:
3070:            /**
3071:             * Return the name that this database server program calls itself.
3072:             */
3073:            String getDatabaseProductName() {
3074:                return databaseProductName;
3075:            }
3076:
3077:            /**
3078:             * Return the name that this database server program calls itself.
3079:             */
3080:            String getDatabaseProductVersion() {
3081:                return databaseProductVersion;
3082:            }
3083:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.