Source Code Cross Referenced for DRDAConnThread.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » drda » 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 DBMS » db derby 10.2 » org.apache.derby.impl.drda 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:            Derby - Class org.apache.derby.impl.drda.DRDAConnThread
0003:
0004:           Licensed to the Apache Software Foundation (ASF) under one or more
0005:           contributor license agreements.  See the NOTICE file distributed with
0006:           this work for additional information regarding copyright ownership.
0007:           The ASF licenses this file to You under the Apache License, Version 2.0
0008:           (the "License"); you may not use this file except in compliance with
0009:           the License.  You may obtain a copy of the License at
0010:
0011:              http://www.apache.org/licenses/LICENSE-2.0
0012:
0013:           Unless required by applicable law or agreed to in writing, software
0014:           distributed under the License is distributed on an "AS IS" BASIS,
0015:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016:           See the License for the specific language governing permissions and
0017:           limitations under the License.
0018:
0019:         */
0020:        /**
0021:         * This class translates DRDA protocol from an application requester to JDBC
0022:         * for Cloudscape and then translates the results from Cloudscape to DRDA
0023:         * for return to the application requester.
0024:         * @author ge, marsden, peachey
0025:         */package org.apache.derby.impl.drda;
0026:
0027:        import java.io.ByteArrayInputStream;
0028:        import java.io.IOException;
0029:        import java.io.InputStream;
0030:        import java.io.OutputStream;
0031:        import java.io.IOException;
0032:        import java.io.UnsupportedEncodingException;
0033:        import java.math.BigDecimal;
0034:        import java.sql.CallableStatement;
0035:        import java.sql.Connection;
0036:        import java.sql.Driver;
0037:        import java.sql.PreparedStatement;
0038:        import java.sql.ResultSet;
0039:        import java.sql.ResultSetMetaData;
0040:        import java.sql.SQLException;
0041:        import java.sql.SQLWarning;
0042:        import java.sql.Statement;
0043:        import java.sql.Types;
0044:        import java.util.ArrayList;
0045:        import java.util.Date;
0046:        import java.util.Properties;
0047:        import java.util.Vector;
0048:
0049:        import org.apache.derby.catalog.SystemProcedures;
0050:        import org.apache.derby.iapi.error.ExceptionSeverity;
0051:        import org.apache.derby.iapi.reference.Attribute;
0052:        import org.apache.derby.iapi.reference.DRDAConstants;
0053:        import org.apache.derby.iapi.reference.JDBC30Translation;
0054:        import org.apache.derby.iapi.reference.Property;
0055:        import org.apache.derby.iapi.reference.SQLState;
0056:        import org.apache.derby.iapi.services.info.JVMInfo;
0057:        import org.apache.derby.iapi.services.monitor.Monitor;
0058:        import org.apache.derby.iapi.services.sanity.SanityManager;
0059:        import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
0060:        import org.apache.derby.iapi.tools.i18n.LocalizedResource;
0061:        import org.apache.derby.iapi.jdbc.AuthenticationService;
0062:        import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
0063:        import org.apache.derby.impl.jdbc.EmbedSQLException;
0064:        import org.apache.derby.impl.jdbc.Util;
0065:        import org.apache.derby.jdbc.InternalDriver;
0066:
0067:        class DRDAConnThread extends Thread {
0068:
0069:            private static final String leftBrace = "{";
0070:            private static final String rightBrace = "}";
0071:            private static final byte NULL_VALUE = (byte) 0xff;
0072:            private static final String SYNTAX_ERR = "42X01";
0073:
0074:            // Manager Level 3 constant.
0075:            private static final int MGRLVL_3 = 0x03;
0076:
0077:            // Manager Level 4 constant.
0078:            private static final int MGRLVL_4 = 0x04;
0079:
0080:            // Manager Level 5 constant.
0081:            private static final int MGRLVL_5 = 0x05;
0082:
0083:            // Manager level 6 constant.
0084:            private static final int MGRLVL_6 = 0x06;
0085:
0086:            // Manager Level 7 constant.
0087:            private static final int MGRLVL_7 = 0x07;
0088:
0089:            // Commit or rollback UOWDSP values
0090:            private static final int COMMIT = 1;
0091:            private static final int ROLLBACK = 2;
0092:
0093:            protected CcsidManager ccsidManager = new EbcdicCcsidManager();
0094:            private int correlationID;
0095:            private InputStream sockis;
0096:            private OutputStream sockos;
0097:            private DDMReader reader;
0098:            private DDMWriter writer;
0099:            private DRDAXAProtocol xaProto;
0100:
0101:            private static int[] ACCRDB_REQUIRED = { CodePoint.RDBACCCL,
0102:                    CodePoint.CRRTKN, CodePoint.PRDID, CodePoint.TYPDEFNAM,
0103:                    CodePoint.TYPDEFOVR };
0104:
0105:            private static int MAX_REQUIRED_LEN = 5;
0106:
0107:            private int currentRequiredLength = 0;
0108:            private int[] required = new int[MAX_REQUIRED_LEN];
0109:
0110:            private NetworkServerControlImpl server; // server who created me
0111:            private Session session; // information about the session
0112:            private long timeSlice; // time slice for this thread
0113:            private Object timeSliceSync = new Object(); // sync object for updating time slice 
0114:            private boolean logConnections; // log connections to databases
0115:
0116:            private boolean sendWarningsOnCNTQRY = false; // Send Warnings for SELECT if true
0117:            private Object logConnectionsSync = new Object(); // sync object for log connect
0118:            private boolean close; // end this thread
0119:            private Object closeSync = new Object(); // sync object for parent to close us down
0120:            private static HeaderPrintWriter logStream;
0121:            private AppRequester appRequester; // pointer to the application requester
0122:            // for the session being serviced
0123:            private Database database; // pointer to the current database
0124:            private int sqlamLevel; // SQLAM Level - determines protocol
0125:
0126:            // DRDA diagnostic level, DIAGLVL0 by default 
0127:            private byte diagnosticLevel = (byte) 0xF0;
0128:
0129:            // manager processing
0130:            private Vector unknownManagers;
0131:            private Vector knownManagers;
0132:            private Vector errorManagers;
0133:            private Vector errorManagersLevel;
0134:
0135:            // database accessed failed
0136:            private SQLException databaseAccessException;
0137:
0138:            // these fields are needed to feed back to jcc about a statement/procedure's PKGNAMCSN
0139:            /** The value returned by the previous call to
0140:             * <code>parsePKGNAMCSN()</code>. */
0141:            private Pkgnamcsn prevPkgnamcsn = null;
0142:            /** Current RDB Package Name. */
0143:            private DRDAString rdbnam = new DRDAString(ccsidManager);
0144:            /** Current RDB Collection Identifier. */
0145:            private DRDAString rdbcolid = new DRDAString(ccsidManager);
0146:            /** Current RDB Package Identifier. */
0147:            private DRDAString pkgid = new DRDAString(ccsidManager);
0148:            /** Current RDB Package Consistency Token. */
0149:            private DRDAString pkgcnstkn = new DRDAString(ccsidManager);
0150:            /** Current RDB Package Section Number. */
0151:            private int pkgsn;
0152:
0153:            private final static String TIMEOUT_STATEMENT = "SET STATEMENT_TIMEOUT ";
0154:
0155:            private int pendingStatementTimeout; // < 0 means no pending timeout to set
0156:
0157:            // this flag is for an execute statement/procedure which actually returns a result set;
0158:            // do not commit the statement, otherwise result set is closed
0159:
0160:            // for decryption
0161:            private static DecryptionManager decryptionManager;
0162:
0163:            // public key generated by Deffie-Hellman algorithm, to be passed to the encrypter,
0164:            // as well as used to initialize the cipher
0165:            private byte[] myPublicKey;
0166:
0167:            // generated target seed to be used to generate the password substitute
0168:            // as part of SECMEC_USRSSBPWD security mechanism
0169:            private byte[] myTargetSeed;
0170:
0171:            // Some byte[] constants that are frequently written into messages. It is more efficient to 
0172:            // use these constants than to convert from a String each time 
0173:            // (This replaces the qryscraft_ and notQryscraft_ static exception objects.)
0174:            private static final byte[] eod00000 = { '0', '0', '0', '0', '0' };
0175:            private static final byte[] eod02000 = { '0', '2', '0', '0', '0' };
0176:            private static final byte[] nullSQLState = { ' ', ' ', ' ', ' ',
0177:                    ' ' };
0178:            private static final byte[] errD4_D6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
0179:                    0, 0, 0 }; // 12x0 
0180:            private static final byte[] warn0_warnA = { ' ', ' ', ' ', ' ',
0181:                    ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; // 11x ' '
0182:
0183:            private final static String AUTHENTICATION_PROVIDER_BUILTIN_CLASS = "org.apache.derby.impl.jdbc.authentication.BasicAuthenticationServiceImpl";
0184:
0185:            private final static String AUTHENTICATION_PROVIDER_NONE_CLASS = "org.apache.derby.impl.jdbc.authentication.NoneAuthenticationServiceImpl";
0186:
0187:            // Work around a classloader bug involving interrupt handling during
0188:            // class loading. If the first request to load the
0189:            // DRDAProtocolExceptionInfo class occurs during shutdown, the
0190:            // loading of the class may be aborted when the Network Server calls
0191:            // Thread.interrupt() on the DRDAConnThread. By including a static
0192:            // reference to the DRDAProtocolExceptionInfo class here, we ensure
0193:            // that it is loaded as soon as the DRDAConnThread class is loaded,
0194:            // and therefore we know we won't be trying to load the class during
0195:            // shutdown. See DERBY-1338 for more background, including pointers
0196:            // to the apparent classloader bug in the JVM.
0197:            private static final DRDAProtocolExceptionInfo dummy = new DRDAProtocolExceptionInfo(
0198:                    0, 0, 0, false);
0199:
0200:            // constructor
0201:            /**
0202:             * Create a new Thread for processing session requests
0203:             *
0204:             * @param session Session requesting processing
0205:             * @param server  Server starting thread
0206:             * @param timeSlice timeSlice for thread
0207:             * @param logConnections
0208:             **/
0209:
0210:            DRDAConnThread(Session session, NetworkServerControlImpl server,
0211:                    long timeSlice, boolean logConnections) {
0212:
0213:                super ();
0214:
0215:                // Create a more meaningful name for this thread (but preserve its
0216:                // thread id from the default name).
0217:                NetworkServerControlImpl.setUniqueThreadName(this ,
0218:                        "DRDAConnThread");
0219:
0220:                this .session = session;
0221:                this .server = server;
0222:                this .timeSlice = timeSlice;
0223:                this .logConnections = logConnections;
0224:                this .pendingStatementTimeout = -1;
0225:                initialize();
0226:            }
0227:
0228:            /**
0229:             * Main routine for thread, loops until the thread is closed
0230:             * Gets a session, does work for the session
0231:             */
0232:            public void run() {
0233:                if (SanityManager.DEBUG)
0234:                    trace("Starting new connection thread");
0235:
0236:                Session prevSession;
0237:                while (!closed()) {
0238:
0239:                    // get a new session
0240:                    prevSession = session;
0241:                    session = server.getNextSession(session);
0242:                    if (session == null)
0243:                        close();
0244:
0245:                    if (closed())
0246:                        break;
0247:                    if (session != prevSession) {
0248:                        initializeForSession();
0249:                    }
0250:                    try {
0251:                        long timeStart = System.currentTimeMillis();
0252:
0253:                        switch (session.state) {
0254:                        case Session.INIT:
0255:                            sessionInitialState();
0256:                            if (session == null)
0257:                                break;
0258:                            // else fallthrough
0259:                        case Session.ATTEXC:
0260:                        case Session.SECACC:
0261:                        case Session.CHKSEC:
0262:                            long currentTimeSlice;
0263:
0264:                            do {
0265:                                processCommands();
0266:                                currentTimeSlice = getTimeSlice();
0267:                            } while ((currentTimeSlice == 0)
0268:                                    || (System.currentTimeMillis() - timeStart < currentTimeSlice));
0269:
0270:                            break;
0271:                        default:
0272:                            // this is an error
0273:                            agentError("Session in invalid state:"
0274:                                    + session.state);
0275:                        }
0276:                    } catch (Exception e) {
0277:                        if (e instanceof  DRDAProtocolException
0278:                                && ((DRDAProtocolException) e)
0279:                                        .isDisconnectException()) {
0280:                            // client went away - this is O.K. here
0281:                            closeSession();
0282:                        } else {
0283:                            handleException(e);
0284:                        }
0285:                    }
0286:                }
0287:                if (SanityManager.DEBUG)
0288:                    trace("Ending connection thread");
0289:                server.removeThread(this );
0290:
0291:            }
0292:
0293:            /**
0294:             * Get input stream
0295:             *
0296:             * @return input stream
0297:             */
0298:            protected InputStream getInputStream() {
0299:                return sockis;
0300:            }
0301:
0302:            /**
0303:             * Get output stream
0304:             *
0305:             * @return output stream
0306:             */
0307:            protected OutputStream getOutputStream() {
0308:                return sockos;
0309:            }
0310:
0311:            /**
0312:             *  get DDMReader
0313:             * @return DDMReader for this thread
0314:             */
0315:            protected DDMReader getReader() {
0316:                return reader;
0317:            }
0318:
0319:            /** 
0320:             * get  DDMWriter 
0321:             * @return DDMWriter for this thread
0322:             */
0323:            protected DDMWriter getWriter() {
0324:                return writer;
0325:            }
0326:
0327:            /**
0328:             * Get correlation id
0329:             *
0330:             * @return correlation id
0331:             */
0332:            protected int getCorrelationID() {
0333:                return correlationID;
0334:            }
0335:
0336:            /**
0337:             * Get session we are working on
0338:             *
0339:             * @return session
0340:             */
0341:            protected Session getSession() {
0342:                return session;
0343:            }
0344:
0345:            /**
0346:             * Get Database we are working on
0347:             *
0348:             * @return database
0349:             */
0350:            protected Database getDatabase() {
0351:                return database;
0352:            }
0353:
0354:            /**
0355:             * Get server
0356:             *
0357:             * @return server
0358:             */
0359:            protected NetworkServerControlImpl getServer() {
0360:                return server;
0361:            }
0362:
0363:            /**
0364:             * Get correlation token
0365:             *
0366:             * @return crrtkn
0367:             */
0368:            protected byte[] getCrrtkn() {
0369:                if (database != null)
0370:                    return database.crrtkn;
0371:                return null;
0372:            }
0373:
0374:            /**
0375:             * Get database name
0376:             *
0377:             * @return database name
0378:             */
0379:            protected String getDbName() {
0380:                if (database != null)
0381:                    return database.dbName;
0382:                return null;
0383:            }
0384:
0385:            /**
0386:             * Close DRDA  connection thread
0387:             */
0388:            protected void close() {
0389:                synchronized (closeSync) {
0390:                    close = true;
0391:                }
0392:            }
0393:
0394:            /**
0395:             * Set logging of connections
0396:             * 
0397:             * @param value value to set for logging connections
0398:             */
0399:            protected void setLogConnections(boolean value) {
0400:                synchronized (logConnectionsSync) {
0401:                    logConnections = value;
0402:                }
0403:            }
0404:
0405:            /**
0406:             * Set time slice value
0407:             *
0408:             * @param value new value for time slice
0409:             */
0410:            protected void setTimeSlice(long value) {
0411:                synchronized (timeSliceSync) {
0412:                    timeSlice = value;
0413:                }
0414:            }
0415:
0416:            /**
0417:             * Indicate a communications failure
0418:             * 
0419:             * @param arg1 - info about the communications failure
0420:             * @param arg2 - info about the communications failure
0421:             * @param arg3 - info about the communications failure
0422:             * @param arg4 - info about the communications failure
0423:             *
0424:             * @exception DRDAProtocolException  disconnect exception always thrown
0425:             */
0426:            protected void markCommunicationsFailure(String arg1, String arg2,
0427:                    String arg3, String arg4) throws DRDAProtocolException {
0428:                Object[] oa = { arg1, arg2, arg3, arg4 };
0429:                throw DRDAProtocolException.newDisconnectException(this , oa);
0430:
0431:            }
0432:
0433:            /**
0434:             * Syntax error
0435:             *
0436:             * @param errcd		Error code
0437:             * @param cpArg  code point value
0438:             * @exception DRDAProtocolException
0439:             */
0440:
0441:            protected void throwSyntaxrm(int errcd, int cpArg)
0442:                    throws DRDAProtocolException {
0443:                throw new DRDAProtocolException(
0444:                        DRDAProtocolException.DRDA_Proto_SYNTAXRM, this , cpArg,
0445:                        errcd);
0446:            }
0447:
0448:            /**
0449:             * Agent error - something very bad happened
0450:             *
0451:             * @param msg	Message describing error
0452:             *
0453:             * @exception DRDAProtocolException  newAgentError always thrown
0454:             */
0455:            protected void agentError(String msg) throws DRDAProtocolException {
0456:
0457:                String dbname = null;
0458:                if (database != null)
0459:                    dbname = database.dbName;
0460:                throw DRDAProtocolException.newAgentError(this ,
0461:                        CodePoint.SVRCOD_PRMDMG, dbname, msg);
0462:            }
0463:
0464:            /**
0465:             * Missing code point
0466:             *
0467:             * @param codePoint  code point value
0468:             * @exception DRDAProtocolException
0469:             */
0470:            protected void missingCodePoint(int codePoint)
0471:                    throws DRDAProtocolException {
0472:                throwSyntaxrm(CodePoint.SYNERRCD_REQ_OBJ_NOT_FOUND, codePoint);
0473:            }
0474:
0475:            /**
0476:             * Print a line to the DB2j log
0477:             *
0478:             * @param dbname  database name
0479:             * @param drdaID	DRDA identifier
0480:             * @param msg	message
0481:             */
0482:            protected static void println2Log(String dbname, String drdaID,
0483:                    String msg) {
0484:                if (logStream == null)
0485:                    logStream = Monitor.getStream();
0486:
0487:                if (dbname != null) {
0488:                    int endOfName = dbname.indexOf(';');
0489:                    if (endOfName != -1)
0490:                        dbname = dbname.substring(0, endOfName);
0491:                }
0492:                logStream.printlnWithHeader("(DATABASE = " + dbname
0493:                        + "), (DRDAID = " + drdaID + "), " + msg);
0494:            }
0495:
0496:            /**
0497:             * Write RDBNAM
0498:             *
0499:             * @param rdbnam 	database name
0500:             * @exception DRDAProtocolException
0501:             */
0502:            protected void writeRDBNAM(String rdbnam)
0503:                    throws DRDAProtocolException {
0504:                int len = rdbnam.length();
0505:                if (len < CodePoint.RDBNAM_LEN)
0506:                    len = CodePoint.RDBNAM_LEN;
0507:                writer.writeScalarHeader(CodePoint.RDBNAM, len);
0508:                try {
0509:                    writer.writeScalarPaddedBytes(rdbnam
0510:                            .getBytes(server.DEFAULT_ENCODING), len,
0511:                            server.SPACE_CHAR);
0512:                } catch (UnsupportedEncodingException e) {
0513:                    agentError("Unsupported coding exception for server encoding "
0514:                            + server.DEFAULT_ENCODING);
0515:                }
0516:            }
0517:
0518:            /***************************************************************************
0519:             *                   Private methods
0520:             ***************************************************************************/
0521:
0522:            /**
0523:             * Initialize class
0524:             */
0525:            private void initialize() {
0526:                // set input and output sockets
0527:                // this needs to be done before creating reader
0528:                sockis = session.sessionInput;
0529:                sockos = session.sessionOutput;
0530:
0531:                reader = new DDMReader(this , session.dssTrace);
0532:                writer = new DDMWriter(ccsidManager, this , session.dssTrace);
0533:            }
0534:
0535:            /**
0536:             * Initialize for a new session
0537:             */
0538:            private void initializeForSession() {
0539:                // set input and output sockets
0540:                sockis = session.sessionInput;
0541:                sockos = session.sessionOutput;
0542:
0543:                // intialize reader and writer
0544:                reader.initialize(this , session.dssTrace);
0545:                writer.reset(session.dssTrace);
0546:
0547:                // initialize local pointers to session info
0548:                database = session.database;
0549:                appRequester = session.appRequester;
0550:
0551:                // set sqlamLevel
0552:                if (session.state == Session.ATTEXC)
0553:                    sqlamLevel = appRequester.getManagerLevel(CodePoint.SQLAM);
0554:
0555:            }
0556:
0557:            /**      
0558:             * In initial state for a session, 
0559:             * determine whether this is a command
0560:             * session or a DRDA protocol session.  A command session is for changing
0561:             * the configuration of the Net server, e.g., turning tracing on
0562:             * If it is a command session, process the command and close the session.
0563:             * If it is a DRDA session, exchange server attributes and change session
0564:             * state.
0565:             */
0566:            private void sessionInitialState() throws Exception {
0567:                // process NetworkServerControl commands - if it is not either valid protocol  let the 
0568:                // DRDA error handling handle it
0569:                if (reader.isCmd()) {
0570:                    try {
0571:                        server.processCommands(reader, writer, session);
0572:                        // reset reader and writer
0573:                        reader.initialize(this , null);
0574:                        writer.reset(null);
0575:                        closeSession();
0576:                    } catch (Throwable t) {
0577:                        if (t instanceof  InterruptedException)
0578:                            throw (InterruptedException) t;
0579:                        else {
0580:                            server.consoleExceptionPrintTrace(t);
0581:                        }
0582:                    }
0583:
0584:                } else {
0585:                    // exchange attributes with application requester
0586:                    exchangeServerAttributes();
0587:                }
0588:            }
0589:
0590:            /**
0591:             * Cleans up and closes a result set if an exception is thrown
0592:             * when collecting QRYDTA in response to OPNQRY or CNTQRY.
0593:             *
0594:             * @param stmt the DRDA statement to clean up
0595:             * @param sqle the exception that was thrown
0596:             * @param writerMark start index for the first DSS to clear from
0597:             * the output buffer
0598:             * @exception DRDAProtocolException if a DRDA protocol error is
0599:             * detected
0600:             */
0601:            private void cleanUpAndCloseResultSet(DRDAStatement stmt,
0602:                    SQLException sqle, int writerMark)
0603:                    throws DRDAProtocolException {
0604:                if (stmt != null) {
0605:                    writer.clearDSSesBackToMark(writerMark);
0606:                    if (!stmt.rsIsClosed()) {
0607:                        try {
0608:                            stmt.rsClose();
0609:                        } catch (SQLException ec) {
0610:                            if (SanityManager.DEBUG) {
0611:                                trace("Warning: Error closing result set");
0612:                            }
0613:                        }
0614:                        writeABNUOWRM();
0615:                        writeSQLCARD(sqle, CodePoint.SVRCOD_ERROR, 0, 0);
0616:                    }
0617:                } else {
0618:                    writeSQLCARDs(sqle, 0);
0619:                }
0620:                errorInChain(sqle);
0621:            }
0622:
0623:            /**
0624:             * Process DRDA commands we can receive once server attributes have been
0625:             * exchanged.
0626:             *
0627:             * @exception DRDAProtocolException
0628:             */
0629:            private void processCommands() throws DRDAProtocolException {
0630:                DRDAStatement stmt = null;
0631:                int updateCount = 0;
0632:                boolean PRPSQLSTTfailed = false;
0633:                boolean checkSecurityCodepoint = session
0634:                        .requiresSecurityCodepoint();
0635:                do {
0636:                    correlationID = reader.readDssHeader();
0637:                    int codePoint = reader.readLengthAndCodePoint();
0638:                    int writerMark = writer.markDSSClearPoint();
0639:
0640:                    if (checkSecurityCodepoint)
0641:                        verifyInOrderACCSEC_SECCHK(codePoint, session
0642:                                .getRequiredSecurityCodepoint());
0643:
0644:                    switch (codePoint) {
0645:                    case CodePoint.CNTQRY:
0646:                        try {
0647:                            stmt = parseCNTQRY();
0648:                            if (stmt != null) {
0649:                                writeQRYDTA(stmt);
0650:                                if (stmt.rsIsClosed()) {
0651:                                    writeENDQRYRM(CodePoint.SVRCOD_WARNING);
0652:                                    writeNullSQLCARDobject();
0653:                                }
0654:                                // Send any warnings if JCC can handle them
0655:                                checkWarning(null, null, stmt.getResultSet(),
0656:                                        0, false, sendWarningsOnCNTQRY);
0657:                            }
0658:                        } catch (SQLException e) {
0659:                            // if we got a SQLException we need to clean up and
0660:                            // close the result set Beetle 4758
0661:                            cleanUpAndCloseResultSet(stmt, e, writerMark);
0662:                        }
0663:                        break;
0664:                    case CodePoint.EXCSQLIMM:
0665:                        try {
0666:                            updateCount = parseEXCSQLIMM();
0667:                            // RESOLVE: checking updateCount is not sufficient
0668:                            // since it will be 0 for creates, we need to know when
0669:                            // any logged changes are made to the database
0670:                            // Not getting this right for JCC is probably O.K., this
0671:                            // will probably be a problem for ODBC and XA
0672:                            // The problem is that JDBC doesn't provide this information
0673:                            // so we would have to expand the JDBC API or call a
0674:                            // builtin method to check(expensive)
0675:                            // For now we will assume that every execute immediate
0676:                            // does an update (that is the most conservative thing)
0677:                            if (database.RDBUPDRM_sent == false) {
0678:                                writeRDBUPDRM();
0679:                            }
0680:
0681:                            // we need to set update count in SQLCARD
0682:                            checkWarning(null, database.getDefaultStatement()
0683:                                    .getStatement(), null, updateCount, true,
0684:                                    true);
0685:                        } catch (SQLException e) {
0686:                            writer.clearDSSesBackToMark(writerMark);
0687:                            writeSQLCARDs(e, 0);
0688:                            errorInChain(e);
0689:                        }
0690:                        break;
0691:
0692:                    case CodePoint.EXCSQLSET:
0693:                        try {
0694:                            if (parseEXCSQLSET())
0695:                                // all went well.
0696:                                writeSQLCARDs(null, 0);
0697:                        } catch (SQLWarning w) {
0698:                            writeSQLCARD(w, CodePoint.SVRCOD_WARNING, 0, 0);
0699:                        } catch (SQLException e) {
0700:                            writer.clearDSSesBackToMark(writerMark);
0701:                            writeSQLCARDs(e, 0);
0702:                            errorInChain(e);
0703:                        }
0704:                        break;
0705:
0706:                    case CodePoint.PRPSQLSTT:
0707:                        int sqldaType;
0708:                        PRPSQLSTTfailed = false;
0709:                        try {
0710:                            database.getConnection().clearWarnings();
0711:                            sqldaType = parsePRPSQLSTT();
0712:                            if (sqldaType > 0) // do write SQLDARD
0713:                                writeSQLDARD(
0714:                                        database.getCurrentStatement(),
0715:                                        (sqldaType == CodePoint.TYPSQLDA_LIGHT_OUTPUT),
0716:                                        database.getConnection().getWarnings());
0717:                            else
0718:                                checkWarning(database.getConnection(), null,
0719:                                        null, 0, true, true);
0720:
0721:                        } catch (SQLException e) {
0722:                            writer.clearDSSesBackToMark(writerMark);
0723:                            writeSQLCARDs(e, 0, true);
0724:                            PRPSQLSTTfailed = true;
0725:                            errorInChain(e);
0726:                        }
0727:                        break;
0728:                    case CodePoint.OPNQRY:
0729:                        PreparedStatement ps = null;
0730:                        try {
0731:                            if (PRPSQLSTTfailed) {
0732:                                // read the command objects
0733:                                // for ps with parameter
0734:                                // Skip objects/parameters
0735:                                skipRemainder(true);
0736:
0737:                                // If we failed to prepare, then we fail
0738:                                // to open, which  means OPNQFLRM.
0739:                                writeOPNQFLRM(null);
0740:                                break;
0741:                            }
0742:                            Pkgnamcsn pkgnamcsn = parseOPNQRY();
0743:                            if (pkgnamcsn != null) {
0744:                                stmt = database.getDRDAStatement(pkgnamcsn);
0745:                                ps = stmt.getPreparedStatement();
0746:                                ps.clearWarnings();
0747:                                if (pendingStatementTimeout >= 0) {
0748:                                    ps.setQueryTimeout(pendingStatementTimeout);
0749:                                    pendingStatementTimeout = -1;
0750:                                }
0751:                                stmt.execute();
0752:                                writeOPNQRYRM(false, stmt);
0753:                                checkWarning(null, ps, null, 0, false, true);
0754:
0755:                                writeQRYDSC(stmt, false);
0756:
0757:                                stmt.rsSuspend();
0758:
0759:                                if (stmt.getQryprctyp() == CodePoint.LMTBLKPRC
0760:                                        && stmt.getQryrowset() != 0) {
0761:                                    // The DRDA spec allows us to send
0762:                                    // QRYDTA here if there are no LOB
0763:                                    // columns.
0764:                                    DRDAResultSet drdars = stmt
0765:                                            .getCurrentDrdaResultSet();
0766:                                    try {
0767:                                        if (drdars != null
0768:                                                && !drdars.hasLobColumns()) {
0769:                                            writeQRYDTA(stmt);
0770:                                        }
0771:                                    } catch (SQLException sqle) {
0772:                                        cleanUpAndCloseResultSet(stmt, sqle,
0773:                                                writerMark);
0774:                                    }
0775:                                }
0776:                            }
0777:                        } catch (SQLException e) {
0778:                            writer.clearDSSesBackToMark(writerMark);
0779:                            // The fix for DERBY-1196 removed code 
0780:                            // here to close the prepared statement 
0781:                            // if OPNQRY failed.
0782:                            writeOPNQFLRM(e);
0783:                        }
0784:                        break;
0785:                    case CodePoint.RDBCMM:
0786:                        try {
0787:                            if (SanityManager.DEBUG)
0788:                                trace("Received commit");
0789:                            if (!database.getConnection().getAutoCommit()) {
0790:                                database.getConnection().clearWarnings();
0791:                                database.commit();
0792:                                writeENDUOWRM(COMMIT);
0793:                                checkWarning(database.getConnection(), null,
0794:                                        null, 0, true, true);
0795:                            }
0796:                            // we only want to write one of these per transaction
0797:                            // so set to false in preparation for next command
0798:                            database.RDBUPDRM_sent = false;
0799:                        } catch (SQLException e) {
0800:                            writer.clearDSSesBackToMark(writerMark);
0801:                            // Even in case of error, we have to write the ENDUOWRM.
0802:                            writeENDUOWRM(COMMIT);
0803:                            writeSQLCARDs(e, 0);
0804:                            errorInChain(e);
0805:                        }
0806:                        break;
0807:                    case CodePoint.RDBRLLBCK:
0808:                        try {
0809:                            if (SanityManager.DEBUG)
0810:                                trace("Received rollback");
0811:                            database.getConnection().clearWarnings();
0812:                            database.rollback();
0813:                            writeENDUOWRM(ROLLBACK);
0814:                            checkWarning(database.getConnection(), null, null,
0815:                                    0, true, true);
0816:                            // we only want to write one of these per transaction
0817:                            // so set to false in preparation for next command
0818:                            database.RDBUPDRM_sent = false;
0819:                        } catch (SQLException e) {
0820:                            writer.clearDSSesBackToMark(writerMark);
0821:                            // Even in case of error, we have to write the ENDUOWRM.
0822:                            writeENDUOWRM(ROLLBACK);
0823:                            writeSQLCARDs(e, 0);
0824:                            errorInChain(e);
0825:                        }
0826:                        break;
0827:                    case CodePoint.CLSQRY:
0828:                        try {
0829:                            stmt = parseCLSQRY();
0830:                            stmt.rsClose();
0831:                            writeSQLCARDs(null, 0);
0832:                        } catch (SQLException e) {
0833:                            writer.clearDSSesBackToMark(writerMark);
0834:                            writeSQLCARDs(e, 0);
0835:                            errorInChain(e);
0836:                        }
0837:                        break;
0838:                    case CodePoint.EXCSAT:
0839:                        parseEXCSAT();
0840:                        writeEXCSATRD();
0841:                        break;
0842:                    case CodePoint.ACCSEC:
0843:                        int securityCheckCode = parseACCSEC();
0844:                        writeACCSECRD(securityCheckCode);
0845:                        checkSecurityCodepoint = true;
0846:                        break;
0847:                    case CodePoint.SECCHK:
0848:                        if (parseDRDAConnection())
0849:                            // security all checked and connection ok
0850:                            checkSecurityCodepoint = false;
0851:                        break;
0852:                    /* since we don't support sqlj, we won't get bind commands from jcc, we
0853:                     * might get it from ccc; just skip them.
0854:                     */
0855:                    case CodePoint.BGNBND:
0856:                        reader.skipBytes();
0857:                        writeSQLCARDs(null, 0);
0858:                        break;
0859:                    case CodePoint.BNDSQLSTT:
0860:                        reader.skipBytes();
0861:                        parseSQLSTTDss();
0862:                        writeSQLCARDs(null, 0);
0863:                        break;
0864:                    case CodePoint.SQLSTTVRB:
0865:                        // optional
0866:                        reader.skipBytes();
0867:                        break;
0868:                    case CodePoint.ENDBND:
0869:                        reader.skipBytes();
0870:                        writeSQLCARDs(null, 0);
0871:                        break;
0872:                    case CodePoint.DSCSQLSTT:
0873:                        if (PRPSQLSTTfailed) {
0874:                            reader.skipBytes();
0875:                            writeSQLCARDs(null, 0);
0876:                            break;
0877:                        }
0878:                        try {
0879:                            boolean rtnOutput = parseDSCSQLSTT();
0880:                            writeSQLDARD(database.getCurrentStatement(),
0881:                                    rtnOutput, null);
0882:
0883:                        } catch (SQLException e) {
0884:                            writer.clearDSSesBackToMark(writerMark);
0885:                            server.consoleExceptionPrint(e);
0886:                            try {
0887:                                writeSQLDARD(database.getCurrentStatement(),
0888:                                        true, e);
0889:                            } catch (SQLException e2) { // should not get here since doing nothing with ps
0890:                                agentError("Why am I getting another SQLException?");
0891:                            }
0892:                            errorInChain(e);
0893:                        }
0894:                        break;
0895:                    case CodePoint.EXCSQLSTT:
0896:                        if (PRPSQLSTTfailed) {
0897:                            // Skip parameters too if they are chained Beetle 4867
0898:                            skipRemainder(true);
0899:                            writeSQLCARDs(null, 0);
0900:                            break;
0901:                        }
0902:                        try {
0903:                            parseEXCSQLSTT();
0904:
0905:                            DRDAStatement curStmt = database
0906:                                    .getCurrentStatement();
0907:                            if (curStmt != null)
0908:                                curStmt.rsSuspend();
0909:                        } catch (SQLException e) {
0910:                            skipRemainder(true);
0911:                            writer.clearDSSesBackToMark(writerMark);
0912:                            if (SanityManager.DEBUG) {
0913:                                server.consoleExceptionPrint(e);
0914:                            }
0915:                            writeSQLCARDs(e, 0);
0916:                            errorInChain(e);
0917:                        }
0918:                        break;
0919:                    case CodePoint.SYNCCTL:
0920:                        if (xaProto == null)
0921:                            xaProto = new DRDAXAProtocol(this );
0922:                        xaProto.parseSYNCCTL();
0923:                        break;
0924:                    default:
0925:                        codePointNotSupported(codePoint);
0926:                    }
0927:
0928:                    // Set the correct chaining bits for whatever
0929:                    // reply DSS(es) we just wrote.  If we've reached
0930:                    // the end of the chain, this method will send
0931:                    // the DSS(es) across.
0932:                    finalizeChain();
0933:
0934:                } while (reader.isChainedWithSameID()
0935:                        || reader.isChainedWithDiffID());
0936:            }
0937:
0938:            /**
0939:             * If there's a severe error in the DDM chain, and if the header indicates
0940:             * "terminate chain on error", we stop processing further commands in the chain
0941:             * nor do we send any reply for them.  In accordance to this, a SQLERRRM message 
0942:             * indicating the severe error must have been sent! (otherwise application requestor,
0943:             * such as JCC, would not terminate the receiving of chain replies.)
0944:             *
0945:             * Each DRDA command is processed independently. DRDA defines no interdependencies
0946:             * across chained commands. A command is processed the same when received within
0947:             * a set of chained commands or received separately.  The chaining was originally
0948:             * defined as a way to save network costs.
0949:             *
0950:             * @param e		the SQLException raised
0951:             * @exception	DRDAProtocolException
0952:             */
0953:            private void errorInChain(SQLException e)
0954:                    throws DRDAProtocolException {
0955:                if (reader.terminateChainOnErr()
0956:                        && (getExceptionSeverity(e) > CodePoint.SVRCOD_ERROR)) {
0957:                    if (SanityManager.DEBUG)
0958:                        trace("terminating the chain on error...");
0959:                    skipRemainder(false);
0960:                }
0961:            }
0962:
0963:            /**
0964:             * Exchange server attributes with application requester
0965:             *
0966:             * @exception DRDAProtocolException
0967:             */
0968:            private void exchangeServerAttributes()
0969:                    throws DRDAProtocolException {
0970:                int codePoint;
0971:                correlationID = reader.readDssHeader();
0972:                if (SanityManager.DEBUG) {
0973:                    if (correlationID == 0) {
0974:                        SanityManager
0975:                                .THROWASSERT("Unexpected value for correlationId = "
0976:                                        + correlationID);
0977:                    }
0978:                }
0979:
0980:                codePoint = reader.readLengthAndCodePoint();
0981:
0982:                // The first code point in the exchange of attributes must be EXCSAT
0983:                if (codePoint != CodePoint.EXCSAT) {
0984:                    //Throw PRCCNVRM 
0985:                    throw new DRDAProtocolException(
0986:                            DRDAProtocolException.DRDA_Proto_PRCCNVRM, this ,
0987:                            codePoint,
0988:                            CodePoint.PRCCNVCD_EXCSAT_FIRST_AFTER_CONN);
0989:                }
0990:
0991:                parseEXCSAT();
0992:                writeEXCSATRD();
0993:                finalizeChain();
0994:                session.setState(session.ATTEXC);
0995:            }
0996:
0997:            private boolean parseDRDAConnection() throws DRDAProtocolException {
0998:                int codePoint;
0999:                boolean sessionOK = true;
1000:
1001:                int securityCheckCode = parseSECCHK();
1002:                if (SanityManager.DEBUG)
1003:                    trace("*** SECCHKRM securityCheckCode is: "
1004:                            + securityCheckCode);
1005:                writeSECCHKRM(securityCheckCode);
1006:                //at this point if the security check failed, we're done, the session failed
1007:                if (securityCheckCode != 0) {
1008:                    return false;
1009:                }
1010:
1011:                correlationID = reader.readDssHeader();
1012:                codePoint = reader.readLengthAndCodePoint();
1013:                verifyRequiredObject(codePoint, CodePoint.ACCRDB);
1014:                int svrcod = parseACCRDB();
1015:
1016:                //If network server gets a null connection form InternalDriver, reply with
1017:                //RDBAFLRM and SQLCARD with null SQLException 
1018:                if (database.getConnection() == null
1019:                        && databaseAccessException == null) {
1020:                    writeRDBfailure(CodePoint.RDBAFLRM);
1021:                    return false;
1022:                }
1023:
1024:                //if earlier we couldn't access the database
1025:                if (databaseAccessException != null) {
1026:
1027:                    //if the Database was not found we will try DS
1028:                    int failureType = getRdbAccessErrorCodePoint();
1029:                    if (failureType == CodePoint.RDBNFNRM
1030:                            || failureType == CodePoint.RDBATHRM) {
1031:                        writeRDBfailure(failureType);
1032:                    } else {
1033:                        writeRDBfailure(CodePoint.RDBAFLRM);
1034:                    }
1035:                    return false;
1036:                } else if (database.accessCount > 1) // already in conversation with database
1037:                {
1038:                    writeRDBfailure(CodePoint.RDBACCRM);
1039:                    return false;
1040:                } else
1041:                    // everything is fine 
1042:                    writeACCRDBRM(svrcod);
1043:
1044:                // compare this application requester with previously stored
1045:                // application requesters and if we have already seen this one
1046:                // use stored application requester 
1047:                session.appRequester = server.getAppRequester(appRequester);
1048:                return sessionOK;
1049:            }
1050:
1051:            /**
1052:             * Write RDB Failure
1053:             *
1054:             * Instance Variables
1055:             * 	SVRCOD - Severity Code - required
1056:             *	RDBNAM - Relational Database name - required
1057:             *  SRVDGN - Server Diagnostics - optional (not sent for now)
1058:             *
1059:             * @param	codePoint	codepoint of failure
1060:             */
1061:            private void writeRDBfailure(int codePoint)
1062:                    throws DRDAProtocolException {
1063:                writer.createDssReply();
1064:                writer.startDdm(codePoint);
1065:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
1066:                        CodePoint.SVRCOD_ERROR);
1067:                writeRDBNAM(database.dbName);
1068:                writer.endDdmAndDss();
1069:
1070:                switch (codePoint) {
1071:                case CodePoint.RDBAFLRM:
1072:                    //RDBAFLRM requires TYPDEFNAM and TYPDEFOVR
1073:                    writer.createDssObject();
1074:                    writer.writeScalarString(CodePoint.TYPDEFNAM,
1075:                            CodePoint.TYPDEFNAM_QTDSQLASC);
1076:                    writeTYPDEFOVR();
1077:                    writer.endDss();
1078:                case CodePoint.RDBNFNRM:
1079:                case CodePoint.RDBATHRM:
1080:                    writeSQLCARD(databaseAccessException,
1081:                            CodePoint.SVRCOD_ERROR, 0, 0);
1082:                case CodePoint.RDBACCRM:
1083:                    //Ignore anything that was chained to the ACCRDB.
1084:                    skipRemainder(false);
1085:
1086:                    // Finalize chain state for whatever we wrote in
1087:                    // response to ACCRDB.
1088:                    finalizeChain();
1089:                    break;
1090:                }
1091:
1092:            }
1093:
1094:            /* Check the database access exception and return the appropriate
1095:               error codepoint.
1096:               RDBNFNRM - Database not found
1097:               RDBATHRM - Not Authorized
1098:               RDBAFLRM - Access failure
1099:               @return RDB Access codepoint 
1100:                       
1101:             */
1102:
1103:            private int getRdbAccessErrorCodePoint() {
1104:                String sqlState = databaseAccessException.getSQLState();
1105:                if (sqlState
1106:                        .regionMatches(0, SQLState.DATABASE_NOT_FOUND, 0, 5)
1107:                        | sqlState.regionMatches(0, SQLState.NO_SUCH_DATABASE,
1108:                                0, 5))
1109:                    return CodePoint.RDBNFNRM;
1110:                else if (sqlState.regionMatches(0, SQLState.LOGIN_FAILED, 0, 5)
1111:                        || sqlState.regionMatches(0,
1112:                                SQLState.AUTH_INVALID_USER_NAME, 0, 5))
1113:                    return CodePoint.RDBATHRM;
1114:                else
1115:                    return CodePoint.RDBAFLRM;
1116:            }
1117:
1118:            /**
1119:             * Verify userId and password
1120:             *
1121:             * Username and password is verified by making a connection to the
1122:             * database
1123:             *
1124:             * @return security check code, 0 is O.K.
1125:             * @exception DRDAProtocolException
1126:             */
1127:            private int verifyUserIdPassword() throws DRDAProtocolException {
1128:                databaseAccessException = null;
1129:                int retSecChkCode = 0;
1130:
1131:                String realName = database.dbName; //first strip off properties
1132:                int endOfName = realName.indexOf(';');
1133:                if (endOfName != -1)
1134:                    realName = realName.substring(0, endOfName);
1135:                retSecChkCode = getConnFromDatabaseName();
1136:                return retSecChkCode;
1137:            }
1138:
1139:            /**
1140:             * Get connection from a database name
1141:             *
1142:             * Username and password is verified by making a connection to the
1143:             * database
1144:             *
1145:             * @return security check code, 0 is O.K.
1146:             * @exception DRDAProtocolException
1147:             */
1148:            private int getConnFromDatabaseName() throws DRDAProtocolException {
1149:                Properties p = new Properties();
1150:                databaseAccessException = null;
1151:                //if we haven't got the correlation token yet, use session number for drdaID
1152:                if (session.drdaID == null)
1153:                    session.drdaID = leftBrace + session.connNum + rightBrace;
1154:                p.put(Attribute.DRDAID_ATTR, session.drdaID);
1155:
1156:                // We pass extra property information for the authentication provider
1157:                // to successfully re-compute the substitute (hashed) password and
1158:                // compare it with what we've got from the requester (source).
1159:                //
1160:                // If a password attribute appears as part of the connection URL
1161:                // attributes, we then don't use the substitute hashed password
1162:                // to authenticate with the engine _as_ the one (if any) as part
1163:                // of the connection URL attributes, will be used to authenticate
1164:                // against Derby's BUILT-IN authentication provider - As a reminder,
1165:                // Derby allows password to be mentioned as part of the connection
1166:                // URL attributes, as this extra capability could be useful to pass
1167:                // passwords to external authentication providers for Derby; hence
1168:                // a password defined as part of the connection URL attributes cannot
1169:                // be substituted (single-hashed) as it is not recoverable.
1170:                if ((database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
1171:                        && (database.dbName.indexOf(Attribute.PASSWORD_ATTR) == -1)) {
1172:                    p.put(Attribute.CLIENT_SECURITY_MECHANISM, String
1173:                            .valueOf(database.securityMechanism));
1174:                    p.put(Attribute.DRDA_SECTKN_IN, DecryptionManager
1175:                            .toHexString(database.secTokenIn, 0,
1176:                                    database.secTokenIn.length));
1177:                    p.put(Attribute.DRDA_SECTKN_OUT, DecryptionManager
1178:                            .toHexString(database.secTokenOut, 0,
1179:                                    database.secTokenOut.length));
1180:                }
1181:
1182:                try {
1183:                    database.makeConnection(p);
1184:                } catch (SQLException se) {
1185:                    String sqlState = se.getSQLState();
1186:                    // need to set the security check code based on the reason the connection     
1187:                    // was denied, Cloudscape doesn't say whether the userid or password caused
1188:                    // the problem, so we will just return userid invalid
1189:                    databaseAccessException = se;
1190:                    for (; se != null; se = se.getNextException()) {
1191:                        if (SanityManager.DEBUG)
1192:                            trace(se.getMessage());
1193:                        println2Log(database.dbName, session.drdaID, se
1194:                                .getMessage());
1195:                    }
1196:
1197:                    if (sqlState.regionMatches(0, SQLState.LOGIN_FAILED, 0, 5))
1198:                        return CodePoint.SECCHKCD_USERIDINVALID;
1199:
1200:                    return 0;
1201:                } catch (Exception e) {
1202:                    // If cloudscape has shut down for some reason,
1203:                    // we will send  an agent error and then try to 
1204:                    // get the driver loaded again.  We have to get
1205:                    // rid of the client first in case they are holding
1206:                    // the DriverManager lock.
1207:                    println2Log(database.dbName, session.drdaID,
1208:                            "Driver not loaded" + e.getMessage());
1209:                    try {
1210:                        agentError("Driver not loaded");
1211:                    } catch (DRDAProtocolException dpe) {
1212:                        // Retry starting the server before rethrowing 
1213:                        // the protocol exception.  Then hopfully all
1214:                        // will be well when they try again.
1215:                        try {
1216:                            server.startNetworkServer();
1217:                        } catch (Exception re) {
1218:                            println2Log(database.dbName, session.drdaID,
1219:                                    "Failed attempt to reload driver "
1220:                                            + re.getMessage());
1221:                        }
1222:                        throw dpe;
1223:                    }
1224:                }
1225:
1226:                // Everything worked so log connection to the database.
1227:                if (getLogConnections())
1228:                    println2Log(database.dbName, session.drdaID,
1229:                            "Apache Derby Network Server connected to database "
1230:                                    + database.dbName);
1231:                return 0;
1232:            }
1233:
1234:            /**
1235:             * Parses EXCSAT (Exchange Server Attributes)
1236:             * Instance variables
1237:             *	EXTNAM(External Name)	- optional
1238:             *  MGRLVLLS(Manager Levels) - optional
1239:             *	SPVNAM(Supervisor Name) - optional
1240:             *  SRVCLSNM(Server Class Name) - optional
1241:             *  SRVNAM(Server Name) - optional, ignorable
1242:             *  SRVRLSLV(Server Product Release Level) - optional, ignorable
1243:             *
1244:             * @exception DRDAProtocolException
1245:             */
1246:            private void parseEXCSAT() throws DRDAProtocolException {
1247:                int codePoint;
1248:                String strVal;
1249:
1250:                // There are three kinds of EXCSAT's we might get.
1251:                // 1) Initial Exchange attributes.
1252:                //    For this we need to initialize the apprequester.
1253:                //    Session state is set to ATTEXC and then the AR must 
1254:                //    follow up with ACCSEC and SECCHK to get the connection.
1255:                //  2) Send of EXCSAT as ping or mangager level adjustment. 
1256:                //     (see parseEXCSAT2())
1257:                //     For this we just ignore the EXCSAT objects that
1258:                //     are already set.
1259:                //  3) Send of EXCSAT for connection reset. (see parseEXCSAT2())
1260:                //     This is treated just like ping and will be followed up 
1261:                //     by an ACCSEC request if in fact it is a connection reset.
1262:
1263:                // If we have already exchanged attributes once just 
1264:                // process any new manager levels and return (case 2 and 3 above)
1265:                if (appRequester != null) {
1266:                    parseEXCSAT2();
1267:                    return;
1268:                }
1269:
1270:                // set up a new Application Requester to store information about the
1271:                // application requester for this session
1272:
1273:                appRequester = new AppRequester();
1274:
1275:                reader.markCollection();
1276:
1277:                codePoint = reader.getCodePoint();
1278:                while (codePoint != -1) {
1279:                    switch (codePoint) {
1280:                    // optional
1281:                    case CodePoint.EXTNAM:
1282:                        appRequester.extnam = reader.readString();
1283:                        if (SanityManager.DEBUG)
1284:                            trace("extName = " + appRequester.extnam);
1285:                        if (appRequester.extnam.length() > CodePoint.MAX_NAME)
1286:                            tooBig(CodePoint.EXTNAM);
1287:                        break;
1288:                    // optional
1289:                    case CodePoint.MGRLVLLS:
1290:                        parseMGRLVLLS(1);
1291:                        break;
1292:                    // optional 
1293:                    case CodePoint.SPVNAM:
1294:                        appRequester.spvnam = reader.readString();
1295:                        // This is specified as a null parameter so length should
1296:                        // be zero
1297:                        if (appRequester.spvnam != null)
1298:                            badObjectLength(CodePoint.SPVNAM);
1299:                        break;
1300:                    // optional
1301:                    case CodePoint.SRVNAM:
1302:                        appRequester.srvnam = reader.readString();
1303:                        if (SanityManager.DEBUG)
1304:                            trace("serverName = " + appRequester.srvnam);
1305:                        if (appRequester.srvnam.length() > CodePoint.MAX_NAME)
1306:                            tooBig(CodePoint.SRVNAM);
1307:                        break;
1308:                    // optional
1309:                    case CodePoint.SRVRLSLV:
1310:                        appRequester.srvrlslv = reader.readString();
1311:                        if (SanityManager.DEBUG)
1312:                            trace("serverlslv = " + appRequester.srvrlslv);
1313:                        if (appRequester.srvrlslv.length() > CodePoint.MAX_NAME)
1314:                            tooBig(CodePoint.SRVRLSLV);
1315:                        break;
1316:                    // optional
1317:                    case CodePoint.SRVCLSNM:
1318:                        appRequester.srvclsnm = reader.readString();
1319:                        if (SanityManager.DEBUG)
1320:                            trace("serverClassName = " + appRequester.srvclsnm);
1321:                        if (appRequester.srvclsnm.length() > CodePoint.MAX_NAME)
1322:                            tooBig(CodePoint.SRVCLSNM);
1323:                        break;
1324:                    default:
1325:                        invalidCodePoint(codePoint);
1326:                    }
1327:                    codePoint = reader.getCodePoint();
1328:                }
1329:            }
1330:
1331:            /**
1332:             * Parses EXCSAT2 (Exchange Server Attributes)
1333:             * Instance variables
1334:             *	EXTNAM(External Name)	- optional
1335:             *  MGRLVLLS(Manager Levels) - optional
1336:             *	SPVNAM(Supervisor Name) - optional
1337:             *  SRVCLSNM(Server Class Name) - optional
1338:             *  SRVNAM(Server Name) - optional, ignorable
1339:             *  SRVRLSLV(Server Product Release Level) - optional, ignorable
1340:             *
1341:             * @exception DRDAProtocolException
1342:             * 
1343:             * This parses a second occurrence of an EXCSAT command
1344:             * The target must ignore the values for extnam, srvclsnm, srvnam and srvrlslv.
1345:             * I am also going to ignore spvnam since it should be null anyway.
1346:             * Only new managers can be added.
1347:             */
1348:            private void parseEXCSAT2() throws DRDAProtocolException {
1349:                int codePoint;
1350:                reader.markCollection();
1351:
1352:                codePoint = reader.getCodePoint();
1353:                while (codePoint != -1) {
1354:                    switch (codePoint) {
1355:                    // optional
1356:                    case CodePoint.EXTNAM:
1357:                    case CodePoint.SRVNAM:
1358:                    case CodePoint.SRVRLSLV:
1359:                    case CodePoint.SRVCLSNM:
1360:                    case CodePoint.SPVNAM:
1361:                        reader.skipBytes();
1362:                        break;
1363:                    // optional
1364:                    case CodePoint.MGRLVLLS:
1365:                        parseMGRLVLLS(2);
1366:                        break;
1367:                    default:
1368:                        invalidCodePoint(codePoint);
1369:                    }
1370:                    codePoint = reader.getCodePoint();
1371:                }
1372:            }
1373:
1374:            /**
1375:             *	Parse manager levels
1376:             *  Instance variables
1377:             *		MGRLVL - repeatable, required
1378:             *		  CODEPOINT
1379:             *			CCSIDMGR - CCSID Manager
1380:             *			CMNAPPC - LU 6.2 Conversational Communications Manager 
1381:             *			CMNSYNCPT - SNA LU 6.2 SyncPoint Conversational Communications Manager
1382:             *			CMNTCPIP - TCP/IP Communication Manager 
1383:             *			DICTIONARY - Dictionary
1384:             *			RDB - Relational Database 
1385:             *			RSYNCMGR - Resynchronization Manager 
1386:             *			SECMGR - Security Manager
1387:             *			SQLAM - SQL Application Manager
1388:             *			SUPERVISOR - Supervisor
1389:             *			SYNCPTMGR - Sync Point Manager 
1390:             *		  VALUE
1391:             *
1392:             *	On the second appearance of this codepoint, it can only add managers
1393:             *
1394:             * @param time	1 for first time this is seen, 2 for subsequent ones
1395:             * @exception DRDAProtocolException
1396:             * 
1397:             */
1398:            private void parseMGRLVLLS(int time) throws DRDAProtocolException {
1399:                int manager, managerLevel;
1400:                int currentLevel;
1401:                // set up vectors to keep track of manager information
1402:                unknownManagers = new Vector();
1403:                knownManagers = new Vector();
1404:                errorManagers = new Vector();
1405:                errorManagersLevel = new Vector();
1406:                if (SanityManager.DEBUG)
1407:                    trace("Manager Levels");
1408:
1409:                while (reader.moreDdmData()) {
1410:                    manager = reader.readNetworkShort();
1411:                    managerLevel = reader.readNetworkShort();
1412:                    if (CodePoint.isKnownManager(manager)) {
1413:                        knownManagers.addElement(new Integer(manager));
1414:                        //if the manager level hasn't been set, set it
1415:                        currentLevel = appRequester.getManagerLevel(manager);
1416:                        if (currentLevel == appRequester.MGR_LEVEL_UNKNOWN)
1417:                            appRequester.setManagerLevel(manager, managerLevel);
1418:                        else {
1419:                            //if the level is still the same we'll ignore it
1420:                            if (currentLevel != managerLevel) {
1421:                                //keep a list of conflicting managers
1422:                                errorManagers.addElement(new Integer(manager));
1423:                                errorManagersLevel.addElement(new Integer(
1424:                                        managerLevel));
1425:                            }
1426:                        }
1427:
1428:                    } else
1429:                        unknownManagers.addElement(new Integer(manager));
1430:                    if (SanityManager.DEBUG)
1431:                        trace("Manager = "
1432:                                + java.lang.Integer.toHexString(manager)
1433:                                + " ManagerLevel " + managerLevel);
1434:                }
1435:                sqlamLevel = appRequester.getManagerLevel(CodePoint.SQLAM);
1436:                // did we have any errors
1437:                if (errorManagers.size() > 0) {
1438:                    Object[] oa = new Object[errorManagers.size() * 2];
1439:                    int j = 0;
1440:                    for (int i = 0; i < errorManagers.size(); i++) {
1441:                        oa[j++] = errorManagers.elementAt(i);
1442:                        oa[j++] = errorManagersLevel.elementAt(i);
1443:                    }
1444:                    throw new DRDAProtocolException(
1445:                            DRDAProtocolException.DRDA_Proto_MGRLVLRM, this , 0,
1446:                            0, oa);
1447:                }
1448:            }
1449:
1450:            /**
1451:             * Write reply to EXCSAT command
1452:             * Instance Variables
1453:             *	EXTNAM - External Name (optional)
1454:             *  MGRLVLLS - Manager Level List (optional)
1455:             *  SRVCLSNM - Server Class Name (optional) - used by JCC
1456:             *  SRVNAM - Server Name (optional)
1457:             *  SRVRLSLV - Server Product Release Level (optional)
1458:             *
1459:             * @exception DRDAProtocolException
1460:             */
1461:            private void writeEXCSATRD() throws DRDAProtocolException {
1462:                writer.createDssReply();
1463:                writer.startDdm(CodePoint.EXCSATRD);
1464:                writer.writeScalarString(CodePoint.EXTNAM, server.att_extnam);
1465:                //only reply with manager levels if we got sent some
1466:                if (knownManagers != null && knownManagers.size() > 0)
1467:                    writeMGRLEVELS();
1468:                writer.writeScalarString(CodePoint.SRVCLSNM,
1469:                        server.att_srvclsnm);
1470:                writer.writeScalarString(CodePoint.SRVNAM, server.ATT_SRVNAM);
1471:                writer.writeScalarString(CodePoint.SRVRLSLV,
1472:                        server.att_srvrlslv);
1473:                writer.endDdmAndDss();
1474:            }
1475:
1476:            /**
1477:             * Write manager levels
1478:             * The target server must not provide information for any target
1479:             * managers unless the source explicitly requests it.
1480:             * For each manager class, if the target server's support level
1481:             * is greater than or equal to the source server's level, then the source
1482:             * server's level is returned for that class if the target server can operate
1483:             * at the source's level; otherwise a level 0 is returned.  If the target
1484:             * server's support level is less than the source server's level, the
1485:             * target server's level is returned for that class.  If the target server
1486:             * does not recognize the code point of a manager class or does not support
1487:             * that class, it returns a level of 0.  The target server then waits
1488:             * for the next command or for the source server to terminate communications.
1489:             * When the source server receives EXCSATRD, it must compare each of the entries
1490:             * in the mgrlvlls parameter it received to the corresponding entries in the mgrlvlls
1491:             * parameter it sent.  If any level mismatches, the source server must decide
1492:             * whether it can use or adjust to the lower level of target support for that manager
1493:             * class.  There are no architectural criteria for making this decision.
1494:             * The source server can terminate communications or continue at the target
1495:             * servers level of support.  It can also attempt to use whatever
1496:             * commands its user requests while receiving error reply messages for real
1497:             * functional mismatches.
1498:             * The manager levels the source server specifies or the target server
1499:             * returns must be compatible with the manager-level dependencies of the specified
1500:             * manangers.  Incompatible manager levels cannot be specified.
1501:             *  Instance variables
1502:             *		MGRLVL - repeatable, required
1503:             *		  CODEPOINT
1504:             *			CCSIDMGR - CCSID Manager
1505:             *			CMNAPPC - LU 6.2 Conversational Communications Manager 
1506:             *			CMNSYNCPT - SNA LU 6.2 SyncPoint Conversational Communications Manager
1507:             *			CMNTCPIP - TCP/IP Communication Manager   
1508:             *			DICTIONARY - Dictionary 
1509:             *			RDB - Relational Database 
1510:             *			RSYNCMGR - Resynchronization Manager   
1511:             *			SECMGR - Security Manager
1512:             *			SQLAM - SQL Application Manager 
1513:             *			SUPERVISOR - Supervisor 
1514:             *			SYNCPTMGR - Sync Point Manager 
1515:             *			XAMGR - XA manager 
1516:             *		  VALUE
1517:             */
1518:            private void writeMGRLEVELS() throws DRDAProtocolException {
1519:                int manager;
1520:                int appLevel;
1521:                int serverLevel;
1522:                writer.startDdm(CodePoint.MGRLVLLS);
1523:                for (int i = 0; i < knownManagers.size(); i++) {
1524:                    manager = ((Integer) knownManagers.elementAt(i)).intValue();
1525:                    appLevel = appRequester.getManagerLevel(manager);
1526:                    serverLevel = server.getManagerLevel(manager);
1527:                    if (serverLevel >= appLevel) {
1528:                        //Note appLevel has already been set to 0 if we can't support
1529:                        //the original app Level
1530:                        writer.writeCodePoint4Bytes(manager, appLevel);
1531:                    } else {
1532:                        writer.writeCodePoint4Bytes(manager, serverLevel);
1533:                        // reset application manager level to server level
1534:                        appRequester.setManagerLevel(manager, serverLevel);
1535:                    }
1536:                }
1537:                // write 0 for all unknown managers
1538:                for (int i = 0; i < unknownManagers.size(); i++) {
1539:                    manager = ((Integer) unknownManagers.elementAt(i))
1540:                            .intValue();
1541:                    writer.writeCodePoint4Bytes(manager, 0);
1542:                }
1543:                writer.endDdm();
1544:            }
1545:
1546:            /**
1547:             *  Parse Access Security
1548:             *
1549:             *	If the target server supports the SECMEC requested by the application requester
1550:             *	then a single value is returned and it is identical to the SECMEC value
1551:             *	in the ACCSEC command. If the target server does not support the SECMEC
1552:             *	requested, then one or more values are returned and the application requester
1553:             *  must choose one of these values for the security mechanism.
1554:             *  We currently support
1555:             *		- user id and password (default for JCC)
1556:             *		- encrypted user id and password
1557:             *      - strong password substitute (USRSSBPWD w/
1558:             *                                    Derby network client only)
1559:             *
1560:             *  Instance variables
1561:             *    SECMGRNM  - security manager name - optional
1562:             *	  SECMEC 	- security mechanism - required
1563:             *	  RDBNAM	- relational database name - optional
1564:             * 	  SECTKN	- security token - optional, (required if sec mech. needs it)
1565:             *
1566:             *  @return security check code - 0 if everything O.K.
1567:             */
1568:            private int parseACCSEC() throws DRDAProtocolException {
1569:                int securityCheckCode = 0;
1570:                int securityMechanism = 0;
1571:                byte[] secTokenIn = null;
1572:
1573:                reader.markCollection();
1574:                int codePoint = reader.getCodePoint();
1575:                while (codePoint != -1) {
1576:                    switch (codePoint) {
1577:                    //optional
1578:                    case CodePoint.SECMGRNM:
1579:                        // this is defined to be 0 length
1580:                        if (reader.getDdmLength() != 0)
1581:                            badObjectLength(CodePoint.SECMGRNM);
1582:                        break;
1583:                    //required
1584:                    case CodePoint.SECMEC:
1585:                        checkLength(CodePoint.SECMEC, 2);
1586:                        securityMechanism = reader.readNetworkShort();
1587:                        if (SanityManager.DEBUG)
1588:                            trace("parseACCSEC - Security mechanism = "
1589:                                    + securityMechanism);
1590:
1591:                        // if Property.DRDA_PROP_SECURITYMECHANISM has been set, then
1592:                        // network server only accepts connections which use that
1593:                        // security mechanism. No other types of connections 
1594:                        // are accepted.
1595:                        // Make check to see if this property has been set.
1596:                        // if set, and if the client requested security mechanism 
1597:                        // is not the same, then return a security check code 
1598:                        // that the server does not support/allow this security 
1599:                        // mechanism
1600:                        if ((server.getSecurityMechanism() != NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM)
1601:                                && securityMechanism != server
1602:                                        .getSecurityMechanism()) {
1603:                            securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
1604:                            if (SanityManager.DEBUG) {
1605:                                trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [1] - "
1606:                                        + securityMechanism
1607:                                        + " <> "
1608:                                        + server.getSecurityMechanism() + "\n");
1609:                            }
1610:                        } else {
1611:                            // for plain text userid,password USRIDPWD, and USRIDONL
1612:                            // no need of decryptionManager
1613:                            if (securityMechanism != CodePoint.SECMEC_USRIDPWD
1614:                                    && securityMechanism != CodePoint.SECMEC_USRIDONL) {
1615:                                // These are the only other mechanisms we understand
1616:                                if (((securityMechanism != CodePoint.SECMEC_EUSRIDPWD) || (securityMechanism == CodePoint.SECMEC_EUSRIDPWD && !server
1617:                                        .supportsEUSRIDPWD()))
1618:                                        && (securityMechanism != CodePoint.SECMEC_USRSSBPWD))
1619:                                //securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
1620:                                {
1621:                                    securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
1622:                                    if (SanityManager.DEBUG) {
1623:                                        trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [2]\n");
1624:                                    }
1625:                                } else {
1626:                                    // We delay the initialization and required
1627:                                    // processing for SECMEC_USRSSBPWD as we need
1628:                                    // to ensure the database is booted so that
1629:                                    // we can verify that the current auth scheme
1630:                                    // is set to BUILT-IN or NONE. For this we need
1631:                                    // to have the RDBNAM codepoint available.
1632:                                    //
1633:                                    // See validateSecMecUSRSSBPWD() call below
1634:                                    if (securityMechanism == CodePoint.SECMEC_USRSSBPWD)
1635:                                        break;
1636:
1637:                                    // SECMEC_EUSRIDPWD initialization
1638:                                    try {
1639:                                        if (decryptionManager == null)
1640:                                            decryptionManager = new DecryptionManager();
1641:                                        myPublicKey = decryptionManager
1642:                                                .obtainPublicKey();
1643:                                    } catch (SQLException e) {
1644:                                        println2Log(null, session.drdaID, e
1645:                                                .getMessage());
1646:                                        // Local security service non-retryable error.
1647:                                        securityCheckCode = CodePoint.SECCHKCD_0A;
1648:                                    }
1649:                                }
1650:                            }
1651:                        }
1652:                        break;
1653:                    //optional (currently required for Cloudscape - needed for
1654:                    //          DERBY-528 as well)
1655:                    case CodePoint.RDBNAM:
1656:                        String dbname = parseRDBNAM();
1657:                        Database d = session.getDatabase(dbname);
1658:                        if (d == null)
1659:                            addDatabase(dbname);
1660:                        else {
1661:                            // reset database for connection re-use 
1662:                            d.reset();
1663:                            database = d;
1664:                        }
1665:                        break;
1666:                    //optional - depending on security Mechanism 
1667:                    case CodePoint.SECTKN:
1668:                        secTokenIn = reader.readBytes();
1669:                        break;
1670:                    default:
1671:                        invalidCodePoint(codePoint);
1672:                    }
1673:                    codePoint = reader.getCodePoint();
1674:                }
1675:
1676:                // check for required CodePoint's
1677:                if (securityMechanism == 0)
1678:                    missingCodePoint(CodePoint.SECMEC);
1679:
1680:                // RESOLVE - when we look further into security we might want to
1681:                // handle this part of the protocol at the session level without
1682:                // requiring a database for when authentication is used but there
1683:                // is no database level security
1684:                if (database == null)
1685:                    missingCodePoint(CodePoint.RDBNAM);
1686:
1687:                database.securityMechanism = securityMechanism;
1688:                database.secTokenIn = secTokenIn;
1689:
1690:                // If security mechanism is SECMEC_USRSSBPWD, then ensure it can be
1691:                // used for the database or system based on the client's connection
1692:                // URL and its identity.
1693:                if (securityCheckCode == 0
1694:                        && (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)) {
1695:                    if (SanityManager.DEBUG)
1696:                        SanityManager
1697:                                .ASSERT(
1698:                                        (securityCheckCode == 0),
1699:                                        "SECMEC_USRSSBPWD: securityCheckCode should not "
1700:                                                + "already be set, found it initialized with "
1701:                                                + "a value of '"
1702:                                                + securityCheckCode + "'.");
1703:                    securityCheckCode = validateSecMecUSRSSBPWD();
1704:                }
1705:
1706:                // need security token
1707:                if (securityCheckCode == 0
1708:                        && (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD || database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
1709:                        && database.secTokenIn == null)
1710:                    securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
1711:
1712:                // shouldn't have security token
1713:                if (securityCheckCode == 0
1714:                        && (database.securityMechanism == CodePoint.SECMEC_USRIDPWD || database.securityMechanism == CodePoint.SECMEC_USRIDONL)
1715:                        && database.secTokenIn != null)
1716:                    securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
1717:
1718:                if (SanityManager.DEBUG)
1719:                    trace("** ACCSECRD securityCheckCode is: "
1720:                            + securityCheckCode);
1721:
1722:                // If the security check was successful set the session state to
1723:                // security accesseed.  Otherwise go back to attributes exchanged so we
1724:                // require another ACCSEC
1725:                if (securityCheckCode == 0)
1726:                    session.setState(session.SECACC);
1727:                else
1728:                    session.setState(session.ATTEXC);
1729:
1730:                return securityCheckCode;
1731:            }
1732:
1733:            /**
1734:             * Parse OPNQRY
1735:             * Instance Variables
1736:             *  RDBNAM - relational database name - optional
1737:             *  PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
1738:             *  QRYBLKSZ - Query Block Size - required
1739:             *  QRYBLKCTL - Query Block Protocol Control - optional 
1740:             *  MAXBLKEXT - Maximum Number of Extra Blocks - optional - default value 0
1741:             *  OUTOVROPT - Output Override Option
1742:             *  QRYROWSET - Query Rowset Size - optional - level 7
1743:             *  MONITOR - Monitor events - optional.
1744:             *
1745:             * @return RDB Package Name, Consistency Token, and Section Number
1746:             * @exception DRDAProtocolException
1747:             */
1748:            private Pkgnamcsn parseOPNQRY() throws DRDAProtocolException,
1749:                    SQLException {
1750:                Pkgnamcsn pkgnamcsn = null;
1751:                boolean gotQryblksz = false;
1752:                int blksize = 0;
1753:                int qryblkctl = CodePoint.QRYBLKCTL_DEFAULT;
1754:                int maxblkext = CodePoint.MAXBLKEXT_DEFAULT;
1755:                int qryrowset = CodePoint.QRYROWSET_DEFAULT;
1756:                int qryclsimp = DRDAResultSet.QRYCLSIMP_DEFAULT;
1757:                int outovropt = CodePoint.OUTOVRFRS;
1758:                reader.markCollection();
1759:                int codePoint = reader.getCodePoint();
1760:                while (codePoint != -1) {
1761:                    switch (codePoint) {
1762:                    //optional
1763:                    case CodePoint.RDBNAM:
1764:                        setDatabase(CodePoint.OPNQRY);
1765:                        break;
1766:                    //required
1767:                    case CodePoint.PKGNAMCSN:
1768:                        pkgnamcsn = parsePKGNAMCSN();
1769:                        break;
1770:                    //required
1771:                    case CodePoint.QRYBLKSZ:
1772:                        blksize = parseQRYBLKSZ();
1773:                        gotQryblksz = true;
1774:                        break;
1775:                    //optional
1776:                    case CodePoint.QRYBLKCTL:
1777:                        qryblkctl = reader.readNetworkShort();
1778:                        //The only type of query block control we can specify here
1779:                        //is forced fixed row
1780:                        if (qryblkctl != CodePoint.FRCFIXROW)
1781:                            invalidCodePoint(qryblkctl);
1782:                        if (SanityManager.DEBUG)
1783:                            trace("!!qryblkctl = "
1784:                                    + Integer.toHexString(qryblkctl));
1785:                        gotQryblksz = true;
1786:                        break;
1787:                    //optional
1788:                    case CodePoint.MAXBLKEXT:
1789:                        maxblkext = reader.readSignedNetworkShort();
1790:                        if (SanityManager.DEBUG)
1791:                            trace("maxblkext = " + maxblkext);
1792:                        break;
1793:                    // optional
1794:                    case CodePoint.OUTOVROPT:
1795:                        outovropt = parseOUTOVROPT();
1796:                        break;
1797:                    //optional
1798:                    case CodePoint.QRYROWSET:
1799:                        //Note minimum for OPNQRY is 0
1800:                        qryrowset = parseQRYROWSET(0);
1801:                        break;
1802:                    case CodePoint.QRYCLSIMP:
1803:                        // Implicitly close non-scrollable cursor
1804:                        qryclsimp = parseQRYCLSIMP();
1805:                        break;
1806:                    case CodePoint.QRYCLSRLS:
1807:                        // Ignore release of read locks.  Nothing we can do here
1808:                        parseQRYCLSRLS();
1809:                        break;
1810:                    // optional
1811:                    case CodePoint.MONITOR:
1812:                        parseMONITOR();
1813:                        break;
1814:                    default:
1815:                        invalidCodePoint(codePoint);
1816:                    }
1817:                    codePoint = reader.getCodePoint();
1818:                }
1819:                // check for required variables
1820:                if (pkgnamcsn == null)
1821:                    missingCodePoint(CodePoint.PKGNAMCSN);
1822:                if (!gotQryblksz)
1823:                    missingCodePoint(CodePoint.QRYBLKSZ);
1824:
1825:                // get the statement we are opening
1826:                DRDAStatement stmt = database.getDRDAStatement(pkgnamcsn);
1827:                if (stmt == null) {
1828:                    //XXX should really throw a SQL Exception here
1829:                    invalidValue(CodePoint.PKGNAMCSN);
1830:                }
1831:
1832:                // check that this statement is not already open
1833:                // commenting this check out for now
1834:                // it turns out that JCC doesn't send a close if executeQuery is
1835:                // done again without closing the previous result set
1836:                // this check can't be done since the second executeQuery should work
1837:                //if (stmt.state != DRDAStatement.NOT_OPENED)
1838:                //{
1839:                //	writeQRYPOPRM();
1840:                //	pkgnamcsn = null;
1841:                //}
1842:                //else
1843:                //{
1844:                stmt.setOPNQRYOptions(blksize, qryblkctl, maxblkext, outovropt,
1845:                        qryrowset, qryclsimp);
1846:                //}
1847:
1848:                // read the command objects
1849:                // for ps with parameter
1850:                if (reader.isChainedWithSameID()) {
1851:                    if (SanityManager.DEBUG)
1852:                        trace("&&&&&& parsing SQLDTA");
1853:                    parseOPNQRYobjects(stmt);
1854:                }
1855:                return pkgnamcsn;
1856:            }
1857:
1858:            /**
1859:             * Parse OPNQRY objects
1860:             * Objects
1861:             *  TYPDEFNAM - Data type definition name - optional
1862:             *  TYPDEFOVR - Type defintion overrides - optional
1863:             *  SQLDTA- SQL Program Variable Data - optional
1864:             *
1865:             * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
1866:             * sent with the statement.  Once the statement is over, the default values
1867:             * sent in the ACCRDB are once again in effect.  If no values are supplied,
1868:             * the values sent in the ACCRDB are used.
1869:             * Objects may follow in one DSS or in several DSS chained together.
1870:             * 
1871:             * @throws DRDAProtocolException
1872:             * @throws SQLException
1873:             */
1874:            private void parseOPNQRYobjects(DRDAStatement stmt)
1875:                    throws DRDAProtocolException, SQLException {
1876:                int codePoint;
1877:                do {
1878:                    correlationID = reader.readDssHeader();
1879:                    while (reader.moreDssData()) {
1880:                        codePoint = reader.readLengthAndCodePoint();
1881:                        switch (codePoint) {
1882:                        // optional
1883:                        case CodePoint.TYPDEFNAM:
1884:                            setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
1885:                            break;
1886:                        // optional
1887:                        case CodePoint.TYPDEFOVR:
1888:                            parseTYPDEFOVR(stmt);
1889:                            break;
1890:                        // optional 
1891:                        case CodePoint.SQLDTA:
1892:                            parseSQLDTA(stmt);
1893:                            break;
1894:                        // optional
1895:                        case CodePoint.EXTDTA:
1896:                            readAndSetAllExtParams(stmt, false);
1897:                            break;
1898:                        default:
1899:                            invalidCodePoint(codePoint);
1900:                        }
1901:                    }
1902:                } while (reader.isChainedWithSameID());
1903:
1904:            }
1905:
1906:            /**
1907:             * Parse OUTOVROPT - this indicates whether output description can be
1908:             * overridden on just the first CNTQRY or on any CNTQRY
1909:             *
1910:             * @return output override option
1911:             * @exception DRDAProtocolException
1912:             */
1913:            private int parseOUTOVROPT() throws DRDAProtocolException {
1914:                checkLength(CodePoint.OUTOVROPT, 1);
1915:                int outovropt = reader.readUnsignedByte();
1916:                if (SanityManager.DEBUG)
1917:                    trace("output override option: " + outovropt);
1918:                if (outovropt != CodePoint.OUTOVRFRS
1919:                        && outovropt != CodePoint.OUTOVRANY)
1920:                    invalidValue(CodePoint.OUTOVROPT);
1921:                return outovropt;
1922:            }
1923:
1924:            /**
1925:             * Parse QRYBLSZ - this gives the maximum size of the query blocks that
1926:             * can be returned to the requester
1927:             *
1928:             * @return query block size
1929:             * @exception DRDAProtocolException
1930:             */
1931:            private int parseQRYBLKSZ() throws DRDAProtocolException {
1932:                checkLength(CodePoint.QRYBLKSZ, 4);
1933:                int blksize = reader.readNetworkInt();
1934:                if (SanityManager.DEBUG)
1935:                    trace("qryblksz = " + blksize);
1936:                if (blksize < CodePoint.QRYBLKSZ_MIN
1937:                        || blksize > CodePoint.QRYBLKSZ_MAX)
1938:                    invalidValue(CodePoint.QRYBLKSZ);
1939:                return blksize;
1940:            }
1941:
1942:            /**
1943:             * Parse QRYROWSET - this is the number of rows to return
1944:             *
1945:             * @param minVal - minimum value
1946:             * @return query row set size
1947:             * @exception DRDAProtocolException
1948:             */
1949:            private int parseQRYROWSET(int minVal) throws DRDAProtocolException {
1950:                checkLength(CodePoint.QRYROWSET, 4);
1951:                int qryrowset = reader.readNetworkInt();
1952:                if (SanityManager.DEBUG)
1953:                    trace("qryrowset = " + qryrowset);
1954:                if (qryrowset < minVal || qryrowset > CodePoint.QRYROWSET_MAX)
1955:                    invalidValue(CodePoint.QRYROWSET);
1956:                return qryrowset;
1957:            }
1958:
1959:            /** Parse a QRYCLSIMP - Implicitly close non-scrollable cursor 
1960:             * after end of data.
1961:             * @return  true to close on end of data 
1962:             */
1963:            private int parseQRYCLSIMP() throws DRDAProtocolException {
1964:
1965:                checkLength(CodePoint.QRYCLSIMP, 1);
1966:                int qryclsimp = reader.readUnsignedByte();
1967:                if (SanityManager.DEBUG)
1968:                    trace("qryclsimp = " + qryclsimp);
1969:                if (qryclsimp != CodePoint.QRYCLSIMP_SERVER_CHOICE
1970:                        && qryclsimp != CodePoint.QRYCLSIMP_YES
1971:                        && qryclsimp != CodePoint.QRYCLSIMP_NO)
1972:                    invalidValue(CodePoint.QRYCLSIMP);
1973:                return qryclsimp;
1974:            }
1975:
1976:            private int parseQRYCLSRLS() throws DRDAProtocolException {
1977:                reader.skipBytes();
1978:                return 0;
1979:            }
1980:
1981:            /**
1982:             * Write a QRYPOPRM - Query Previously opened
1983:             * Instance Variables
1984:             *  SVRCOD - Severity Code - required - 8 ERROR
1985:             *  RDBNAM - Relational Database Name - required
1986:             *  PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
1987:             * 
1988:             * @exception DRDAProtocolException
1989:             */
1990:            private void writeQRYPOPRM() throws DRDAProtocolException {
1991:                writer.createDssReply();
1992:                writer.startDdm(CodePoint.QRYPOPRM);
1993:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
1994:                        CodePoint.SVRCOD_ERROR);
1995:                writeRDBNAM(database.dbName);
1996:                writePKGNAMCSN();
1997:                writer.endDdmAndDss();
1998:            }
1999:
2000:            /**
2001:             * Write a QRYNOPRM - Query Not Opened
2002:             * Instance Variables
2003:             *  SVRCOD - Severity Code - required -  4 Warning 8 ERROR
2004:             *  RDBNAM - Relational Database Name - required
2005:             *  PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
2006:             * 
2007:             * @param svrCod	Severity Code
2008:             * @exception DRDAProtocolException
2009:             */
2010:            private void writeQRYNOPRM(int svrCod) throws DRDAProtocolException {
2011:                writer.createDssReply();
2012:                writer.startDdm(CodePoint.QRYNOPRM);
2013:                writer.writeScalar2Bytes(CodePoint.SVRCOD, svrCod);
2014:                writeRDBNAM(database.dbName);
2015:                writePKGNAMCSN();
2016:                writer.endDdmAndDss();
2017:            }
2018:
2019:            /**
2020:             * Write a OPNQFLRM - Open Query Failure
2021:             * Instance Variables
2022:             *  SVRCOD - Severity Code - required - 8 ERROR
2023:             *  RDBNAM - Relational Database Name - required
2024:             *
2025:             * @param	e	Exception describing failure
2026:             *
2027:             * @exception DRDAProtocolException
2028:             */
2029:            private void writeOPNQFLRM(SQLException e)
2030:                    throws DRDAProtocolException {
2031:                writer.createDssReply();
2032:                writer.startDdm(CodePoint.OPNQFLRM);
2033:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
2034:                        CodePoint.SVRCOD_ERROR);
2035:                writeRDBNAM(database.dbName);
2036:                writer.endDdm();
2037:                writer.startDdm(CodePoint.SQLCARD);
2038:                writeSQLCAGRP(e, getSqlCode(getExceptionSeverity(e)), 0, 0);
2039:                writer.endDdmAndDss();
2040:            }
2041:
2042:            /**
2043:             * Write PKGNAMCSN
2044:             * Instance Variables
2045:             *   NAMESYMDR - database name - not validated
2046:             *   RDBCOLID - RDB Collection Identifier
2047:             *   PKGID - RDB Package Identifier
2048:             *   PKGCNSTKN - RDB Package Consistency Token
2049:             *   PKGSN - RDB Package Section Number
2050:             *
2051:             * There are two possible formats, fixed and extended which includes length
2052:             * information for the strings
2053:             *
2054:             * @throws DRDAProtocolException
2055:             */
2056:            private void writePKGNAMCSN(byte[] pkgcnstkn)
2057:                    throws DRDAProtocolException {
2058:                writer.startDdm(CodePoint.PKGNAMCSN);
2059:                if (rdbnam.length() <= CodePoint.RDBNAM_LEN
2060:                        && rdbcolid.length() <= CodePoint.RDBCOLID_LEN
2061:                        && pkgid.length() <= CodePoint.PKGID_LEN) { // if none of RDBNAM, RDBCOLID and PKGID have a length of
2062:                    // more than 18, use fixed format
2063:                    writer
2064:                            .writeScalarPaddedString(rdbnam,
2065:                                    CodePoint.RDBNAM_LEN);
2066:                    writer.writeScalarPaddedString(rdbcolid,
2067:                            CodePoint.RDBCOLID_LEN);
2068:                    writer.writeScalarPaddedString(pkgid, CodePoint.PKGID_LEN);
2069:                    writer.writeScalarPaddedBytes(pkgcnstkn,
2070:                            CodePoint.PKGCNSTKN_LEN, (byte) 0);
2071:                    writer.writeShort(pkgsn);
2072:                } else // extended format
2073:                {
2074:                    int len = Math.max(CodePoint.RDBNAM_LEN, rdbnam.length());
2075:                    writer.writeShort(len);
2076:                    writer.writeScalarPaddedString(rdbnam, len);
2077:                    len = Math.max(CodePoint.RDBCOLID_LEN, rdbcolid.length());
2078:                    writer.writeShort(len);
2079:                    writer.writeScalarPaddedString(rdbcolid, len);
2080:                    len = Math.max(CodePoint.PKGID_LEN, pkgid.length());
2081:                    writer.writeShort(len);
2082:                    writer.writeScalarPaddedString(pkgid, len);
2083:                    writer.writeScalarPaddedBytes(pkgcnstkn,
2084:                            CodePoint.PKGCNSTKN_LEN, (byte) 0);
2085:                    writer.writeShort(pkgsn);
2086:                }
2087:                writer.endDdm();
2088:            }
2089:
2090:            private void writePKGNAMCSN() throws DRDAProtocolException {
2091:                writePKGNAMCSN(pkgcnstkn.getBytes());
2092:            }
2093:
2094:            /**
2095:             * Parse CNTQRY - Continue Query
2096:             * Instance Variables
2097:             *   RDBNAM - Relational Database Name - optional
2098:             *   PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
2099:             *   QRYBLKSZ - Query Block Size - required
2100:             *   QRYRELSCR - Query Relative Scrolling Action - optional
2101:             *   QRYSCRORN - Query Scroll Orientation - optional - level 7
2102:             *   QRYROWNBR - Query Row Number - optional
2103:             *   QRYROWSNS - Query Row Sensitivity - optional - level 7
2104:             *   QRYBLKRST - Query Block Reset - optional - level 7
2105:             *   QRYRTNDTA - Query Returns Data - optional - level 7
2106:             *   QRYROWSET - Query Rowset Size - optional - level 7
2107:             *   QRYRFRTBL - Query Refresh Answer Set Table - optional
2108:             *   NBRROW - Number of Fetch or Insert Rows - optional
2109:             *   MAXBLKEXT - Maximum number of extra blocks - optional
2110:             *   RTNEXTDTA - Return of EXTDTA Option - optional
2111:             *   MONITOR - Monitor events - optional.
2112:             *
2113:             * @return DRDAStatement we are continuing
2114:             * @throws DRDAProtocolException
2115:             * @throws SQLException
2116:             */
2117:            private DRDAStatement parseCNTQRY() throws DRDAProtocolException,
2118:                    SQLException {
2119:                byte val;
2120:                Pkgnamcsn pkgnamcsn = null;
2121:                boolean gotQryblksz = false;
2122:                boolean qryrelscr = true;
2123:                long qryrownbr = 1;
2124:                boolean qryrfrtbl = false;
2125:                int nbrrow = 1;
2126:                int blksize = 0;
2127:                int maxblkext = -1;
2128:                long qryinsid;
2129:                boolean gotQryinsid = false;
2130:                int qryscrorn = CodePoint.QRYSCRREL;
2131:                boolean qryrowsns = false;
2132:                boolean gotQryrowsns = false;
2133:                boolean qryblkrst = false;
2134:                boolean qryrtndta = true;
2135:                int qryrowset = CodePoint.QRYROWSET_DEFAULT;
2136:                int rtnextdta = CodePoint.RTNEXTROW;
2137:                reader.markCollection();
2138:                int codePoint = reader.getCodePoint();
2139:                while (codePoint != -1) {
2140:                    switch (codePoint) {
2141:                    //optional
2142:                    case CodePoint.RDBNAM:
2143:                        setDatabase(CodePoint.CNTQRY);
2144:                        break;
2145:                    //required
2146:                    case CodePoint.PKGNAMCSN:
2147:                        pkgnamcsn = parsePKGNAMCSN();
2148:                        break;
2149:                    //required
2150:                    case CodePoint.QRYBLKSZ:
2151:                        blksize = parseQRYBLKSZ();
2152:                        gotQryblksz = true;
2153:                        break;
2154:                    //optional
2155:                    case CodePoint.QRYRELSCR:
2156:                        qryrelscr = readBoolean(CodePoint.QRYRELSCR);
2157:                        if (SanityManager.DEBUG)
2158:                            trace("qryrelscr = " + qryrelscr);
2159:                        break;
2160:                    //optional
2161:                    case CodePoint.QRYSCRORN:
2162:                        checkLength(CodePoint.QRYSCRORN, 1);
2163:                        qryscrorn = reader.readUnsignedByte();
2164:                        if (SanityManager.DEBUG)
2165:                            trace("qryscrorn = " + qryscrorn);
2166:                        switch (qryscrorn) {
2167:                        case CodePoint.QRYSCRREL:
2168:                        case CodePoint.QRYSCRABS:
2169:                        case CodePoint.QRYSCRAFT:
2170:                        case CodePoint.QRYSCRBEF:
2171:                            break;
2172:                        default:
2173:                            invalidValue(CodePoint.QRYSCRORN);
2174:                        }
2175:                        break;
2176:                    //optional
2177:                    case CodePoint.QRYROWNBR:
2178:                        checkLength(CodePoint.QRYROWNBR, 8);
2179:                        qryrownbr = reader.readNetworkLong();
2180:                        if (SanityManager.DEBUG)
2181:                            trace("qryrownbr = " + qryrownbr);
2182:                        break;
2183:                    //optional
2184:                    case CodePoint.QRYROWSNS:
2185:                        checkLength(CodePoint.QRYROWSNS, 1);
2186:                        qryrowsns = readBoolean(CodePoint.QRYROWSNS);
2187:                        if (SanityManager.DEBUG)
2188:                            trace("qryrowsns = " + qryrowsns);
2189:                        gotQryrowsns = true;
2190:                        break;
2191:                    //optional
2192:                    case CodePoint.QRYBLKRST:
2193:                        checkLength(CodePoint.QRYBLKRST, 1);
2194:                        qryblkrst = readBoolean(CodePoint.QRYBLKRST);
2195:                        if (SanityManager.DEBUG)
2196:                            trace("qryblkrst = " + qryblkrst);
2197:                        break;
2198:                    //optional
2199:                    case CodePoint.QRYRTNDTA:
2200:                        qryrtndta = readBoolean(CodePoint.QRYRTNDTA);
2201:                        if (SanityManager.DEBUG)
2202:                            trace("qryrtndta = " + qryrtndta);
2203:                        break;
2204:                    //optional
2205:                    case CodePoint.QRYROWSET:
2206:                        //Note minimum for CNTQRY is 1
2207:                        qryrowset = parseQRYROWSET(1);
2208:                        if (SanityManager.DEBUG)
2209:                            trace("qryrowset = " + qryrowset);
2210:                        break;
2211:                    //optional
2212:                    case CodePoint.QRYRFRTBL:
2213:                        qryrfrtbl = readBoolean(CodePoint.QRYRFRTBL);
2214:                        if (SanityManager.DEBUG)
2215:                            trace("qryrfrtbl = " + qryrfrtbl);
2216:                        break;
2217:                    //optional
2218:                    case CodePoint.NBRROW:
2219:                        checkLength(CodePoint.NBRROW, 4);
2220:                        nbrrow = reader.readNetworkInt();
2221:                        if (SanityManager.DEBUG)
2222:                            trace("nbrrow = " + nbrrow);
2223:                        break;
2224:                    //optional
2225:                    case CodePoint.MAXBLKEXT:
2226:                        checkLength(CodePoint.MAXBLKEXT, 2);
2227:                        maxblkext = reader.readSignedNetworkShort();
2228:                        if (SanityManager.DEBUG)
2229:                            trace("maxblkext = " + maxblkext);
2230:                        break;
2231:                    //optional
2232:                    case CodePoint.RTNEXTDTA:
2233:                        checkLength(CodePoint.RTNEXTDTA, 1);
2234:                        rtnextdta = reader.readUnsignedByte();
2235:                        if (rtnextdta != CodePoint.RTNEXTROW
2236:                                && rtnextdta != CodePoint.RTNEXTALL)
2237:                            invalidValue(CodePoint.RTNEXTDTA);
2238:                        if (SanityManager.DEBUG)
2239:                            trace("rtnextdta = " + rtnextdta);
2240:                        break;
2241:                    // required for SQLAM >= 7
2242:                    case CodePoint.QRYINSID:
2243:                        checkLength(CodePoint.QRYINSID, 8);
2244:                        qryinsid = reader.readNetworkLong();
2245:                        gotQryinsid = true;
2246:                        if (SanityManager.DEBUG)
2247:                            trace("qryinsid = " + qryinsid);
2248:                        break;
2249:                    // optional
2250:                    case CodePoint.MONITOR:
2251:                        parseMONITOR();
2252:                        break;
2253:                    default:
2254:                        invalidCodePoint(codePoint);
2255:                    }
2256:                    codePoint = reader.getCodePoint();
2257:                }
2258:                // check for required variables
2259:                if (pkgnamcsn == null)
2260:                    missingCodePoint(CodePoint.PKGNAMCSN);
2261:                if (!gotQryblksz)
2262:                    missingCodePoint(CodePoint.QRYBLKSZ);
2263:                if (sqlamLevel >= MGRLVL_7 && !gotQryinsid)
2264:                    missingCodePoint(CodePoint.QRYINSID);
2265:
2266:                // get the statement we are continuing
2267:                DRDAStatement stmt = database.getDRDAStatement(pkgnamcsn);
2268:                if (stmt == null) {
2269:                    //XXX should really throw a SQL Exception here
2270:                    invalidValue(CodePoint.CNTQRY);
2271:                }
2272:
2273:                if (stmt.rsIsClosed()) {
2274:                    writeQRYNOPRM(CodePoint.SVRCOD_ERROR);
2275:                    skipRemainder(true);
2276:                    return null;
2277:                }
2278:                stmt.setQueryOptions(blksize, qryrelscr, qryrownbr, qryrfrtbl,
2279:                        nbrrow, maxblkext, qryscrorn, qryrowsns, qryblkrst,
2280:                        qryrtndta, qryrowset, rtnextdta);
2281:
2282:                if (reader.isChainedWithSameID())
2283:                    parseCNTQRYobjects(stmt);
2284:                return stmt;
2285:            }
2286:
2287:            /**
2288:             * Skip remainder of current DSS and all chained DSS'es
2289:             *
2290:             * @param onlySkipSameIds True if we _only_ want to skip DSS'es
2291:             *   that are chained with the SAME id as the current DSS.
2292:             *   False means skip ALL chained DSSes, whether they're
2293:             *   chained with same or different ids.
2294:             * @exception DRDAProtocolException
2295:             */
2296:            private void skipRemainder(boolean onlySkipSameIds)
2297:                    throws DRDAProtocolException {
2298:                reader.skipDss();
2299:                while (reader.isChainedWithSameID()
2300:                        || (!onlySkipSameIds && reader.isChainedWithDiffID())) {
2301:                    reader.readDssHeader();
2302:                    reader.skipDss();
2303:                }
2304:            }
2305:
2306:            /**
2307:             * Parse CNTQRY objects
2308:             * Instance Variables
2309:             *   OUTOVR - Output Override Descriptor - optional
2310:             *
2311:             * @param stmt DRDA statement we are working on
2312:             * @exception DRDAProtocolException
2313:             */
2314:            private void parseCNTQRYobjects(DRDAStatement stmt)
2315:                    throws DRDAProtocolException, SQLException {
2316:                int codePoint;
2317:                do {
2318:                    correlationID = reader.readDssHeader();
2319:                    while (reader.moreDssData()) {
2320:                        codePoint = reader.readLengthAndCodePoint();
2321:                        switch (codePoint) {
2322:                        // optional
2323:                        case CodePoint.OUTOVR:
2324:                            parseOUTOVR(stmt);
2325:                            break;
2326:                        default:
2327:                            invalidCodePoint(codePoint);
2328:                        }
2329:                    }
2330:                } while (reader.isChainedWithSameID());
2331:
2332:            }
2333:
2334:            /**
2335:             * Parse OUTOVR - Output Override Descriptor
2336:             * This specifies the output format for data to be returned as output to a SQL
2337:             * statement or as output from a query.
2338:             *
2339:             * @param stmt	DRDA statement this applies to
2340:             * @exception DRDAProtocolException
2341:             */
2342:            private void parseOUTOVR(DRDAStatement stmt)
2343:                    throws DRDAProtocolException, SQLException {
2344:                boolean first = true;
2345:                int numVars;
2346:                int dtaGrpLen;
2347:                int tripType;
2348:                int tripId;
2349:                int precision;
2350:                int start = 0;
2351:                while (true) {
2352:                    dtaGrpLen = reader.readUnsignedByte();
2353:                    tripType = reader.readUnsignedByte();
2354:                    tripId = reader.readUnsignedByte();
2355:                    // check if we have reached the end of the data
2356:                    if (tripType == FdocaConstants.RLO_TRIPLET_TYPE) {
2357:                        //read last part of footer
2358:                        reader.skipBytes();
2359:                        break;
2360:                    }
2361:                    numVars = (dtaGrpLen - 3) / 3;
2362:                    if (SanityManager.DEBUG)
2363:                        trace("num of vars is: " + numVars);
2364:                    int[] outovr_drdaType = null;
2365:                    if (first) {
2366:                        outovr_drdaType = new int[numVars];
2367:                        first = false;
2368:                    } else {
2369:                        int[] oldoutovr_drdaType = stmt.getOutovr_drdaType();
2370:                        int oldlen = oldoutovr_drdaType.length;
2371:                        // create new array and copy over already read stuff
2372:                        outovr_drdaType = new int[oldlen + numVars];
2373:                        System.arraycopy(oldoutovr_drdaType, 0,
2374:                                outovr_drdaType, 0, oldlen);
2375:                        start = oldlen;
2376:                    }
2377:                    for (int i = start; i < numVars + start; i++) {
2378:                        outovr_drdaType[i] = reader.readUnsignedByte();
2379:                        if (SanityManager.DEBUG)
2380:                            trace("drdaType is: " + outovr_drdaType[i]);
2381:                        precision = reader.readNetworkShort();
2382:                        if (SanityManager.DEBUG)
2383:                            trace("drdaLength is: " + precision);
2384:                        outovr_drdaType[i] |= (precision << 8);
2385:                    }
2386:                    stmt.setOutovr_drdaType(outovr_drdaType);
2387:                }
2388:            }
2389:
2390:            /**
2391:             * Write OPNQRYRM - Open Query Complete
2392:             * Instance Variables
2393:             *   SVRCOD - Severity Code - required
2394:             *   QRYPRCTYP - Query Protocol Type - required
2395:             *   SQLCSRHLD - Hold Cursor Position - optional
2396:             *   QRYATTSCR - Query Attribute for Scrollability - optional - level 7
2397:             *   QRYATTSNS - Query Attribute for Sensitivity - optional - level 7
2398:             *   QRYATTUPD - Query Attribute for Updatability -optional - level 7
2399:             *   QRYINSID - Query Instance Identifier - required - level 7
2400:             *   SRVDGN - Server Diagnostic Information - optional
2401:             *
2402:             * @param isDssObject - return as a DSS object (part of a reply) 
2403:             * @param stmt - DRDA statement we are processing
2404:             *
2405:             * @exception DRDAProtocolException
2406:             */
2407:            private void writeOPNQRYRM(boolean isDssObject, DRDAStatement stmt)
2408:                    throws DRDAProtocolException, SQLException {
2409:                if (SanityManager.DEBUG)
2410:                    trace("WriteOPNQRYRM");
2411:
2412:                if (isDssObject)
2413:                    writer.createDssObject();
2414:                else
2415:                    writer.createDssReply();
2416:                writer.startDdm(CodePoint.OPNQRYRM);
2417:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
2418:                        CodePoint.SVRCOD_INFO);
2419:
2420:                // There is currently a problem specifying LMTBLKPRC for LOBs with JCC
2421:                // JCC will throw an ArrayOutOfBounds exception.  Once this is fixed, we
2422:                // don't need to pass the two arguments for getQryprctyp.
2423:                int prcType = stmt.getQryprctyp();
2424:                if (SanityManager.DEBUG)
2425:                    trace("sending QRYPRCTYP: " + prcType);
2426:                writer.writeScalar2Bytes(CodePoint.QRYPRCTYP, prcType);
2427:
2428:                //pass the SQLCSRHLD codepoint only if statement producing the ResultSet has 
2429:                //hold cursors over commit set. In case of stored procedures which use server-side
2430:                //JDBC, the holdability of the ResultSet will be the holdability of the statement 
2431:                //in the stored procedure, not the holdability of the calling statement.
2432:                if (stmt.getCurrentDrdaResultSet().withHoldCursor == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT)
2433:                    writer
2434:                            .writeScalar1Byte(CodePoint.SQLCSRHLD,
2435:                                    CodePoint.TRUE);
2436:                if (sqlamLevel >= MGRLVL_7) {
2437:                    writer.writeScalarHeader(CodePoint.QRYINSID, 8);
2438:                    //This is implementer defined.  DB2 uses this for the nesting level
2439:                    //of the query.  A query from an application would be nesting level 0,
2440:                    //from a stored procedure, nesting level 1, from a recursive call of
2441:                    //a stored procedure, nesting level 2, etc.
2442:                    writer.writeInt(0);
2443:                    //This is a unique sequence number per session
2444:                    writer.writeInt(session.qryinsid++);
2445:                    //Write the scroll attributes if they are set
2446:                    if (stmt.isScrollable()) {
2447:                        writer.writeScalar1Byte(CodePoint.QRYATTSCR,
2448:                                CodePoint.TRUE);
2449:                        if ((stmt.getConcurType() == ResultSet.CONCUR_UPDATABLE)
2450:                                && (stmt.getResultSet().getType() == ResultSet.TYPE_SCROLL_INSENSITIVE)) {
2451:                            writer.writeScalar1Byte(CodePoint.QRYATTSNS,
2452:                                    CodePoint.QRYSNSSTC);
2453:                        } else {
2454:                            writer.writeScalar1Byte(CodePoint.QRYATTSNS,
2455:                                    CodePoint.QRYINS);
2456:                        }
2457:                    }
2458:                    if (stmt.getConcurType() == ResultSet.CONCUR_UPDATABLE) {
2459:                        if (stmt.getResultSet() != null) {
2460:                            // Resultset concurrency can be less than statement
2461:                            // concurreny if the underlying language resultset
2462:                            // is not updatable.
2463:                            if (stmt.getResultSet().getConcurrency() == ResultSet.CONCUR_UPDATABLE) {
2464:                                writer.writeScalar1Byte(CodePoint.QRYATTUPD,
2465:                                        CodePoint.QRYUPD);
2466:                            } else {
2467:                                writer.writeScalar1Byte(CodePoint.QRYATTUPD,
2468:                                        CodePoint.QRYRDO);
2469:                            }
2470:                        } else {
2471:                            writer.writeScalar1Byte(CodePoint.QRYATTUPD,
2472:                                    CodePoint.QRYUPD);
2473:                        }
2474:                    } else {
2475:                        writer.writeScalar1Byte(CodePoint.QRYATTUPD,
2476:                                CodePoint.QRYRDO);
2477:                    }
2478:                }
2479:                writer.endDdmAndDss();
2480:            }
2481:
2482:            /**
2483:             * Write ENDQRYRM - query process has terminated in such a manner that the
2484:             *	query or result set is now closed.  It cannot be resumed with the CNTQRY
2485:             *  command or closed with the CLSQRY command
2486:             * @param svrCod  Severity code - WARNING or ERROR
2487:             * @exception DRDAProtocolException
2488:             */
2489:            private void writeENDQRYRM(int svrCod) throws DRDAProtocolException {
2490:                writer.createDssReply();
2491:                writer.startDdm(CodePoint.ENDQRYRM);
2492:                writer.writeScalar2Bytes(CodePoint.SVRCOD, svrCod);
2493:                writer.endDdmAndDss();
2494:            }
2495:
2496:            /**
2497:             * Write ABNUOWRM - query process has terminated in an error condition
2498:             * such as deadlock or lock timeout.
2499:             * Severity code is always error
2500:             * 	 * @exception DRDAProtocolException
2501:             */
2502:            private void writeABNUOWRM() throws DRDAProtocolException {
2503:                writer.createDssReply();
2504:                writer.startDdm(CodePoint.ABNUOWRM);
2505:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
2506:                        CodePoint.SVRCOD_ERROR);
2507:                writeRDBNAM(database.dbName);
2508:                writer.endDdmAndDss();
2509:            }
2510:
2511:            /**
2512:             * Parse database name
2513:             *
2514:             * @return database name
2515:             *
2516:             * @exception DRDAProtocolException
2517:             */
2518:            private String parseRDBNAM() throws DRDAProtocolException {
2519:                String name;
2520:                byte[] rdbName = reader.readBytes();
2521:                if (rdbName.length == 0) {
2522:                    // throw RDBNFNRM
2523:                    rdbNotFound(null);
2524:                }
2525:                //SQLAM level 7 allows db name up to 255, level 6 fixed len 18
2526:                if (rdbName.length < CodePoint.RDBNAM_LEN
2527:                        || rdbName.length > CodePoint.MAX_NAME)
2528:                    badObjectLength(CodePoint.RDBNAM);
2529:                name = reader.convertBytes(rdbName);
2530:                // trim trailing blanks from the database name
2531:                name = name.trim();
2532:                if (SanityManager.DEBUG)
2533:                    trace("RdbName " + name);
2534:                return name;
2535:            }
2536:
2537:            /**
2538:             * Write ACCSECRD
2539:             * If the security mechanism is known, we just send it back along with
2540:             * the security token if encryption is going to be used.
2541:             * If the security mechanism is not known, we send a list of the ones
2542:             * we know.
2543:             * Instance Variables
2544:             * 	SECMEC - security mechanism - required
2545:             *	SECTKN - security token	- optional (required if security mechanism 
2546:             *						uses encryption)
2547:             *  SECCHKCD - security check code - error occurred in processing ACCSEC
2548:             *
2549:             * @param securityCheckCode
2550:             * 
2551:             * @exception DRDAProtocolException
2552:             */
2553:            private void writeACCSECRD(int securityCheckCode)
2554:                    throws DRDAProtocolException {
2555:                writer.createDssReply();
2556:                writer.startDdm(CodePoint.ACCSECRD);
2557:
2558:                if (securityCheckCode != CodePoint.SECCHKCD_NOTSUPPORTED)
2559:                    writer.writeScalar2Bytes(CodePoint.SECMEC,
2560:                            database.securityMechanism);
2561:                else {
2562:                    // if server doesnt recognize or allow the client requested security mechanism,
2563:                    // then need to return the list of security mechanisms supported/allowed by the server
2564:
2565:                    // check if server is set to accept connections from client at a certain 
2566:                    // security mechanism, if so send only the security mechanism  that the 
2567:                    // server will accept, to the client
2568:                    if (server.getSecurityMechanism() != NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM)
2569:                        writer.writeScalar2Bytes(CodePoint.SECMEC, server
2570:                                .getSecurityMechanism());
2571:                    else {
2572:                        // note: per the DDM manual , ACCSECRD response is of 
2573:                        // form SECMEC (value{value..})  
2574:                        // Need to fix the below to send a list of supported security 
2575:                        // mechanisms for value of one SECMEC codepoint (JIRA 926)
2576:                        // these are the ones we know about
2577:                        writer.writeScalar2Bytes(CodePoint.SECMEC,
2578:                                CodePoint.SECMEC_USRIDPWD);
2579:                        // include EUSRIDPWD in the list of supported secmec only if 
2580:                        // server can truely support it in the jvm that is running in
2581:                        if (server.supportsEUSRIDPWD())
2582:                            writer.writeScalar2Bytes(CodePoint.SECMEC,
2583:                                    CodePoint.SECMEC_EUSRIDPWD);
2584:                        writer.writeScalar2Bytes(CodePoint.SECMEC,
2585:                                CodePoint.SECMEC_USRIDONL);
2586:                        writer.writeScalar2Bytes(CodePoint.SECMEC,
2587:                                CodePoint.SECMEC_USRSSBPWD);
2588:                    }
2589:                }
2590:
2591:                if (securityCheckCode != 0) {
2592:                    writer.writeScalar1Byte(CodePoint.SECCHKCD,
2593:                            securityCheckCode);
2594:                } else {
2595:                    // we need to send back the key if encryption is being used
2596:                    if (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD)
2597:                        writer.writeScalarBytes(CodePoint.SECTKN, myPublicKey);
2598:                    else if (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
2599:                        writer.writeScalarBytes(CodePoint.SECTKN, myTargetSeed);
2600:                }
2601:                writer.endDdmAndDss();
2602:
2603:                if (securityCheckCode != 0) {
2604:                    // then we have an error and so can ignore the rest of the
2605:                    // DSS request chain.
2606:                    skipRemainder(false);
2607:                }
2608:
2609:                finalizeChain();
2610:            }
2611:
2612:            /**
2613:             * Parse security check
2614:             * Instance Variables
2615:             *	SECMGRNM - security manager name - optional, ignorable
2616:             *  SECMEC	- security mechanism - required
2617:             *	SECTKN	- security token - optional, (required if encryption used)
2618:             *	PASSWORD - password - optional, (required if security mechanism uses it)
2619:             *	NEWPASSWORD - new password - optional, (required if sec mech. uses it)
2620:             *	USRID	- user id - optional, (required if sec mec. uses it)
2621:             *	RDBNAM	- database name - optional (required if databases can have own sec.)
2622:             *
2623:             * 
2624:             * @return security check code
2625:             * @exception DRDAProtocolException
2626:             */
2627:            private int parseSECCHK() throws DRDAProtocolException {
2628:                int codePoint, securityCheckCode = 0;
2629:                int securityMechanism = 0;
2630:                databaseAccessException = null;
2631:                reader.markCollection();
2632:                codePoint = reader.getCodePoint();
2633:                while (codePoint != -1) {
2634:                    switch (codePoint) {
2635:                    //optional, ignorable
2636:                    case CodePoint.SECMGRNM:
2637:                        reader.skipBytes();
2638:                        break;
2639:                    //required
2640:                    case CodePoint.SECMEC:
2641:                        checkLength(CodePoint.SECMEC, 2);
2642:                        securityMechanism = reader.readNetworkShort();
2643:                        if (SanityManager.DEBUG)
2644:                            trace("parseSECCHK - Security mechanism = "
2645:                                    + securityMechanism);
2646:                        //RESOLVE - spec is not clear on what should happen
2647:                        //in this case
2648:                        if (securityMechanism != database.securityMechanism)
2649:                            invalidValue(CodePoint.SECMEC);
2650:                        break;
2651:                    //optional - depending on security Mechanism 
2652:                    case CodePoint.SECTKN:
2653:                        if ((database.securityMechanism != CodePoint.SECMEC_EUSRIDPWD)
2654:                                && (database.securityMechanism != CodePoint.SECMEC_USRSSBPWD)) {
2655:                            securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
2656:                            reader.skipBytes();
2657:                        } else if (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD) {
2658:                            if (database.decryptedUserId == null) {
2659:                                try {
2660:                                    database.decryptedUserId = reader
2661:                                            .readEncryptedString(
2662:                                                    decryptionManager,
2663:                                                    database.securityMechanism,
2664:                                                    myPublicKey,
2665:                                                    database.secTokenIn);
2666:                                } catch (SQLException se) {
2667:                                    println2Log(database.dbName,
2668:                                            session.drdaID, se.getMessage());
2669:                                    if (securityCheckCode == 0)
2670:                                        //userid invalid
2671:                                        securityCheckCode = CodePoint.SECCHKCD_13;
2672:                                }
2673:                                database.userId = database.decryptedUserId;
2674:                                if (SanityManager.DEBUG)
2675:                                    trace("**decrypted userid is: "
2676:                                            + database.userId);
2677:                            } else if (database.decryptedPassword == null) {
2678:                                try {
2679:                                    database.decryptedPassword = reader
2680:                                            .readEncryptedString(
2681:                                                    decryptionManager,
2682:                                                    database.securityMechanism,
2683:                                                    myPublicKey,
2684:                                                    database.secTokenIn);
2685:                                } catch (SQLException se) {
2686:                                    println2Log(database.dbName,
2687:                                            session.drdaID, se.getMessage());
2688:                                    if (securityCheckCode == 0)
2689:                                        //password invalid
2690:                                        securityCheckCode = CodePoint.SECCHKCD_0F;
2691:                                }
2692:                                database.password = database.decryptedPassword;
2693:                                if (SanityManager.DEBUG)
2694:                                    trace("**decrypted password is: "
2695:                                            + database.password);
2696:                            }
2697:                        } else if (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) {
2698:                            if (database.passwordSubstitute == null) {
2699:                                database.passwordSubstitute = reader
2700:                                        .readBytes();
2701:                                if (SanityManager.DEBUG)
2702:                                    trace("** Substitute Password is:"
2703:                                            + DecryptionManager
2704:                                                    .toHexString(
2705:                                                            database.passwordSubstitute,
2706:                                                            0,
2707:                                                            database.passwordSubstitute.length));
2708:                                database.password = DecryptionManager
2709:                                        .toHexString(
2710:                                                database.passwordSubstitute,
2711:                                                0,
2712:                                                database.passwordSubstitute.length);
2713:                            }
2714:                        } else {
2715:                            tooMany(CodePoint.SECTKN);
2716:                        }
2717:                        break;
2718:                    //optional - depending on security Mechanism
2719:                    case CodePoint.PASSWORD:
2720:                        database.password = reader.readString();
2721:                        if (SanityManager.DEBUG)
2722:                            trace("PASSWORD " + database.password);
2723:                        break;
2724:                    //optional - depending on security Mechanism
2725:                    //we are not supporting this method so we'll skip bytes
2726:                    case CodePoint.NEWPASSWORD:
2727:                        reader.skipBytes();
2728:                        break;
2729:                    //optional - depending on security Mechanism
2730:                    case CodePoint.USRID:
2731:                        database.userId = reader.readString();
2732:                        if (SanityManager.DEBUG)
2733:                            trace("USERID " + database.userId);
2734:                        break;
2735:                    //optional - depending on security Mechanism
2736:                    case CodePoint.RDBNAM:
2737:                        String dbname = parseRDBNAM();
2738:                        if (database != null) {
2739:                            if (!database.dbName.equals(dbname))
2740:                                rdbnamMismatch(CodePoint.SECCHK);
2741:                        } else {
2742:                            // we should already have added the database in ACCSEC
2743:                            // added code here in case we make the SECMEC session rather
2744:                            // than database wide
2745:                            addDatabase(dbname);
2746:                        }
2747:                        break;
2748:                    default:
2749:                        invalidCodePoint(codePoint);
2750:
2751:                    }
2752:                    codePoint = reader.getCodePoint();
2753:                }
2754:                // check for SECMEC which is required
2755:                if (securityMechanism == 0)
2756:                    missingCodePoint(CodePoint.SECMEC);
2757:
2758:                //check if we have a userid and password when we need it
2759:                if (securityCheckCode == 0
2760:                        && (database.securityMechanism == CodePoint.SECMEC_USRIDPWD || database.securityMechanism == CodePoint.SECMEC_USRIDONL)) {
2761:                    if (database.userId == null)
2762:                        securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
2763:                    else if (database.securityMechanism == CodePoint.SECMEC_USRIDPWD) {
2764:                        if (database.password == null)
2765:                            securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
2766:                    }
2767:                    //Note, we'll ignore encryptedUserId and encryptedPassword if they
2768:                    //are also set
2769:                }
2770:
2771:                if (securityCheckCode == 0
2772:                        && database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) {
2773:                    if (database.userId == null)
2774:                        securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
2775:                    else if (database.passwordSubstitute == null)
2776:                        securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
2777:                }
2778:
2779:                if (securityCheckCode == 0
2780:                        && database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD) {
2781:                    if (database.decryptedUserId == null)
2782:                        securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
2783:                    else if (database.decryptedPassword == null)
2784:                        securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
2785:                }
2786:                // RESOLVE - when we do security we need to decrypt encrypted userid & password
2787:                // before proceeding
2788:
2789:                // verify userid and password, if we haven't had any errors thus far.
2790:                if ((securityCheckCode == 0)
2791:                        && (databaseAccessException == null)) {
2792:                    securityCheckCode = verifyUserIdPassword();
2793:                }
2794:
2795:                // Security all checked 
2796:                if (securityCheckCode == 0)
2797:                    session.setState(session.CHKSEC);
2798:
2799:                return securityCheckCode;
2800:
2801:            }
2802:
2803:            /**
2804:             * Write security check reply
2805:             * Instance variables
2806:             * 	SVRCOD - serverity code - required
2807:             *	SECCHKCD	- security check code  - required
2808:             *	SECTKN - security token - optional, ignorable
2809:             *	SVCERRNO	- security service error number
2810:             *	SRVDGN	- Server Diagnostic Information
2811:             *
2812:             * @exception DRDAProtocolException
2813:             */
2814:            private void writeSECCHKRM(int securityCheckCode)
2815:                    throws DRDAProtocolException {
2816:                writer.createDssReply();
2817:                writer.startDdm(CodePoint.SECCHKRM);
2818:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
2819:                        svrcodFromSecchkcd(securityCheckCode));
2820:                writer.writeScalar1Byte(CodePoint.SECCHKCD, securityCheckCode);
2821:                writer.endDdmAndDss();
2822:
2823:                if (securityCheckCode != 0) {
2824:                    // then we have an error and are going to end up ignoring the rest
2825:                    // of the DSS request chain.
2826:                    skipRemainder(false);
2827:                }
2828:
2829:                finalizeChain();
2830:
2831:            }
2832:
2833:            /**
2834:             * Calculate SVRCOD value from SECCHKCD
2835:             *
2836:             * @param securityCheckCode
2837:             * @return SVRCOD value
2838:             */
2839:            private int svrcodFromSecchkcd(int securityCheckCode) {
2840:                if (securityCheckCode == 0 || securityCheckCode == 2
2841:                        || securityCheckCode == 5 || securityCheckCode == 8)
2842:                    return CodePoint.SVRCOD_INFO;
2843:                else
2844:                    return CodePoint.SVRCOD_ERROR;
2845:            }
2846:
2847:            /**
2848:             * Parse access RDB
2849:             * Instance variables
2850:             *	RDBACCCL - RDB Access Manager Class - required must be SQLAM
2851:             *  CRRTKN - Correlation Token - required
2852:             *  RDBNAM - Relational database name -required
2853:             *  PRDID - Product specific identifier - required
2854:             *  TYPDEFNAM	- Data Type Definition Name -required
2855:             *  TYPDEFOVR	- Type definition overrides -required
2856:             *  RDBALWUPD -  RDB Allow Updates optional
2857:             *  PRDDTA - Product Specific Data - optional - ignorable
2858:             *  STTDECDEL - Statement Decimal Delimiter - optional
2859:             *  STTSTRDEL - Statement String Delimiter - optional
2860:             *  TRGDFTRT - Target Default Value Return - optional
2861:             *
2862:             * @return severity code
2863:             *
2864:             * @exception DRDAProtocolException
2865:             */
2866:            private int parseACCRDB() throws DRDAProtocolException {
2867:                int codePoint;
2868:                int svrcod = 0;
2869:                copyToRequired(ACCRDB_REQUIRED);
2870:                reader.markCollection();
2871:                codePoint = reader.getCodePoint();
2872:                while (codePoint != -1) {
2873:                    switch (codePoint) {
2874:                    //required
2875:                    case CodePoint.RDBACCCL:
2876:                        checkLength(CodePoint.RDBACCCL, 2);
2877:                        int sqlam = reader.readNetworkShort();
2878:                        if (SanityManager.DEBUG)
2879:                            trace("RDBACCCL = " + sqlam);
2880:                        // required to be SQLAM 
2881:
2882:                        if (sqlam != CodePoint.SQLAM)
2883:                            invalidValue(CodePoint.RDBACCCL);
2884:                        removeFromRequired(CodePoint.RDBACCCL);
2885:                        break;
2886:                    //required
2887:                    case CodePoint.CRRTKN:
2888:                        database.crrtkn = reader.readBytes();
2889:                        if (SanityManager.DEBUG)
2890:                            trace("crrtkn "
2891:                                    + convertToHexString(database.crrtkn));
2892:                        removeFromRequired(CodePoint.CRRTKN);
2893:                        int l = database.crrtkn.length;
2894:                        if (l > CodePoint.MAX_NAME)
2895:                            tooBig(CodePoint.CRRTKN);
2896:                        // the format of the CRRTKN is defined in the DRDA reference
2897:                        // x.yz where x is 1 to 8 bytes (variable)
2898:                        // 		y is 1 to 8 bytes (variable)
2899:                        //		x is 6 bytes fixed
2900:                        //		size is variable between 9 and 23
2901:                        if (l < 9 || l > 23)
2902:                            invalidValue(CodePoint.CRRTKN);
2903:                        byte[] part1 = new byte[l - 6];
2904:                        for (int i = 0; i < part1.length; i++)
2905:                            part1[i] = database.crrtkn[i];
2906:                        long time = SignedBinary.getLong(database.crrtkn,
2907:                                l - 8, SignedBinary.BIG_ENDIAN); // as "long" as unique
2908:                        session.drdaID = reader.convertBytes(part1) + time
2909:                                + leftBrace + session.connNum + rightBrace;
2910:                        if (SanityManager.DEBUG)
2911:                            trace("******************************************drdaID is: "
2912:                                    + session.drdaID);
2913:                        database.setDrdaID(session.drdaID);
2914:
2915:                        break;
2916:                    //required
2917:                    case CodePoint.RDBNAM:
2918:                        String dbname = parseRDBNAM();
2919:                        if (database != null) {
2920:                            if (!database.dbName.equals(dbname))
2921:                                rdbnamMismatch(CodePoint.ACCRDB);
2922:                        } else {
2923:                            //first time we have seen a database name
2924:                            Database d = session.getDatabase(dbname);
2925:                            if (d == null)
2926:                                addDatabase(dbname);
2927:                            else {
2928:                                database = d;
2929:                                database.accessCount++;
2930:                            }
2931:                        }
2932:                        removeFromRequired(CodePoint.RDBNAM);
2933:                        break;
2934:                    //required
2935:                    case CodePoint.PRDID:
2936:                        appRequester.setClientVersion(reader.readString());
2937:                        if (SanityManager.DEBUG)
2938:                            trace("prdId " + appRequester.prdid);
2939:                        if (appRequester.prdid.length() > CodePoint.PRDID_MAX)
2940:                            tooBig(CodePoint.PRDID);
2941:
2942:                        /* If JCC version is 1.5 or later, send SQLWarning on CNTQRY */
2943:                        if (((appRequester.getClientType() == appRequester.JCC_CLIENT) && (appRequester
2944:                                .greaterThanOrEqualTo(1, 5, 0)))
2945:                                || (appRequester.getClientType() == appRequester.DNC_CLIENT)) {
2946:                            sendWarningsOnCNTQRY = true;
2947:                        } else
2948:                            sendWarningsOnCNTQRY = false;
2949:
2950:                        // The client can not request DIAGLVL because when run with
2951:                        // an older server it will cause an exception. Older version
2952:                        // of the server do not recognize requests for DIAGLVL.
2953:                        if ((appRequester.getClientType() == appRequester.DNC_CLIENT)
2954:                                && appRequester.greaterThanOrEqualTo(10, 2, 0)) {
2955:                            diagnosticLevel = CodePoint.DIAGLVL1;
2956:                        }
2957:
2958:                        removeFromRequired(CodePoint.PRDID);
2959:                        break;
2960:                    //required
2961:                    case CodePoint.TYPDEFNAM:
2962:                        setStmtOrDbByteOrder(true, null, parseTYPDEFNAM());
2963:                        removeFromRequired(CodePoint.TYPDEFNAM);
2964:                        break;
2965:                    //required
2966:                    case CodePoint.TYPDEFOVR:
2967:                        parseTYPDEFOVR(null);
2968:                        removeFromRequired(CodePoint.TYPDEFOVR);
2969:                        break;
2970:                    //optional 
2971:                    case CodePoint.RDBALWUPD:
2972:                        checkLength(CodePoint.RDBALWUPD, 1);
2973:                        database.rdbAllowUpdates = readBoolean(CodePoint.RDBALWUPD);
2974:                        if (SanityManager.DEBUG)
2975:                            trace("rdbAllowUpdates = "
2976:                                    + database.rdbAllowUpdates);
2977:                        break;
2978:                    //optional, ignorable
2979:                    case CodePoint.PRDDTA:
2980:                        // check that it fits in maximum but otherwise ignore for now
2981:                        if (reader.getDdmLength() > CodePoint.MAX_NAME)
2982:                            tooBig(CodePoint.PRDDTA);
2983:                        reader.skipBytes();
2984:                        break;
2985:                    case CodePoint.TRGDFTRT:
2986:                        byte b = reader.readByte();
2987:                        if (b == 0xF1)
2988:                            database.sendTRGDFTRT = true;
2989:                        break;
2990:                    //optional - not used in JCC so skip for now
2991:                    case CodePoint.STTDECDEL:
2992:                    case CodePoint.STTSTRDEL:
2993:                        codePointNotSupported(codePoint);
2994:                        break;
2995:                    default:
2996:                        invalidCodePoint(codePoint);
2997:                    }
2998:                    codePoint = reader.getCodePoint();
2999:                }
3000:                checkRequired(CodePoint.ACCRDB);
3001:                // check that we can support the double-byte and mixed-byte CCSIDS
3002:                // set svrcod to warning if they are not supported
3003:                if ((database.ccsidDBC != 0 && !server
3004:                        .supportsCCSID(database.ccsidDBC))
3005:                        || (database.ccsidMBC != 0 && !server
3006:                                .supportsCCSID(database.ccsidMBC)))
3007:                    svrcod = CodePoint.SVRCOD_WARNING;
3008:                return svrcod;
3009:            }
3010:
3011:            /**
3012:             * Parse TYPDEFNAM
3013:             *
3014:             * @return typdefnam
3015:             * @exception DRDAProtocolException
3016:             */
3017:            private String parseTYPDEFNAM() throws DRDAProtocolException {
3018:                String typDefNam = reader.readString();
3019:                if (SanityManager.DEBUG)
3020:                    trace("typeDefName " + typDefNam);
3021:                if (typDefNam.length() > CodePoint.MAX_NAME)
3022:                    tooBig(CodePoint.TYPDEFNAM);
3023:                checkValidTypDefNam(typDefNam);
3024:                // check if the typedef is one we support
3025:                if (!typDefNam.equals(CodePoint.TYPDEFNAM_QTDSQLASC)
3026:                        && !typDefNam.equals(CodePoint.TYPDEFNAM_QTDSQLJVM)
3027:                        && !typDefNam.equals(CodePoint.TYPDEFNAM_QTDSQLX86))
3028:                    valueNotSupported(CodePoint.TYPDEFNAM);
3029:                return typDefNam;
3030:            }
3031:
3032:            /**
3033:             * Set a statement or the database' byte order, depending on the arguments
3034:             *
3035:             * @param setDatabase   if true, set database' byte order, otherwise set statement's
3036:             * @param stmt          DRDAStatement, used when setDatabase is false
3037:             * @param typDefNam     TYPDEFNAM value
3038:             */
3039:            private void setStmtOrDbByteOrder(boolean setDatabase,
3040:                    DRDAStatement stmt, String typDefNam) {
3041:                int byteOrder = (typDefNam
3042:                        .equals(CodePoint.TYPDEFNAM_QTDSQLX86) ? SignedBinary.LITTLE_ENDIAN
3043:                        : SignedBinary.BIG_ENDIAN);
3044:                if (setDatabase) {
3045:                    database.typDefNam = typDefNam;
3046:                    database.byteOrder = byteOrder;
3047:                } else {
3048:                    stmt.typDefNam = typDefNam;
3049:                    stmt.byteOrder = byteOrder;
3050:                }
3051:            }
3052:
3053:            /**
3054:             * Write Access to RDB Completed
3055:             * Instance Variables
3056:             *  SVRCOD - severity code - 0 info, 4 warning -required
3057:             *  PRDID - product specific identifier -required
3058:             *  TYPDEFNAM - type definition name -required
3059:             *  TYPDEFOVR - type definition overrides - required
3060:             *  RDBINTTKN - token which can be used to interrupt DDM commands - optional
3061:             *  CRRTKN	- correlation token - only returned if we didn't get one from requester
3062:             *  SRVDGN - server diagnostic information - optional
3063:             *  PKGDFTCST - package default character subtype - optional
3064:             *  USRID - User ID at the target system - optional
3065:             *  SRVLST - Server List
3066:             * 
3067:             * @exception DRDAProtocolException
3068:             */
3069:            private void writeACCRDBRM(int svrcod) throws DRDAProtocolException {
3070:                writer.createDssReply();
3071:                writer.startDdm(CodePoint.ACCRDBRM);
3072:                writer.writeScalar2Bytes(CodePoint.SVRCOD, svrcod);
3073:                writer.writeScalarString(CodePoint.PRDID, server.prdId);
3074:                //TYPDEFNAM -required - JCC doesn't support QTDSQLJVM so for now we
3075:                // just use ASCII, though we should eventually be able to use QTDSQLJVM
3076:                // at level 7
3077:                writer.writeScalarString(CodePoint.TYPDEFNAM,
3078:                        CodePoint.TYPDEFNAM_QTDSQLASC);
3079:                writeTYPDEFOVR();
3080:                writer.endDdmAndDss();
3081:                finalizeChain();
3082:            }
3083:
3084:            private void writeTYPDEFOVR() throws DRDAProtocolException {
3085:                //TYPDEFOVR - required - only single byte and mixed byte are specified
3086:                writer.startDdm(CodePoint.TYPDEFOVR);
3087:                writer.writeScalar2Bytes(CodePoint.CCSIDSBC, server.CCSIDSBC);
3088:                writer.writeScalar2Bytes(CodePoint.CCSIDMBC, server.CCSIDMBC);
3089:                // PKGDFTCST - Send character subtype and userid if requested
3090:                if (database.sendTRGDFTRT) {
3091:                    // default to multibyte character
3092:                    writer.startDdm(CodePoint.PKGDFTCST);
3093:                    writer.writeShort(CodePoint.CSTMBCS);
3094:                    writer.endDdm();
3095:                    // userid
3096:                    writer.startDdm(CodePoint.USRID);
3097:                    writer.writeString(database.userId);
3098:                    writer.endDdm();
3099:                }
3100:                writer.endDdm();
3101:
3102:            }
3103:
3104:            /**
3105:             * Parse Type Defintion Overrides
3106:             * 	TYPDEF Overrides specifies the Coded Character SET Identifiers (CCSIDs)
3107:             *  that are in a named TYPDEF.
3108:             * Instance Variables
3109:             *  CCSIDSBC - CCSID for Single-Byte - optional
3110:             *  CCSIDDBC - CCSID for Double-Byte - optional
3111:             *  CCSIDMBC - CCSID for Mixed-byte characters -optional
3112:             *
3113:             * @param st	Statement this TYPDEFOVR applies to
3114:             *
3115:             * @exception DRDAProtocolException
3116:             */
3117:            private void parseTYPDEFOVR(DRDAStatement st)
3118:                    throws DRDAProtocolException {
3119:                int codePoint;
3120:                int ccsidSBC = 0;
3121:                int ccsidDBC = 0;
3122:                int ccsidMBC = 0;
3123:                String ccsidSBCEncoding = null;
3124:                String ccsidDBCEncoding = null;
3125:                String ccsidMBCEncoding = null;
3126:
3127:                reader.markCollection();
3128:
3129:                codePoint = reader.getCodePoint();
3130:                // at least one of the following instance variable is required
3131:                // if the TYPDEFOVR is specified in a command object
3132:                if (codePoint == -1 && st != null)
3133:                    missingCodePoint(CodePoint.CCSIDSBC);
3134:
3135:                while (codePoint != -1) {
3136:                    switch (codePoint) {
3137:                    case CodePoint.CCSIDSBC:
3138:                        checkLength(CodePoint.CCSIDSBC, 2);
3139:                        ccsidSBC = reader.readNetworkShort();
3140:                        try {
3141:                            ccsidSBCEncoding = CharacterEncodings
3142:                                    .getJavaEncoding(ccsidSBC);
3143:                        } catch (Exception e) {
3144:                            valueNotSupported(CodePoint.CCSIDSBC);
3145:                        }
3146:                        if (SanityManager.DEBUG)
3147:                            trace("ccsidsbc = " + ccsidSBC + " encoding = "
3148:                                    + ccsidSBCEncoding);
3149:                        break;
3150:                    case CodePoint.CCSIDDBC:
3151:                        checkLength(CodePoint.CCSIDDBC, 2);
3152:                        ccsidDBC = reader.readNetworkShort();
3153:                        try {
3154:                            ccsidDBCEncoding = CharacterEncodings
3155:                                    .getJavaEncoding(ccsidDBC);
3156:                        } catch (Exception e) {
3157:                            // we write a warning later for this so no error
3158:                            // unless for a statement
3159:                            ccsidDBCEncoding = null;
3160:                            if (st != null)
3161:                                valueNotSupported(CodePoint.CCSIDSBC);
3162:                        }
3163:                        if (SanityManager.DEBUG)
3164:                            trace("ccsiddbc = " + ccsidDBC + " encoding = "
3165:                                    + ccsidDBCEncoding);
3166:                        break;
3167:                    case CodePoint.CCSIDMBC:
3168:                        checkLength(CodePoint.CCSIDMBC, 2);
3169:                        ccsidMBC = reader.readNetworkShort();
3170:                        try {
3171:                            ccsidMBCEncoding = CharacterEncodings
3172:                                    .getJavaEncoding(ccsidMBC);
3173:                        } catch (Exception e) {
3174:                            // we write a warning later for this so no error
3175:                            ccsidMBCEncoding = null;
3176:                            if (st != null)
3177:                                valueNotSupported(CodePoint.CCSIDMBC);
3178:                        }
3179:                        if (SanityManager.DEBUG)
3180:                            trace("ccsidmbc = " + ccsidMBC + " encoding = "
3181:                                    + ccsidMBCEncoding);
3182:                        break;
3183:                    default:
3184:                        invalidCodePoint(codePoint);
3185:
3186:                    }
3187:                    codePoint = reader.getCodePoint();
3188:                }
3189:                if (st == null) {
3190:                    if (ccsidSBC != 0) {
3191:                        database.ccsidSBC = ccsidSBC;
3192:                        database.ccsidSBCEncoding = ccsidSBCEncoding;
3193:                    }
3194:                    if (ccsidDBC != 0) {
3195:                        database.ccsidDBC = ccsidDBC;
3196:                        database.ccsidDBCEncoding = ccsidDBCEncoding;
3197:                    }
3198:                    if (ccsidMBC != 0) {
3199:                        database.ccsidMBC = ccsidMBC;
3200:                        database.ccsidMBCEncoding = ccsidMBCEncoding;
3201:                    }
3202:                } else {
3203:                    if (ccsidSBC != 0) {
3204:                        st.ccsidSBC = ccsidSBC;
3205:                        st.ccsidSBCEncoding = ccsidSBCEncoding;
3206:                    }
3207:                    if (ccsidDBC != 0) {
3208:                        st.ccsidDBC = ccsidDBC;
3209:                        st.ccsidDBCEncoding = ccsidDBCEncoding;
3210:                    }
3211:                    if (ccsidMBC != 0) {
3212:                        st.ccsidMBC = ccsidMBC;
3213:                        st.ccsidMBCEncoding = ccsidMBCEncoding;
3214:                    }
3215:                }
3216:            }
3217:
3218:            /**
3219:             * Parse PRPSQLSTT - Prepare SQL Statement
3220:             * Instance Variables
3221:             *   RDBNAM - Relational Database Name - optional
3222:             *   PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
3223:             *   RTNSQLDA - Return SQL Descriptor Area - optional
3224:             *   MONITOR - Monitor events - optional.
3225:             *   
3226:             * @return return 0 - don't return sqlda, 1 - return input sqlda, 
3227:             * 		2 - return output sqlda
3228:             * @throws DRDAProtocolException
3229:             * @throws SQLException
3230:             */
3231:            private int parsePRPSQLSTT() throws DRDAProtocolException,
3232:                    SQLException {
3233:                int codePoint;
3234:                boolean rtnsqlda = false;
3235:                boolean rtnOutput = true; // Return output SQLDA is default
3236:                String typdefnam;
3237:                Pkgnamcsn pkgnamcsn = null;
3238:
3239:                DRDAStatement stmt = null;
3240:                Database databaseToSet = null;
3241:
3242:                reader.markCollection();
3243:
3244:                codePoint = reader.getCodePoint();
3245:                while (codePoint != -1) {
3246:                    switch (codePoint) {
3247:                    // optional
3248:                    case CodePoint.RDBNAM:
3249:                        setDatabase(CodePoint.PRPSQLSTT);
3250:                        databaseToSet = database;
3251:                        break;
3252:                    // required
3253:                    case CodePoint.PKGNAMCSN:
3254:                        pkgnamcsn = parsePKGNAMCSN();
3255:                        break;
3256:                    //optional
3257:                    case CodePoint.RTNSQLDA:
3258:                        // Return SQLDA with description of statement
3259:                        rtnsqlda = readBoolean(CodePoint.RTNSQLDA);
3260:                        break;
3261:                    //optional
3262:                    case CodePoint.TYPSQLDA:
3263:                        rtnOutput = parseTYPSQLDA();
3264:                        break;
3265:                    //optional
3266:                    case CodePoint.MONITOR:
3267:                        parseMONITOR();
3268:                        break;
3269:                    default:
3270:                        invalidCodePoint(codePoint);
3271:
3272:                    }
3273:                    codePoint = reader.getCodePoint();
3274:                }
3275:
3276:                stmt = database.newDRDAStatement(pkgnamcsn);
3277:                String sqlStmt = parsePRPSQLSTTobjects(stmt);
3278:                if (databaseToSet != null)
3279:                    stmt.setDatabase(database);
3280:                stmt.explicitPrepare(sqlStmt);
3281:                // set the statement as the current statement
3282:                database.setCurrentStatement(stmt);
3283:
3284:                if (!rtnsqlda)
3285:                    return 0;
3286:                else if (rtnOutput)
3287:                    return 2;
3288:                else
3289:                    return 1;
3290:            }
3291:
3292:            /**
3293:             * Parse PRPSQLSTT objects
3294:             * Objects
3295:             *  TYPDEFNAM - Data type definition name - optional
3296:             *  TYPDEFOVR - Type defintion overrides - optional
3297:             *  SQLSTT - SQL Statement required
3298:             *  SQLATTR - Cursor attributes on prepare - optional - level 7
3299:             *
3300:             * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
3301:             * sent with the statement.  Once the statement is over, the default values
3302:             * sent in the ACCRDB are once again in effect.  If no values are supplied,
3303:             * the values sent in the ACCRDB are used.
3304:             * Objects may follow in one DSS or in several DSS chained together.
3305:             * 
3306:             * @return SQL statement
3307:             * @throws DRDAProtocolException
3308:             * @throws SQLException
3309:             */
3310:            private String parsePRPSQLSTTobjects(DRDAStatement stmt)
3311:                    throws DRDAProtocolException, SQLException {
3312:                String sqlStmt = null;
3313:                int codePoint;
3314:                do {
3315:                    correlationID = reader.readDssHeader();
3316:                    while (reader.moreDssData()) {
3317:                        codePoint = reader.readLengthAndCodePoint();
3318:                        switch (codePoint) {
3319:                        // required
3320:                        case CodePoint.SQLSTT:
3321:                            sqlStmt = parseEncodedString();
3322:                            if (SanityManager.DEBUG)
3323:                                trace("sqlStmt = " + sqlStmt);
3324:                            break;
3325:                        // optional
3326:                        case CodePoint.TYPDEFNAM:
3327:                            setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
3328:                            break;
3329:                        // optional
3330:                        case CodePoint.TYPDEFOVR:
3331:                            parseTYPDEFOVR(stmt);
3332:                            break;
3333:                        // optional
3334:                        case CodePoint.SQLATTR:
3335:                            parseSQLATTR(stmt);
3336:                            break;
3337:                        default:
3338:                            invalidCodePoint(codePoint);
3339:                        }
3340:                    }
3341:                } while (reader.isChainedWithSameID());
3342:                if (sqlStmt == null)
3343:                    missingCodePoint(CodePoint.SQLSTT);
3344:
3345:                return sqlStmt;
3346:            }
3347:
3348:            /**
3349:             * Parse TYPSQLDA - Type of the SQL Descriptor Area
3350:             *
3351:             * @return true if for output; false otherwise
3352:             * @exception DRDAProtocolException
3353:             */
3354:            private boolean parseTYPSQLDA() throws DRDAProtocolException {
3355:                checkLength(CodePoint.TYPSQLDA, 1);
3356:                byte sqldaType = reader.readByte();
3357:                if (SanityManager.DEBUG)
3358:                    trace("typSQLDa " + sqldaType);
3359:                if (sqldaType == CodePoint.TYPSQLDA_STD_OUTPUT
3360:                        || sqldaType == CodePoint.TYPSQLDA_LIGHT_OUTPUT
3361:                        || sqldaType == CodePoint.TYPSQLDA_X_OUTPUT)
3362:                    return true;
3363:                else if (sqldaType == CodePoint.TYPSQLDA_STD_INPUT
3364:                        || sqldaType == CodePoint.TYPSQLDA_LIGHT_INPUT
3365:                        || sqldaType == CodePoint.TYPSQLDA_X_INPUT)
3366:                    return false;
3367:                else
3368:                    invalidValue(CodePoint.TYPSQLDA);
3369:
3370:                // shouldn't get here but have to shut up compiler
3371:                return false;
3372:            }
3373:
3374:            /**
3375:             * Parse SQLATTR - Cursor attributes on prepare
3376:             *   This is an encoded string. Can have combination of following, eg INSENSITIVE SCROLL WITH HOLD
3377:             * Possible strings are
3378:             *  SENSITIVE DYNAMIC SCROLL [FOR UPDATE]
3379:             *  SENSITIVE STATIC SCROLL [FOR UPDATE]
3380:             *  INSENSITIVE SCROLL
3381:             *  FOR UPDATE
3382:             *  WITH HOLD
3383:             *
3384:             * @param stmt DRDAStatement
3385:             * @exception DRDAProtocolException
3386:             */
3387:            protected void parseSQLATTR(DRDAStatement stmt)
3388:                    throws DRDAProtocolException {
3389:                String attrs = parseEncodedString();
3390:                if (SanityManager.DEBUG)
3391:                    trace("sqlattr = '" + attrs + "'");
3392:                //let Cloudscape handle any errors in the types it doesn't support
3393:                //just set the attributes
3394:
3395:                boolean validAttribute = false;
3396:                if (attrs.indexOf("INSENSITIVE SCROLL") != -1
3397:                        || attrs.indexOf("SCROLL INSENSITIVE") != -1) //CLI
3398:                {
3399:                    stmt.scrollType = ResultSet.TYPE_SCROLL_INSENSITIVE;
3400:                    stmt.concurType = ResultSet.CONCUR_READ_ONLY;
3401:                    validAttribute = true;
3402:                }
3403:                if ((attrs.indexOf("SENSITIVE DYNAMIC SCROLL") != -1)
3404:                        || (attrs.indexOf("SENSITIVE STATIC SCROLL") != -1)) {
3405:                    stmt.scrollType = ResultSet.TYPE_SCROLL_SENSITIVE;
3406:                    validAttribute = true;
3407:                }
3408:
3409:                if ((attrs.indexOf("FOR UPDATE") != -1)) {
3410:                    validAttribute = true;
3411:                    stmt.concurType = ResultSet.CONCUR_UPDATABLE;
3412:                }
3413:
3414:                if (attrs.indexOf("WITH HOLD") != -1) {
3415:                    stmt.withHoldCursor = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
3416:                    validAttribute = true;
3417:                }
3418:
3419:                if (!validAttribute) {
3420:                    invalidValue(CodePoint.SQLATTR);
3421:                }
3422:            }
3423:
3424:            /**
3425:             * Parse DSCSQLSTT - Describe SQL Statement previously prepared
3426:             * Instance Variables
3427:             *	TYPSQLDA - sqlda type expected (output or input)
3428:             *  RDBNAM - relational database name - optional
3429:             *  PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
3430:             *  MONITOR - Monitor events - optional.
3431:             *
3432:             * @return expect "output sqlda" or not
3433:             * @throws DRDAProtocolException
3434:             * @throws SQLException
3435:             */
3436:            private boolean parseDSCSQLSTT() throws DRDAProtocolException,
3437:                    SQLException {
3438:                int codePoint;
3439:                boolean rtnOutput = true; // default
3440:                Pkgnamcsn pkgnamcsn = null;
3441:                reader.markCollection();
3442:
3443:                codePoint = reader.getCodePoint();
3444:                while (codePoint != -1) {
3445:                    switch (codePoint) {
3446:                    // optional
3447:                    case CodePoint.TYPSQLDA:
3448:                        rtnOutput = parseTYPSQLDA();
3449:                        break;
3450:                    // optional
3451:                    case CodePoint.RDBNAM:
3452:                        setDatabase(CodePoint.DSCSQLSTT);
3453:                        break;
3454:                    // required
3455:                    case CodePoint.PKGNAMCSN:
3456:                        pkgnamcsn = parsePKGNAMCSN();
3457:                        DRDAStatement stmt = database
3458:                                .getDRDAStatement(pkgnamcsn);
3459:                        if (stmt == null) {
3460:                            invalidValue(CodePoint.PKGNAMCSN);
3461:                        }
3462:                        break;
3463:                    //optional
3464:                    case CodePoint.MONITOR:
3465:                        parseMONITOR();
3466:                        break;
3467:                    default:
3468:                        invalidCodePoint(codePoint);
3469:                    }
3470:                    codePoint = reader.getCodePoint();
3471:                }
3472:                if (pkgnamcsn == null)
3473:                    missingCodePoint(CodePoint.PKGNAMCSN);
3474:                return rtnOutput;
3475:            }
3476:
3477:            /**
3478:             * Parse EXCSQLSTT - Execute non-cursor SQL Statement previously prepared
3479:             * Instance Variables
3480:             *  RDBNAM - relational database name - optional
3481:             *  PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
3482:             *  OUTEXP - Output expected
3483:             *  NBRROW - Number of rows to be inserted if it's an insert
3484:             *  PRCNAM - procedure name if specified by host variable, not needed for Cloudscape
3485:             *  QRYBLKSZ - query block size
3486:             *  MAXRSLCNT - max resultset count
3487:             *  MAXBLKEXT - Max number of extra blocks
3488:             *  RSLSETFLG - resultset flag
3489:             *  RDBCMTOK - RDB Commit Allowed - optional
3490:             *  OUTOVROPT - output override option
3491:             *  QRYROWSET - Query Rowset Size - Level 7
3492:             *  MONITOR - Monitor events - optional.
3493:             *
3494:             * @throws DRDAProtocolException
3495:             * @throws SQLException
3496:             */
3497:            private void parseEXCSQLSTT() throws DRDAProtocolException,
3498:                    SQLException {
3499:                int codePoint;
3500:                String strVal;
3501:                reader.markCollection();
3502:
3503:                codePoint = reader.getCodePoint();
3504:                boolean outputExpected = false;
3505:                Pkgnamcsn pkgnamcsn = null;
3506:                int numRows = 1; // default value
3507:                int blkSize = 0;
3508:                int maxrslcnt = 0; // default value
3509:                int maxblkext = CodePoint.MAXBLKEXT_DEFAULT;
3510:                int qryrowset = CodePoint.QRYROWSET_DEFAULT;
3511:                int outovropt = CodePoint.OUTOVRFRS;
3512:                byte[] rslsetflg = null;
3513:                String procName = null;
3514:
3515:                while (codePoint != -1) {
3516:                    switch (codePoint) {
3517:                    // optional
3518:                    case CodePoint.RDBNAM:
3519:                        setDatabase(CodePoint.EXCSQLSTT);
3520:                        break;
3521:                    // required
3522:                    case CodePoint.PKGNAMCSN:
3523:                        pkgnamcsn = parsePKGNAMCSN();
3524:                        break;
3525:                    // optional
3526:                    case CodePoint.OUTEXP:
3527:                        outputExpected = readBoolean(CodePoint.OUTEXP);
3528:                        if (SanityManager.DEBUG)
3529:                            trace("outexp = " + outputExpected);
3530:                        break;
3531:                    // optional
3532:                    case CodePoint.NBRROW:
3533:                        checkLength(CodePoint.NBRROW, 4);
3534:                        numRows = reader.readNetworkInt();
3535:                        if (SanityManager.DEBUG)
3536:                            trace("# of rows: " + numRows);
3537:                        break;
3538:                    // optional
3539:                    case CodePoint.PRCNAM:
3540:                        procName = reader.readString();
3541:                        if (SanityManager.DEBUG)
3542:                            trace("Procedure Name = " + procName);
3543:                        break;
3544:                    // optional
3545:                    case CodePoint.QRYBLKSZ:
3546:                        blkSize = parseQRYBLKSZ();
3547:                        break;
3548:                    // optional
3549:                    case CodePoint.MAXRSLCNT:
3550:                        // this is the maximum result set count
3551:                        // values are 0 - requester is not capabable of receiving result
3552:                        // sets as reply data in the response to EXCSQLSTT
3553:                        // -1 - requester is able to receive all result sets
3554:                        checkLength(CodePoint.MAXRSLCNT, 2);
3555:                        maxrslcnt = reader.readNetworkShort();
3556:                        if (SanityManager.DEBUG)
3557:                            trace("max rs count: " + maxrslcnt);
3558:                        break;
3559:                    // optional
3560:                    case CodePoint.MAXBLKEXT:
3561:                        // number of extra qury blocks of answer set data per result set
3562:                        // 0 - no extra query blocks
3563:                        // -1 - can receive entire result set
3564:                        checkLength(CodePoint.MAXBLKEXT, 2);
3565:                        maxblkext = reader.readNetworkShort();
3566:                        if (SanityManager.DEBUG)
3567:                            trace("max extra blocks: " + maxblkext);
3568:                        break;
3569:                    // optional
3570:                    case CodePoint.RSLSETFLG:
3571:                        //Result set flags
3572:                        rslsetflg = reader.readBytes();
3573:                        for (int i = 0; i < rslsetflg.length; i++)
3574:                            if (SanityManager.DEBUG)
3575:                                trace("rslsetflg: " + rslsetflg[i]);
3576:                        break;
3577:                    // optional
3578:                    case CodePoint.RDBCMTOK:
3579:                        parseRDBCMTOK();
3580:                        break;
3581:                    // optional
3582:                    case CodePoint.OUTOVROPT:
3583:                        outovropt = parseOUTOVROPT();
3584:                        break;
3585:                    // optional
3586:                    case CodePoint.QRYROWSET:
3587:                        //Note minimum for OPNQRY is 0, we'll assume it is the same
3588:                        //for EXCSQLSTT though the standard doesn't say
3589:                        qryrowset = parseQRYROWSET(0);
3590:                        break;
3591:                    //optional
3592:                    case CodePoint.MONITOR:
3593:                        parseMONITOR();
3594:                        break;
3595:                    default:
3596:                        invalidCodePoint(codePoint);
3597:                    }
3598:                    codePoint = reader.getCodePoint();
3599:                }
3600:
3601:                if (pkgnamcsn == null)
3602:                    missingCodePoint(CodePoint.PKGNAMCSN);
3603:
3604:                DRDAStatement stmt;
3605:                boolean needPrepareCall = false;
3606:
3607:                stmt = database.getDRDAStatement(pkgnamcsn);
3608:                boolean isProcedure = (procName != null || (stmt != null
3609:                        && stmt.wasExplicitlyPrepared() && stmt.isCall));
3610:
3611:                if (isProcedure) // stored procedure call
3612:                {
3613:                    if (stmt == null || !(stmt.wasExplicitlyPrepared())) {
3614:                        stmt = database.newDRDAStatement(pkgnamcsn);
3615:                        stmt.setQryprctyp(CodePoint.QRYBLKCTL_DEFAULT);
3616:                        needPrepareCall = true;
3617:                    }
3618:
3619:                    stmt.procName = procName;
3620:                    stmt.outputExpected = outputExpected;
3621:                } else {
3622:                    // we can't find the statement
3623:                    if (stmt == null) {
3624:                        invalidValue(CodePoint.PKGNAMCSN);
3625:                    }
3626:                    stmt.setQryprctyp(CodePoint.QRYBLKCTL_DEFAULT);
3627:                }
3628:
3629:                stmt.nbrrow = numRows;
3630:                stmt.qryrowset = qryrowset;
3631:                stmt.blksize = blkSize;
3632:                stmt.maxblkext = maxblkext;
3633:                stmt.maxrslcnt = maxrslcnt;
3634:                stmt.outovropt = outovropt;
3635:                stmt.rslsetflg = rslsetflg;
3636:                if (pendingStatementTimeout >= 0) {
3637:                    stmt.getPreparedStatement().setQueryTimeout(
3638:                            pendingStatementTimeout);
3639:                    pendingStatementTimeout = -1;
3640:                }
3641:
3642:                // set the statement as the current statement
3643:                database.setCurrentStatement(stmt);
3644:
3645:                boolean hasResultSet;
3646:                if (reader.isChainedWithSameID()) {
3647:                    hasResultSet = parseEXCSQLSTTobjects(stmt);
3648:                } else {
3649:                    if (isProcedure && (needPrepareCall)) {
3650:                        // if we had parameters the callable statement would
3651:                        // be prepared with parseEXCQLSTTobjects, otherwise we
3652:                        // have to do it here
3653:                        String prepareString = "call " + stmt.procName + "()";
3654:                        if (SanityManager.DEBUG)
3655:                            trace("$$$prepareCall is: " + prepareString);
3656:                        database.getConnection().clearWarnings();
3657:                        CallableStatement cs = (CallableStatement) stmt
3658:                                .prepare(prepareString);
3659:                    }
3660:                    stmt.ps.clearWarnings();
3661:                    hasResultSet = stmt.execute();
3662:                }
3663:
3664:                ResultSet rs = null;
3665:                if (hasResultSet) {
3666:                    rs = stmt.getResultSet();
3667:                }
3668:                // temp until ps.execute() return value fixed
3669:                hasResultSet = (rs != null);
3670:                int numResults = 0;
3671:                if (hasResultSet) {
3672:                    numResults = stmt.getNumResultSets();
3673:                    writeRSLSETRM(stmt);
3674:                }
3675:
3676:                // First of all, we send if there really are output params. Otherwise
3677:                // CLI (.Net driver) fails. DRDA spec (page 151,152) says send SQLDTARD
3678:                // if server has output param data to send.
3679:                boolean sendSQLDTARD = stmt.hasOutputParams() && outputExpected;
3680:                if (isProcedure) {
3681:                    if (sendSQLDTARD) {
3682:                        writer.createDssObject();
3683:                        writer.startDdm(CodePoint.SQLDTARD);
3684:                        writer.startDdm(CodePoint.FDODSC);
3685:                        writeQRYDSC(stmt, true);
3686:                        writer.endDdm();
3687:                        writer.startDdm(CodePoint.FDODTA);
3688:                        writeFDODTA(stmt);
3689:                        writer.endDdm();
3690:                        writer.endDdmAndDss();
3691:                    } else if (hasResultSet)
3692:                        // DRDA spec says that we MUST return either an
3693:                        // SQLDTARD or an SQLCARD--the former when we have
3694:                        // output parameters, the latter when we don't.
3695:                        // If we have a result set, then we have to write
3696:                        // the SQLCARD _now_, since it is expected before
3697:                        // we send the result set info below; if we don't
3698:                        // have a result set and we don't send SQLDTARD,
3699:                        // then we can wait until we reach the call to
3700:                        // checkWarning() below, which will write an
3701:                        // SQLCARD for us.
3702:                        writeNullSQLCARDobject();
3703:                }
3704:
3705:                //We need to marke that params are finished so that we know we 
3706:                // are ready to send resultset info.
3707:                stmt.finishParams();
3708:
3709:                PreparedStatement ps = stmt.getPreparedStatement();
3710:                int rsNum = 0;
3711:                do {
3712:                    if (hasResultSet) {
3713:                        stmt.setCurrentDrdaResultSet(rsNum);
3714:                        //indicate that we are going to return data
3715:                        stmt.setQryrtndta(true);
3716:                        if (!isProcedure)
3717:                            checkWarning(null, ps, null, -1, true, true);
3718:                        if (rsNum == 0)
3719:                            writeSQLRSLRD(stmt);
3720:                        writeOPNQRYRM(true, stmt);
3721:                        writeSQLCINRD(stmt);
3722:                        writeQRYDSC(stmt, false);
3723:                        stmt.rsSuspend();
3724:
3725:                        /* Currently, if LMTBLKPRC is used, a pre-condition is that no lob columns.
3726:                         * But in the future, when we do support LOB in LMTBLKPRC, the drda spec still
3727:                         * does not allow LOB to be sent with OPNQRYRM.  So this "if" here will have
3728:                         * to add "no lob columns".
3729:                         */
3730:                        if (stmt.getQryprctyp() == CodePoint.LMTBLKPRC)
3731:                            writeQRYDTA(stmt);
3732:                    } else if (!sendSQLDTARD) {
3733:                        int updateCount = ps.getUpdateCount();
3734:                        if (false && (database.RDBUPDRM_sent == false)
3735:                                && !isProcedure) {
3736:                            writeRDBUPDRM();
3737:                        }
3738:
3739:                        checkWarning(database.getConnection(), stmt.ps, null,
3740:                                updateCount, true, true);
3741:                    }
3742:
3743:                } while (hasResultSet && (++rsNum < numResults));
3744:
3745:                return; // we are done
3746:            }
3747:
3748:            /**
3749:             * Parse RDBCMTOK - tells the database whether to allow commits or rollbacks
3750:             * to be executed as part of the command
3751:             * Since we don't have a SQL commit or rollback command, we will just ignore
3752:             * this for now
3753:             *
3754:             * @exception DRDAProtocolException
3755:             */
3756:            private void parseRDBCMTOK() throws DRDAProtocolException {
3757:                boolean rdbcmtok = readBoolean(CodePoint.RDBCMTOK);
3758:                if (SanityManager.DEBUG)
3759:                    trace("rdbcmtok = " + rdbcmtok);
3760:            }
3761:
3762:            /**
3763:             * Parse EXCSQLSTT command objects
3764:             * Command Objects
3765:             *  TYPDEFNAM - Data Type Definition Name - optional
3766:             *  TYPDEFOVR - TYPDEF Overrides -optional
3767:             *	SQLDTA - optional, variable data, specified if prpared statement has input parameters
3768:             *	EXTDTA - optional, externalized FD:OCA data
3769:             *	OUTOVR - output override descriptor, not allowed for stored procedure calls
3770:             *
3771:             * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
3772:             * sent with the statement.  Once the statement is over, the default values
3773:             * sent in the ACCRDB are once again in effect.  If no values are supplied,
3774:             * the values sent in the ACCRDB are used.
3775:             * Objects may follow in one DSS or in several DSS chained together.
3776:             * 
3777:             * @param stmt	the DRDAStatement to execute
3778:             * @throws DRDAProtocolException
3779:             * @throws SQLException
3780:             */
3781:            private boolean parseEXCSQLSTTobjects(DRDAStatement stmt)
3782:                    throws DRDAProtocolException, SQLException {
3783:                int codePoint;
3784:                boolean gotSQLDTA = false, gotEXTDTA = false;
3785:                boolean result = false;
3786:                do {
3787:                    correlationID = reader.readDssHeader();
3788:                    while (reader.moreDssData()) {
3789:                        codePoint = reader.readLengthAndCodePoint();
3790:                        switch (codePoint) {
3791:                        // optional
3792:                        case CodePoint.TYPDEFNAM:
3793:                            setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
3794:                            stmt.setTypDefValues();
3795:                            break;
3796:                        // optional
3797:                        case CodePoint.TYPDEFOVR:
3798:                            parseTYPDEFOVR(stmt);
3799:                            stmt.setTypDefValues();
3800:                            break;
3801:                        // required
3802:                        case CodePoint.SQLDTA:
3803:                            parseSQLDTA(stmt);
3804:                            gotSQLDTA = true;
3805:                            break;
3806:                        // optional
3807:                        case CodePoint.EXTDTA:
3808:                            readAndSetAllExtParams(stmt, true);
3809:                            stmt.ps.clearWarnings();
3810:                            result = stmt.execute();
3811:                            gotEXTDTA = true;
3812:                            break;
3813:                        // optional
3814:                        case CodePoint.OUTOVR:
3815:                            parseOUTOVR(stmt);
3816:                            break;
3817:                        default:
3818:                            invalidCodePoint(codePoint);
3819:                        }
3820:                    }
3821:                } while (reader.isChainedWithSameID());
3822:
3823:                // SQLDTA is required
3824:                if (!gotSQLDTA)
3825:                    missingCodePoint(CodePoint.SQLDTA);
3826:
3827:                if (!gotEXTDTA) {
3828:                    stmt.ps.clearWarnings();
3829:                    result = stmt.execute();
3830:                }
3831:
3832:                return result;
3833:            }
3834:
3835:            /**
3836:             * Write SQLCINRD - result set column information
3837:             *
3838:             * @throws DRDAProtocolException
3839:             * @throws SQLException
3840:             */
3841:            private void writeSQLCINRD(DRDAStatement stmt)
3842:                    throws DRDAProtocolException, SQLException {
3843:                ResultSet rs = null;
3844:                // todo ps is never used or closed - could this be a memory leak?
3845:                PreparedStatement ps = stmt.getPreparedStatement();
3846:
3847:                if (!stmt.needsToSendParamData)
3848:                    rs = stmt.getResultSet();
3849:
3850:                writer.createDssObject();
3851:                writer.startDdm(CodePoint.SQLCINRD);
3852:                if (sqlamLevel >= MGRLVL_7)
3853:                    writeSQLDHROW(stmt);
3854:
3855:                ResultSetMetaData rsmeta = rs.getMetaData();
3856:                int ncols = rsmeta.getColumnCount();
3857:                writer.writeShort(ncols); // num of columns
3858:                if (sqlamLevel >= MGRLVL_7) {
3859:                    for (int i = 0; i < ncols; i++)
3860:                        writeSQLDAGRP(rsmeta, null, i, true);
3861:                } else {
3862:                    for (int i = 0; i < ncols; i++) {
3863:                        writeVCMorVCS(rsmeta.getColumnName(i + 1));
3864:                        writeVCMorVCS(rsmeta.getColumnLabel(i + 1));
3865:                        writeVCMorVCS(null);
3866:                    }
3867:                }
3868:                writer.endDdmAndDss();
3869:            }
3870:
3871:            /**
3872:             * Write SQLRSLRD - result set reply data
3873:             *
3874:             * @throws DRDAProtocolException
3875:             * @throws SQLException
3876:             */
3877:            private void writeSQLRSLRD(DRDAStatement stmt)
3878:                    throws DRDAProtocolException, SQLException {
3879:                int numResults = stmt.getNumResultSets();
3880:
3881:                writer.createDssObject();
3882:                writer.startDdm(CodePoint.SQLRSLRD);
3883:                writer.writeShort(numResults); // num of result sets
3884:
3885:                for (int i = 0; i < numResults; i++) {
3886:                    writer.writeInt(i); // rsLocator
3887:                    writeVCMorVCS(stmt.getResultSetCursorName(i));
3888:                    writer.writeInt(1); // num of rows XXX resolve, it doesn't matter for now
3889:
3890:                }
3891:                writer.endDdmAndDss();
3892:            }
3893:
3894:            /**
3895:             * Write RSLSETRM
3896:             * Instance variables
3897:             *  SVRCOD - Severity code - Information only - required
3898:             *  PKGSNLST - list of PKGNAMCSN -required
3899:             *  SRVDGN - Server Diagnostic Information -optional
3900:             *
3901:             * @throws DRDAProtocolException
3902:             * @throws SQLException
3903:             */
3904:            private void writeRSLSETRM(DRDAStatement stmt)
3905:                    throws DRDAProtocolException, SQLException {
3906:                int numResults = stmt.getNumResultSets();
3907:                writer.createDssReply();
3908:                writer.startDdm(CodePoint.RSLSETRM);
3909:                writer.writeScalar2Bytes(CodePoint.SVRCOD, 0);
3910:                writer.startDdm(CodePoint.PKGSNLST);
3911:
3912:                for (int i = 0; i < numResults; i++)
3913:                    writePKGNAMCSN(stmt.getResultSetPkgcnstkn(i).getBytes());
3914:                writer.endDdm();
3915:                writer.endDdmAndDss();
3916:            }
3917:
3918:            /**
3919:             * Parse SQLDTA - SQL program variable data 
3920:             * and handle exception.
3921:             * @see #parseSQLDTA_work
3922:             */
3923:
3924:            private void parseSQLDTA(DRDAStatement stmt)
3925:                    throws DRDAProtocolException, SQLException {
3926:                try {
3927:                    parseSQLDTA_work(stmt);
3928:                } catch (SQLException se) {
3929:                    skipRemainder(true);
3930:                    throw se;
3931:                }
3932:            }
3933:
3934:            /**
3935:             * Parse SQLDTA - SQL program variable data
3936:             * Instance Variables
3937:             *  FDODSC - FD:OCA data descriptor - required
3938:             *  FDODTA - FD:OCA data - optional
3939:             *    
3940:             * @throws DRDAProtocolException
3941:             * @throws SQLException
3942:             */
3943:            private void parseSQLDTA_work(DRDAStatement stmt)
3944:                    throws DRDAProtocolException, SQLException {
3945:                String strVal;
3946:                PreparedStatement ps = stmt.getPreparedStatement();
3947:                int codePoint;
3948:                EngineParameterMetaData pmeta = null;
3949:                Vector paramDrdaTypes = new Vector();
3950:                Vector paramLens = new Vector();
3951:                ArrayList paramExtPositions = null;
3952:                int numVars = 0;
3953:                boolean rtnParam = false;
3954:
3955:                reader.markCollection();
3956:                codePoint = reader.getCodePoint();
3957:                while (codePoint != -1) {
3958:                    switch (codePoint) {
3959:                    // required
3960:                    case CodePoint.FDODSC:
3961:                        while (reader.getDdmLength() > 6) //we get parameter info til last 6 byte
3962:                        {
3963:                            int dtaGrpLen = reader.readUnsignedByte();
3964:                            int numVarsInGrp = (dtaGrpLen - 3) / 3;
3965:                            if (SanityManager.DEBUG)
3966:                                trace("num of vars in this group is: "
3967:                                        + numVarsInGrp);
3968:                            reader.readByte(); // tripletType
3969:                            reader.readByte(); // id
3970:                            for (int j = 0; j < numVarsInGrp; j++) {
3971:                                paramDrdaTypes.addElement(new Byte(reader
3972:                                        .readByte()));
3973:                                if (SanityManager.DEBUG)
3974:                                    trace("drdaType is: "
3975:                                            + "0x"
3976:                                            + Integer
3977:                                                    .toHexString(((Byte) paramDrdaTypes
3978:                                                            .lastElement())
3979:                                                            .byteValue()));
3980:                                int drdaLength = reader.readNetworkShort();
3981:                                if (SanityManager.DEBUG)
3982:                                    trace("drdaLength is: " + drdaLength);
3983:                                paramLens.addElement(new Integer(drdaLength));
3984:                            }
3985:                        }
3986:                        numVars = paramDrdaTypes.size();
3987:                        if (SanityManager.DEBUG)
3988:                            trace("numVars = " + numVars);
3989:                        if (ps == null) // it is a CallableStatement under construction
3990:                        {
3991:                            String marks = "(?"; // construct parameter marks
3992:                            for (int i = 1; i < numVars; i++)
3993:                                marks += ", ?";
3994:                            String prepareString = "call " + stmt.procName
3995:                                    + marks + ")";
3996:                            if (SanityManager.DEBUG)
3997:                                trace("$$ prepareCall is: " + prepareString);
3998:                            CallableStatement cs = null;
3999:                            try {
4000:                                cs = (CallableStatement) stmt
4001:                                        .prepare(prepareString);
4002:                                stmt.registerAllOutParams();
4003:                            } catch (SQLException se) {
4004:                                if (!stmt.outputExpected
4005:                                        || (!se.getSQLState().equals(
4006:                                                SQLState.LANG_NO_METHOD_FOUND)))
4007:                                    throw se;
4008:                                if (SanityManager.DEBUG)
4009:                                    trace("****** second try with return parameter...");
4010:                                // Save first SQLException most likely suspect
4011:                                if (numVars == 1)
4012:                                    prepareString = "? = call " + stmt.procName
4013:                                            + "()";
4014:                                else
4015:                                    prepareString = "? = call " + stmt.procName
4016:                                            + "(" + marks.substring(3) + ")";
4017:                                if (SanityManager.DEBUG)
4018:                                    trace("$$ prepareCall is: " + prepareString);
4019:                                try {
4020:                                    cs = (CallableStatement) stmt
4021:                                            .prepare(prepareString);
4022:                                } catch (SQLException se2) {
4023:                                    // The first exception is the most likely suspect
4024:                                    throw se;
4025:                                }
4026:                                rtnParam = true;
4027:                            }
4028:                            ps = cs;
4029:                            stmt.ps = ps;
4030:                        }
4031:
4032:                        pmeta = stmt.getParameterMetaData();
4033:
4034:                        reader.readBytes(6); // descriptor footer
4035:                        break;
4036:                    // optional
4037:                    case CodePoint.FDODTA:
4038:                        reader.readByte(); // row indicator
4039:                        for (int i = 0; i < numVars; i++) {
4040:
4041:                            if ((((Byte) paramDrdaTypes.elementAt(i))
4042:                                    .byteValue() & 0x1) == 0x1) // nullable
4043:                            {
4044:                                int nullData = reader.readUnsignedByte();
4045:                                if ((nullData & 0xFF) == FdocaConstants.NULL_DATA) {
4046:                                    if (SanityManager.DEBUG)
4047:                                        trace("******param null");
4048:                                    if (pmeta.getParameterMode(i + 1) != JDBC30Translation.PARAMETER_MODE_OUT)
4049:                                        ps.setNull(i + 1, pmeta
4050:                                                .getParameterType(i + 1));
4051:                                    if (stmt.isOutputParam(i + 1))
4052:                                        stmt.registerOutParam(i + 1);
4053:                                    continue;
4054:                                }
4055:                            }
4056:
4057:                            // not null, read and set it
4058:                            paramExtPositions = readAndSetParams(i, stmt,
4059:                                    ((Byte) paramDrdaTypes.elementAt(i))
4060:                                            .byteValue(), pmeta,
4061:                                    paramExtPositions, ((Integer) (paramLens
4062:                                            .elementAt(i))).intValue());
4063:                        }
4064:                        stmt.cliParamExtPositions = paramExtPositions;
4065:                        stmt.cliParamDrdaTypes = paramDrdaTypes;
4066:                        stmt.cliParamLens = paramLens;
4067:                        break;
4068:                    case CodePoint.EXTDTA:
4069:                        readAndSetAllExtParams(stmt, false);
4070:                        break;
4071:                    default:
4072:                        invalidCodePoint(codePoint);
4073:
4074:                    }
4075:                    codePoint = reader.getCodePoint();
4076:                }
4077:
4078:            }
4079:
4080:            private int getByteOrder() {
4081:                DRDAStatement stmt = database.getCurrentStatement();
4082:                return ((stmt != null && stmt.typDefNam != null) ? stmt.byteOrder
4083:                        : database.byteOrder);
4084:            }
4085:
4086:            /**
4087:             * Read different types of input parameters and set them in PreparedStatement
4088:             * @param i			index of the parameter
4089:             * @param stmt       drda statement
4090:             * @param drdaType	drda type of the parameter
4091:             * @param pmeta		parameter meta data
4092:             * @param paramExtPositions  ArrayList of parameters with extdta
4093:             * @param paramLenNumBytes Number of bytes for encoding LOB Length
4094:             *
4095:             * @return updated paramExtPositions
4096:             * @throws DRDAProtocolException
4097:             * @throws SQLException
4098:             */
4099:            private ArrayList readAndSetParams(int i, DRDAStatement stmt,
4100:                    int drdaType, EngineParameterMetaData pmeta,
4101:                    ArrayList paramExtPositions, int paramLenNumBytes)
4102:                    throws DRDAProtocolException, SQLException {
4103:                PreparedStatement ps = stmt.getPreparedStatement();
4104:                // mask out null indicator
4105:                drdaType = ((drdaType | 0x01) & 0x000000ff);
4106:
4107:                if (ps instanceof  CallableStatement) {
4108:                    if (stmt.isOutputParam(i + 1)) {
4109:                        CallableStatement cs = (CallableStatement) ps;
4110:                        cs.registerOutParameter(i + 1, stmt
4111:                                .getOutputParamType(i + 1));
4112:                    }
4113:                }
4114:
4115:                switch (drdaType) {
4116:                case DRDAConstants.DRDA_TYPE_NSMALL: {
4117:                    short paramVal = (short) reader.readShort(getByteOrder());
4118:                    if (SanityManager.DEBUG)
4119:                        trace("short parameter value is: " + paramVal);
4120:                    // DB2 does not have a BOOLEAN java.sql.bit type, it's sent as small
4121:                    if (pmeta.getParameterType(i + 1) == JDBC30Translation.BOOLEAN)
4122:                        ps.setBoolean(i + 1, (paramVal == 1));
4123:                    else
4124:                        ps.setShort(i + 1, paramVal);
4125:                    break;
4126:                }
4127:                case DRDAConstants.DRDA_TYPE_NINTEGER: {
4128:                    int paramVal = reader.readInt(getByteOrder());
4129:                    if (SanityManager.DEBUG)
4130:                        trace("integer parameter value is: " + paramVal);
4131:                    ps.setInt(i + 1, paramVal);
4132:                    break;
4133:                }
4134:                case DRDAConstants.DRDA_TYPE_NINTEGER8: {
4135:                    long paramVal = reader.readLong(getByteOrder());
4136:                    if (SanityManager.DEBUG)
4137:                        trace("parameter value is: " + paramVal);
4138:                    ps.setLong(i + 1, paramVal);
4139:                    break;
4140:                }
4141:                case DRDAConstants.DRDA_TYPE_NFLOAT4: {
4142:                    float paramVal = reader.readFloat(getByteOrder());
4143:                    if (SanityManager.DEBUG)
4144:                        trace("parameter value is: " + paramVal);
4145:                    ps.setFloat(i + 1, paramVal);
4146:                    break;
4147:                }
4148:                case DRDAConstants.DRDA_TYPE_NFLOAT8: {
4149:                    double paramVal = reader.readDouble(getByteOrder());
4150:                    if (SanityManager.DEBUG)
4151:                        trace("nfloat8 parameter value is: " + paramVal);
4152:                    ps.setDouble(i + 1, paramVal);
4153:                    break;
4154:                }
4155:                case DRDAConstants.DRDA_TYPE_NDECIMAL: {
4156:                    int precision = (paramLenNumBytes >> 8) & 0xff;
4157:                    int scale = paramLenNumBytes & 0xff;
4158:                    BigDecimal paramVal = reader.readBigDecimal(precision,
4159:                            scale);
4160:                    if (SanityManager.DEBUG)
4161:                        trace("ndecimal parameter value is: " + paramVal);
4162:                    ps.setBigDecimal(i + 1, paramVal);
4163:                    break;
4164:                }
4165:                case DRDAConstants.DRDA_TYPE_NDATE: {
4166:                    String paramVal = reader.readStringData(10).trim(); //parameter may be char value
4167:                    if (SanityManager.DEBUG)
4168:                        trace("ndate parameter value is: \"" + paramVal + "\"");
4169:                    try {
4170:                        ps.setDate(i + 1, java.sql.Date.valueOf(paramVal));
4171:                    } catch (java.lang.IllegalArgumentException e) {
4172:                        // Just use SQLSTATE as message since, if user wants to
4173:                        // retrieve it, the message will be looked up by the
4174:                        // sqlcamessage() proc, which will get the localized
4175:                        // message based on SQLSTATE, and will ignore the
4176:                        // the message we use here...
4177:                        throw new SQLException(
4178:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4179:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(
4180:                                        0, 5));
4181:                    }
4182:                    break;
4183:                }
4184:                case DRDAConstants.DRDA_TYPE_NTIME: {
4185:                    String paramVal = reader.readStringData(8).trim(); //parameter may be char value
4186:                    if (SanityManager.DEBUG)
4187:                        trace("ntime parameter value is: " + paramVal);
4188:                    try {
4189:                        ps.setTime(i + 1, java.sql.Time.valueOf(paramVal));
4190:                    } catch (java.lang.IllegalArgumentException e) {
4191:                        throw new SQLException(
4192:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4193:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(
4194:                                        0, 5));
4195:                    }
4196:                    break;
4197:                }
4198:                case DRDAConstants.DRDA_TYPE_NTIMESTAMP: {
4199:                    // JCC represents ts in a slightly different format than Java standard, so
4200:                    // we do the conversion to Java standard here.
4201:                    String paramVal = reader.readStringData(26).trim(); //parameter may be char value
4202:                    if (SanityManager.DEBUG)
4203:                        trace("ntimestamp parameter value is: " + paramVal);
4204:                    try {
4205:                        String tsString = paramVal.substring(0, 10) + " "
4206:                                + paramVal.substring(11, 19).replace('.', ':')
4207:                                + paramVal.substring(19);
4208:                        if (SanityManager.DEBUG)
4209:                            trace("tsString is: " + tsString);
4210:                        ps.setTimestamp(i + 1, java.sql.Timestamp
4211:                                .valueOf(tsString));
4212:                    } catch (java.lang.IllegalArgumentException e1) {
4213:                        // thrown by Timestamp.valueOf(...) for bad syntax...
4214:                        throw new SQLException(
4215:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4216:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(
4217:                                        0, 5));
4218:                    } catch (java.lang.StringIndexOutOfBoundsException e2) {
4219:                        // can be thrown by substring(...) if syntax is invalid...
4220:                        throw new SQLException(
4221:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4222:                                SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(
4223:                                        0, 5));
4224:                    }
4225:                    break;
4226:                }
4227:                case DRDAConstants.DRDA_TYPE_NCHAR:
4228:                case DRDAConstants.DRDA_TYPE_NVARCHAR:
4229:                case DRDAConstants.DRDA_TYPE_NLONG:
4230:                case DRDAConstants.DRDA_TYPE_NVARMIX:
4231:                case DRDAConstants.DRDA_TYPE_NLONGMIX: {
4232:                    String paramVal = reader
4233:                            .readLDStringData(stmt.ccsidMBCEncoding);
4234:                    if (SanityManager.DEBUG)
4235:                        trace("char/varchar parameter value is: " + paramVal);
4236:                    ps.setString(i + 1, paramVal);
4237:                    break;
4238:                }
4239:                case DRDAConstants.DRDA_TYPE_NFIXBYTE: {
4240:                    byte[] paramVal = reader.readBytes();
4241:                    if (SanityManager.DEBUG)
4242:                        trace("fix bytes parameter value is: "
4243:                                + convertToHexString(paramVal));
4244:                    ps.setBytes(i + 1, paramVal);
4245:                    break;
4246:                }
4247:                case DRDAConstants.DRDA_TYPE_NVARBYTE:
4248:                case DRDAConstants.DRDA_TYPE_NLONGVARBYTE: {
4249:                    int length = reader.readNetworkShort(); //protocol control data always follows big endian
4250:                    if (SanityManager.DEBUG)
4251:                        trace("===== binary param length is: " + length);
4252:                    byte[] paramVal = reader.readBytes(length);
4253:                    ps.setBytes(i + 1, paramVal);
4254:                    break;
4255:                }
4256:                case DRDAConstants.DRDA_TYPE_NLOBBYTES:
4257:                case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
4258:                case DRDAConstants.DRDA_TYPE_NLOBCSBCS:
4259:                case DRDAConstants.DRDA_TYPE_NLOBCDBCS: {
4260:                    long length = readLobLength(paramLenNumBytes);
4261:                    if (length != 0) //can be -1 for CLI if "data at exec" mode, see clifp/exec test
4262:                    {
4263:                        if (paramExtPositions == null)
4264:                            paramExtPositions = new ArrayList();
4265:                        paramExtPositions.add(new Integer(i));
4266:                    } else /* empty */
4267:                    {
4268:                        if (drdaType == DRDAConstants.DRDA_TYPE_NLOBBYTES)
4269:                            ps.setBytes(i + 1, new byte[0]);
4270:                        else
4271:                            ps.setString(i + 1, "");
4272:                    }
4273:                    break;
4274:                }
4275:                default: {
4276:                    String paramVal = reader
4277:                            .readLDStringData(stmt.ccsidMBCEncoding);
4278:                    if (SanityManager.DEBUG)
4279:                        trace("default type parameter value is: " + paramVal);
4280:                    ps.setObject(i + 1, paramVal);
4281:                }
4282:                }
4283:                return paramExtPositions;
4284:            }
4285:
4286:            private long readLobLength(int extLenIndicator)
4287:                    throws DRDAProtocolException {
4288:                switch (extLenIndicator) {
4289:                case 0x8002:
4290:                    return (long) reader.readNetworkShort();
4291:                case 0x8004:
4292:                    return (long) reader.readNetworkInt();
4293:                case 0x8006:
4294:                    return (long) reader.readNetworkSixByteLong();
4295:                case 0x8008:
4296:                    return (long) reader.readNetworkLong();
4297:                default:
4298:                    throwSyntaxrm(CodePoint.SYNERRCD_INCORRECT_EXTENDED_LEN,
4299:                            extLenIndicator);
4300:                    return 0L;
4301:                }
4302:
4303:            }
4304:
4305:            private void readAndSetAllExtParams(final DRDAStatement stmt,
4306:                    final boolean streamLOB) throws SQLException,
4307:                    DRDAProtocolException {
4308:                int numExt = stmt.cliParamExtPositions.size();
4309:                for (int i = 0; i < stmt.cliParamExtPositions.size(); i++) {
4310:                    int paramPos = ((Integer) (stmt.cliParamExtPositions)
4311:                            .get(i)).intValue();
4312:                    final boolean doStreamLOB = (streamLOB && i == numExt - 1);
4313:                    readAndSetExtParam(paramPos, stmt,
4314:                            ((Byte) stmt.cliParamDrdaTypes.elementAt(paramPos))
4315:                                    .intValue(), ((Integer) (stmt.cliParamLens
4316:                                    .elementAt(paramPos))).intValue(),
4317:                            doStreamLOB);
4318:                    // Each extdta in it's own dss
4319:                    if (i < numExt - 1) {
4320:                        correlationID = reader.readDssHeader();
4321:                        int codePoint = reader.readLengthAndCodePoint();
4322:                    }
4323:                }
4324:
4325:            }
4326:
4327:            /**
4328:             * Read different types of input parameters and set them in PreparedStatement
4329:             * @param i			index of the parameter
4330:             * @param stmt			associated ps
4331:             * @param drdaType	drda type of the parameter
4332:             *
4333:             * @throws DRDAProtocolException
4334:             * @throws SQLException
4335:             */
4336:            private void readAndSetExtParam(int i, DRDAStatement stmt,
4337:                    int drdaType, int extLen, boolean streamLOB)
4338:                    throws DRDAProtocolException, SQLException {
4339:                PreparedStatement ps = stmt.getPreparedStatement();
4340:                drdaType = (drdaType & 0x000000ff); // need unsigned value
4341:                boolean checkNullability = false;
4342:                if (sqlamLevel >= MGRLVL_7
4343:                        && FdocaConstants.isNullable(drdaType))
4344:                    checkNullability = true;
4345:
4346:                try {
4347:                    final byte[] paramBytes;
4348:                    final String paramString;
4349:
4350:                    switch (drdaType) {
4351:                    case DRDAConstants.DRDA_TYPE_LOBBYTES:
4352:                    case DRDAConstants.DRDA_TYPE_NLOBBYTES:
4353:                        paramString = "";
4354:                        final boolean useSetBinaryStream = stmt
4355:                                .getParameterMetaData().getParameterType(i + 1) == Types.BLOB;
4356:
4357:                        if (streamLOB && useSetBinaryStream) {
4358:                            paramBytes = null;
4359:                            final EXTDTAReaderInputStream stream = reader
4360:                                    .getEXTDTAReaderInputStream(checkNullability);
4361:                            if (stream == null) {
4362:                                ps.setBytes(i + 1, null);
4363:                            } else {
4364:                                ps.setBinaryStream(i + 1, stream, (int) stream
4365:                                        .getLength());
4366:                            }
4367:
4368:                            if (SanityManager.DEBUG) {
4369:                                if (stream == null) {
4370:                                    trace("parameter value : NULL");
4371:                                } else {
4372:                                    trace("parameter value will be streamed");
4373:                                }
4374:                            }
4375:                        } else {
4376:                            paramBytes = reader.getExtData(checkNullability);
4377:                            if (paramBytes == null || !useSetBinaryStream) {
4378:                                ps.setBytes(i + 1, paramBytes);
4379:                            } else {
4380:                                ps.setBinaryStream(i + 1,
4381:                                        new ByteArrayInputStream(paramBytes),
4382:                                        paramBytes.length);
4383:                            }
4384:                            if (SanityManager.DEBUG) {
4385:                                if (paramBytes == null) {
4386:                                    trace("parameter value : NULL");
4387:                                } else {
4388:                                    trace("parameter value is a LOB with length:"
4389:                                            + paramBytes.length);
4390:                                }
4391:                            }
4392:                        }
4393:                        break;
4394:                    case DRDAConstants.DRDA_TYPE_LOBCSBCS:
4395:                    case DRDAConstants.DRDA_TYPE_NLOBCSBCS:
4396:                        paramBytes = reader.getExtData(checkNullability);
4397:                        paramString = new String(paramBytes,
4398:                                stmt.ccsidSBCEncoding);
4399:                        if (SanityManager.DEBUG)
4400:                            trace("parameter value is: " + paramString);
4401:                        ps.setString(i + 1, paramString);
4402:                        break;
4403:                    case DRDAConstants.DRDA_TYPE_LOBCDBCS:
4404:                    case DRDAConstants.DRDA_TYPE_NLOBCDBCS:
4405:                        paramBytes = reader.getExtData(checkNullability);
4406:                        paramString = new String(paramBytes,
4407:                                stmt.ccsidDBCEncoding);
4408:                        if (SanityManager.DEBUG)
4409:                            trace("parameter value is: " + paramString);
4410:                        ps.setString(i + 1, paramString);
4411:                        break;
4412:                    case DRDAConstants.DRDA_TYPE_LOBCMIXED:
4413:                    case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
4414:                        paramBytes = reader.getExtData(checkNullability);
4415:                        paramString = new String(paramBytes,
4416:                                stmt.ccsidMBCEncoding);
4417:                        if (SanityManager.DEBUG)
4418:                            trace("parameter value is: " + paramString);
4419:                        ps.setString(i + 1, paramString);
4420:                        break;
4421:                    default:
4422:                        paramBytes = null;
4423:                        paramString = "";
4424:
4425:                        invalidValue(drdaType);
4426:                    }
4427:
4428:                } catch (java.io.UnsupportedEncodingException e) {
4429:                    throw new SQLException(e.getMessage());
4430:                }
4431:            }
4432:
4433:            /**
4434:             * Parse EXCSQLIMM - Execute Immediate Statement
4435:             * Instance Variables
4436:             *  RDBNAM - relational database name - optional
4437:             *  PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
4438:             *  RDBCMTOK - RDB Commit Allowed - optional
4439:             *  MONITOR - Monitor Events - optional
4440:             *
4441:             * Command Objects
4442:             *  TYPDEFNAM - Data Type Definition Name - optional
4443:             *  TYPDEFOVR - TYPDEF Overrides -optional
4444:             *  SQLSTT - SQL Statement -required
4445:             *
4446:             * @return update count
4447:             * @throws DRDAProtocolException
4448:             * @throws SQLException
4449:             */
4450:            private int parseEXCSQLIMM() throws DRDAProtocolException,
4451:                    SQLException {
4452:                int codePoint;
4453:                reader.markCollection();
4454:                Pkgnamcsn pkgnamcsn = null;
4455:                codePoint = reader.getCodePoint();
4456:                while (codePoint != -1) {
4457:                    switch (codePoint) {
4458:                    // optional
4459:                    case CodePoint.RDBNAM:
4460:                        setDatabase(CodePoint.EXCSQLIMM);
4461:                        break;
4462:                    // required
4463:                    case CodePoint.PKGNAMCSN:
4464:                        pkgnamcsn = parsePKGNAMCSN();
4465:                        break;
4466:                    case CodePoint.RDBCMTOK:
4467:                        parseRDBCMTOK();
4468:                        break;
4469:                    //optional
4470:                    case CodePoint.MONITOR:
4471:                        parseMONITOR();
4472:                        break;
4473:                    default:
4474:                        invalidCodePoint(codePoint);
4475:
4476:                    }
4477:                    codePoint = reader.getCodePoint();
4478:                }
4479:                DRDAStatement drdaStmt = database
4480:                        .getDefaultStatement(pkgnamcsn);
4481:                // initialize statement for reuse
4482:                drdaStmt.initialize();
4483:                String sqlStmt = parseEXECSQLIMMobjects();
4484:                Statement statement = drdaStmt.getStatement();
4485:                statement.clearWarnings();
4486:                if (pendingStatementTimeout >= 0) {
4487:                    statement.setQueryTimeout(pendingStatementTimeout);
4488:                    pendingStatementTimeout = -1;
4489:                }
4490:                int updCount = statement.executeUpdate(sqlStmt);
4491:                return updCount;
4492:            }
4493:
4494:            /**
4495:             * Parse EXCSQLSET - Execute Set SQL Environment
4496:             * Instance Variables
4497:             *  RDBNAM - relational database name - optional
4498:             *  PKGNAMCT - RDB Package Name, Consistency Token  - optional
4499:             *  MONITOR - Monitor Events - optional
4500:             *
4501:             * Command Objects
4502:             *  TYPDEFNAM - Data Type Definition Name - required
4503:             *  TYPDEFOVR - TYPDEF Overrides - required
4504:             *  SQLSTT - SQL Statement - required (at least one; may be more)
4505:             *
4506:             * @throws DRDAProtocolException
4507:             * @throws SQLException
4508:             */
4509:            private boolean parseEXCSQLSET() throws DRDAProtocolException,
4510:                    SQLException {
4511:
4512:                int codePoint;
4513:                reader.markCollection();
4514:
4515:                codePoint = reader.getCodePoint();
4516:                while (codePoint != -1) {
4517:                    switch (codePoint) {
4518:                    // optional
4519:                    case CodePoint.RDBNAM:
4520:                        setDatabase(CodePoint.EXCSQLSET);
4521:                        break;
4522:                    // optional
4523:                    case CodePoint.PKGNAMCT:
4524:                        // we are going to ignore this for EXCSQLSET
4525:                        // since we are just going to reuse an existing statement
4526:                        String pkgnamct = parsePKGNAMCT();
4527:                        break;
4528:                    // optional
4529:                    case CodePoint.MONITOR:
4530:                        parseMONITOR();
4531:                        break;
4532:                    // required
4533:                    case CodePoint.PKGNAMCSN:
4534:                        // we are going to ignore this for EXCSQLSET.
4535:                        // since we are just going to reuse an existing statement.
4536:                        // NOTE: This codepoint is not in the DDM spec for 'EXCSQLSET',
4537:                        // but since it DOES get sent by jcc1.2, we have to have
4538:                        // a case for it...
4539:                        Pkgnamcsn pkgnamcsn = parsePKGNAMCSN();
4540:                        break;
4541:                    default:
4542:                        invalidCodePoint(codePoint);
4543:
4544:                    }
4545:                    codePoint = reader.getCodePoint();
4546:                }
4547:
4548:                parseEXCSQLSETobjects();
4549:                return true;
4550:            }
4551:
4552:            /**
4553:             * Parse EXCSQLIMM objects
4554:             * Objects
4555:             *  TYPDEFNAM - Data type definition name - optional
4556:             *  TYPDEFOVR - Type defintion overrides
4557:             *  SQLSTT - SQL Statement required
4558:             *
4559:             * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
4560:             * sent with the statement.  Once the statement is over, the default values
4561:             * sent in the ACCRDB are once again in effect.  If no values are supplied,
4562:             * the values sent in the ACCRDB are used.
4563:             * Objects may follow in one DSS or in several DSS chained together.
4564:             * 
4565:             * @return SQL Statement
4566:             * @throws DRDAProtocolException
4567:             * @throws SQLException
4568:             */
4569:            private String parseEXECSQLIMMobjects()
4570:                    throws DRDAProtocolException, SQLException {
4571:                String sqlStmt = null;
4572:                int codePoint;
4573:                DRDAStatement stmt = database.getDefaultStatement();
4574:                do {
4575:                    correlationID = reader.readDssHeader();
4576:                    while (reader.moreDssData()) {
4577:                        codePoint = reader.readLengthAndCodePoint();
4578:                        switch (codePoint) {
4579:                        // optional
4580:                        case CodePoint.TYPDEFNAM:
4581:                            setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
4582:                            break;
4583:                        // optional
4584:                        case CodePoint.TYPDEFOVR:
4585:                            parseTYPDEFOVR(stmt);
4586:                            break;
4587:                        // required
4588:                        case CodePoint.SQLSTT:
4589:                            sqlStmt = parseEncodedString();
4590:                            if (SanityManager.DEBUG)
4591:                                trace("sqlStmt = " + sqlStmt);
4592:                            break;
4593:                        default:
4594:                            invalidCodePoint(codePoint);
4595:                        }
4596:                    }
4597:                } while (reader.isChainedWithSameID());
4598:
4599:                // SQLSTT is required
4600:                if (sqlStmt == null)
4601:                    missingCodePoint(CodePoint.SQLSTT);
4602:                return sqlStmt;
4603:            }
4604:
4605:            /**
4606:             * Parse EXCSQLSET objects
4607:             * Objects
4608:             *  TYPDEFNAM - Data type definition name - optional
4609:             *  TYPDEFOVR - Type defintion overrides - optional
4610:             *  SQLSTT - SQL Statement - required (a list of at least one)
4611:             *
4612:             * Objects may follow in one DSS or in several DSS chained together.
4613:             * 
4614:             * @throws DRDAProtocolException
4615:             * @throws SQLException
4616:             */
4617:            private void parseEXCSQLSETobjects() throws DRDAProtocolException,
4618:                    SQLException {
4619:
4620:                boolean gotSqlStt = false;
4621:                boolean hadUnrecognizedStmt = false;
4622:
4623:                String sqlStmt = null;
4624:                int codePoint;
4625:                DRDAStatement drdaStmt = database.getDefaultStatement();
4626:                drdaStmt.initialize();
4627:
4628:                do {
4629:                    correlationID = reader.readDssHeader();
4630:                    while (reader.moreDssData()) {
4631:
4632:                        codePoint = reader.readLengthAndCodePoint();
4633:
4634:                        switch (codePoint) {
4635:                        // optional
4636:                        case CodePoint.TYPDEFNAM:
4637:                            setStmtOrDbByteOrder(false, drdaStmt,
4638:                                    parseTYPDEFNAM());
4639:                            break;
4640:                        // optional
4641:                        case CodePoint.TYPDEFOVR:
4642:                            parseTYPDEFOVR(drdaStmt);
4643:                            break;
4644:                        // required
4645:                        case CodePoint.SQLSTT:
4646:                            sqlStmt = parseEncodedString();
4647:                            if (sqlStmt != null)
4648:                                // then we have at least one SQL Statement.
4649:                                gotSqlStt = true;
4650:
4651:                            if (sqlStmt.startsWith(TIMEOUT_STATEMENT)) {
4652:                                String timeoutString = sqlStmt
4653:                                        .substring(TIMEOUT_STATEMENT.length());
4654:                                pendingStatementTimeout = Integer.valueOf(
4655:                                        timeoutString).intValue();
4656:                                break;
4657:                            }
4658:
4659:                            if (canIgnoreStmt(sqlStmt)) {
4660:                                // We _know_ Cloudscape doesn't recognize this
4661:                                // statement; don't bother trying to execute it.
4662:                                // NOTE: at time of writing, this only applies
4663:                                // to "SET CLIENT" commands, and it was decided
4664:                                // that throwing a Warning for these commands
4665:                                // would confuse people, so even though the DDM
4666:                                // spec says to do so, we choose not to (but
4667:                                // only for SET CLIENT cases).  If this changes
4668:                                // at some point in the future, simply remove
4669:                                // the follwing line; we will then throw a
4670:                                // warning.
4671:                                //							hadUnrecognizedStmt = true;
4672:                                break;
4673:                            }
4674:
4675:                            if (SanityManager.DEBUG)
4676:                                trace("sqlStmt = " + sqlStmt);
4677:
4678:                            // initialize statement for reuse
4679:                            drdaStmt.initialize();
4680:                            drdaStmt.getStatement().clearWarnings();
4681:                            try {
4682:                                drdaStmt.getStatement().executeUpdate(sqlStmt);
4683:                            } catch (SQLException e) {
4684:
4685:                                // if this is a syntax error, then we take it
4686:                                // to mean that the given SET statement is not
4687:                                // recognized; take note (so we can throw a
4688:                                // warning later), but don't interfere otherwise.
4689:                                if (e.getSQLState().equals(SYNTAX_ERR))
4690:                                    hadUnrecognizedStmt = true;
4691:                                else
4692:                                    // something else; assume it's serious.
4693:                                    throw e;
4694:                            }
4695:                            break;
4696:                        default:
4697:                            invalidCodePoint(codePoint);
4698:                        }
4699:                    }
4700:
4701:                } while (reader.isChainedWithSameID());
4702:
4703:                // SQLSTT is required.
4704:                if (!gotSqlStt)
4705:                    missingCodePoint(CodePoint.SQLSTT);
4706:
4707:                // Now that we've processed all SET statements (assuming no
4708:                // severe exceptions), check for warnings and, if we had any,
4709:                // note this in the SQLCARD reply object (but DON'T cause the
4710:                // EXCSQLSET statement to fail).
4711:                if (hadUnrecognizedStmt) {
4712:                    SQLWarning warn = new SQLWarning(
4713:                            "One or more SET statements " + "not recognized.",
4714:                            "01000");
4715:                    throw warn;
4716:                } // end if.
4717:
4718:                return;
4719:            }
4720:
4721:            private boolean canIgnoreStmt(String stmt) {
4722:                if (stmt.indexOf("SET CLIENT") != -1)
4723:                    return true;
4724:                return false;
4725:            }
4726:
4727:            /**
4728:             * Write RDBUPDRM
4729:             * Instance variables
4730:             *  SVRCOD - Severity code - Information only - required
4731:             *  RDBNAM - Relational database name -required
4732:             *  SRVDGN - Server Diagnostic Information -optional
4733:             *
4734:             * @exception DRDAProtocolException
4735:             */
4736:            private void writeRDBUPDRM() throws DRDAProtocolException {
4737:                database.RDBUPDRM_sent = true;
4738:                writer.createDssReply();
4739:                writer.startDdm(CodePoint.RDBUPDRM);
4740:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
4741:                        CodePoint.SVRCOD_INFO);
4742:                writeRDBNAM(database.dbName);
4743:                writer.endDdmAndDss();
4744:            }
4745:
4746:            private String parsePKGNAMCT() throws DRDAProtocolException {
4747:                reader.skipBytes();
4748:                return null;
4749:            }
4750:
4751:            /**
4752:             * Parse PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number
4753:             * Instance Variables
4754:             *   NAMESYMDR - database name - not validated
4755:             *   RDBCOLID - RDB Collection Identifier
4756:             *   PKGID - RDB Package Identifier
4757:             *   PKGCNSTKN - RDB Package Consistency Token
4758:             *   PKGSN - RDB Package Section Number
4759:             *
4760:             * @return <code>Pkgnamcsn</code> value
4761:             * @throws DRDAProtocolException
4762:             */
4763:            private Pkgnamcsn parsePKGNAMCSN() throws DRDAProtocolException {
4764:                if (reader.getDdmLength() == CodePoint.PKGNAMCSN_LEN) {
4765:                    // This is a scalar object with the following fields
4766:                    reader.readString(rdbnam, CodePoint.RDBNAM_LEN, true);
4767:                    if (SanityManager.DEBUG)
4768:                        trace("rdbnam = " + rdbnam);
4769:
4770:                    reader.readString(rdbcolid, CodePoint.RDBCOLID_LEN, true);
4771:                    if (SanityManager.DEBUG)
4772:                        trace("rdbcolid = " + rdbcolid);
4773:
4774:                    reader.readString(pkgid, CodePoint.PKGID_LEN, true);
4775:                    if (SanityManager.DEBUG)
4776:                        trace("pkgid = " + pkgid);
4777:
4778:                    // we need to use the same UCS2 encoding, as this can be
4779:                    // bounced back to jcc (or keep the byte array)
4780:                    reader
4781:                            .readString(pkgcnstkn, CodePoint.PKGCNSTKN_LEN,
4782:                                    false);
4783:                    if (SanityManager.DEBUG)
4784:                        trace("pkgcnstkn = " + pkgcnstkn);
4785:
4786:                    pkgsn = reader.readNetworkShort();
4787:                    if (SanityManager.DEBUG)
4788:                        trace("pkgsn = " + pkgsn);
4789:                } else // extended format
4790:                {
4791:                    int length = reader.readNetworkShort();
4792:                    if (length < CodePoint.RDBNAM_LEN
4793:                            || length > CodePoint.MAX_NAME)
4794:                        badObjectLength(CodePoint.RDBNAM);
4795:                    reader.readString(rdbnam, length, true);
4796:                    if (SanityManager.DEBUG)
4797:                        trace("rdbnam = " + rdbnam);
4798:
4799:                    //RDBCOLID can be variable length in this format
4800:                    length = reader.readNetworkShort();
4801:                    reader.readString(rdbcolid, length, true);
4802:                    if (SanityManager.DEBUG)
4803:                        trace("rdbcolid = " + rdbcolid);
4804:
4805:                    length = reader.readNetworkShort();
4806:                    if (length != CodePoint.PKGID_LEN)
4807:                        badObjectLength(CodePoint.PKGID);
4808:                    reader.readString(pkgid, CodePoint.PKGID_LEN, true);
4809:                    if (SanityManager.DEBUG)
4810:                        trace("pkgid = " + pkgid);
4811:
4812:                    reader
4813:                            .readString(pkgcnstkn, CodePoint.PKGCNSTKN_LEN,
4814:                                    false);
4815:                    if (SanityManager.DEBUG)
4816:                        trace("pkgcnstkn = " + pkgcnstkn);
4817:
4818:                    pkgsn = reader.readNetworkShort();
4819:                    if (SanityManager.DEBUG)
4820:                        trace("pkgsn = " + pkgsn);
4821:                }
4822:
4823:                // In most cases, the pkgnamcsn object is equal to the
4824:                // previously returned object. To avoid allocation of a new
4825:                // object in these cases, we first check to see if the old
4826:                // object can be reused.
4827:                if ((prevPkgnamcsn == null) || rdbnam.wasModified()
4828:                        || rdbcolid.wasModified() || pkgid.wasModified()
4829:                        || pkgcnstkn.wasModified()
4830:                        || (prevPkgnamcsn.getPkgsn() != pkgsn)) {
4831:                    // The byte array returned by pkgcnstkn.getBytes() might
4832:                    // be modified by DDMReader.readString() later, so we have
4833:                    // to create a copy of the array.
4834:                    byte[] token = new byte[pkgcnstkn.length()];
4835:                    System.arraycopy(pkgcnstkn.getBytes(), 0, token, 0,
4836:                            token.length);
4837:
4838:                    prevPkgnamcsn = new Pkgnamcsn(rdbnam.toString(), rdbcolid
4839:                            .toString(), pkgid.toString(), pkgsn,
4840:                            new ConsistencyToken(token));
4841:                }
4842:
4843:                return prevPkgnamcsn;
4844:            }
4845:
4846:            /**
4847:             * Parse SQLSTT Dss
4848:             * @exception DRDAProtocolException
4849:             */
4850:            private String parseSQLSTTDss() throws DRDAProtocolException {
4851:                correlationID = reader.readDssHeader();
4852:                int codePoint = reader.readLengthAndCodePoint();
4853:                String strVal = parseEncodedString();
4854:                if (SanityManager.DEBUG)
4855:                    trace("SQL Statement = " + strVal);
4856:                return strVal;
4857:            }
4858:
4859:            /**
4860:             * Parse an encoded data string from the Application Requester
4861:             *
4862:             * @return string value
4863:             * @exception DRDAProtocolException
4864:             */
4865:            private String parseEncodedString() throws DRDAProtocolException {
4866:                if (sqlamLevel < 7)
4867:                    return parseVCMorVCS();
4868:                else
4869:                    return parseNOCMorNOCS();
4870:            }
4871:
4872:            /**
4873:             * Parse variable character mixed byte or variable character single byte
4874:             * Format
4875:             *  I2 - VCM Length
4876:             *  N bytes - VCM value
4877:             *  I2 - VCS Length
4878:             *  N bytes - VCS value 
4879:             * Only 1 of VCM length or VCS length can be non-zero
4880:             *
4881:             * @return string value
4882:             */
4883:            private String parseVCMorVCS() throws DRDAProtocolException {
4884:                String strVal = null;
4885:                int vcm_length = reader.readNetworkShort();
4886:                if (vcm_length > 0)
4887:                    strVal = parseCcsidMBC(vcm_length);
4888:                int vcs_length = reader.readNetworkShort();
4889:                if (vcs_length > 0) {
4890:                    if (strVal != null)
4891:                        agentError("Both VCM and VCS have lengths > 0");
4892:                    strVal = parseCcsidSBC(vcs_length);
4893:                }
4894:                return strVal;
4895:            }
4896:
4897:            /**
4898:             * Parse nullable character mixed byte or nullable character single byte
4899:             * Format
4900:             *  1 byte - null indicator
4901:             *  I4 - mixed character length
4902:             *  N bytes - mixed character string
4903:             *  1 byte - null indicator
4904:             *  I4 - single character length
4905:             *  N bytes - single character length string
4906:             *
4907:             * @return string value
4908:             * @exception DRDAProtocolException
4909:             */
4910:            private String parseNOCMorNOCS() throws DRDAProtocolException {
4911:                byte nocm_nullByte = reader.readByte();
4912:                String strVal = null;
4913:                int length;
4914:                if (nocm_nullByte != NULL_VALUE) {
4915:                    length = reader.readNetworkInt();
4916:                    strVal = parseCcsidMBC(length);
4917:                }
4918:                byte nocs_nullByte = reader.readByte();
4919:                if (nocs_nullByte != NULL_VALUE) {
4920:                    if (strVal != null)
4921:                        agentError("Both CM and CS are non null");
4922:                    length = reader.readNetworkInt();
4923:                    strVal = parseCcsidSBC(length);
4924:                }
4925:                return strVal;
4926:            }
4927:
4928:            /**
4929:             * Parse mixed character string
4930:             * 
4931:             * @return string value
4932:             * @exception DRDAProtocolException
4933:             */
4934:            private String parseCcsidMBC(int length)
4935:                    throws DRDAProtocolException {
4936:                String strVal = null;
4937:                DRDAStatement currentStatement;
4938:
4939:                currentStatement = database.getCurrentStatement();
4940:                if (currentStatement == null) {
4941:                    currentStatement = database.getDefaultStatement();
4942:                    currentStatement.initialize();
4943:                }
4944:                String ccsidMBCEncoding = currentStatement.ccsidMBCEncoding;
4945:
4946:                if (length == 0)
4947:                    return null;
4948:                byte[] byteStr = reader.readBytes(length);
4949:                if (ccsidMBCEncoding != null) {
4950:                    try {
4951:                        strVal = new String(byteStr, 0, length,
4952:                                ccsidMBCEncoding);
4953:                    } catch (UnsupportedEncodingException e) {
4954:                        agentError("Unsupported encoding " + ccsidMBCEncoding
4955:                                + "in parseCcsidMBC");
4956:                    }
4957:                } else
4958:                    agentError("Attempt to decode mixed byte string without CCSID being set");
4959:                return strVal;
4960:            }
4961:
4962:            /**
4963:             * Parse single byte character string
4964:             * 
4965:             * @return string value
4966:             * @exception DRDAProtocolException
4967:             */
4968:            private String parseCcsidSBC(int length)
4969:                    throws DRDAProtocolException {
4970:                String strVal = null;
4971:                DRDAStatement currentStatement;
4972:
4973:                currentStatement = database.getCurrentStatement();
4974:                if (currentStatement == null) {
4975:                    currentStatement = database.getDefaultStatement();
4976:                    currentStatement.initialize();
4977:                }
4978:                String ccsidSBCEncoding = currentStatement.ccsidSBCEncoding;
4979:                System.out.println("ccsidSBCEncoding - " + ccsidSBCEncoding);
4980:
4981:                if (length == 0)
4982:                    return null;
4983:                byte[] byteStr = reader.readBytes(length);
4984:                if (ccsidSBCEncoding != null) {
4985:                    try {
4986:                        strVal = new String(byteStr, 0, length,
4987:                                ccsidSBCEncoding);
4988:                    } catch (UnsupportedEncodingException e) {
4989:                        agentError("Unsupported encoding " + ccsidSBCEncoding
4990:                                + "in parseCcsidSBC");
4991:                    }
4992:                } else
4993:                    agentError("Attempt to decode single byte string without CCSID being set");
4994:                return strVal;
4995:            }
4996:
4997:            /**
4998:             * Parse CLSQRY
4999:             * Instance Variables
5000:             *  RDBNAM - relational database name - optional
5001:             *  PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
5002:             *  QRYINSID - Query Instance Identifier - required - level 7
5003:             *  MONITOR - Monitor events - optional.
5004:             *
5005:             * @return DRDAstatement being closed
5006:             * @throws DRDAProtocolException
5007:             * @throws SQLException
5008:             */
5009:            private DRDAStatement parseCLSQRY() throws DRDAProtocolException,
5010:                    SQLException {
5011:                Pkgnamcsn pkgnamcsn = null;
5012:                reader.markCollection();
5013:                long qryinsid = 0;
5014:                boolean gotQryinsid = false;
5015:
5016:                int codePoint = reader.getCodePoint();
5017:                while (codePoint != -1) {
5018:                    switch (codePoint) {
5019:                    // optional
5020:                    case CodePoint.RDBNAM:
5021:                        setDatabase(CodePoint.CLSQRY);
5022:                        break;
5023:                    // required
5024:                    case CodePoint.PKGNAMCSN:
5025:                        pkgnamcsn = parsePKGNAMCSN();
5026:                        break;
5027:                    case CodePoint.QRYINSID:
5028:                        qryinsid = reader.readNetworkLong();
5029:                        gotQryinsid = true;
5030:                        break;
5031:                    // optional
5032:                    case CodePoint.MONITOR:
5033:                        parseMONITOR();
5034:                        break;
5035:                    default:
5036:                        invalidCodePoint(codePoint);
5037:                    }
5038:                    codePoint = reader.getCodePoint();
5039:                }
5040:                // check for required variables
5041:                if (pkgnamcsn == null)
5042:                    missingCodePoint(CodePoint.PKGNAMCSN);
5043:                if (sqlamLevel >= MGRLVL_7 && !gotQryinsid)
5044:                    missingCodePoint(CodePoint.QRYINSID);
5045:
5046:                DRDAStatement stmt = database.getDRDAStatement(pkgnamcsn);
5047:                if (stmt == null) {
5048:                    //XXX should really throw a SQL Exception here
5049:                    invalidValue(CodePoint.PKGNAMCSN);
5050:                }
5051:
5052:                if (stmt.wasExplicitlyClosed()) {
5053:                    // JCC still sends a CLSQRY even though we have
5054:                    // implicitly closed the resultSet.
5055:                    // Then complains if we send the writeQRYNOPRM
5056:                    // So for now don't send it
5057:                    // Also metadata calls seem to get bound to the same
5058:                    // PGKNAMCSN, so even for explicit closes we have
5059:                    // to ignore.
5060:                    //writeQRYNOPRM(CodePoint.SVRCOD_ERROR);
5061:                    pkgnamcsn = null;
5062:                }
5063:
5064:                stmt.CLSQRY();
5065:
5066:                return stmt;
5067:            }
5068:
5069:            /**
5070:             * Parse MONITOR
5071:             * DRDA spec says this is optional.  Since we
5072:             * don't currently support it, we just ignore.
5073:             */
5074:            private void parseMONITOR() throws DRDAProtocolException {
5075:
5076:                // Just ignore it.
5077:                reader.skipBytes();
5078:                return;
5079:
5080:            }
5081:
5082:            private void writeSQLCARDs(SQLException e, int updateCount)
5083:                    throws DRDAProtocolException {
5084:                writeSQLCARDs(e, updateCount, false);
5085:            }
5086:
5087:            private void writeSQLCARDs(SQLException e, int updateCount,
5088:                    boolean sendSQLERRRM) throws DRDAProtocolException {
5089:
5090:                int severity = CodePoint.SVRCOD_INFO;
5091:                if (e == null) {
5092:                    writeSQLCARD(e, severity, updateCount, 0);
5093:                    return;
5094:                }
5095:
5096:                // instead of writing a chain of sql error or warning, we send the first one, this is
5097:                // jcc/db2 limitation, see beetle 4629
5098:
5099:                // If it is a real SQL Error write a SQLERRRM first
5100:                severity = getExceptionSeverity(e);
5101:                if (severity > CodePoint.SVRCOD_ERROR) {
5102:                    // For a session ending error > CodePoint.SRVCOD_ERROR you cannot
5103:                    // send a SQLERRRM. A CMDCHKRM is required.  In XA if there is a
5104:                    // lock timeout it ends the whole session. I am not sure this 
5105:                    // is the correct behaviour but if it occurs we have to send 
5106:                    // a CMDCHKRM instead of SQLERRM
5107:                    writeCMDCHKRM(severity);
5108:                } else if (sendSQLERRRM) {
5109:                    writeSQLERRRM(severity);
5110:                }
5111:                writeSQLCARD(e, severity, updateCount, 0);
5112:            }
5113:
5114:            private int getSqlCode(int severity) {
5115:                if (severity == CodePoint.SVRCOD_WARNING) // warning
5116:                    return 100; //CLI likes it
5117:                else if (severity == CodePoint.SVRCOD_INFO)
5118:                    return 0;
5119:                else
5120:                    return -1;
5121:            }
5122:
5123:            private void writeSQLCARD(SQLException e, int severity,
5124:                    int updateCount, long rowCount)
5125:                    throws DRDAProtocolException {
5126:                writer.createDssObject();
5127:                writer.startDdm(CodePoint.SQLCARD);
5128:                writeSQLCAGRP(e, getSqlCode(severity), updateCount, rowCount);
5129:                writer.endDdmAndDss();
5130:
5131:                // If we have a shutdown exception, restart the server.
5132:                if (e != null) {
5133:                    String sqlState = e.getSQLState();
5134:                    if (sqlState.regionMatches(0,
5135:                            SQLState.CLOUDSCAPE_SYSTEM_SHUTDOWN, 0, 5)) {
5136:                        // then we're here because of a shutdown exception;
5137:                        // "clean up" by restarting the server.
5138:                        try {
5139:                            server.startNetworkServer();
5140:                        } catch (Exception restart)
5141:                        // any error messages should have already been printed,
5142:                        // so we ignore this exception here.
5143:                        {
5144:                        }
5145:                    }
5146:                }
5147:
5148:            }
5149:
5150:            /**
5151:             * Write a null SQLCARD as an object
5152:             *
5153:             * @exception DRDAProtocolException
5154:             */
5155:            private void writeNullSQLCARDobject() throws DRDAProtocolException {
5156:                writer.createDssObject();
5157:                writer.startDdm(CodePoint.SQLCARD);
5158:                writeSQLCAGRP(nullSQLState, 0, 0, 0);
5159:                writer.endDdmAndDss();
5160:            }
5161:
5162:            /**
5163:             * Write SQLERRRM
5164:             *
5165:             * Instance Variables
5166:             * 	SVRCOD - Severity Code - required
5167:             *
5168:             * @param	severity	severity of error
5169:             *
5170:             * @exception DRDAProtocolException
5171:             */
5172:            private void writeSQLERRRM(int severity)
5173:                    throws DRDAProtocolException {
5174:                writer.createDssReply();
5175:                writer.startDdm(CodePoint.SQLERRRM);
5176:                writer.writeScalar2Bytes(CodePoint.SVRCOD, severity);
5177:                writer.endDdmAndDss();
5178:
5179:            }
5180:
5181:            /**
5182:             * Write CMDCHKRM
5183:             *
5184:             * Instance Variables
5185:             * 	SVRCOD - Severity Code - required 
5186:             *
5187:             * @param	severity	severity of error
5188:             *
5189:             * @exception DRDAProtocolException
5190:             */
5191:            private void writeCMDCHKRM(int severity)
5192:                    throws DRDAProtocolException {
5193:                writer.createDssReply();
5194:                writer.startDdm(CodePoint.CMDCHKRM);
5195:                writer.writeScalar2Bytes(CodePoint.SVRCOD, severity);
5196:                writer.endDdmAndDss();
5197:
5198:            }
5199:
5200:            /**
5201:             * Translate from Cloudscape exception severity to SVRCOD
5202:             *
5203:             * @param e SQLException
5204:             */
5205:            private int getExceptionSeverity(SQLException e) {
5206:                int severity = CodePoint.SVRCOD_INFO;
5207:
5208:                if (e == null)
5209:                    return severity;
5210:
5211:                int ec = e.getErrorCode();
5212:                switch (ec) {
5213:                case ExceptionSeverity.STATEMENT_SEVERITY:
5214:                case ExceptionSeverity.TRANSACTION_SEVERITY:
5215:                    severity = CodePoint.SVRCOD_ERROR;
5216:                    break;
5217:                case ExceptionSeverity.WARNING_SEVERITY:
5218:                    severity = CodePoint.SVRCOD_WARNING;
5219:                    break;
5220:                case ExceptionSeverity.SESSION_SEVERITY:
5221:                case ExceptionSeverity.DATABASE_SEVERITY:
5222:                case ExceptionSeverity.SYSTEM_SEVERITY:
5223:                    severity = CodePoint.SVRCOD_SESDMG;
5224:                    break;
5225:                default:
5226:                    String sqlState = e.getSQLState();
5227:                    if (sqlState != null && sqlState.startsWith("01")) // warning
5228:                        severity = CodePoint.SVRCOD_WARNING;
5229:                    else
5230:                        severity = CodePoint.SVRCOD_ERROR;
5231:                }
5232:
5233:                return severity;
5234:
5235:            }
5236:
5237:            /**
5238:             * Write SQLCAGRP
5239:             *
5240:             * SQLCAGRP : FDOCA EARLY GROUP
5241:             * SQL Communcations Area Group Description
5242:             *
5243:             * FORMAT FOR SQLAM <= 6
5244:             *   SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5245:             *   SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5246:             *   SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5247:             *   SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5248:             *
5249:             * FORMAT FOR SQLAM >= 7
5250:             *   SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5251:             *   SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5252:             *   SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5253:             *   SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5254:             *   SQLDIAGGRP; DRDA TYPE N-GDA; ENVLID 0x56; Length Override 0
5255:             *
5256:             * @param e 	SQLException encountered
5257:             * @param sqlcode	sqlcode
5258:             * 
5259:             * @exception DRDAProtocolException
5260:             */
5261:            private void writeSQLCAGRP(SQLException e, int sqlcode,
5262:                    int updateCount, long rowCount)
5263:                    throws DRDAProtocolException {
5264:                if (e == null) {
5265:                    // Forwarding to the optimized version when there is no
5266:                    // exception object
5267:                    writeSQLCAGRP(nullSQLState, sqlcode, updateCount, rowCount);
5268:                    return;
5269:                }
5270:
5271:                if (rowCount < 0 && updateCount < 0) {
5272:                    writer.writeByte(CodePoint.NULLDATA);
5273:                    return;
5274:                }
5275:
5276:                if (SanityManager.DEBUG && server.debugOutput && sqlcode < 0) {
5277:                    trace("handle SQLException here");
5278:                    trace("reason is: " + e.getMessage());
5279:                    trace("SQLState is: " + e.getSQLState());
5280:                    trace("vendorCode is: " + e.getErrorCode());
5281:                    trace("nextException is: " + e.getNextException());
5282:                    server.consoleExceptionPrint(e);
5283:                    trace("wrapping SQLException into SQLCARD...");
5284:                }
5285:
5286:                //null indicator
5287:                writer.writeByte(0);
5288:
5289:                // SQLCODE
5290:                writer.writeInt(sqlcode);
5291:
5292:                // SQLSTATE
5293:                writer.writeString(e.getSQLState());
5294:
5295:                // SQLERRPROC
5296:                // Write the byte[] constant rather than the string, for efficiency
5297:                writer.writeBytes(server.prdIdBytes_);
5298:
5299:                // SQLCAXGRP
5300:                writeSQLCAXGRP(updateCount, rowCount, buildSqlerrmc(e), e
5301:                        .getNextException());
5302:            }
5303:
5304:            /**
5305:             * Same as writeSQLCAGRP, but optimized for the case
5306:             * when there is no real exception, i.e. the exception is null, or "End
5307:             * of data"
5308:             *
5309:             * SQLCAGRP : FDOCA EARLY GROUP
5310:             * SQL Communcations Area Group Description
5311:             *
5312:             * FORMAT FOR SQLAM <= 6
5313:             *   SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5314:             *   SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5315:             *   SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5316:             *   SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5317:             *
5318:             * FORMAT FOR SQLAM >= 7
5319:             *   SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5320:             *   SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5321:             *   SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5322:             *   SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5323:             *   SQLDIAGGRP; DRDA TYPE N-GDA; ENVLID 0x56; Length Override 0
5324:             *
5325:             * @param sqlState     SQLState (already converted to UTF8)
5326:             * @param sqlcode    sqlcode
5327:             * @param updateCount
5328:             * @param rowCount
5329:             * 
5330:             * @exception DRDAProtocolException
5331:             */
5332:
5333:            private void writeSQLCAGRP(byte[] sqlState, int sqlcode,
5334:                    int updateCount, long rowCount)
5335:                    throws DRDAProtocolException {
5336:                if (rowCount < 0 && updateCount < 0) {
5337:                    writer.writeByte(CodePoint.NULLDATA);
5338:                    return;
5339:                }
5340:
5341:                //null indicator
5342:                writer.writeByte(0);
5343:
5344:                // SQLCODE
5345:                writer.writeInt(sqlcode);
5346:
5347:                // SQLSTATE
5348:                writer.writeBytes(sqlState);
5349:
5350:                // SQLERRPROC
5351:                writer.writeBytes(server.prdIdBytes_);
5352:
5353:                // SQLCAXGRP (Uses null as sqlerrmc since there is no error)
5354:                writeSQLCAXGRP(updateCount, rowCount, null, null);
5355:            }
5356:
5357:            // Delimiters for SQLERRMC values.
5358:            // The token delimiter value will be used to parse the MessageId from the 
5359:            // SQLERRMC in MessageService.getLocalizedMessage and the MessageId will be
5360:            // used to retrive the localized message. If this delimiter value is changed
5361:            // please make sure to make appropriate changes in
5362:            // MessageService.getLocalizedMessage that gets called from 
5363:            // SystemProcedures.SQLCAMESSAGE
5364:            /**
5365:             * <code>SQLERRMC_TOKEN_DELIMITER</code> separates message argument tokens 
5366:             */
5367:            private static String SQLERRMC_TOKEN_DELIMITER = new String(
5368:                    new char[] { (char) 20 });
5369:
5370:            /**
5371:             * <code>SQLERRMC_PREFORMATTED_MESSAGE_DELIMITER</code>, When full message text is 
5372:             * sent for severe errors. This value separates the messages. 
5373:             */
5374:            private static String SQLERRMC_PREFORMATTED_MESSAGE_DELIMITER = new String(
5375:                    "::");
5376:
5377:            /**
5378:             * Create error message or message argements to return to client.  
5379:             * The SQLERRMC will normally be passed back  to the server in a call 
5380:             * to the SYSIBM.SQLCAMESSAGE but for severe exceptions the stored procedure 
5381:             * call cannot be made. So for Severe messages we will just send the message text.
5382:             * 
5383:             * This method will also truncate the value according the client capacity.
5384:             * CCC can only handle 70 characters.
5385:             * 
5386:             * Server sends the sqlerrmc using UTF8 encoding to the client.
5387:             * To get the message, client sends back information to the server
5388:             * calling SYSIBM.SQLCAMESSAGE (see Sqlca.getMessage).  Several parameters 
5389:             * are sent to this procedure including the locale, the sqlerrmc that the 
5390:             * client received from the server. 
5391:             * On server side, the procedure SQLCAMESSAGE in SystemProcedures then calls
5392:             * the MessageService.getLocalizedMessage to retrieve the localized error message. 
5393:             * In MessageService.getLocalizedMessage the sqlerrmc that is passed in, 
5394:             * is parsed to retrieve the message id. The value it uses to parse the MessageId
5395:             * is char value of 20, otherwise it uses the entire sqlerrmc as the message id. 
5396:             * This messageId is then used to retrieve the localized message if present, to 
5397:             * the client.
5398:             * 
5399:             * @param se  SQLException to build SQLERRMC
5400:             *  
5401:             * @return  String which is either the message arguments to be passed to 
5402:             *          SYSIBM.SQLCAMESSAGE or just message text for severe errors.  
5403:             */
5404:            private String buildSqlerrmc(SQLException se) {
5405:                boolean severe = (se.getErrorCode() >= ExceptionSeverity.SESSION_SEVERITY);
5406:                String sqlerrmc = null;
5407:
5408:                // get exception which carries Derby messageID and args, per DERBY-1178
5409:                se = Util.getExceptionFactory().getArgumentFerry(se);
5410:
5411:                if (se instanceof  EmbedSQLException && !severe)
5412:                    sqlerrmc = buildTokenizedSqlerrmc((EmbedSQLException) se);
5413:                else {
5414:                    // If this is not an EmbedSQLException or is a severe excecption where
5415:                    // we have no hope of succussfully calling the SYSIBM.SQLCAMESSAGE send
5416:                    // preformatted message using the server locale
5417:                    sqlerrmc = buildPreformattedSqlerrmc(se);
5418:                }
5419:                // Truncate the sqlerrmc to a length that the client can support.
5420:                int maxlen = (sqlerrmc == null) ? -1 : Math.min(sqlerrmc
5421:                        .length(), appRequester.supportedMessageParamLength());
5422:                if ((maxlen >= 0) && (sqlerrmc.length() > maxlen))
5423:                    // have to truncate so the client can handle it.
5424:                    sqlerrmc = sqlerrmc.substring(0, maxlen);
5425:                return sqlerrmc;
5426:            }
5427:
5428:            /**
5429:             * Build preformatted SQLException text 
5430:             * for severe exceptions or SQLExceptions that are not EmbedSQLExceptions.
5431:             * Just send the message text localized to the server locale.
5432:             * 
5433:             * @param se  SQLException for which to build SQLERRMC
5434:             * @return preformated message text 
5435:             * 			with messages separted by SQLERRMC_PREFORMATED_MESSAGE_DELIMITER
5436:             * 
5437:             */
5438:            private String buildPreformattedSqlerrmc(SQLException se) {
5439:                if (se == null)
5440:                    return "";
5441:
5442:                StringBuffer sb = new StringBuffer();
5443:                // String buffer to build up message
5444:                do {
5445:                    sb.append(se.getLocalizedMessage());
5446:                    se = se.getNextException();
5447:                    if (se != null)
5448:                        sb.append(SQLERRMC_PREFORMATTED_MESSAGE_DELIMITER
5449:                                + "SQLSTATE: " + se.getSQLState());
5450:                } while (se != null);
5451:                return sb.toString();
5452:            }
5453:
5454:            /**
5455:             * Build Tokenized SQLERRMC to just send the tokenized arguments to the client.
5456:             * for a Derby SQLException
5457:             * Message argument tokens are separated by SQLERRMC_TOKEN_DELIMITER 
5458:             * Multiple messages are separated by SystemProcedures.SQLERRMC_MESSAGE_DELIMITER
5459:             * 
5460:             *                 ...
5461:             * @param se   SQLException to print
5462:             * 
5463:             */
5464:            private String buildTokenizedSqlerrmc(EmbedSQLException se) {
5465:
5466:                String sqlerrmc = "";
5467:                do {
5468:                    String messageId = se.getMessageId();
5469:                    // arguments are variable part of a message
5470:                    Object[] args = se.getArguments();
5471:                    for (int i = 0; args != null && i < args.length; i++)
5472:                        sqlerrmc += args[i] + SQLERRMC_TOKEN_DELIMITER;
5473:                    sqlerrmc += messageId;
5474:                    se = (EmbedSQLException) se.getNextException();
5475:                    if (se != null) {
5476:                        sqlerrmc += SystemProcedures.SQLERRMC_MESSAGE_DELIMITER
5477:                                + se.getSQLState() + ":";
5478:                    }
5479:                } while (se != null);
5480:                return sqlerrmc;
5481:            }
5482:
5483:            /**
5484:             * Write SQLCAXGRP
5485:             *
5486:             * SQLCAXGRP : EARLY FDOCA GROUP
5487:             * SQL Communications Area Exceptions Group Description
5488:             *
5489:             * FORMAT FOR SQLAM <= 6
5490:             *   SQLRDBNME; DRDA TYPE FCS; ENVLID 0x30; Length Override 18
5491:             *   SQLERRD1; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5492:             *   SQLERRD2; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5493:             *   SQLERRD3; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5494:             *   SQLERRD4; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5495:             *   SQLERRD5; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5496:             *   SQLERRD6; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5497:             *   SQLWARN0; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5498:             *   SQLWARN1; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5499:             *   SQLWARN2; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5500:             *   SQLWARN3; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5501:             *   SQLWARN4; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5502:             *   SQLWARN5; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5503:             *   SQLWARN6; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5504:             *   SQLWARN7; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5505:             *   SQLWARN8; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5506:             *   SQLWARN9; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5507:             *   SQLWARNA; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5508:             *   SQLERRMSG_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 70
5509:             *   SQLERRMSG_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 70
5510:             *
5511:             * FORMAT FOR SQLAM >= 7
5512:             *   SQLERRD1; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5513:             *   SQLERRD2; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5514:             *   SQLERRD3; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5515:             *   SQLERRD4; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5516:             *   SQLERRD5; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5517:             *   SQLERRD6; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5518:             *   SQLWARN0; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5519:             *   SQLWARN1; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5520:             *   SQLWARN2; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5521:             *   SQLWARN3; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5522:             *   SQLWARN4; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5523:             *   SQLWARN5; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5524:             *   SQLWARN6; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5525:             *   SQLWARN7; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5526:             *   SQLWARN8; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5527:             *   SQLWARN9; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5528:             *   SQLWARNA; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5529:             *   SQLRDBNAME; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
5530:             *   SQLERRMSG_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 70
5531:             *   SQLERRMSG_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 70
5532:             * @param nextException SQLException encountered
5533:             * @param sqlerrmc sqlcode
5534:             * 
5535:             * @exception DRDAProtocolException
5536:             */
5537:            private void writeSQLCAXGRP(int updateCount, long rowCount,
5538:                    String sqlerrmc, SQLException nextException)
5539:                    throws DRDAProtocolException {
5540:                writer.writeByte(0); // SQLCAXGRP INDICATOR
5541:                if (sqlamLevel < 7) {
5542:                    writeRDBNAM(database.dbName);
5543:                    writeSQLCAERRWARN(updateCount, rowCount);
5544:                } else {
5545:                    // SQL ERRD1 - D6, WARN0-WARNA (35 bytes)
5546:                    writeSQLCAERRWARN(updateCount, rowCount);
5547:                    writer.writeShort(0); //CCC on Win does not take RDBNAME
5548:                }
5549:                writeVCMorVCS(sqlerrmc);
5550:                if (sqlamLevel >= 7)
5551:                    writeSQLDIAGGRP(nextException);
5552:            }
5553:
5554:            /**
5555:             * Write the ERR and WARN part of the SQLCA
5556:             *
5557:             * @param updateCount
5558:             * @param rowCount 
5559:             */
5560:            private void writeSQLCAERRWARN(int updateCount, long rowCount) {
5561:                // SQL ERRD1 - ERRD2 - row Count
5562:                writer.writeInt((int) ((rowCount >>> 32)));
5563:                writer.writeInt((int) (rowCount & 0x0000000ffffffffL));
5564:                // SQL ERRD3 - updateCount
5565:                writer.writeInt(updateCount);
5566:                // SQL ERRD4 - D6 (12 bytes)
5567:                writer.writeBytes(errD4_D6); // byte[] constant
5568:                // WARN0-WARNA (11 bytes)
5569:                writer.writeBytes(warn0_warnA); // byte[] constant
5570:            }
5571:
5572:            /**
5573:             * Write SQLDIAGGRP: SQL Diagnostics Group Description - Identity 0xD1
5574:             * Nullable Group
5575:             * SQLDIAGSTT; DRDA TYPE N-GDA; ENVLID 0xD3; Length Override 0
5576:             * SQLDIAGCN;  DRFA TYPE N-RLO; ENVLID 0xF6; Length Override 0
5577:             * SQLDIAGCI;  DRDA TYPE N-RLO; ENVLID 0xF5; Length Override 0
5578:             */
5579:            private void writeSQLDIAGGRP(SQLException nextException)
5580:                    throws DRDAProtocolException {
5581:                // for now we only want to send ROW_DELETED and ROW_UPDATED warnings
5582:                // as extended diagnostics
5583:                // move to first ROW_DELETED or ROW_UPDATED exception. These have been
5584:                // added to the end of the warning chain.
5585:                while (nextException != null
5586:                        && nextException.getSQLState() != SQLState.ROW_UPDATED
5587:                        && nextException.getSQLState() != SQLState.ROW_DELETED) {
5588:                    nextException = nextException.getNextException();
5589:                }
5590:
5591:                if ((nextException == null)
5592:                        || (diagnosticLevel == CodePoint.DIAGLVL0)) {
5593:                    writer.writeByte(CodePoint.NULLDATA);
5594:                    return;
5595:                }
5596:                writer.writeByte(0); // SQLDIAGGRP indicator
5597:
5598:                writeSQLDIAGSTT();
5599:                writeSQLDIAGCI(nextException);
5600:                writeSQLDIAGCN();
5601:            }
5602:
5603:            /*
5604:             * writeSQLDIAGSTT: Write NULLDATA for now
5605:             */
5606:            private void writeSQLDIAGSTT() throws DRDAProtocolException {
5607:                writer.writeByte(CodePoint.NULLDATA);
5608:                return;
5609:            }
5610:
5611:            /**
5612:             * writeSQLDIAGCI: SQL Diagnostics Condition Information Array - Identity 0xF5
5613:             * SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
5614:             * SQLDCIROW; ROW LID 0xE5; ELEMENT TAKEN 0(all); REP FACTOR 0(all)
5615:             */
5616:            private void writeSQLDIAGCI(SQLException nextException)
5617:                    throws DRDAProtocolException {
5618:                SQLException se = nextException;
5619:                long rowNum = 1;
5620:
5621:                /* Write the number of next exceptions to expect */
5622:                writeSQLNUMROW(se);
5623:
5624:                while (se != null) {
5625:                    String sqlState = se.getSQLState();
5626:
5627:                    // SQLCode > 0 -> Warning
5628:                    // SQLCode = 0 -> Info
5629:                    // SQLCode < 0 -> Error
5630:                    int severity = getExceptionSeverity(se);
5631:                    int sqlCode = -1;
5632:                    if (severity == CodePoint.SVRCOD_WARNING)
5633:                        sqlCode = 1;
5634:                    else if (severity == CodePoint.SVRCOD_INFO)
5635:                        sqlCode = 0;
5636:
5637:                    String sqlerrmc = "";
5638:                    if (diagnosticLevel == CodePoint.DIAGLVL1) {
5639:                        sqlerrmc = se.getLocalizedMessage();
5640:                    }
5641:
5642:                    // arguments are variable part of a message
5643:                    // only send arguments for diagnostic level 0
5644:                    if (diagnosticLevel == CodePoint.DIAGLVL0) {
5645:                        // we are only able to get arguments of EmbedSQLException
5646:                        if (se instanceof  EmbedSQLException) {
5647:                            Object[] args = ((EmbedSQLException) se)
5648:                                    .getArguments();
5649:                            for (int i = 0; args != null && i < args.length; i++)
5650:                                sqlerrmc += args[i].toString()
5651:                                        + SQLERRMC_TOKEN_DELIMITER;
5652:                        }
5653:                    }
5654:
5655:                    String dbname = null;
5656:                    if (database != null)
5657:                        dbname = database.dbName;
5658:
5659:                    writeSQLDCROW(rowNum++, sqlCode, sqlState, dbname, sqlerrmc);
5660:
5661:                    se = se.getNextException();
5662:                }
5663:
5664:                return;
5665:            }
5666:
5667:            /**
5668:             * writeSQLNUMROW: Writes SQLNUMROW : FDOCA EARLY ROW
5669:             * SQL Number of Elements Row Description
5670:             * FORMAT FOR SQLAM LEVELS
5671:             * SQLNUMGRP; GROUP LID 0x58; ELEMENT TAKEN 0(all); REP FACTOR 1
5672:             */
5673:            private void writeSQLNUMROW(SQLException nextException)
5674:                    throws DRDAProtocolException {
5675:                writeSQLNUMGRP(nextException);
5676:            }
5677:
5678:            /**
5679:             * writeSQLNUMGRP: Writes SQLNUMGRP : FDOCA EARLY GROUP
5680:             * SQL Number of Elements Group Description
5681:             * FORMAT FOR ALL SQLAM LEVELS
5682:             * SQLNUM; DRDA TYPE I2; ENVLID 0x04; Length Override 2
5683:             */
5684:            private void writeSQLNUMGRP(SQLException nextException)
5685:                    throws DRDAProtocolException {
5686:                int i = 0;
5687:                SQLException se;
5688:
5689:                /* Count the number of chained exceptions to be sent */
5690:                for (se = nextException; se != null; se = se.getNextException())
5691:                    i++;
5692:                writer.writeShort(i);
5693:            }
5694:
5695:            /**
5696:             * writeSQLDCROW: SQL Diagnostics Condition Row - Identity 0xE5
5697:             * SQLDCGRP; GROUP LID 0xD5; ELEMENT TAKEN 0(all); REP FACTOR 1
5698:             */
5699:            private void writeSQLDCROW(long rowNum, int sqlCode,
5700:                    String sqlState, String dbname, String sqlerrmc)
5701:                    throws DRDAProtocolException {
5702:                writeSQLDCGRP(rowNum, sqlCode, sqlState, dbname, sqlerrmc);
5703:            }
5704:
5705:            /**
5706:             * writeSQLDCGRP: SQL Diagnostics Condition Group Description
5707:             * 
5708:             * SQLDCCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5709:             * SQLDCSTATE; DRDA TYPE FCS; ENVLID Ox30; Lengeh Override 5
5710:             * SQLDCREASON; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5711:             * SQLDCLINEN; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5712:             * SQLDCROWN; DRDA TYPE FD; ENVLID 0x0E; Lengeh Override 31
5713:             * SQLDCER01; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5714:             * SQLDCER02; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5715:             * SQLDCER03; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5716:             * SQLDCER04; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5717:             * SQLDCPART; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5718:             * SQLDCPPOP; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5719:             * SQLDCMSGID; DRDA TYPE FCS; ENVLID 0x30; Length Override 10
5720:             * SQLDCMDE; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5721:             * SQLDCPMOD; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5722:             * SQLDCRDB; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
5723:             * SQLDCTOKS; DRDA TYPE N-RLO; ENVLID 0xF7; Length Override 0
5724:             * SQLDCMSG_m; DRDA TYPE NVMC; ENVLID 0x3F; Length Override 32672
5725:             * SQLDCMSG_S; DRDA TYPE NVCS; ENVLID 0x33; Length Override 32672
5726:             * SQLDCCOLN_m; DRDA TYPE NVCM ; ENVLID 0x3F; Length Override 255
5727:             * SQLDCCOLN_s; DRDA TYPE NVCS; ENVLID 0x33; Length Override 255
5728:             * SQLDCCURN_m; DRDA TYPE NVCM; ENVLID 0x3F; Length Override 255
5729:             * SQLDCCURN_s; DRDA TYPE NVCS; ENVLID 0x33; Length Override 255
5730:             * SQLDCPNAM_m; DRDA TYPE NVCM; ENVLID 0x3F; Length Override 255
5731:             * SQLDCPNAM_s; DRDA TYPE NVCS; ENVLID 0x33; Length Override 255
5732:             * SQLDCXGRP; DRDA TYPE N-GDA; ENVLID 0xD3; Length Override 1
5733:             */
5734:            private void writeSQLDCGRP(long rowNum, int sqlCode,
5735:                    String sqlState, String dbname, String sqlerrmc)
5736:                    throws DRDAProtocolException {
5737:                // SQLDCCODE
5738:                writer.writeInt(sqlCode);
5739:
5740:                // SQLDCSTATE
5741:                writer.writeString(sqlState);
5742:
5743:                writer.writeInt(0); // REASON_CODE
5744:                writer.writeInt(0); // LINE_NUMBER
5745:                writer.writeLong(rowNum); // ROW_NUMBER
5746:
5747:                byte[] byteArray = new byte[1];
5748:                writer.writeScalarPaddedBytes(byteArray, 47, (byte) 0);
5749:
5750:                writer.writeShort(0); // CCC on Win does not take RDBNAME
5751:                writer.writeByte(CodePoint.NULLDATA); // MESSAGE_TOKENS
5752:                writer.writeLDString(sqlerrmc); // MESSAGE_TEXT
5753:
5754:                writeVCMorVCS(null); // COLUMN_NAME
5755:                writeVCMorVCS(null); // PARAMETER_NAME
5756:                writeVCMorVCS(null); // EXTENDED_NAME
5757:                writer.writeByte(CodePoint.NULLDATA); // SQLDCXGRP
5758:            }
5759:
5760:            /*
5761:             * writeSQLDIAGCN: Write NULLDATA for now
5762:             */
5763:            private void writeSQLDIAGCN() throws DRDAProtocolException {
5764:                writer.writeByte(CodePoint.NULLDATA);
5765:                return;
5766:            }
5767:
5768:            /** 
5769:             * Write SQLDARD
5770:             *
5771:             * SQLDARD : FDOCA EARLY ARRAY
5772:             * SQL Descriptor Area Row Description with SQL Communications Area
5773:             *
5774:             * FORMAT FOR SQLAM <= 6
5775:             *   SQLCARD; ROW LID 0x64; ELEMENT TAKEN 0(all); REP FACTOR 1
5776:             *   SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
5777:             *   SQLDAROW; ROW LID 0x60; ELEMENT TAKEN 0(all); REP FACTOR 0(all)
5778:             *
5779:             * FORMAT FOR SQLAM >= 7
5780:             *   SQLCARD; ROW LID 0x64; ELEMENT TAKEN 0(all); REP FACTOR 1
5781:             *   SQLDHROW; ROW LID 0xE0; ELEMENT TAKEN 0(all); REP FACTOR 1
5782:             *   SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
5783:             *
5784:             * @param stmt	prepared statement
5785:             *
5786:             * @throws DRDAProtocolException
5787:             * @throws SQLException
5788:             */
5789:            private void writeSQLDARD(DRDAStatement stmt, boolean rtnOutput,
5790:                    SQLException e) throws DRDAProtocolException, SQLException {
5791:                PreparedStatement ps = stmt.getPreparedStatement();
5792:                ResultSetMetaData rsmeta = ps.getMetaData();
5793:                EngineParameterMetaData pmeta = stmt.getParameterMetaData();
5794:                int numElems = 0;
5795:                if (e == null || e instanceof  SQLWarning) {
5796:                    if (rtnOutput && (rsmeta != null))
5797:                        numElems = rsmeta.getColumnCount();
5798:                    else if ((!rtnOutput) && (pmeta != null))
5799:                        numElems = pmeta.getParameterCount();
5800:                }
5801:
5802:                writer.createDssObject();
5803:
5804:                // all went well we will just write a null SQLCA
5805:                writer.startDdm(CodePoint.SQLDARD);
5806:                writeSQLCAGRP(e, getSqlCode(getExceptionSeverity(e)), 0, 0);
5807:
5808:                if (sqlamLevel >= MGRLVL_7)
5809:                    writeSQLDHROW(stmt);
5810:
5811:                //SQLNUMROW
5812:                if (SanityManager.DEBUG)
5813:                    trace("num Elements = " + numElems);
5814:                writer.writeShort(numElems);
5815:
5816:                for (int i = 0; i < numElems; i++)
5817:                    writeSQLDAGRP(rsmeta, pmeta, i, rtnOutput);
5818:                writer.endDdmAndDss();
5819:
5820:            }
5821:
5822:            /**
5823:             * Write QRYDSC - Query Answer Set Description
5824:             *
5825:             * @param stmt DRDAStatement we are working on
5826:             * @param FDODSConly	simply the FDODSC, without the wrap
5827:             *
5828:             * Instance Variables
5829:             *   SQLDTAGRP - required
5830:             * 
5831:             * Only 84 columns can be sent in a single QRYDSC.  If there are more columns
5832:             * they must be sent in subsequent QRYDSC.
5833:             * If the QRYDSC will not fit into the current block, as many columns as can
5834:             * fit are sent and then the remaining are sent in the following blocks.
5835:             * 
5836:             * @throws DRDAProtocolException
5837:             * @throws SQLException
5838:             */
5839:            private void writeQRYDSC(DRDAStatement stmt, boolean FDODSConly)
5840:                    throws DRDAProtocolException, SQLException {
5841:
5842:                ResultSet rs = null;
5843:                ResultSetMetaData rsmeta = null;
5844:                EngineParameterMetaData pmeta = null;
5845:                if (!stmt.needsToSendParamData)
5846:                    rs = stmt.getResultSet();
5847:                if (rs == null) // this is a CallableStatement, use parameter meta data
5848:                    pmeta = stmt.getParameterMetaData();
5849:                else
5850:                    rsmeta = rs.getMetaData();
5851:
5852:                int numCols = (rsmeta != null ? rsmeta.getColumnCount() : pmeta
5853:                        .getParameterCount());
5854:                int numGroups = 1;
5855:                int colStart = 1;
5856:                int colEnd = numCols;
5857:                int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize()
5858:                        : CodePoint.QRYBLKSZ_MAX;
5859:
5860:                // check for remaining space in current query block
5861:                // Need to mod with blksize so remaining doesn't go negative. 4868
5862:                int remaining = blksize - (writer.getDSSLength() % blksize)
5863:                        - (3 + FdocaConstants.SQLCADTA_SQLDTARD_RLO_SIZE);
5864:
5865:                // calcuate how may columns can be sent in the current query block
5866:                int firstcols = remaining
5867:                        / FdocaConstants.SQLDTAGRP_COL_DSC_SIZE;
5868:
5869:                // check if it doesn't all fit into the first block and 
5870:                //	under FdocaConstants.MAX_VARS_IN_NGDA
5871:                if (firstcols < numCols
5872:                        || numCols > FdocaConstants.MAX_VARS_IN_NGDA) {
5873:                    // we are limited to FdocaConstants.MAX_VARS_IN_NGDA
5874:                    if (firstcols > FdocaConstants.MAX_VARS_IN_NGDA) {
5875:                        if (SanityManager.DEBUG)
5876:                            SanityManager.ASSERT(
5877:                                    numCols > FdocaConstants.MAX_VARS_IN_NGDA,
5878:                                    "Number of columns " + numCols
5879:                                            + " is less than MAX_VARS_IN_NGDA");
5880:                        numGroups = numCols / FdocaConstants.MAX_VARS_IN_NGDA;
5881:                        // some left over
5882:                        if (FdocaConstants.MAX_VARS_IN_NGDA * numGroups < numCols)
5883:                            numGroups++;
5884:                        colEnd = FdocaConstants.MAX_VARS_IN_NGDA;
5885:                    } else {
5886:                        colEnd = firstcols;
5887:                        numGroups += (numCols - firstcols)
5888:                                / FdocaConstants.MAX_VARS_IN_NGDA;
5889:                        if (FdocaConstants.MAX_VARS_IN_NGDA * numGroups < numCols)
5890:                            numGroups++;
5891:                    }
5892:                }
5893:
5894:                if (!FDODSConly) {
5895:                    writer.createDssObject();
5896:                    writer.startDdm(CodePoint.QRYDSC);
5897:                }
5898:
5899:                for (int i = 0; i < numGroups; i++) {
5900:                    writeSQLDTAGRP(stmt, rsmeta, pmeta, colStart, colEnd,
5901:                            (i == 0 ? true : false));
5902:                    colStart = colEnd + 1;
5903:                    // 4868 - Limit range to MAX_VARS_IN_NGDA (used to have extra col)
5904:                    colEnd = colEnd + FdocaConstants.MAX_VARS_IN_NGDA;
5905:                    if (colEnd > numCols)
5906:                        colEnd = numCols;
5907:                }
5908:                writer.writeBytes(FdocaConstants.SQLCADTA_SQLDTARD_RLO);
5909:                if (!FDODSConly)
5910:                    writer.endDdmAndDss();
5911:            }
5912:
5913:            /**
5914:             * Write SQLDTAGRP
5915:             * SQLDAGRP : Late FDOCA GROUP
5916:             * SQL Data Value Group Descriptor
5917:             *  LENGTH - length of the SQLDTAGRP
5918:             *  TRIPLET_TYPE - NGDA for first, CPT for following
5919:             *  ID - SQLDTAGRP_LID for first, NULL_LID for following
5920:             *  For each column
5921:             *    DRDA TYPE 
5922:             *	  LENGTH OVERRIDE
5923:             *	    For numeric/decimal types
5924:             *		  PRECISON
5925:             *		  SCALE
5926:             *	    otherwise
5927:             *		  LENGTH or DISPLAY_WIDTH
5928:             *
5929:             * @param stmt		drda statement
5930:             * @param rsmeta	resultset meta data
5931:             * @param pmeta		parameter meta data for CallableStatement
5932:             * @param colStart	starting column for group to send
5933:             * @param colEnd	end column to send
5934:             * @param first		is this the first group
5935:             *
5936:             * @throws DRDAProtocolException
5937:             * @throws SQLException
5938:             */
5939:            private void writeSQLDTAGRP(DRDAStatement stmt,
5940:                    ResultSetMetaData rsmeta, EngineParameterMetaData pmeta,
5941:                    int colStart, int colEnd, boolean first)
5942:                    throws DRDAProtocolException, SQLException {
5943:
5944:                int length = (FdocaConstants.SQLDTAGRP_COL_DSC_SIZE * ((colEnd + 1) - colStart)) + 3;
5945:                writer.writeByte(length);
5946:                if (first) {
5947:
5948:                    writer.writeByte(FdocaConstants.NGDA_TRIPLET_TYPE);
5949:                    writer.writeByte(FdocaConstants.SQLDTAGRP_LID);
5950:                } else {
5951:                    //continued
5952:                    writer.writeByte(FdocaConstants.CPT_TRIPLET_TYPE);
5953:                    writer.writeByte(FdocaConstants.NULL_LID);
5954:
5955:                }
5956:
5957:                boolean hasRs = (rsmeta != null); //  if don't have result, then we look at parameter meta
5958:
5959:                for (int i = colStart; i <= colEnd; i++) {
5960:                    boolean nullable = (hasRs ? (rsmeta.isNullable(i) == rsmeta.columnNullable)
5961:                            : (pmeta.isNullable(i) == JDBC30Translation.PARAMETER_NULLABLE));
5962:                    int colType = (hasRs ? rsmeta.getColumnType(i) : pmeta
5963:                            .getParameterType(i));
5964:                    int[] outlen = { -1 };
5965:                    int drdaType = (hasRs ? FdocaConstants
5966:                            .mapJdbcTypeToDrdaType(colType, nullable, outlen)
5967:                            : stmt.getParamDRDAType(i));
5968:
5969:                    boolean isDecimal = ((drdaType | 1) == DRDAConstants.DRDA_TYPE_NDECIMAL);
5970:                    int precision = 0, scale = 0;
5971:                    if (hasRs) {
5972:                        precision = rsmeta.getPrecision(i);
5973:                        scale = rsmeta.getScale(i);
5974:                        stmt.setRsDRDAType(i, drdaType);
5975:                        stmt.setRsPrecision(i, precision);
5976:                        stmt.setRsScale(i, scale);
5977:                    }
5978:
5979:                    else if (isDecimal) {
5980:                        if (stmt.isOutputParam(i))
5981:                            ((CallableStatement) stmt.ps).registerOutParameter(
5982:                                    i, Types.DECIMAL);
5983:                        precision = pmeta.getPrecision(i);
5984:                        scale = pmeta.getScale(i);
5985:
5986:                    }
5987:
5988:                    if (SanityManager.DEBUG)
5989:                        trace("jdbcType=" + colType + "  \tdrdaType="
5990:                                + Integer.toHexString(drdaType));
5991:
5992:                    // Length or precision and scale for decimal values.
5993:                    writer.writeByte(drdaType);
5994:                    if (isDecimal) {
5995:                        writer.writeByte(precision);
5996:                        writer.writeByte(scale);
5997:                    } else if (outlen[0] != -1)
5998:                        writer.writeShort(outlen[0]);
5999:                    else if (hasRs)
6000:                        writer.writeShort(rsmeta.getColumnDisplaySize(i));
6001:                    else
6002:                        writer.writeShort(stmt.getParamLen(i));
6003:                }
6004:            }
6005:
6006:            //pass PreparedStatement here so we can send correct holdability on the wire for jdk1.3 and higher
6007:            //For jdk1.3, we provide hold cursor support through reflection.
6008:            private void writeSQLDHROW(DRDAStatement stmt)
6009:                    throws DRDAProtocolException, SQLException {
6010:                if (JVMInfo.JDK_ID < 2) //write null indicator for SQLDHROW because there is no holdability support prior to jdk1.3
6011:                {
6012:                    writer.writeByte(CodePoint.NULLDATA);
6013:                    return;
6014:                }
6015:
6016:                writer.writeByte(0); // SQLDHROW INDICATOR
6017:
6018:                //SQLDHOLD
6019:                writer.writeShort(stmt.getResultSetHoldability());
6020:
6021:                //SQLDRETURN
6022:                writer.writeShort(0);
6023:                //SQLDSCROLL
6024:                writer.writeShort(0);
6025:                //SQLDSENSITIVE
6026:                writer.writeShort(0);
6027:                //SQLDFCODE
6028:                writer.writeShort(0);
6029:                //SQLDKEYTYPE
6030:                writer.writeShort(0);
6031:                //SQLRDBNAME
6032:                writer.writeShort(0); //CCC on Windows somehow does not take any dbname
6033:                //SQLDSCHEMA
6034:                writeVCMorVCS(null);
6035:
6036:            }
6037:
6038:            /**
6039:             * Write QRYDTA - Query Answer Set Data
6040:             *  Contains some or all of the answer set data resulting from a query
6041:             *  If the client is not using rowset processing, this routine attempts
6042:             *  to pack as much data into the QRYDTA as it can. This may result in
6043:             *  splitting the last row across the block, in which case when the
6044:             *  client calls CNTQRY we will return the remainder of the row.
6045:             *
6046:             *  Splitting a QRYDTA block is expensive, for several reasons:
6047:             *  - extra logic must be run, on both client and server side
6048:             *  - more network round-trips are involved
6049:             *  - the QRYDTA block which contains the continuation of the split
6050:             *    row is generally wasteful, since it contains the remainder of
6051:             *    the split row but no additional rows.
6052:             *  Since splitting is expensive, the server makes some attempt to
6053:             *  avoid it. Currently, the server's algorithm for this is to
6054:             *  compute the length of the current row, and to stop trying to pack
6055:             *  more rows into this buffer if another row of that length would
6056:             *  not fit. However, since rows can vary substantially in length,
6057:             *  this algorithm is often ineffective at preventing splits. For
6058:             *  example, if a short row near the end of the buffer is then
6059:             *  followed by a long row, that long row will be split. It is possible
6060:             *  to improve this algorithm substantially:
6061:             *  - instead of just using the length of the previous row as a guide
6062:             *    for whether to attempt packing another row in, use some sort of
6063:             *    overall average row size computed over multiple rows (e.g., all
6064:             *    the rows we've placed into this QRYDTA block, or all the rows
6065:             *    we've process for this result set)
6066:             *  - when we discover that the next row will not fit, rather than
6067:             *    splitting the row across QRYDTA blocks, if it is relatively
6068:             *    small, we could just hold the entire row in a buffer to place
6069:             *    it entirely into the next QRYDTA block, or reset the result
6070:             *    set cursor back one row to "unread" this row.
6071:             *  - when splitting a row across QRYDTA blocks, we tend to copy
6072:             *    data around multiple times. Careful coding could remove some
6073:             *    of these copies.
6074:             *  However, it is important not to over-complicate this code: it is
6075:             *  better to be correct than to be efficient, and there have been
6076:             *  several bugs in the split logic already.
6077:             *
6078:             * Instance Variables
6079:             *   Byte string
6080:             *
6081:             * @param stmt	DRDA statement we are processing
6082:             * @throws DRDAProtocolException
6083:             * @throws SQLException
6084:             */
6085:            private void writeQRYDTA(DRDAStatement stmt)
6086:                    throws DRDAProtocolException, SQLException {
6087:                boolean getMoreData = true;
6088:                boolean sentExtData = false;
6089:                int startLength = 0;
6090:                writer.createDssObject();
6091:
6092:                if (SanityManager.DEBUG)
6093:                    trace("Write QRYDTA");
6094:                writer.startDdm(CodePoint.QRYDTA);
6095:                // Check to see if there was leftover data from splitting
6096:                // the previous QRYDTA for this result set. If there was, and
6097:                // if we have now sent all of it, send any EXTDTA for that row
6098:                // and increment the rowCount which we failed to increment in
6099:                // writeFDODTA when we realized the row needed to be split.
6100:                if (processLeftoverQRYDTA(stmt)) {
6101:                    if (stmt.getSplitQRYDTA() == null) {
6102:                        stmt.rowCount += 1;
6103:                        if (stmt.getExtDtaObjects() != null)
6104:                            writeEXTDTA(stmt);
6105:                    }
6106:                    return;
6107:                }
6108:
6109:                while (getMoreData) {
6110:                    sentExtData = false;
6111:                    getMoreData = writeFDODTA(stmt);
6112:
6113:                    if (stmt.getExtDtaObjects() != null
6114:                            && stmt.getSplitQRYDTA() == null) {
6115:                        writer.endDdmAndDss();
6116:                        writeEXTDTA(stmt);
6117:                        getMoreData = false;
6118:                        sentExtData = true;
6119:                    }
6120:
6121:                    // if we don't have enough room for a row of the 
6122:                    // last row's size, don't try to cram it in.
6123:                    // It would get split up but it is not very efficient.
6124:                    if (getMoreData == true) {
6125:                        int endLength = writer.getDSSLength();
6126:                        int rowsize = endLength - startLength;
6127:                        if ((stmt.getBlksize() - endLength) < rowsize)
6128:                            getMoreData = false;
6129:
6130:                        startLength = endLength;
6131:                    }
6132:
6133:                }
6134:                // If we sent extDta we will rely on
6135:                // writeScalarStream to end the dss with the proper chaining.
6136:                // otherwise end it here.
6137:                if (!sentExtData)
6138:                    writer.endDdmAndDss();
6139:
6140:                if (!stmt.hasdata()) {
6141:                    final boolean qryclsOnLmtblkprc = appRequester
6142:                            .supportsQryclsimpForLmtblkprc();
6143:                    if (stmt.isRSCloseImplicit(qryclsOnLmtblkprc)) {
6144:                        stmt.rsClose();
6145:                    }
6146:                }
6147:            }
6148:
6149:            /**
6150:             * This routine places some data into the current QRYDTA block using
6151:             * FDODTA (Formatted Data Object DaTA rules).
6152:             *
6153:             * There are 3 basic types of processing flow for this routine:
6154:             * - In normal non-rowset, non-scrollable cursor flow, this routine
6155:             *   places a single row into the QRYDTA block and returns TRUE,
6156:             *   indicating that the caller can call us back to place another
6157:             *   row into the result set if he wishes. (The caller may need to
6158:             *   send Externalized Data, which would be a reason for him NOT to
6159:             *   place any more rows into the QRYDTA).
6160:             * - In ROWSET processing, this routine places an entire ROWSET of
6161:             *   rows into the QRYDTA block and returns FALSE, indicating that
6162:             *   the QRYDTA block is full and should now be sent.
6163:             * - In callable statement processing, this routine places the
6164:             *   results from the output parameters of the called procedure into
6165:             *   the QRYDTA block. This code path is really dramatically
6166:             *   different from the other two paths and shares only a very small
6167:             *   amount of common code in this routine.
6168:             *
6169:             * In all cases, it is possible that the data we wish to return may
6170:             * not fit into the QRYDTA block, in which case we call splitQRYDTA
6171:             * to split the data and remember the remainder data in the result set.
6172:             * Splitting the data is relatively rare in the normal cursor case,
6173:             * because our caller (writeQRYDTA) uses a coarse estimation
6174:             * technique to avoid calling us if he thinks a split is likely.
6175:             *
6176:             * The overall structure of this routine is implemented as two
6177:             * loops:
6178:             * - the outer "do ... while ... " loop processes a ROWSET, one row
6179:             *   at a time. For non-ROWSET cursors, and for callable statements,
6180:             *   this loop executes only once.
6181:             * - the inner "for ... i < numCols ..." loop processes each column
6182:             *   in the current row, or each output parmeter in the procedure.
6183:             *
6184:             * Most column data is written directly inline in the QRYDTA block.
6185:             * Some data, however, is written as Externalized Data. This is
6186:             * commonly used for Large Objects. In that case, an Externalized
6187:             * Data Pointer is written into the QRYDTA block, and the actual
6188:             * data flows in separate EXTDTA blocks which are returned
6189:             * after this QRYDTA block.
6190:             */
6191:            private boolean writeFDODTA(DRDAStatement stmt)
6192:                    throws DRDAProtocolException, SQLException {
6193:                boolean hasdata = false;
6194:                int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize()
6195:                        : CodePoint.QRYBLKSZ_MAX;
6196:                long rowCount = 0;
6197:                ResultSet rs = null;
6198:                boolean moreData = (stmt.getQryprctyp() == CodePoint.LMTBLKPRC);
6199:                int numCols;
6200:
6201:                if (!stmt.needsToSendParamData) {
6202:                    rs = stmt.getResultSet();
6203:                }
6204:
6205:                if (rs != null) {
6206:                    numCols = stmt.getNumRsCols();
6207:                    if (stmt.isScrollable())
6208:                        hasdata = positionCursor(stmt, rs);
6209:                    else
6210:                        hasdata = rs.next();
6211:                } else // it's for a CallableStatement
6212:                {
6213:                    hasdata = stmt.hasOutputParams();
6214:                    numCols = stmt.getNumParams();
6215:                }
6216:
6217:                do {
6218:                    if (!hasdata) {
6219:                        doneData(stmt, rs);
6220:                        moreData = false;
6221:                        return moreData;
6222:                    }
6223:
6224:                    // Send ResultSet warnings if there are any
6225:                    SQLWarning sqlw = (rs != null) ? rs.getWarnings() : null;
6226:                    if (rs != null) {
6227:                        rs.clearWarnings();
6228:                    }
6229:
6230:                    // for updatable, insensitive result sets we signal the
6231:                    // row updated condition to the client via a warning to be 
6232:                    // popped by client onto its rowUpdated state, i.e. this 
6233:                    // warning should not reach API level.
6234:                    if (rs != null && rs.rowUpdated()) {
6235:                        SQLWarning w = new SQLWarning("", SQLState.ROW_UPDATED,
6236:                                ExceptionSeverity.WARNING_SEVERITY);
6237:                        if (sqlw != null) {
6238:                            sqlw.setNextWarning(w);
6239:                        } else {
6240:                            sqlw = w;
6241:                        }
6242:                    }
6243:                    // Delete holes are manifest as a row consisting of a non-null
6244:                    // SQLCARD and a null data group. The SQLCARD has a warning
6245:                    // SQLSTATE of 02502
6246:                    if (rs != null && rs.rowDeleted()) {
6247:                        SQLWarning w = new SQLWarning("", SQLState.ROW_DELETED,
6248:                                ExceptionSeverity.WARNING_SEVERITY);
6249:                        if (sqlw != null) {
6250:                            sqlw.setNextWarning(w);
6251:                        } else {
6252:                            sqlw = w;
6253:                        }
6254:                    }
6255:
6256:                    if (sqlw == null)
6257:                        writeSQLCAGRP(nullSQLState, 0, -1, -1);
6258:                    else
6259:                        writeSQLCAGRP(sqlw, sqlw.getErrorCode(), 1, -1);
6260:
6261:                    // if we were asked not to return data, mark QRYDTA null; do not
6262:                    // return yet, need to make rowCount right
6263:                    // if the row has been deleted return QRYDTA null (delete hole)
6264:                    boolean noRetrieveRS = (rs != null && (!stmt.getQryrtndta() || rs
6265:                            .rowDeleted()));
6266:                    if (noRetrieveRS)
6267:                        writer.writeByte(0xFF); //QRYDTA null indicator: IS NULL
6268:                    else
6269:                        writer.writeByte(0); //QRYDTA null indicator: not null
6270:
6271:                    for (int i = 1; i <= numCols; i++) {
6272:                        if (noRetrieveRS)
6273:                            break;
6274:
6275:                        int drdaType;
6276:                        int ndrdaType;
6277:                        int precision;
6278:                        int scale;
6279:
6280:                        Object val = null;
6281:                        boolean valNull;
6282:                        if (rs != null) {
6283:                            drdaType = stmt.getRsDRDAType(i) & 0xff;
6284:                            precision = stmt.getRsPrecision(i);
6285:                            scale = stmt.getRsScale(i);
6286:                            ndrdaType = drdaType | 1;
6287:
6288:                            if (SanityManager.DEBUG)
6289:                                trace("!!drdaType = "
6290:                                        + java.lang.Integer
6291:                                                .toHexString(drdaType)
6292:                                        + "precision = " + precision
6293:                                        + " scale = " + scale);
6294:                            switch (ndrdaType) {
6295:                            case DRDAConstants.DRDA_TYPE_NLOBBYTES:
6296:                            case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
6297:                                EXTDTAInputStream extdtaStream = EXTDTAInputStream
6298:                                        .getEXTDTAStream(rs, i, drdaType);
6299:                                writeFdocaVal(i, extdtaStream, drdaType,
6300:                                        precision, scale, rs.wasNull(), stmt);
6301:                                break;
6302:                            case DRDAConstants.DRDA_TYPE_NINTEGER:
6303:                                int ival = rs.getInt(i);
6304:                                valNull = rs.wasNull();
6305:                                if (SanityManager.DEBUG)
6306:                                    trace("====== writing int: " + ival
6307:                                            + " is null: " + valNull);
6308:                                writeNullability(drdaType, valNull);
6309:                                if (!valNull)
6310:                                    writer.writeInt(ival);
6311:                                break;
6312:                            case DRDAConstants.DRDA_TYPE_NSMALL:
6313:                                short sval = rs.getShort(i);
6314:                                valNull = rs.wasNull();
6315:                                if (SanityManager.DEBUG)
6316:                                    trace("====== writing small: " + sval
6317:                                            + " is null: " + valNull);
6318:                                writeNullability(drdaType, valNull);
6319:                                if (!valNull)
6320:                                    writer.writeShort(sval);
6321:                                break;
6322:                            case DRDAConstants.DRDA_TYPE_NINTEGER8:
6323:                                long lval = rs.getLong(i);
6324:                                valNull = rs.wasNull();
6325:                                if (SanityManager.DEBUG)
6326:                                    trace("====== writing long: " + lval
6327:                                            + " is null: " + valNull);
6328:                                writeNullability(drdaType, valNull);
6329:                                if (!valNull)
6330:                                    writer.writeLong(lval);
6331:                                break;
6332:                            case DRDAConstants.DRDA_TYPE_NFLOAT4:
6333:                                float fval = rs.getFloat(i);
6334:                                valNull = rs.wasNull();
6335:                                if (SanityManager.DEBUG)
6336:                                    trace("====== writing float: " + fval
6337:                                            + " is null: " + valNull);
6338:                                writeNullability(drdaType, valNull);
6339:                                if (!valNull)
6340:                                    writer.writeFloat(fval);
6341:                                break;
6342:                            case DRDAConstants.DRDA_TYPE_NFLOAT8:
6343:                                double dval = rs.getDouble(i);
6344:                                valNull = rs.wasNull();
6345:                                if (SanityManager.DEBUG)
6346:                                    trace("====== writing double: " + dval
6347:                                            + " is null: " + valNull);
6348:                                writeNullability(drdaType, valNull);
6349:                                if (!valNull)
6350:                                    writer.writeDouble(dval);
6351:                                break;
6352:                            case DRDAConstants.DRDA_TYPE_NCHAR:
6353:                            case DRDAConstants.DRDA_TYPE_NVARCHAR:
6354:                            case DRDAConstants.DRDA_TYPE_NVARMIX:
6355:                            case DRDAConstants.DRDA_TYPE_NLONG:
6356:                            case DRDAConstants.DRDA_TYPE_NLONGMIX:
6357:                                String valStr = rs.getString(i);
6358:                                if (SanityManager.DEBUG)
6359:                                    trace("====== writing char/varchar/mix :"
6360:                                            + valStr + ":");
6361:                                writeFdocaVal(i, valStr, drdaType, precision,
6362:                                        scale, rs.wasNull(), stmt);
6363:                                break;
6364:                            default:
6365:                                writeFdocaVal(i, rs.getObject(i), drdaType,
6366:                                        precision, scale, rs.wasNull(), stmt);
6367:                            }
6368:                        } else {
6369:                            drdaType = stmt.getParamDRDAType(i) & 0xff;
6370:                            precision = stmt.getParamPrecision(i);
6371:                            scale = stmt.getParamScale(i);
6372:                            ndrdaType = drdaType | 1;
6373:
6374:                            if (stmt.isOutputParam(i)) {
6375:                                if (SanityManager.DEBUG)
6376:                                    trace("***getting Object " + i);
6377:                                val = ((CallableStatement) stmt.ps)
6378:                                        .getObject(i);
6379:                                valNull = (val == null);
6380:                                writeFdocaVal(i, val, drdaType, precision,
6381:                                        scale, valNull, stmt);
6382:                            } else
6383:                                writeFdocaVal(i, null, drdaType, precision,
6384:                                        scale, true, stmt);
6385:
6386:                        }
6387:                    }
6388:                    // does all this fit in one QRYDTA
6389:                    if (writer.getDSSLength() > blksize) {
6390:                        splitQRYDTA(stmt, blksize);
6391:                        return false;
6392:                    }
6393:
6394:                    if (rs == null)
6395:                        return moreData;
6396:
6397:                    //get the next row
6398:                    rowCount++;
6399:                    if (rowCount < stmt.getQryrowset()) {
6400:                        hasdata = rs.next();
6401:                    }
6402:                    /*(1) scrollable we return at most a row set; OR (2) no retrieve data
6403:                     */
6404:                    else if (stmt.isScrollable() || noRetrieveRS)
6405:                        moreData = false;
6406:
6407:                } while (hasdata && rowCount < stmt.getQryrowset());
6408:
6409:                // add rowCount to statement row count
6410:                // for non scrollable cursors
6411:                if (!stmt.isScrollable())
6412:                    stmt.rowCount += rowCount;
6413:
6414:                if (!hasdata) {
6415:                    doneData(stmt, rs);
6416:                    moreData = false;
6417:                }
6418:
6419:                if (!stmt.isScrollable())
6420:                    stmt.setHasdata(hasdata);
6421:                return moreData;
6422:            }
6423:
6424:            /**
6425:             * Split QRYDTA into blksize chunks
6426:             *
6427:             * This routine is called if the QRYDTA data will not fit. It writes
6428:             * as much data as it can, then stores the remainder in the result
6429:             * set. At some later point, when the client returns with a CNTQRY,
6430:             * we will call processLeftoverQRYDTA to handle that data.
6431:             *
6432:             * The interaction between DRDAConnThread and DDMWriter is rather
6433:             * complicated here. This routine gets called because DRDAConnThread
6434:             * realizes that it has constructed a QRYDTA message which is too
6435:             * large. At that point, we need to reclaim the "extra" data and
6436:             * hold on to it. To aid us in that processing, DDMWriter provides
6437:             * the routines getDSSLength, copyDSSDataToEnd, and truncateDSS.
6438:             * For some additional detail on this complex sub-protocol, the
6439:             * interested reader should study bug DERBY-491 and 492 at:
6440:             * http://issues.apache.org/jira/browse/DERBY-491 and
6441:             * http://issues.apache.org/jira/browse/DERBY-492
6442:             *
6443:             * @param stmt DRDA statment
6444:             * @param blksize size of query block
6445:             * 
6446:             * @throws SQLException
6447:             * @throws DRDAProtocolException
6448:             */
6449:            private void splitQRYDTA(DRDAStatement stmt, int blksize)
6450:                    throws SQLException, DRDAProtocolException {
6451:                // make copy of extra data
6452:                byte[] temp = writer.copyDSSDataToEnd(blksize);
6453:                // truncate to end of blocksize
6454:                writer.truncateDSS(blksize);
6455:                if (temp.length == 0)
6456:                    agentError("LMTBLKPRC violation: splitQRYDTA was "
6457:                            + "called to split a QRYDTA block, but the "
6458:                            + "entire row fit successfully into the "
6459:                            + "current block. Server rowsize computation "
6460:                            + "was probably incorrect (perhaps an off-by-"
6461:                            + "one bug?). QRYDTA blocksize: " + blksize);
6462:                stmt.setSplitQRYDTA(temp);
6463:            }
6464:
6465:            /*
6466:             * Process remainder data resulting from a split.
6467:             *
6468:             * This routine is called at the start of building each QRYDTA block.
6469:             * Normally, it observes that there is no remainder data from the
6470:             * previous QRYDTA block, and returns FALSE, indicating that there
6471:             * was nothing to do.
6472:             *
6473:             * However, if it discovers that the previous QRYDTA block was split,
6474:             * then it retrieves the remainder data from the result set, writes
6475:             * as much of it as will fit into the QRYDTA block (hopefully all of
6476:             * it will fit, but the row may be very long), and returns TRUE,
6477:             * indicating that this QRYDTA block has been filled with remainder
6478:             * data and should now be sent immediately.
6479:             */
6480:            private boolean processLeftoverQRYDTA(DRDAStatement stmt)
6481:                    throws SQLException, DRDAProtocolException {
6482:                byte[] leftovers = stmt.getSplitQRYDTA();
6483:                if (leftovers == null)
6484:                    return false;
6485:                int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize()
6486:                        : CodePoint.QRYBLKSZ_MAX;
6487:                blksize = blksize - 10; //DSS header + QRYDTA and length
6488:                if (leftovers.length < blksize) {
6489:                    writer.writeBytes(leftovers, 0, leftovers.length);
6490:                    stmt.setSplitQRYDTA(null);
6491:                } else {
6492:                    writer.writeBytes(leftovers, 0, blksize);
6493:                    byte[] newLeftovers = new byte[leftovers.length - blksize];
6494:                    for (int i = 0; i < newLeftovers.length; i++)
6495:                        newLeftovers[i] = leftovers[blksize + i];
6496:                    stmt.setSplitQRYDTA(newLeftovers);
6497:                }
6498:                // finish off query block and send
6499:                writer.endDdmAndDss();
6500:                return true;
6501:            }
6502:
6503:            /**
6504:             * Done data
6505:             * Send SQLCARD for the end of the data
6506:             * 
6507:             * @param stmt DRDA statement
6508:             * @param rs Result set
6509:             * @throws DRDAProtocolException
6510:             * @throws SQLException
6511:             */
6512:            private void doneData(DRDAStatement stmt, ResultSet rs)
6513:                    throws DRDAProtocolException, SQLException {
6514:                if (SanityManager.DEBUG)
6515:                    trace("*****NO MORE DATA!!");
6516:                int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize()
6517:                        : CodePoint.QRYBLKSZ_MAX;
6518:                if (rs != null) {
6519:                    if (stmt.isScrollable()) {
6520:                        //keep isAfterLast and isBeforeFirst to be able 
6521:                        //to reposition after counting rows
6522:                        boolean isAfterLast = rs.isAfterLast();
6523:                        boolean isBeforeFirst = rs.isBeforeFirst();
6524:
6525:                        // for scrollable cursors - calculate the row count
6526:                        // since we may not have gone through each row
6527:                        rs.last();
6528:                        stmt.rowCount = rs.getRow();
6529:
6530:                        // reposition after last or before first
6531:                        if (isAfterLast) {
6532:                            rs.afterLast();
6533:                        }
6534:                        if (isBeforeFirst) {
6535:                            rs.beforeFirst();
6536:                        }
6537:                    } else // non-scrollable cursor
6538:                    {
6539:                        final boolean qryclsOnLmtblkprc = appRequester
6540:                                .supportsQryclsimpForLmtblkprc();
6541:                        if (stmt.isRSCloseImplicit(qryclsOnLmtblkprc)) {
6542:                            stmt.rsClose();
6543:                            stmt.rsSuspend();
6544:                        }
6545:
6546:                    }
6547:                }
6548:
6549:                // For scrollable cursor's QRYSCRAFT, when we reach here, DRDA spec says sqlstate
6550:                // is 00000, sqlcode is not mentioned.  But DB2 CLI code expects sqlcode to be 0.
6551:                // We return sqlcode 0 in this case, as the DB2 server does.
6552:                boolean isQRYSCRAFT = (stmt.getQryscrorn() == CodePoint.QRYSCRAFT);
6553:
6554:                // Using sqlstate 00000 or 02000 for end of data.
6555:                writeSQLCAGRP((isQRYSCRAFT ? eod00000 : eod02000),
6556:                        (isQRYSCRAFT ? 0 : 100), 0, stmt.rowCount);
6557:
6558:                writer.writeByte(CodePoint.NULLDATA);
6559:                // does all this fit in one QRYDTA
6560:                if (writer.getDSSLength() > blksize) {
6561:                    splitQRYDTA(stmt, blksize);
6562:                }
6563:            }
6564:
6565:            /**
6566:             * Position cursor for insensitive scrollable cursors
6567:             *
6568:             * @param stmt	DRDA statement 
6569:             * @param rs	Result set
6570:             */
6571:            private boolean positionCursor(DRDAStatement stmt, ResultSet rs)
6572:                    throws SQLException, DRDAProtocolException {
6573:                boolean retval = false;
6574:                switch (stmt.getQryscrorn()) {
6575:                case CodePoint.QRYSCRREL:
6576:                    int rows = (int) stmt.getQryrownbr();
6577:                    if ((rs.isAfterLast() && rows > 0)
6578:                            || (rs.isBeforeFirst() && rows < 0)) {
6579:                        retval = false;
6580:                    } else {
6581:                        retval = rs.relative(rows);
6582:                    }
6583:                    break;
6584:                case CodePoint.QRYSCRABS:
6585:                    // JCC uses an absolute value of 0 which is not allowed in JDBC
6586:                    // We translate it into beforeFirst which seems to work.
6587:                    if (stmt.getQryrownbr() == 0) {
6588:                        rs.beforeFirst();
6589:                        retval = false;
6590:                    } else {
6591:                        retval = rs.absolute((int) stmt.getQryrownbr());
6592:                    }
6593:                    break;
6594:                case CodePoint.QRYSCRAFT:
6595:                    rs.afterLast();
6596:                    retval = false;
6597:                    break;
6598:                case CodePoint.QRYSCRBEF:
6599:                    rs.beforeFirst();
6600:                    retval = false;
6601:                    break;
6602:                default:
6603:                    agentError("Invalid value for cursor orientation "
6604:                            + stmt.getQryscrorn());
6605:                }
6606:                return retval;
6607:            }
6608:
6609:            /**
6610:             * Write SQLDAGRP
6611:             * SQLDAGRP : EARLY FDOCA GROUP
6612:             * SQL Data Area Group Description
6613:             *
6614:             * FORMAT FOR SQLAM <= 6
6615:             *   SQLPRECISION; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6616:             *   SQLSCALE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6617:             *   SQLLENGTH; DRDA TYPE I4; ENVLID 0x02; Length Override 4
6618:             *   SQLTYPE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6619:             *   SQLCCSID; DRDA TYPE FB; ENVLID 0x26; Length Override 2
6620:             *   SQLNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6621:             *   SQLNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6622:             *   SQLLABEL_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6623:             *   SQLLABEL_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6624:             *   SQLCOMMENTS_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 254
6625:             *   SQLCOMMENTS_m; DRDA TYPE VCS; ENVLID 0x32; Length Override 254
6626:             *
6627:             * FORMAT FOR SQLAM == 6
6628:             *   SQLPRECISION; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6629:             *   SQLSCALE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6630:             *   SQLLENGTH; DRDA TYPE I8; ENVLID 0x16; Length Override 8
6631:             *   SQLTYPE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6632:             *   SQLCCSID; DRDA TYPE FB; ENVLID 0x26; Length Override 2
6633:             *   SQLNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6634:             *   SQLNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6635:             *   SQLLABEL_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6636:             *   SQLLABEL_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6637:             *   SQLCOMMENTS_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 254
6638:             *   SQLCOMMENTS_m; DRDA TYPE VCS; ENVLID 0x32; Length Override 254
6639:             *   SQLUDTGRP; DRDA TYPE N-GDA; ENVLID 0x51; Length Override 0
6640:             *
6641:             * FORMAT FOR SQLAM >= 7
6642:             *   SQLPRECISION; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6643:             *   SQLSCALE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6644:             *   SQLLENGTH; DRDA TYPE I8; ENVLID 0x16; Length Override 8
6645:             *   SQLTYPE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6646:             *   SQLCCSID; DRDA TYPE FB; ENVLID 0x26; Length Override 2
6647:             *   SQLDOPTGRP; DRDA TYPE N-GDA; ENVLID 0xD2; Length Override 0
6648:             *
6649:             * @param rsmeta	resultset meta data
6650:             * @param pmeta		parameter meta data
6651:             * @param elemNum	column number we are returning (in case of result set), or,
6652:             *					parameter number (in case of parameter)
6653:             * @param rtnOutput	whether this is for a result set	
6654:             *
6655:             * @throws DRDAProtocolException
6656:             * @throws SQLException
6657:             */
6658:            private void writeSQLDAGRP(ResultSetMetaData rsmeta,
6659:                    EngineParameterMetaData pmeta, int elemNum,
6660:                    boolean rtnOutput) throws DRDAProtocolException,
6661:                    SQLException {
6662:                //jdbc uses offset of 1
6663:
6664:                int jdbcElemNum = elemNum + 1;
6665:                // length to be retreived as output parameter
6666:                int[] outlen = { -1 };
6667:
6668:                int elemType = rtnOutput ? rsmeta.getColumnType(jdbcElemNum)
6669:                        : pmeta.getParameterType(jdbcElemNum);
6670:
6671:                int precision = rtnOutput ? rsmeta.getPrecision(jdbcElemNum)
6672:                        : pmeta.getPrecision(jdbcElemNum);
6673:                if (precision > FdocaConstants.NUMERIC_MAX_PRECISION)
6674:                    precision = FdocaConstants.NUMERIC_MAX_PRECISION;
6675:
6676:                // 2-byte precision
6677:                writer.writeShort(precision);
6678:                // 2-byte scale
6679:                int scale = (rtnOutput ? rsmeta.getScale(jdbcElemNum) : pmeta
6680:                        .getScale(jdbcElemNum));
6681:                writer.writeShort(scale);
6682:
6683:                boolean nullable = rtnOutput ? (rsmeta.isNullable(jdbcElemNum) == ResultSetMetaData.columnNullable)
6684:                        : (pmeta.isNullable(jdbcElemNum) == JDBC30Translation.PARAMETER_NULLABLE);
6685:
6686:                int sqlType = SQLTypes.mapJdbcTypeToDB2SqlType(elemType,
6687:                        nullable, outlen);
6688:
6689:                if (outlen[0] == -1) //some types not set
6690:                {
6691:                    switch (elemType) {
6692:                    case Types.DECIMAL:
6693:                    case Types.NUMERIC:
6694:                        scale = rtnOutput ? rsmeta.getScale(jdbcElemNum)
6695:                                : pmeta.getScale(jdbcElemNum);
6696:                        outlen[0] = ((precision << 8) | (scale << 0));
6697:                        if (SanityManager.DEBUG)
6698:                            trace("\n\nprecision =" + precision + " scale ="
6699:                                    + scale);
6700:                        break;
6701:                    default:
6702:                        outlen[0] = Math.min(
6703:                                FdocaConstants.LONGVARCHAR_MAX_LEN,
6704:                                (rtnOutput ? rsmeta
6705:                                        .getColumnDisplaySize(jdbcElemNum)
6706:                                        : pmeta.getPrecision(jdbcElemNum)));
6707:                    }
6708:                }
6709:
6710:                switch (elemType) {
6711:                case Types.BINARY:
6712:                case Types.VARBINARY:
6713:                case Types.LONGVARBINARY:
6714:                case Types.BLOB: //for CLI describe to be correct
6715:                case Types.CLOB:
6716:                    outlen[0] = (rtnOutput ? rsmeta.getPrecision(jdbcElemNum)
6717:                            : pmeta.getPrecision(jdbcElemNum));
6718:                }
6719:
6720:                if (SanityManager.DEBUG)
6721:                    trace("SQLDAGRP len ="
6722:                            + java.lang.Integer.toHexString(outlen[0])
6723:                            + "for type:" + elemType);
6724:
6725:                // 8 or 4 byte sqllength
6726:                if (sqlamLevel >= MGRLVL_6)
6727:                    writer.writeLong(outlen[0]);
6728:                else
6729:                    writer.writeInt(outlen[0]);
6730:
6731:                String typeName = rtnOutput ? rsmeta
6732:                        .getColumnTypeName(jdbcElemNum) : pmeta
6733:                        .getParameterTypeName(jdbcElemNum);
6734:                if (SanityManager.DEBUG)
6735:                    trace("jdbcType =" + typeName + "  sqlType =" + sqlType
6736:                            + "len =" + outlen[0]);
6737:
6738:                writer.writeShort(sqlType);
6739:
6740:                // CCSID
6741:                // CCSID should be 0 for Binary Types.
6742:
6743:                if (elemType == java.sql.Types.CHAR
6744:                        || elemType == java.sql.Types.VARCHAR
6745:                        || elemType == java.sql.Types.LONGVARCHAR
6746:                        || elemType == java.sql.Types.CLOB)
6747:                    writer.writeScalar2Bytes(1208);
6748:                else
6749:                    writer.writeScalar2Bytes(0);
6750:
6751:                if (sqlamLevel < MGRLVL_7) {
6752:
6753:                    //SQLName
6754:                    writeVCMorVCS(rtnOutput ? rsmeta.getColumnName(jdbcElemNum)
6755:                            : null);
6756:                    //SQLLabel
6757:                    writeVCMorVCS(null);
6758:                    //SQLComments
6759:                    writeVCMorVCS(null);
6760:
6761:                    if (sqlamLevel == MGRLVL_6)
6762:                        writeSQLUDTGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
6763:                } else {
6764:                    writeSQLDOPTGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
6765:                }
6766:
6767:            }
6768:
6769:            /**
6770:             * Write variable character mixed byte or single byte
6771:             * The preference is to write mixed byte if it is defined for the server,
6772:             * since that is our default and we don't allow it to be changed, we always
6773:             * write mixed byte.
6774:             * 
6775:             * @param s	string to write
6776:             * @exception DRDAProtocolException
6777:             */
6778:            private void writeVCMorVCS(String s) throws DRDAProtocolException {
6779:                //Write only VCM and 0 length for VCS
6780:
6781:                if (s == null) {
6782:                    writer.writeShort(0);
6783:                    writer.writeShort(0);
6784:                    return;
6785:                }
6786:
6787:                // VCM
6788:                writer.writeLDString(s);
6789:                // VCS
6790:                writer.writeShort(0);
6791:            }
6792:
6793:            private void writeSQLUDTGRP(ResultSetMetaData rsmeta,
6794:                    EngineParameterMetaData pmeta, int jdbcElemNum,
6795:                    boolean rtnOutput) throws DRDAProtocolException,
6796:                    SQLException {
6797:                writer.writeByte(CodePoint.NULLDATA);
6798:
6799:            }
6800:
6801:            private void writeSQLDOPTGRP(ResultSetMetaData rsmeta,
6802:                    EngineParameterMetaData pmeta, int jdbcElemNum,
6803:                    boolean rtnOutput) throws DRDAProtocolException,
6804:                    SQLException {
6805:
6806:                writer.writeByte(0);
6807:                //SQLUNAMED
6808:                writer.writeShort(0);
6809:                //SQLName
6810:                writeVCMorVCS(rtnOutput ? rsmeta.getColumnName(jdbcElemNum)
6811:                        : null);
6812:                //SQLLabel
6813:                writeVCMorVCS(null);
6814:                //SQLComments
6815:                writeVCMorVCS(null);
6816:                //SQLDUDTGRP 
6817:                writeSQLUDTGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
6818:                //SQLDXGRP
6819:                writeSQLDXGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
6820:            }
6821:
6822:            private void writeSQLDXGRP(ResultSetMetaData rsmeta,
6823:                    EngineParameterMetaData pmeta, int jdbcElemNum,
6824:                    boolean rtnOutput) throws DRDAProtocolException,
6825:                    SQLException {
6826:                // Null indicator indicates we have data
6827:                writer.writeByte(0);
6828:                //   SQLXKEYMEM; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6829:                // Hard to get primary key info. Send 0 for now
6830:                writer.writeShort(0);
6831:                //   SQLXUPDATEABLE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6832:                writer.writeShort(rtnOutput ? rsmeta.isWritable(jdbcElemNum)
6833:                        : false);
6834:
6835:                //   SQLXGENERATED; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6836:                if (rtnOutput && rsmeta.isAutoIncrement(jdbcElemNum))
6837:                    writer.writeShort(2);
6838:                else
6839:                    writer.writeShort(0);
6840:
6841:                //   SQLXPARMMODE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6842:                if (pmeta != null && !rtnOutput) {
6843:                    int mode = pmeta.getParameterMode(jdbcElemNum);
6844:                    if (mode == JDBC30Translation.PARAMETER_MODE_UNKNOWN) {
6845:                        // For old style callable statements. We assume in/out if it
6846:                        // is an output parameter.
6847:                        int type = DRDAStatement
6848:                                .getOutputParameterTypeFromClassName(pmeta
6849:                                        .getParameterClassName(jdbcElemNum));
6850:                        if (type != DRDAStatement.NOT_OUTPUT_PARAM)
6851:                            mode = JDBC30Translation.PARAMETER_MODE_IN_OUT;
6852:                    }
6853:                    writer.writeShort(mode);
6854:                } else {
6855:                    writer.writeShort(0);
6856:                }
6857:
6858:                //   SQLXRDBNAM; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
6859:                // JCC uses this as the catalog name so we will send null.
6860:                writer.writeShort(0);
6861:
6862:                //   SQLXCORNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
6863:                //   SQLXCORNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
6864:                writeVCMorVCS(null);
6865:
6866:                //   SQLXBASENAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
6867:                //   SQLXBASENAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
6868:                writeVCMorVCS(rtnOutput ? rsmeta.getTableName(jdbcElemNum)
6869:                        : null);
6870:
6871:                //   SQLXSCHEMA_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
6872:                //   SQLXSCHEMA_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
6873:                writeVCMorVCS(rtnOutput ? rsmeta.getSchemaName(jdbcElemNum)
6874:                        : null);
6875:
6876:                //   SQLXNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
6877:                //   SQLXNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
6878:                writeVCMorVCS(rtnOutput ? rsmeta.getColumnName(jdbcElemNum)
6879:                        : null);
6880:
6881:            }
6882:
6883:            /**
6884:             * Write Fdoca Value to client 
6885:             * @param index     Index of column being returned
6886:             * @param val       Value to write to client
6887:             * @param drdaType  FD:OCA DRDA Type from FdocaConstants
6888:             * @param precision Precision
6889:             * @param stmt       Statement being processed
6890:             *
6891:             * @exception DRDAProtocolException  
6892:             * @exception SQLException
6893:             *
6894:             * @see FdocaConstants
6895:             */
6896:
6897:            protected void writeFdocaVal(int index, Object val, int drdaType,
6898:                    int precision, int scale, boolean valNull,
6899:
6900:                    DRDAStatement stmt) throws DRDAProtocolException,
6901:                    SQLException {
6902:                writeNullability(drdaType, valNull);
6903:
6904:                if (!valNull) {
6905:                    int ndrdaType = drdaType | 1;
6906:                    long valLength = 0;
6907:                    switch (ndrdaType) {
6908:                    case DRDAConstants.DRDA_TYPE_NSMALL:
6909:                        // DB2 does not have a BOOLEAN java.sql.bit type,
6910:                        // so we need to send it as a small
6911:                        if (val instanceof  Boolean) {
6912:                            writer.writeShort(((Boolean) val).booleanValue());
6913:                        } else if (val instanceof  Short)
6914:                            writer.writeShort(((Short) val).shortValue());
6915:                        else if (val instanceof  Byte)
6916:                            writer.writeShort(((Byte) val).byteValue());
6917:                        else
6918:                            writer.writeShort(((Integer) val).shortValue());
6919:                        break;
6920:                    case DRDAConstants.DRDA_TYPE_NINTEGER:
6921:                        writer.writeInt(((Integer) val).intValue());
6922:                        break;
6923:                    case DRDAConstants.DRDA_TYPE_NINTEGER8:
6924:                        writer.writeLong(((Long) val).longValue());
6925:                        break;
6926:                    case DRDAConstants.DRDA_TYPE_NFLOAT4:
6927:                        writer.writeFloat(((Float) val).floatValue());
6928:                        break;
6929:                    case DRDAConstants.DRDA_TYPE_NFLOAT8:
6930:                        writer.writeDouble(((Double) val).doubleValue());
6931:                        break;
6932:                    case DRDAConstants.DRDA_TYPE_NDECIMAL:
6933:                        if (precision == 0)
6934:                            precision = FdocaConstants.NUMERIC_DEFAULT_PRECISION;
6935:                        BigDecimal bd = (java.math.BigDecimal) val;
6936:                        writer.writeBigDecimal(bd, precision, scale);
6937:                        break;
6938:                    case DRDAConstants.DRDA_TYPE_NDATE:
6939:                        writer.writeString(((java.sql.Date) val).toString());
6940:                        break;
6941:                    case DRDAConstants.DRDA_TYPE_NTIME:
6942:                        writer.writeString(((java.sql.Time) val).toString());
6943:                        break;
6944:                    case DRDAConstants.DRDA_TYPE_NTIMESTAMP:
6945:                        // we need to send it in a slightly different format, and pad it
6946:                        // up to or truncate it into 26 chars
6947:                        String ts1 = ((java.sql.Timestamp) val).toString();
6948:                        String ts2 = ts1.replace(' ', '-').replace(':', '.');
6949:                        int tsLen = ts2.length();
6950:                        if (tsLen < 26) {
6951:                            for (int i = 0; i < 26 - tsLen; i++)
6952:                                ts2 += "0";
6953:                        } else if (tsLen > 26)
6954:                            ts2 = ts2.substring(0, 26);
6955:                        writer.writeString(ts2);
6956:                        break;
6957:                    case DRDAConstants.DRDA_TYPE_NCHAR:
6958:                        writer.writeString(((String) val).toString());
6959:                        break;
6960:                    case DRDAConstants.DRDA_TYPE_NVARCHAR:
6961:                    case DRDAConstants.DRDA_TYPE_NVARMIX:
6962:                    case DRDAConstants.DRDA_TYPE_NLONG:
6963:                    case DRDAConstants.DRDA_TYPE_NLONGMIX:
6964:                        //WriteLDString and generate warning if truncated
6965:                        // which will be picked up by checkWarning()
6966:                        writer.writeLDString(val.toString(), index);
6967:                        break;
6968:                    case DRDAConstants.DRDA_TYPE_NLOBBYTES:
6969:                    case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
6970:
6971:                        // do not send EXTDTA for lob of length 0, beetle 5967
6972:                        if (!((EXTDTAInputStream) val).isEmptyStream()) {
6973:                            stmt.addExtDtaObject(val, index);
6974:
6975:                            //indicate externalized and size is unknown.
6976:                            writer.writeExtendedLength(0x8000);
6977:
6978:                        } else {
6979:                            writer.writeExtendedLength(0);
6980:
6981:                        }
6982:
6983:                        break;
6984:
6985:                    case DRDAConstants.DRDA_TYPE_NFIXBYTE:
6986:                        writer.writeBytes((byte[]) val);
6987:                        break;
6988:                    case DRDAConstants.DRDA_TYPE_NVARBYTE:
6989:                    case DRDAConstants.DRDA_TYPE_NLONGVARBYTE:
6990:                        writer.writeLDBytes((byte[]) val, index);
6991:                        break;
6992:                    default:
6993:                        if (SanityManager.DEBUG)
6994:                            trace("ndrdaType is: " + ndrdaType);
6995:                        writer.writeLDString(val.toString(), index);
6996:                    }
6997:                }
6998:            }
6999:
7000:            /**
7001:             * write nullability if this is a nullable drdatype and FDOCA null
7002:             * value if appropriate
7003:             * @param drdaType      FDOCA type
7004:             * @param valNull       true if this is a null value. False otherwise
7005:             * 
7006:             **/
7007:            private void writeNullability(int drdaType, boolean valNull) {
7008:                if (FdocaConstants.isNullable(drdaType)) {
7009:                    if (valNull)
7010:                        writer.writeByte(FdocaConstants.NULL_DATA);
7011:                    else {
7012:                        writer.writeByte(FdocaConstants.INDICATOR_NULLABLE);
7013:                    }
7014:                }
7015:
7016:            }
7017:
7018:            /**
7019:             * Methods to keep track of required codepoints
7020:             */
7021:            /**
7022:             * Copy a list of required code points to template for checking
7023:             *
7024:             * @param req list of required codepoints
7025:             */
7026:            private void copyToRequired(int[] req) {
7027:                currentRequiredLength = req.length;
7028:                if (currentRequiredLength > required.length)
7029:                    required = new int[currentRequiredLength];
7030:                for (int i = 0; i < req.length; i++)
7031:                    required[i] = req[i];
7032:            }
7033:
7034:            /**
7035:             * Remove codepoint from required list
7036:             *
7037:             * @param codePoint - code point to be removed
7038:             */
7039:            private void removeFromRequired(int codePoint) {
7040:                for (int i = 0; i < currentRequiredLength; i++)
7041:                    if (required[i] == codePoint)
7042:                        required[i] = 0;
7043:
7044:            }
7045:
7046:            /**
7047:             * Check whether we have seen all the required code points
7048:             *
7049:             * @param codePoint code point for which list of code points is required
7050:             */
7051:            private void checkRequired(int codePoint)
7052:                    throws DRDAProtocolException {
7053:                int firstMissing = 0;
7054:                for (int i = 0; i < currentRequiredLength; i++) {
7055:                    if (required[i] != 0) {
7056:                        firstMissing = required[i];
7057:                        break;
7058:                    }
7059:                }
7060:                if (firstMissing != 0)
7061:                    missingCodePoint(firstMissing);
7062:            }
7063:
7064:            /**
7065:             * Error routines
7066:             */
7067:            /**
7068:             * Seen too many of this code point
7069:             *
7070:             * @param codePoint  code point which has been duplicated
7071:             *
7072:             * @exception DRDAProtocolException
7073:             */
7074:            private void tooMany(int codePoint) throws DRDAProtocolException {
7075:                throwSyntaxrm(CodePoint.SYNERRCD_TOO_MANY, codePoint);
7076:            }
7077:
7078:            /**
7079:             * Object too big
7080:             *
7081:             * @param codePoint  code point with too big object
7082:             * @exception DRDAProtocolException
7083:             */
7084:            private void tooBig(int codePoint) throws DRDAProtocolException {
7085:                throwSyntaxrm(CodePoint.SYNERRCD_TOO_BIG, codePoint);
7086:            }
7087:
7088:            /**
7089:             * Object length not allowed
7090:             *
7091:             * @param codePoint  code point with bad object length
7092:             * @exception DRDAProtocolException
7093:             */
7094:            private void badObjectLength(int codePoint)
7095:                    throws DRDAProtocolException {
7096:                throwSyntaxrm(CodePoint.SYNERRCD_OBJ_LEN_NOT_ALLOWED, codePoint);
7097:            }
7098:
7099:            /**
7100:             * RDB not found
7101:             *
7102:             * @param rdbnam  name of database
7103:             * @exception DRDAProtocolException
7104:             */
7105:            private void rdbNotFound(String rdbnam)
7106:                    throws DRDAProtocolException {
7107:                Object[] oa = { rdbnam };
7108:                throw new DRDAProtocolException(
7109:                        DRDAProtocolException.DRDA_Proto_RDBNFNRM, this , 0,
7110:                        DRDAProtocolException.NO_ASSOC_ERRCD, oa);
7111:            }
7112:
7113:            /**
7114:             * Invalid value for this code point
7115:             *
7116:             * @param codePoint  code point value
7117:             * @exception DRDAProtocolException
7118:             */
7119:            private void invalidValue(int codePoint)
7120:                    throws DRDAProtocolException {
7121:                throwSyntaxrm(CodePoint.SYNERRCD_REQ_VAL_NOT_FOUND, codePoint);
7122:            }
7123:
7124:            /**
7125:             * Invalid codepoint for this command
7126:             *
7127:             * @param codePoint code point value
7128:             *
7129:             * @exception DRDAProtocolException
7130:             */
7131:            protected void invalidCodePoint(int codePoint)
7132:                    throws DRDAProtocolException {
7133:                throwSyntaxrm(CodePoint.SYNERRCD_INVALID_CP_FOR_CMD, codePoint);
7134:            }
7135:
7136:            /**
7137:             * Don't support this code point
7138:             *
7139:             * @param codePoint  code point value
7140:             * @exception DRDAProtocolException
7141:             */
7142:            protected void codePointNotSupported(int codePoint)
7143:                    throws DRDAProtocolException {
7144:                throw new DRDAProtocolException(
7145:                        DRDAProtocolException.DRDA_Proto_CMDNSPRM, this ,
7146:                        codePoint, DRDAProtocolException.NO_ASSOC_ERRCD);
7147:            }
7148:
7149:            /**
7150:             * Don't support this value
7151:             *
7152:             * @param codePoint  code point value
7153:             * @exception DRDAProtocolException
7154:             */
7155:            private void valueNotSupported(int codePoint)
7156:                    throws DRDAProtocolException {
7157:                throw new DRDAProtocolException(
7158:                        DRDAProtocolException.DRDA_Proto_VALNSPRM, this ,
7159:                        codePoint, DRDAProtocolException.NO_ASSOC_ERRCD);
7160:            }
7161:
7162:            /**
7163:             * Verify that the code point is the required code point
7164:             *
7165:             * @param codePoint code point we have
7166:             * @param reqCodePoint code point required at this time
7167:             *
7168:             * @exception DRDAProtocolException
7169:             */
7170:            private void verifyRequiredObject(int codePoint, int reqCodePoint)
7171:                    throws DRDAProtocolException {
7172:                if (codePoint != reqCodePoint) {
7173:                    throwSyntaxrm(CodePoint.SYNERRCD_REQ_OBJ_NOT_FOUND,
7174:                            codePoint);
7175:                }
7176:            }
7177:
7178:            /**
7179:             * Verify that the code point is in the right order
7180:             *
7181:             * @param codePoint code point we have
7182:             * @param reqCodePoint code point required at this time
7183:             *
7184:             * @exception DRDAProtocolException
7185:             */
7186:            private void verifyInOrderACCSEC_SECCHK(int codePoint,
7187:                    int reqCodePoint) throws DRDAProtocolException {
7188:                if (codePoint != reqCodePoint) {
7189:                    throw new DRDAProtocolException(
7190:                            DRDAProtocolException.DRDA_Proto_PRCCNVRM, this ,
7191:                            codePoint,
7192:                            CodePoint.PRCCNVCD_ACCSEC_SECCHK_WRONG_STATE);
7193:                }
7194:            }
7195:
7196:            /**
7197:             * Database name given under code point doesn't match previous database names
7198:             *
7199:             * @param codePoint codepoint where the mismatch occurred
7200:             *
7201:             * @exception DRDAProtocolException
7202:             */
7203:            private void rdbnamMismatch(int codePoint)
7204:                    throws DRDAProtocolException {
7205:                throw new DRDAProtocolException(
7206:                        DRDAProtocolException.DRDA_Proto_PRCCNVRM, this ,
7207:                        codePoint, CodePoint.PRCCNVCD_RDBNAM_MISMATCH);
7208:            }
7209:
7210:            /**
7211:             * Close the current session
7212:             */
7213:            private void closeSession() {
7214:                if (session == null)
7215:                    return;
7216:                server.removeFromSessionTable(session.connNum);
7217:                try {
7218:                    session.close();
7219:                } catch (SQLException se) {
7220:                    // If something went wrong closing down the session.
7221:                    // Print an error to the console and close this 
7222:                    //thread. (6013)
7223:                    sendUnexpectedException(se);
7224:                    close();
7225:                } finally {
7226:                    session = null;
7227:                    database = null;
7228:                    appRequester = null;
7229:                    sockis = null;
7230:                    sockos = null;
7231:                    databaseAccessException = null;
7232:                }
7233:            }
7234:
7235:            /**
7236:             * Handle Exceptions - write error protocol if appropriate and close session
7237:             *	or thread as appropriate
7238:             */
7239:            private void handleException(Exception e) {
7240:                try {
7241:                    if (e instanceof  DRDAProtocolException) {
7242:                        // protocol error - write error message
7243:                        sendProtocolException((DRDAProtocolException) e);
7244:                    } else {
7245:                        // something unexpected happened
7246:                        sendUnexpectedException(e);
7247:                        server.consoleExceptionPrintTrace(e);
7248:                    }
7249:                } finally {
7250:                    // always close the session and stop the thread after handling
7251:                    // these exceptions
7252:                    closeSession();
7253:                    close();
7254:                }
7255:            }
7256:
7257:            /**
7258:             * Notice the client about a protocol error.
7259:             *
7260:             * @param de <code>DRDAProtocolException</code> to be sent
7261:             */
7262:            private void sendProtocolException(DRDAProtocolException de) {
7263:                String dbname = null;
7264:                if (database != null) {
7265:                    dbname = database.dbName;
7266:                }
7267:
7268:                try {
7269:                    println2Log(dbname, session.drdaID, de.getMessage());
7270:                    server.consoleExceptionPrintTrace(de);
7271:                    reader.clearBuffer();
7272:                    de.write(writer);
7273:                    finalizeChain();
7274:                } catch (DRDAProtocolException ioe) {
7275:                    // There may be an IO exception in the write.
7276:                    println2Log(dbname, session.drdaID, de.getMessage());
7277:                    server.consoleExceptionPrintTrace(ioe);
7278:                }
7279:            }
7280:
7281:            /**
7282:             * Send unpexpected error to the client
7283:             * @param e Exception to be sent
7284:             */
7285:            private void sendUnexpectedException(Exception e) {
7286:
7287:                DRDAProtocolException unExpDe;
7288:                String dbname = null;
7289:                try {
7290:                    if (database != null)
7291:                        dbname = database.dbName;
7292:                    println2Log(dbname, session.drdaID, e.getMessage());
7293:                    server.consoleExceptionPrintTrace(e);
7294:                    unExpDe = DRDAProtocolException.newAgentError(this ,
7295:                            CodePoint.SVRCOD_PRMDMG, dbname, e.getMessage());
7296:
7297:                    reader.clearBuffer();
7298:                    unExpDe.write(writer);
7299:                    finalizeChain();
7300:                } catch (DRDAProtocolException nde) {
7301:                    // we can't tell the client, but we tried.
7302:                }
7303:
7304:            }
7305:
7306:            /**
7307:             * Test if DRDA connection thread is closed
7308:             *
7309:             * @return true if close; false otherwise
7310:             */
7311:            private boolean closed() {
7312:                synchronized (closeSync) {
7313:                    return close;
7314:                }
7315:            }
7316:
7317:            /**
7318:             * Get whether connections are logged
7319:             *
7320:             * @return true if connections are being logged; false otherwise
7321:             */
7322:            private boolean getLogConnections() {
7323:                synchronized (logConnectionsSync) {
7324:                    return logConnections;
7325:                }
7326:            }
7327:
7328:            /**
7329:             * Get time slice value for length of time to work on a session
7330:             *
7331:             * @return time slice
7332:             */
7333:            private long getTimeSlice() {
7334:                synchronized (timeSliceSync) {
7335:                    return timeSlice;
7336:                }
7337:            }
7338:
7339:            /**
7340:             * Send string to console
7341:             *
7342:             * @param value - value to print on console
7343:             */
7344:            protected void trace(String value) {
7345:                if (SanityManager.DEBUG && server.debugOutput == true)
7346:                    server.consoleMessage(value);
7347:            }
7348:
7349:            /***
7350:             * Show runtime memory
7351:             *
7352:             ***/
7353:            public static void showmem() {
7354:                Runtime rt = null;
7355:                Date d = null;
7356:                rt = Runtime.getRuntime();
7357:                rt.gc();
7358:                d = new Date();
7359:                System.out.println("total memory: " + rt.totalMemory()
7360:                        + " free: " + rt.freeMemory() + " " + d.toString());
7361:
7362:            }
7363:
7364:            /**
7365:             * convert byte array to a Hex string
7366:             * 
7367:             * @param buf buffer to  convert
7368:             * @return hex string representation of byte array
7369:             */
7370:            private String convertToHexString(byte[] buf) {
7371:                StringBuffer str = new StringBuffer();
7372:                str.append("0x");
7373:                String val;
7374:                int byteVal;
7375:                for (int i = 0; i < buf.length; i++) {
7376:                    byteVal = buf[i] & 0xff;
7377:                    val = Integer.toHexString(byteVal);
7378:                    if (val.length() < 2)
7379:                        str.append("0");
7380:                    str.append(val);
7381:                }
7382:                return str.toString();
7383:            }
7384:
7385:            /**
7386:             * check that the given typdefnam is acceptable
7387:             * 
7388:             * @param typdefnam 
7389:             *
7390:             * @exception DRDAProtocolException
7391:             */
7392:            private void checkValidTypDefNam(String typdefnam)
7393:                    throws DRDAProtocolException {
7394:                if (typdefnam.equals("QTDSQL370"))
7395:                    return;
7396:                if (typdefnam.equals("QTDSQL400"))
7397:                    return;
7398:                if (typdefnam.equals("QTDSQLX86"))
7399:                    return;
7400:                if (typdefnam.equals("QTDSQLASC"))
7401:                    return;
7402:                if (typdefnam.equals("QTDSQLVAX"))
7403:                    return;
7404:                if (typdefnam.equals("QTDSQLJVM"))
7405:                    return;
7406:                invalidValue(CodePoint.TYPDEFNAM);
7407:            }
7408:
7409:            /**
7410:             * Check that the length is equal to the required length for this codepoint
7411:             *
7412:             * @param codepoint	codepoint we are checking
7413:             * @param reqlen	required length
7414:             * 
7415:             * @exception DRDAProtocolException
7416:             */
7417:            private void checkLength(int codepoint, int reqlen)
7418:                    throws DRDAProtocolException {
7419:                long len = reader.getDdmLength();
7420:                if (len < reqlen)
7421:                    badObjectLength(codepoint);
7422:                else if (len > reqlen)
7423:                    tooBig(codepoint);
7424:            }
7425:
7426:            /**
7427:             * Read and check a boolean value
7428:             * 
7429:             * @param codepoint codePoint to be used in error reporting
7430:             * @return true or false depending on boolean value read
7431:             *
7432:             * @exception DRDAProtocolException
7433:             */
7434:            private boolean readBoolean(int codepoint)
7435:                    throws DRDAProtocolException {
7436:                checkLength(codepoint, 1);
7437:                byte val = reader.readByte();
7438:                if (val == CodePoint.TRUE)
7439:                    return true;
7440:                else if (val == CodePoint.FALSE)
7441:                    return false;
7442:                else
7443:                    invalidValue(codepoint);
7444:                return false; //to shut the compiler up
7445:            }
7446:
7447:            /**
7448:             * Add a database to the current session
7449:             *
7450:             */
7451:            private void addDatabase(String dbname) {
7452:                Database db;
7453:                if (appRequester.isXARequester()) {
7454:                    db = new XADatabase(dbname);
7455:                } else
7456:                    db = new Database(dbname);
7457:                session.addDatabase(db);
7458:                session.database = db;
7459:                database = db;
7460:            }
7461:
7462:            /**
7463:             * Set the current database
7464:             * 
7465:             * @param codePoint 	codepoint we are processing
7466:             *
7467:             * @exception DRDAProtocolException
7468:             */
7469:            private void setDatabase(int codePoint)
7470:                    throws DRDAProtocolException {
7471:                String rdbnam = parseRDBNAM();
7472:                // using same database so we are done
7473:                if (database != null && database.dbName.equals(rdbnam))
7474:                    return;
7475:                Database d = session.getDatabase(rdbnam);
7476:                if (d == null)
7477:                    rdbnamMismatch(codePoint);
7478:                else
7479:                    database = d;
7480:                session.database = d;
7481:            }
7482:
7483:            /**
7484:             * Write ENDUOWRM
7485:             * Instance Variables
7486:             *  SVCOD - severity code - WARNING - required
7487:             *  UOWDSP - Unit of Work Disposition - required
7488:             *  RDBNAM - Relational Database name - optional
7489:             *  SRVDGN - Server Diagnostics information - optional
7490:             *
7491:             * @param opType - operation type 1 - commit, 2 -rollback
7492:             */
7493:            private void writeENDUOWRM(int opType) {
7494:                writer.createDssReply();
7495:                writer.startDdm(CodePoint.ENDUOWRM);
7496:                writer.writeScalar2Bytes(CodePoint.SVRCOD,
7497:                        CodePoint.SVRCOD_WARNING);
7498:                writer.writeScalar1Byte(CodePoint.UOWDSP, opType);
7499:                writer.endDdmAndDss();
7500:            }
7501:
7502:            void writeEXTDTA(DRDAStatement stmt) throws SQLException,
7503:                    DRDAProtocolException {
7504:
7505:                ArrayList extdtaValues = stmt.getExtDtaObjects();
7506:                // build the EXTDTA data, if necessary
7507:                if (extdtaValues == null)
7508:                    return;
7509:                boolean chainFlag, chainedWithSameCorrelator;
7510:                boolean writeNullByte = false;
7511:
7512:                for (int i = 0; i < extdtaValues.size(); i++) {
7513:                    // is this the last EXTDTA to be built?
7514:                    if (i != extdtaValues.size() - 1) { // no
7515:                        chainFlag = true;
7516:                        chainedWithSameCorrelator = true;
7517:                    } else { // yes
7518:                        chainFlag = false; //last blob DSS stream itself is NOT chained with the NEXT DSS
7519:                        chainedWithSameCorrelator = false;
7520:                    }
7521:
7522:                    if (sqlamLevel >= MGRLVL_7)
7523:                        if (stmt.isExtDtaValueNullable(i))
7524:                            writeNullByte = true;
7525:
7526:                    Object o = extdtaValues.get(i);
7527:                    if (o instanceof  EXTDTAInputStream) {
7528:                        EXTDTAInputStream stream = (EXTDTAInputStream) o;
7529:                        try {
7530:                            writer.writeScalarStream(chainedWithSameCorrelator,
7531:                                    CodePoint.EXTDTA, stream, writeNullByte);
7532:
7533:                        } finally {
7534:                            // close the stream when done
7535:                            closeStream(stream);
7536:                        }
7537:
7538:                    }
7539:                }
7540:                // reset extdtaValues after sending
7541:                stmt.clearExtDtaObjects();
7542:
7543:            }
7544:
7545:            /**
7546:             * Check SQLWarning and write SQLCARD as needed.
7547:             * 
7548:             * @param conn 		connection to check
7549:             * @param stmt 		statement to check
7550:             * @param rs 		result set to check
7551:             * @param updateCount 	update count to include in SQLCARD
7552:             * @param alwaysSend 	whether always send SQLCARD regardless of
7553:             *						the existance of warnings
7554:             * @param sendWarn 	whether to send any warnings or not. 
7555:             *
7556:             * @exception DRDAProtocolException
7557:             */
7558:            private void checkWarning(Connection conn, Statement stmt,
7559:                    ResultSet rs, int updateCount, boolean alwaysSend,
7560:                    boolean sendWarn) throws DRDAProtocolException,
7561:                    SQLException {
7562:                // instead of writing a chain of sql warning, we send the first one, this is
7563:                // jcc/db2 limitation, see beetle 4629
7564:                SQLWarning warning = null;
7565:                SQLWarning reportWarning = null;
7566:                try {
7567:                    if (stmt != null) {
7568:                        warning = stmt.getWarnings();
7569:                        if (warning != null) {
7570:                            stmt.clearWarnings();
7571:                            reportWarning = warning;
7572:                        }
7573:                    }
7574:                    if (rs != null) {
7575:                        warning = rs.getWarnings();
7576:                        if (warning != null) {
7577:                            rs.clearWarnings();
7578:                            if (reportWarning == null)
7579:                                reportWarning = warning;
7580:                        }
7581:                    }
7582:                    if (conn != null) {
7583:                        warning = conn.getWarnings();
7584:                        if (warning != null) {
7585:                            conn.clearWarnings();
7586:                            if (reportWarning == null)
7587:                                reportWarning = warning;
7588:                        }
7589:                    }
7590:
7591:                } catch (SQLException se) {
7592:                    if (SanityManager.DEBUG)
7593:                        trace("got SQLException while trying to get warnings.");
7594:                }
7595:
7596:                if ((alwaysSend || reportWarning != null) && sendWarn)
7597:                    writeSQLCARDs(reportWarning, updateCount);
7598:            }
7599:
7600:            protected String buildRuntimeInfo(String indent,
7601:                    LocalizedResource localLangUtil) {
7602:                String s = "";
7603:                if (session == null)
7604:                    return s;
7605:                else
7606:                    s += session.buildRuntimeInfo("", localLangUtil);
7607:                s += "\n";
7608:                return s;
7609:            }
7610:
7611:            /**
7612:             * Finalize the current DSS chain and send it if
7613:             * needed.
7614:             */
7615:            private void finalizeChain() throws DRDAProtocolException {
7616:
7617:                writer.finalizeChain(reader.getCurrChainState(),
7618:                        getOutputStream());
7619:                return;
7620:
7621:            }
7622:
7623:            /**
7624:             *  Validate SECMEC_USRSSBPWD (Strong Password Substitute) can be used as
7625:             *  DRDA security mechanism.
7626:             *
7627:             *	Here we check that the target server can support SECMEC_USRSSBPWD
7628:             *	security mechanism based on the environment, application
7629:             *	requester's identity (PRDID) and connection URL.
7630:             *
7631:             *	IMPORTANT NOTE:
7632:             *	--------------
7633:             *	SECMEC_USRSSBPWD is ONLY supported by the target server if:
7634:             *	    - current authentication provider is Derby BUILTIN or
7635:             *	      NONE. (database / system level) (Phase I)
7636:             *		- Application requester is 'DNC' (Derby Network Client)
7637:             *		  (Phase I)
7638:             *
7639:             *  @return security check code - 0 if everything O.K.
7640:             */
7641:            private int validateSecMecUSRSSBPWD() throws DRDAProtocolException {
7642:                String dbName = null;
7643:                AuthenticationService authenticationService = null;
7644:                org.apache.derby.iapi.db.Database databaseObj = null;
7645:                String srvrlslv = appRequester.srvrlslv;
7646:
7647:                // Check if application requester is the Derby Network Client (DNC)
7648:                //
7649:                // We use a trick here - as the product ID is not yet available
7650:                // since ACCRDB message is only coming later, we check the server
7651:                // release level field sent as part of the initial EXCSAT message;
7652:                // indeed, the product ID (PRDID) is prefixed to in the field.
7653:                // Derby always sets it as part of the EXCSAT message so if it is
7654:                // not available, we stop here and inform the requester that
7655:                // SECMEC_USRSSBPWD cannot be supported for this connection.
7656:                if ((srvrlslv == null)
7657:                        || (srvrlslv.length() == 0)
7658:                        || (srvrlslv.length() < CodePoint.PRDID_MAX)
7659:                        || (srvrlslv
7660:                                .indexOf(DRDAConstants.DERBY_DRDA_CLIENT_ID) == -1))
7661:                    return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
7662:
7663:                // Client product version is extracted from the srvrlslv field.
7664:                // srvrlslv has the format <PRDID>/<ALTERNATE VERSION FORMAT>
7665:                // typically, a known Derby client has a four part version number
7666:                // with a pattern such as DNC10020/10.2.0.3 alpha. If the alternate
7667:                // version format is not specified, clientProductVersion_ will just
7668:                // be set to the srvrlslvl. Final fallback will be the product id.
7669:                //
7670:                // SECMEC_USRSSBPWD is only supported by the Derby engine and network
7671:                // server code starting at version major '10' and minor '02'. Hence,
7672:                // as this is the same for the derby client driver, we need to ensure
7673:                // our DNC client is at version and release level of 10.2 at least.
7674:                // We set the client version in the application requester and check
7675:                // if it is at the level we require at a minimum.
7676:                appRequester.setClientVersion(srvrlslv.substring(0,
7677:                        (int) CodePoint.PRDID_MAX));
7678:
7679:                if (appRequester.supportsSecMecUSRSSBPWD() == false)
7680:                    return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
7681:
7682:                dbName = database.shortDbName;
7683:                // Check if the database is available (booted)
7684:                // 
7685:                // First we need to have the database name available and it should
7686:                // have been set as part of the ACCSEC request (in the case of a Derby
7687:                // 'DNC' client)
7688:                if ((dbName == null) || (dbName.length() == 0)) {
7689:                    // No database specified in the connection URL attributes
7690:                    //
7691:                    // In this case, we get the authentication service handle from the
7692:                    // local driver, as the requester may simply be trying to shutdown
7693:                    // the engine.
7694:                    authenticationService = ((InternalDriver) NetworkServerControlImpl
7695:                            .getDriver()).getAuthenticationService();
7696:                } else {
7697:                    // We get the authentication service from the database as this
7698:                    // last one might have specified its own auth provider (at the
7699:                    // database level).
7700:                    // 
7701:                    // if monitor is never setup by any ModuleControl, getMonitor
7702:                    // returns null and no cloudscape database has been booted. 
7703:                    if (Monitor.getMonitor() != null)
7704:                        databaseObj = (org.apache.derby.iapi.db.Database) Monitor
7705:                                .findService(Property.DATABASE_MODULE, dbName);
7706:
7707:                    if (databaseObj == null) {
7708:                        // If database is not found, try connecting to it. 
7709:                        database.makeDummyConnection();
7710:
7711:                        // now try to find it again
7712:                        databaseObj = (org.apache.derby.iapi.db.Database) Monitor
7713:                                .findService(Property.DATABASE_MODULE, dbName);
7714:                    }
7715:
7716:                    // If database still could not be found, it means the database
7717:                    // does not exist - we just return security mechanism not
7718:                    // supported down below as we could not verify we can handle
7719:                    // it.
7720:                    if (databaseObj != null)
7721:                        authenticationService = databaseObj
7722:                                .getAuthenticationService();
7723:                }
7724:
7725:                // Now we check if the authentication provider is NONE or BUILTIN
7726:                if (authenticationService != null) {
7727:                    String authClassName = authenticationService.getClass()
7728:                            .getName();
7729:
7730:                    if (!authClassName
7731:                            .equals(AUTHENTICATION_PROVIDER_BUILTIN_CLASS)
7732:                            && !authClassName
7733:                                    .equals(AUTHENTICATION_PROVIDER_NONE_CLASS))
7734:                        return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
7735:                }
7736:
7737:                // SECMEC_USRSSBPWD target initialization
7738:                try {
7739:                    myTargetSeed = decryptionManager.generateSeed();
7740:                    database.secTokenOut = myTargetSeed;
7741:                } catch (SQLException se) {
7742:                    println2Log(null, session.drdaID, se.getMessage());
7743:                    // Local security service non-retryable error.
7744:                    return CodePoint.SECCHKCD_0A;
7745:                }
7746:
7747:                return 0; // SECMEC_USRSSBPWD is supported
7748:            }
7749:
7750:            private static int peekStream(EXTDTAInputStream is)
7751:                    throws IOException {
7752:
7753:                is.mark(1);
7754:
7755:                try {
7756:                    return is.read();
7757:
7758:                } finally {
7759:                    is.reset();
7760:                }
7761:
7762:            }
7763:
7764:            private static void closeStream(InputStream stream) {
7765:
7766:                try {
7767:                    if (stream != null)
7768:                        stream.close();
7769:
7770:                } catch (IOException e) {
7771:                    Util.javaException(e);
7772:
7773:                }
7774:
7775:            }
7776:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.