KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > drda > DRDAConnThread


1 /*
2     Derby - Class org.apache.derby.impl.drda.DRDAConnThread
3
4    Licensed to the Apache Software Foundation (ASF) under one or more
5    contributor license agreements. See the NOTICE file distributed with
6    this work for additional information regarding copyright ownership.
7    The ASF licenses this file to You under the Apache License, Version 2.0
8    (the "License"); you may not use this file except in compliance with
9    the License. You may obtain a copy of the License at
10
11       http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18
19 */

20 /**
21  * This class translates DRDA protocol from an application requester to JDBC
22  * for Cloudscape and then translates the results from Cloudscape to DRDA
23  * for return to the application requester.
24  * @author ge, marsden, peachey
25  */

26 package org.apache.derby.impl.drda;
27
28 import java.io.ByteArrayInputStream JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.io.InputStream JavaDoc;
31 import java.io.OutputStream JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.UnsupportedEncodingException JavaDoc;
34 import java.math.BigDecimal JavaDoc;
35 import java.sql.CallableStatement JavaDoc;
36 import java.sql.Connection JavaDoc;
37 import java.sql.Driver JavaDoc;
38 import java.sql.PreparedStatement JavaDoc;
39 import java.sql.ResultSet JavaDoc;
40 import java.sql.ResultSetMetaData JavaDoc;
41 import java.sql.SQLException JavaDoc;
42 import java.sql.SQLWarning JavaDoc;
43 import java.sql.Statement JavaDoc;
44 import java.sql.Types JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.Date JavaDoc;
47 import java.util.Properties JavaDoc;
48 import java.util.Vector JavaDoc;
49
50 import org.apache.derby.catalog.SystemProcedures;
51 import org.apache.derby.iapi.error.ExceptionSeverity;
52 import org.apache.derby.iapi.reference.Attribute;
53 import org.apache.derby.iapi.reference.DRDAConstants;
54 import org.apache.derby.iapi.reference.JDBC30Translation;
55 import org.apache.derby.iapi.reference.Property;
56 import org.apache.derby.iapi.reference.SQLState;
57 import org.apache.derby.iapi.services.info.JVMInfo;
58 import org.apache.derby.iapi.services.monitor.Monitor;
59 import org.apache.derby.iapi.services.sanity.SanityManager;
60 import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
61 import org.apache.derby.iapi.tools.i18n.LocalizedResource;
62 import org.apache.derby.iapi.jdbc.AuthenticationService;
63 import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
64 import org.apache.derby.impl.jdbc.EmbedSQLException;
65 import org.apache.derby.impl.jdbc.Util;
66 import org.apache.derby.jdbc.InternalDriver;
67
68 class DRDAConnThread extends Thread JavaDoc {
69
70     private static final String JavaDoc leftBrace = "{";
71     private static final String JavaDoc rightBrace = "}";
72     private static final byte NULL_VALUE = (byte)0xff;
73     private static final String JavaDoc SYNTAX_ERR = "42X01";
74
75     // Manager Level 3 constant.
76
private static final int MGRLVL_3 = 0x03;
77
78     // Manager Level 4 constant.
79
private static final int MGRLVL_4 = 0x04;
80
81     // Manager Level 5 constant.
82
private static final int MGRLVL_5 = 0x05;
83
84     // Manager level 6 constant.
85
private static final int MGRLVL_6 = 0x06;
86
87     // Manager Level 7 constant.
88
private static final int MGRLVL_7 = 0x07;
89
90
91     // Commit or rollback UOWDSP values
92
private static final int COMMIT = 1;
93     private static final int ROLLBACK = 2;
94
95
96     protected CcsidManager ccsidManager = new EbcdicCcsidManager();
97     private int correlationID;
98     private InputStream JavaDoc sockis;
99     private OutputStream JavaDoc sockos;
100     private DDMReader reader;
101     private DDMWriter writer;
102     private DRDAXAProtocol xaProto;
103
104     private static int [] ACCRDB_REQUIRED = {CodePoint.RDBACCCL,
105                                              CodePoint.CRRTKN,
106                                              CodePoint.PRDID,
107                                              CodePoint.TYPDEFNAM,
108                                              CodePoint.TYPDEFOVR};
109
110     private static int MAX_REQUIRED_LEN = 5;
111
112     private int currentRequiredLength = 0;
113     private int [] required = new int[MAX_REQUIRED_LEN];
114
115
116     private NetworkServerControlImpl server; // server who created me
117
private Session session; // information about the session
118
private long timeSlice; // time slice for this thread
119
private Object JavaDoc timeSliceSync = new Object JavaDoc(); // sync object for updating time slice
120
private boolean logConnections; // log connections to databases
121

122     private boolean sendWarningsOnCNTQRY = false; // Send Warnings for SELECT if true
123
private Object JavaDoc logConnectionsSync = new Object JavaDoc(); // sync object for log connect
124
private boolean close; // end this thread
125
private Object JavaDoc closeSync = new Object JavaDoc(); // sync object for parent to close us down
126
private static HeaderPrintWriter logStream;
127     private AppRequester appRequester; // pointer to the application requester
128
// for the session being serviced
129
private Database database; // pointer to the current database
130
private int sqlamLevel; // SQLAM Level - determines protocol
131

132     // DRDA diagnostic level, DIAGLVL0 by default
133
private byte diagnosticLevel = (byte)0xF0;
134
135     // manager processing
136
private Vector JavaDoc unknownManagers;
137     private Vector JavaDoc knownManagers;
138     private Vector JavaDoc errorManagers;
139     private Vector JavaDoc errorManagersLevel;
140
141     // database accessed failed
142
private SQLException JavaDoc databaseAccessException;
143
144     // these fields are needed to feed back to jcc about a statement/procedure's PKGNAMCSN
145
/** The value returned by the previous call to
146      * <code>parsePKGNAMCSN()</code>. */

147     private Pkgnamcsn prevPkgnamcsn = null;
148     /** Current RDB Package Name. */
149     private DRDAString rdbnam = new DRDAString(ccsidManager);
150     /** Current RDB Collection Identifier. */
151     private DRDAString rdbcolid = new DRDAString(ccsidManager);
152     /** Current RDB Package Identifier. */
153     private DRDAString pkgid = new DRDAString(ccsidManager);
154     /** Current RDB Package Consistency Token. */
155     private DRDAString pkgcnstkn = new DRDAString(ccsidManager);
156     /** Current RDB Package Section Number. */
157     private int pkgsn;
158
159     private final static String JavaDoc TIMEOUT_STATEMENT = "SET STATEMENT_TIMEOUT ";
160
161     private int pendingStatementTimeout; // < 0 means no pending timeout to set
162

163     // this flag is for an execute statement/procedure which actually returns a result set;
164
// do not commit the statement, otherwise result set is closed
165

166     // for decryption
167
private static DecryptionManager decryptionManager;
168
169     // public key generated by Deffie-Hellman algorithm, to be passed to the encrypter,
170
// as well as used to initialize the cipher
171
private byte[] myPublicKey;
172
173     // generated target seed to be used to generate the password substitute
174
// as part of SECMEC_USRSSBPWD security mechanism
175
private byte[] myTargetSeed;
176
177     // Some byte[] constants that are frequently written into messages. It is more efficient to
178
// use these constants than to convert from a String each time
179
// (This replaces the qryscraft_ and notQryscraft_ static exception objects.)
180
private static final byte[] eod00000 = { '0', '0', '0', '0', '0' };
181     private static final byte[] eod02000 = { '0', '2', '0', '0', '0' };
182     private static final byte[] nullSQLState = { ' ', ' ', ' ', ' ', ' ' };
183     private static final byte[] errD4_D6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 12x0
184
private static final byte[] warn0_warnA = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; // 11x ' '
185

186     private final static String JavaDoc AUTHENTICATION_PROVIDER_BUILTIN_CLASS =
187     "org.apache.derby.impl.jdbc.authentication.BasicAuthenticationServiceImpl";
188
189     private final static String JavaDoc AUTHENTICATION_PROVIDER_NONE_CLASS =
190     "org.apache.derby.impl.jdbc.authentication.NoneAuthenticationServiceImpl";
191
192     // Work around a classloader bug involving interrupt handling during
193
// class loading. If the first request to load the
194
// DRDAProtocolExceptionInfo class occurs during shutdown, the
195
// loading of the class may be aborted when the Network Server calls
196
// Thread.interrupt() on the DRDAConnThread. By including a static
197
// reference to the DRDAProtocolExceptionInfo class here, we ensure
198
// that it is loaded as soon as the DRDAConnThread class is loaded,
199
// and therefore we know we won't be trying to load the class during
200
// shutdown. See DERBY-1338 for more background, including pointers
201
// to the apparent classloader bug in the JVM.
202
private static final DRDAProtocolExceptionInfo dummy =
203         new DRDAProtocolExceptionInfo(0,0,0,false);
204
205     // constructor
206
/**
207      * Create a new Thread for processing session requests
208      *
209      * @param session Session requesting processing
210      * @param server Server starting thread
211      * @param timeSlice timeSlice for thread
212      * @param logConnections
213      **/

214
215     DRDAConnThread(Session session, NetworkServerControlImpl server,
216                           long timeSlice,
217                           boolean logConnections) {
218     
219     super();
220
221         // Create a more meaningful name for this thread (but preserve its
222
// thread id from the default name).
223
NetworkServerControlImpl.setUniqueThreadName(this, "DRDAConnThread");
224
225         this.session = session;
226         this.server = server;
227         this.timeSlice = timeSlice;
228         this.logConnections = logConnections;
229         this.pendingStatementTimeout = -1;
230         initialize();
231     }
232
233     /**
234      * Main routine for thread, loops until the thread is closed
235      * Gets a session, does work for the session
236      */

237     public void run() {
238         if (SanityManager.DEBUG)
239             trace("Starting new connection thread");
240
241         Session prevSession;
242         while(!closed())
243         {
244
245             // get a new session
246
prevSession = session;
247             session = server.getNextSession(session);
248             if (session == null)
249                 close();
250
251             if (closed())
252                 break;
253             if (session != prevSession)
254             {
255                 initializeForSession();
256             }
257             try {
258                 long timeStart = System.currentTimeMillis();
259
260                 switch (session.state)
261                 {
262                     case Session.INIT:
263                         sessionInitialState();
264                         if (session == null)
265                             break;
266                         // else fallthrough
267
case Session.ATTEXC:
268                     case Session.SECACC:
269                     case Session.CHKSEC:
270                         long currentTimeSlice;
271
272                         do {
273                             processCommands();
274                             currentTimeSlice = getTimeSlice();
275                         } while ((currentTimeSlice == 0) ||
276                             (System.currentTimeMillis() - timeStart < currentTimeSlice));
277
278                         break;
279                     default:
280                         // this is an error
281
agentError("Session in invalid state:" + session.state);
282                 }
283             } catch (Exception JavaDoc e) {
284                 if (e instanceof DRDAProtocolException &&
285                         ((DRDAProtocolException)e).isDisconnectException())
286                 {
287                     // client went away - this is O.K. here
288
closeSession();
289                 }
290                 else
291                 {
292                     handleException(e);
293                 }
294             }
295         }
296         if (SanityManager.DEBUG)
297             trace("Ending connection thread");
298         server.removeThread(this);
299
300     }
301     /**
302      * Get input stream
303      *
304      * @return input stream
305      */

306     protected InputStream JavaDoc getInputStream()
307     {
308         return sockis;
309     }
310
311     /**
312      * Get output stream
313      *
314      * @return output stream
315      */

316     protected OutputStream JavaDoc getOutputStream()
317     {
318         return sockos;
319     }
320
321     /**
322      * get DDMReader
323      * @return DDMReader for this thread
324      */

325     protected DDMReader getReader()
326     {
327         return reader;
328     }
329     
330     /**
331      * get DDMWriter
332      * @return DDMWriter for this thread
333      */

334     protected DDMWriter getWriter()
335     {
336         return writer;
337     }
338
339     /**
340      * Get correlation id
341      *
342      * @return correlation id
343      */

344     protected int getCorrelationID ()
345     {
346         return correlationID;
347     }
348
349     /**
350      * Get session we are working on
351      *
352      * @return session
353      */

354     protected Session getSession()
355     {
356         return session;
357     }
358
359     /**
360      * Get Database we are working on
361      *
362      * @return database
363      */

364     protected Database getDatabase()
365     {
366         return database;
367     }
368     /**
369      * Get server
370      *
371      * @return server
372      */

373     protected NetworkServerControlImpl getServer()
374     {
375         return server;
376     }
377     /**
378      * Get correlation token
379      *
380      * @return crrtkn
381      */

382     protected byte[] getCrrtkn()
383     {
384         if (database != null)
385             return database.crrtkn;
386         return null;
387     }
388     /**
389      * Get database name
390      *
391      * @return database name
392      */

393     protected String JavaDoc getDbName()
394     {
395         if (database != null)
396             return database.dbName;
397         return null;
398     }
399     /**
400      * Close DRDA connection thread
401      */

402     protected void close()
403     {
404         synchronized (closeSync)
405         {
406             close = true;
407         }
408     }
409
410     /**
411      * Set logging of connections
412      *
413      * @param value value to set for logging connections
414      */

415     protected void setLogConnections(boolean value)
416     {
417         synchronized(logConnectionsSync) {
418             logConnections = value;
419         }
420     }
421     /**
422      * Set time slice value
423      *
424      * @param value new value for time slice
425      */

426     protected void setTimeSlice(long value)
427     {
428         synchronized(timeSliceSync) {
429             timeSlice = value;
430         }
431     }
432     /**
433      * Indicate a communications failure
434      *
435      * @param arg1 - info about the communications failure
436      * @param arg2 - info about the communications failure
437      * @param arg3 - info about the communications failure
438      * @param arg4 - info about the communications failure
439      *
440      * @exception DRDAProtocolException disconnect exception always thrown
441      */

442     protected void markCommunicationsFailure(String JavaDoc arg1, String JavaDoc arg2, String JavaDoc arg3,
443         String JavaDoc arg4) throws DRDAProtocolException
444     {
445         Object JavaDoc[] oa = {arg1,arg2,arg3,arg4};
446         throw DRDAProtocolException.newDisconnectException(this,oa);
447
448     }
449     /**
450      * Syntax error
451      *
452      * @param errcd Error code
453      * @param cpArg code point value
454      * @exception DRDAProtocolException
455      */

456
457     protected void throwSyntaxrm(int errcd, int cpArg)
458         throws DRDAProtocolException
459     {
460         throw new
461             DRDAProtocolException(DRDAProtocolException.DRDA_Proto_SYNTAXRM,
462                                   this,
463                                   cpArg,
464                                   errcd);
465     }
466     /**
467      * Agent error - something very bad happened
468      *
469      * @param msg Message describing error
470      *
471      * @exception DRDAProtocolException newAgentError always thrown
472      */

473     protected void agentError(String JavaDoc msg) throws DRDAProtocolException
474     {
475
476         String JavaDoc dbname = null;
477         if (database != null)
478             dbname = database.dbName;
479         throw DRDAProtocolException.newAgentError(this, CodePoint.SVRCOD_PRMDMG,
480             dbname, msg);
481     }
482     /**
483      * Missing code point
484      *
485      * @param codePoint code point value
486      * @exception DRDAProtocolException
487      */

488     protected void missingCodePoint(int codePoint) throws DRDAProtocolException
489     {
490         throwSyntaxrm(CodePoint.SYNERRCD_REQ_OBJ_NOT_FOUND, codePoint);
491     }
492     /**
493      * Print a line to the DB2j log
494      *
495      * @param dbname database name
496      * @param drdaID DRDA identifier
497      * @param msg message
498      */

499     protected static void println2Log(String JavaDoc dbname, String JavaDoc drdaID, String JavaDoc msg)
500     {
501         if (logStream == null)
502             logStream = Monitor.getStream();
503
504         if (dbname != null)
505         {
506             int endOfName = dbname.indexOf(';');
507             if (endOfName != -1)
508                 dbname = dbname.substring(0, endOfName);
509         }
510         logStream.printlnWithHeader("(DATABASE = " + dbname + "), (DRDAID = " + drdaID + "), " + msg);
511     }
512     /**
513      * Write RDBNAM
514      *
515      * @param rdbnam database name
516      * @exception DRDAProtocolException
517      */

518     protected void writeRDBNAM(String JavaDoc rdbnam)
519         throws DRDAProtocolException
520     {
521         int len = rdbnam.length();
522         if (len < CodePoint.RDBNAM_LEN)
523             len = CodePoint.RDBNAM_LEN;
524         writer.writeScalarHeader(CodePoint.RDBNAM, len);
525         try {
526             writer.writeScalarPaddedBytes(rdbnam.getBytes(server.DEFAULT_ENCODING),
527                 len, server.SPACE_CHAR);
528         }
529         catch (UnsupportedEncodingException JavaDoc e)
530         {
531             agentError("Unsupported coding exception for server encoding "
532                 + server.DEFAULT_ENCODING);
533         }
534     }
535     /***************************************************************************
536      * Private methods
537      ***************************************************************************/

538
539     /**
540      * Initialize class
541      */

542     private void initialize()
543     {
544         // set input and output sockets
545
// this needs to be done before creating reader
546
sockis = session.sessionInput;
547         sockos = session.sessionOutput;
548
549         reader = new DDMReader(this, session.dssTrace);
550         writer = new DDMWriter(ccsidManager, this, session.dssTrace);
551     }
552
553     /**
554      * Initialize for a new session
555      */

556     private void initializeForSession()
557     {
558         // set input and output sockets
559
sockis = session.sessionInput;
560         sockos = session.sessionOutput;
561
562         // intialize reader and writer
563
reader.initialize(this, session.dssTrace);
564         writer.reset(session.dssTrace);
565
566         // initialize local pointers to session info
567
database = session.database;
568         appRequester = session.appRequester;
569
570         // set sqlamLevel
571
if (session.state == Session.ATTEXC)
572             sqlamLevel = appRequester.getManagerLevel(CodePoint.SQLAM);
573
574     }
575     /**
576      * In initial state for a session,
577      * determine whether this is a command
578      * session or a DRDA protocol session. A command session is for changing
579      * the configuration of the Net server, e.g., turning tracing on
580      * If it is a command session, process the command and close the session.
581      * If it is a DRDA session, exchange server attributes and change session
582      * state.
583      */

584     private void sessionInitialState()
585         throws Exception JavaDoc
586     {
587         // process NetworkServerControl commands - if it is not either valid protocol let the
588
// DRDA error handling handle it
589
if (reader.isCmd())
590         {
591             try {
592                 server.processCommands(reader, writer, session);
593                 // reset reader and writer
594
reader.initialize(this, null);
595                 writer.reset(null);
596                 closeSession();
597             } catch (Throwable JavaDoc t) {
598                 if (t instanceof InterruptedException JavaDoc)
599                     throw (InterruptedException JavaDoc)t;
600                 else
601                 {
602                     server.consoleExceptionPrintTrace(t);
603                 }
604             }
605
606         }
607         else
608         {
609             // exchange attributes with application requester
610
exchangeServerAttributes();
611         }
612     }
613
614     /**
615      * Cleans up and closes a result set if an exception is thrown
616      * when collecting QRYDTA in response to OPNQRY or CNTQRY.
617      *
618      * @param stmt the DRDA statement to clean up
619      * @param sqle the exception that was thrown
620      * @param writerMark start index for the first DSS to clear from
621      * the output buffer
622      * @exception DRDAProtocolException if a DRDA protocol error is
623      * detected
624      */

625     private void cleanUpAndCloseResultSet(DRDAStatement stmt,
626                                           SQLException JavaDoc sqle,
627                                           int writerMark)
628         throws DRDAProtocolException
629     {
630         if (stmt != null) {
631             writer.clearDSSesBackToMark(writerMark);
632             if (!stmt.rsIsClosed()) {
633                 try {
634                     stmt.rsClose();
635                 } catch (SQLException JavaDoc ec) {
636                     if (SanityManager.DEBUG) {
637                         trace("Warning: Error closing result set");
638                     }
639                 }
640                 writeABNUOWRM();
641                 writeSQLCARD(sqle, CodePoint.SVRCOD_ERROR, 0, 0);
642             }
643         } else {
644             writeSQLCARDs(sqle, 0);
645         }
646         errorInChain(sqle);
647     }
648
649     /**
650      * Process DRDA commands we can receive once server attributes have been
651      * exchanged.
652      *
653      * @exception DRDAProtocolException
654      */

655     private void processCommands() throws DRDAProtocolException
656     {
657         DRDAStatement stmt = null;
658         int updateCount = 0;
659         boolean PRPSQLSTTfailed = false;
660         boolean checkSecurityCodepoint = session.requiresSecurityCodepoint();
661         do
662         {
663             correlationID = reader.readDssHeader();
664             int codePoint = reader.readLengthAndCodePoint();
665             int writerMark = writer.markDSSClearPoint();
666             
667             if (checkSecurityCodepoint)
668                 verifyInOrderACCSEC_SECCHK(codePoint,session.getRequiredSecurityCodepoint());
669
670             switch(codePoint)
671             {
672                 case CodePoint.CNTQRY:
673                     try{
674                         stmt = parseCNTQRY();
675                         if (stmt != null)
676                         {
677                             writeQRYDTA(stmt);
678                             if (stmt.rsIsClosed())
679                             {
680                                 writeENDQRYRM(CodePoint.SVRCOD_WARNING);
681                                 writeNullSQLCARDobject();
682                             }
683                             // Send any warnings if JCC can handle them
684
checkWarning(null, null, stmt.getResultSet(), 0, false, sendWarningsOnCNTQRY);
685                         }
686                     }
687                     catch(SQLException JavaDoc e)
688                     {
689                         // if we got a SQLException we need to clean up and
690
// close the result set Beetle 4758
691
cleanUpAndCloseResultSet(stmt, e, writerMark);
692                     }
693                     break;
694                 case CodePoint.EXCSQLIMM:
695                     try {
696                         updateCount = parseEXCSQLIMM();
697                         // RESOLVE: checking updateCount is not sufficient
698
// since it will be 0 for creates, we need to know when
699
// any logged changes are made to the database
700
// Not getting this right for JCC is probably O.K., this
701
// will probably be a problem for ODBC and XA
702
// The problem is that JDBC doesn't provide this information
703
// so we would have to expand the JDBC API or call a
704
// builtin method to check(expensive)
705
// For now we will assume that every execute immediate
706
// does an update (that is the most conservative thing)
707
if (database.RDBUPDRM_sent == false)
708                         {
709                             writeRDBUPDRM();
710                         }
711
712                         // we need to set update count in SQLCARD
713
checkWarning(null, database.getDefaultStatement().getStatement(),
714                             null, updateCount, true, true);
715                     } catch (SQLException JavaDoc e)
716                     {
717                         writer.clearDSSesBackToMark(writerMark);
718                         writeSQLCARDs(e, 0);
719                         errorInChain(e);
720                     }
721                     break;
722
723                 case CodePoint.EXCSQLSET:
724                     try {
725                         if (parseEXCSQLSET())
726                         // all went well.
727
writeSQLCARDs(null,0);
728                     }
729                     catch (SQLWarning JavaDoc w)
730                     {
731                         writeSQLCARD(w, CodePoint.SVRCOD_WARNING, 0, 0);
732                     }
733                     catch (SQLException JavaDoc e)
734                     {
735                         writer.clearDSSesBackToMark(writerMark);
736                         writeSQLCARDs(e, 0);
737                         errorInChain(e);
738                     }
739                     break;
740                     
741                 case CodePoint.PRPSQLSTT:
742                     int sqldaType;
743                     PRPSQLSTTfailed = false;
744                     try {
745                         database.getConnection().clearWarnings();
746                         sqldaType = parsePRPSQLSTT();
747                         if (sqldaType > 0) // do write SQLDARD
748
writeSQLDARD(database.getCurrentStatement(),
749                                          (sqldaType == CodePoint.TYPSQLDA_LIGHT_OUTPUT),
750                                          database.getConnection().getWarnings());
751                         else
752                             checkWarning(database.getConnection(), null, null, 0, true, true);
753
754                     } catch (SQLException JavaDoc e)
755                     {
756                         writer.clearDSSesBackToMark(writerMark);
757                         writeSQLCARDs(e, 0, true);
758                         PRPSQLSTTfailed = true;
759                         errorInChain(e);
760                     }
761                     break;
762                 case CodePoint.OPNQRY:
763                     PreparedStatement JavaDoc ps = null;
764                     try {
765                         if (PRPSQLSTTfailed) {
766                             // read the command objects
767
// for ps with parameter
768
// Skip objects/parameters
769
skipRemainder(true);
770
771                             // If we failed to prepare, then we fail
772
// to open, which means OPNQFLRM.
773
writeOPNQFLRM(null);
774                             break;
775                         }
776                         Pkgnamcsn pkgnamcsn = parseOPNQRY();
777                         if (pkgnamcsn != null)
778                         {
779                             stmt = database.getDRDAStatement(pkgnamcsn);
780                             ps = stmt.getPreparedStatement();
781                             ps.clearWarnings();
782                             if (pendingStatementTimeout >= 0) {
783                                 ps.setQueryTimeout(pendingStatementTimeout);
784                                 pendingStatementTimeout = -1;
785                             }
786                             stmt.execute();
787                             writeOPNQRYRM(false, stmt);
788                             checkWarning(null, ps, null, 0, false, true);
789
790                             writeQRYDSC(stmt, false);
791
792                             stmt.rsSuspend();
793
794                             if (stmt.getQryprctyp() == CodePoint.LMTBLKPRC &&
795                                     stmt.getQryrowset() != 0) {
796                                 // The DRDA spec allows us to send
797
// QRYDTA here if there are no LOB
798
// columns.
799
DRDAResultSet drdars =
800                                     stmt.getCurrentDrdaResultSet();
801                                 try {
802                                     if (drdars != null &&
803                                         !drdars.hasLobColumns()) {
804                                         writeQRYDTA(stmt);
805                                     }
806                                 } catch (SQLException JavaDoc sqle) {
807                                     cleanUpAndCloseResultSet(stmt, sqle,
808                                                              writerMark);
809                                 }
810                             }
811                         }
812                     }
813                     catch (SQLException JavaDoc e)
814                     {
815                         writer.clearDSSesBackToMark(writerMark);
816                         // The fix for DERBY-1196 removed code
817
// here to close the prepared statement
818
// if OPNQRY failed.
819
writeOPNQFLRM(e);
820                     }
821                     break;
822                 case CodePoint.RDBCMM:
823                     try
824                     {
825                         if (SanityManager.DEBUG)
826                             trace("Received commit");
827                         if (!database.getConnection().getAutoCommit())
828                         {
829                             database.getConnection().clearWarnings();
830                             database.commit();
831                             writeENDUOWRM(COMMIT);
832                             checkWarning(database.getConnection(), null, null, 0, true, true);
833                         }
834                         // we only want to write one of these per transaction
835
// so set to false in preparation for next command
836
database.RDBUPDRM_sent = false;
837                     }
838                     catch (SQLException JavaDoc e)
839                     {
840                         writer.clearDSSesBackToMark(writerMark);
841                         // Even in case of error, we have to write the ENDUOWRM.
842
writeENDUOWRM(COMMIT);
843                         writeSQLCARDs(e, 0);
844                         errorInChain(e);
845                     }
846                     break;
847                 case CodePoint.RDBRLLBCK:
848                     try
849                     {
850                         if (SanityManager.DEBUG)
851                             trace("Received rollback");
852                         database.getConnection().clearWarnings();
853                         database.rollback();
854                         writeENDUOWRM(ROLLBACK);
855                         checkWarning(database.getConnection(), null, null, 0, true, true);
856                         // we only want to write one of these per transaction
857
// so set to false in preparation for next command
858
database.RDBUPDRM_sent = false;
859                     }
860                     catch (SQLException JavaDoc e)
861                     {
862                         writer.clearDSSesBackToMark(writerMark);
863                         // Even in case of error, we have to write the ENDUOWRM.
864
writeENDUOWRM(ROLLBACK);
865                         writeSQLCARDs(e, 0);
866                         errorInChain(e);
867                     }
868                     break;
869                 case CodePoint.CLSQRY:
870                     try{
871                         stmt = parseCLSQRY();
872                         stmt.rsClose();
873                         writeSQLCARDs(null, 0);
874                     }
875                     catch (SQLException JavaDoc e)
876                     {
877                         writer.clearDSSesBackToMark(writerMark);
878                         writeSQLCARDs(e, 0);
879                         errorInChain(e);
880                     }
881                     break;
882                 case CodePoint.EXCSAT:
883                     parseEXCSAT();
884                     writeEXCSATRD();
885                     break;
886                 case CodePoint.ACCSEC:
887                     int securityCheckCode = parseACCSEC();
888                     writeACCSECRD(securityCheckCode);
889                     checkSecurityCodepoint = true;
890                     break;
891                 case CodePoint.SECCHK:
892                     if(parseDRDAConnection())
893                         // security all checked and connection ok
894
checkSecurityCodepoint = false;
895                     break;
896                 /* since we don't support sqlj, we won't get bind commands from jcc, we
897                  * might get it from ccc; just skip them.
898                  */

899                 case CodePoint.BGNBND:
900                     reader.skipBytes();
901                     writeSQLCARDs(null, 0);
902                     break;
903                 case CodePoint.BNDSQLSTT:
904                     reader.skipBytes();
905                     parseSQLSTTDss();
906                     writeSQLCARDs(null, 0);
907                     break;
908                 case CodePoint.SQLSTTVRB:
909                     // optional
910
reader.skipBytes();
911                     break;
912                 case CodePoint.ENDBND:
913                     reader.skipBytes();
914                     writeSQLCARDs(null, 0);
915                     break;
916                 case CodePoint.DSCSQLSTT:
917                     if (PRPSQLSTTfailed) {
918                         reader.skipBytes();
919                         writeSQLCARDs(null, 0);
920                         break;
921                     }
922                     try {
923                         boolean rtnOutput = parseDSCSQLSTT();
924                         writeSQLDARD(database.getCurrentStatement(), rtnOutput,
925                                      null);
926                         
927                     } catch (SQLException JavaDoc e)
928                     {
929                         writer.clearDSSesBackToMark(writerMark);
930                         server.consoleExceptionPrint(e);
931                         try {
932                             writeSQLDARD(database.getCurrentStatement(), true, e);
933                         } catch (SQLException JavaDoc e2) { // should not get here since doing nothing with ps
934
agentError("Why am I getting another SQLException?");
935                         }
936                         errorInChain(e);
937                     }
938                     break;
939                 case CodePoint.EXCSQLSTT:
940                     if (PRPSQLSTTfailed) {
941                         // Skip parameters too if they are chained Beetle 4867
942
skipRemainder(true);
943                         writeSQLCARDs(null, 0);
944                         break;
945                     }
946                     try {
947                         parseEXCSQLSTT();
948
949                         DRDAStatement curStmt = database.getCurrentStatement();
950                         if (curStmt != null)
951                             curStmt.rsSuspend();
952                     } catch (SQLException JavaDoc e)
953                     {
954                         skipRemainder(true);
955                         writer.clearDSSesBackToMark(writerMark);
956                         if (SanityManager.DEBUG)
957                         {
958                             server.consoleExceptionPrint(e);
959                         }
960                         writeSQLCARDs(e, 0);
961                         errorInChain(e);
962                     }
963                     break;
964                 case CodePoint.SYNCCTL:
965                     if (xaProto == null)
966                         xaProto = new DRDAXAProtocol(this);
967                     xaProto.parseSYNCCTL();
968                     break;
969                 default:
970                     codePointNotSupported(codePoint);
971             }
972
973             // Set the correct chaining bits for whatever
974
// reply DSS(es) we just wrote. If we've reached
975
// the end of the chain, this method will send
976
// the DSS(es) across.
977
finalizeChain();
978
979         }
980         while (reader.isChainedWithSameID() || reader.isChainedWithDiffID());
981     }
982
983     /**
984      * If there's a severe error in the DDM chain, and if the header indicates
985      * "terminate chain on error", we stop processing further commands in the chain
986      * nor do we send any reply for them. In accordance to this, a SQLERRRM message
987      * indicating the severe error must have been sent! (otherwise application requestor,
988      * such as JCC, would not terminate the receiving of chain replies.)
989      *
990      * Each DRDA command is processed independently. DRDA defines no interdependencies
991      * across chained commands. A command is processed the same when received within
992      * a set of chained commands or received separately. The chaining was originally
993      * defined as a way to save network costs.
994      *
995      * @param e the SQLException raised
996      * @exception DRDAProtocolException
997      */

998     private void errorInChain(SQLException JavaDoc e) throws DRDAProtocolException
999     {
1000        if (reader.terminateChainOnErr() && (getExceptionSeverity(e) > CodePoint.SVRCOD_ERROR))
1001        {
1002            if (SanityManager.DEBUG) trace("terminating the chain on error...");
1003            skipRemainder(false);
1004        }
1005    }
1006
1007    /**
1008     * Exchange server attributes with application requester
1009     *
1010     * @exception DRDAProtocolException
1011     */

1012    private void exchangeServerAttributes()
1013        throws DRDAProtocolException
1014    {
1015        int codePoint;
1016        correlationID = reader.readDssHeader();
1017        if (SanityManager.DEBUG) {
1018          if (correlationID == 0)
1019          {
1020            SanityManager.THROWASSERT(
1021                          "Unexpected value for correlationId = " + correlationID);
1022          }
1023        }
1024
1025        codePoint = reader.readLengthAndCodePoint();
1026
1027        // The first code point in the exchange of attributes must be EXCSAT
1028
if (codePoint != CodePoint.EXCSAT)
1029        {
1030            //Throw PRCCNVRM
1031
throw
1032                new DRDAProtocolException(DRDAProtocolException.DRDA_Proto_PRCCNVRM,
1033                                          this, codePoint,
1034                                          CodePoint.PRCCNVCD_EXCSAT_FIRST_AFTER_CONN);
1035        }
1036
1037        parseEXCSAT();
1038        writeEXCSATRD();
1039        finalizeChain();
1040        session.setState(session.ATTEXC);
1041    }
1042    
1043
1044    private boolean parseDRDAConnection() throws DRDAProtocolException
1045    {
1046        int codePoint;
1047        boolean sessionOK = true;
1048
1049
1050        int securityCheckCode = parseSECCHK();
1051        if (SanityManager.DEBUG)
1052            trace("*** SECCHKRM securityCheckCode is: "+securityCheckCode);
1053        writeSECCHKRM(securityCheckCode);
1054        //at this point if the security check failed, we're done, the session failed
1055
if (securityCheckCode != 0)
1056        {
1057            return false;
1058        }
1059
1060        correlationID = reader.readDssHeader();
1061        codePoint = reader.readLengthAndCodePoint();
1062        verifyRequiredObject(codePoint,CodePoint.ACCRDB);
1063        int svrcod = parseACCRDB();
1064
1065        //If network server gets a null connection form InternalDriver, reply with
1066
//RDBAFLRM and SQLCARD with null SQLException
1067
if(database.getConnection() == null && databaseAccessException == null){
1068            writeRDBfailure(CodePoint.RDBAFLRM);
1069            return false;
1070        }
1071        
1072        //if earlier we couldn't access the database
1073
if (databaseAccessException != null)
1074        {
1075
1076            //if the Database was not found we will try DS
1077
int failureType = getRdbAccessErrorCodePoint();
1078            if (failureType == CodePoint.RDBNFNRM
1079                || failureType == CodePoint.RDBATHRM)
1080            {
1081                writeRDBfailure(failureType);
1082            }
1083            else
1084            {
1085                writeRDBfailure(CodePoint.RDBAFLRM);
1086            }
1087            return false;
1088        }
1089        else if (database.accessCount > 1 ) // already in conversation with database
1090
{
1091            writeRDBfailure(CodePoint.RDBACCRM);
1092            return false;
1093        }
1094        else // everything is fine
1095
writeACCRDBRM(svrcod);
1096
1097        // compare this application requester with previously stored
1098
// application requesters and if we have already seen this one
1099
// use stored application requester
1100
session.appRequester = server.getAppRequester(appRequester);
1101        return sessionOK;
1102    }
1103
1104    /**
1105     * Write RDB Failure
1106     *
1107     * Instance Variables
1108     * SVRCOD - Severity Code - required
1109     * RDBNAM - Relational Database name - required
1110     * SRVDGN - Server Diagnostics - optional (not sent for now)
1111     *
1112     * @param codePoint codepoint of failure
1113     */

1114    private void writeRDBfailure(int codePoint) throws DRDAProtocolException
1115    {
1116        writer.createDssReply();
1117        writer.startDdm(codePoint);
1118        writer.writeScalar2Bytes(CodePoint.SVRCOD, CodePoint.SVRCOD_ERROR);
1119        writeRDBNAM(database.dbName);
1120        writer.endDdmAndDss();
1121        
1122        switch(codePoint){
1123            case CodePoint.RDBAFLRM:
1124                //RDBAFLRM requires TYPDEFNAM and TYPDEFOVR
1125
writer.createDssObject();
1126                writer.writeScalarString(CodePoint.TYPDEFNAM,
1127                                         CodePoint.TYPDEFNAM_QTDSQLASC);
1128                writeTYPDEFOVR();
1129                writer.endDss();
1130            case CodePoint.RDBNFNRM:
1131            case CodePoint.RDBATHRM:
1132                writeSQLCARD(databaseAccessException,CodePoint.SVRCOD_ERROR,0,0);
1133            case CodePoint.RDBACCRM:
1134                //Ignore anything that was chained to the ACCRDB.
1135
skipRemainder(false);
1136
1137                // Finalize chain state for whatever we wrote in
1138
// response to ACCRDB.
1139
finalizeChain();
1140                break;
1141        }
1142        
1143    }
1144
1145    /* Check the database access exception and return the appropriate
1146       error codepoint.
1147       RDBNFNRM - Database not found
1148       RDBATHRM - Not Authorized
1149       RDBAFLRM - Access failure
1150       @return RDB Access codepoint
1151               
1152    */

1153
1154    private int getRdbAccessErrorCodePoint()
1155    {
1156        String JavaDoc sqlState = databaseAccessException.getSQLState();
1157        if (sqlState.regionMatches(0,SQLState.DATABASE_NOT_FOUND,0,5) |
1158            sqlState.regionMatches(0,SQLState.NO_SUCH_DATABASE,0,5))
1159            return CodePoint.RDBNFNRM;
1160        else
1161            if (sqlState.regionMatches(0,SQLState.LOGIN_FAILED,0,5) ||
1162                sqlState.regionMatches(0,SQLState.AUTH_INVALID_USER_NAME,0,5))
1163                return CodePoint.RDBATHRM;
1164        else
1165                return CodePoint.RDBAFLRM;
1166    }
1167
1168
1169    /**
1170     * Verify userId and password
1171     *
1172     * Username and password is verified by making a connection to the
1173     * database
1174     *
1175     * @return security check code, 0 is O.K.
1176     * @exception DRDAProtocolException
1177     */

1178    private int verifyUserIdPassword() throws DRDAProtocolException
1179    {
1180        databaseAccessException = null;
1181        int retSecChkCode = 0;
1182
1183        String JavaDoc realName = database.dbName; //first strip off properties
1184
int endOfName = realName.indexOf(';');
1185        if (endOfName != -1)
1186            realName = realName.substring(0, endOfName);
1187        retSecChkCode = getConnFromDatabaseName();
1188        return retSecChkCode;
1189    }
1190
1191    /**
1192     * Get connection from a database name
1193     *
1194     * Username and password is verified by making a connection to the
1195     * database
1196     *
1197     * @return security check code, 0 is O.K.
1198     * @exception DRDAProtocolException
1199     */

1200    private int getConnFromDatabaseName() throws DRDAProtocolException
1201    {
1202        Properties JavaDoc p = new Properties JavaDoc();
1203        databaseAccessException = null;
1204        //if we haven't got the correlation token yet, use session number for drdaID
1205
if (session.drdaID == null)
1206            session.drdaID = leftBrace + session.connNum + rightBrace;
1207        p.put(Attribute.DRDAID_ATTR, session.drdaID);
1208
1209        // We pass extra property information for the authentication provider
1210
// to successfully re-compute the substitute (hashed) password and
1211
// compare it with what we've got from the requester (source).
1212
//
1213
// If a password attribute appears as part of the connection URL
1214
// attributes, we then don't use the substitute hashed password
1215
// to authenticate with the engine _as_ the one (if any) as part
1216
// of the connection URL attributes, will be used to authenticate
1217
// against Derby's BUILT-IN authentication provider - As a reminder,
1218
// Derby allows password to be mentioned as part of the connection
1219
// URL attributes, as this extra capability could be useful to pass
1220
// passwords to external authentication providers for Derby; hence
1221
// a password defined as part of the connection URL attributes cannot
1222
// be substituted (single-hashed) as it is not recoverable.
1223
if ((database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) &&
1224            (database.dbName.indexOf(Attribute.PASSWORD_ATTR) == -1))
1225        {
1226            p.put(Attribute.CLIENT_SECURITY_MECHANISM,
1227                  String.valueOf(database.securityMechanism));
1228            p.put(Attribute.DRDA_SECTKN_IN,
1229                  DecryptionManager.toHexString(database.secTokenIn, 0,
1230                                                database.secTokenIn.length));
1231            p.put(Attribute.DRDA_SECTKN_OUT,
1232                  DecryptionManager.toHexString(database.secTokenOut, 0,
1233                                                database.secTokenOut.length));
1234        }
1235            
1236        try {
1237            database.makeConnection(p);
1238        } catch (SQLException JavaDoc se) {
1239            String JavaDoc sqlState = se.getSQLState();
1240            // need to set the security check code based on the reason the connection
1241
// was denied, Cloudscape doesn't say whether the userid or password caused
1242
// the problem, so we will just return userid invalid
1243
databaseAccessException = se;
1244            for (; se != null; se = se.getNextException())
1245            {
1246                if (SanityManager.DEBUG)
1247                    trace(se.getMessage());
1248                println2Log(database.dbName, session.drdaID, se.getMessage());
1249            }
1250
1251            if (sqlState.regionMatches(0,SQLState.LOGIN_FAILED,0,5))
1252                return CodePoint.SECCHKCD_USERIDINVALID;
1253
1254            return 0;
1255        }
1256        catch (Exception JavaDoc e)
1257        {
1258            // If cloudscape has shut down for some reason,
1259
// we will send an agent error and then try to
1260
// get the driver loaded again. We have to get
1261
// rid of the client first in case they are holding
1262
// the DriverManager lock.
1263
println2Log(database.dbName, session.drdaID,
1264                        "Driver not loaded"
1265                        + e.getMessage());
1266                try {
1267                    agentError("Driver not loaded");
1268                }
1269                catch (DRDAProtocolException dpe)
1270                {
1271                    // Retry starting the server before rethrowing
1272
// the protocol exception. Then hopfully all
1273
// will be well when they try again.
1274
try {
1275                        server.startNetworkServer();
1276                    } catch (Exception JavaDoc re) {
1277                        println2Log(database.dbName, session.drdaID, "Failed attempt to reload driver " +re.getMessage() );
1278                    }
1279                    throw dpe;
1280                }
1281        }
1282        
1283    
1284        // Everything worked so log connection to the database.
1285
if (getLogConnections())
1286            println2Log(database.dbName, session.drdaID,
1287                "Apache Derby Network Server connected to database " +
1288                        database.dbName);
1289        return 0;
1290    }
1291
1292
1293    /**
1294     * Parses EXCSAT (Exchange Server Attributes)
1295     * Instance variables
1296     * EXTNAM(External Name) - optional
1297     * MGRLVLLS(Manager Levels) - optional
1298     * SPVNAM(Supervisor Name) - optional
1299     * SRVCLSNM(Server Class Name) - optional
1300     * SRVNAM(Server Name) - optional, ignorable
1301     * SRVRLSLV(Server Product Release Level) - optional, ignorable
1302     *
1303     * @exception DRDAProtocolException
1304     */

1305    private void parseEXCSAT() throws DRDAProtocolException
1306    {
1307        int codePoint;
1308        String JavaDoc strVal;
1309
1310        // There are three kinds of EXCSAT's we might get.
1311
// 1) Initial Exchange attributes.
1312
// For this we need to initialize the apprequester.
1313
// Session state is set to ATTEXC and then the AR must
1314
// follow up with ACCSEC and SECCHK to get the connection.
1315
// 2) Send of EXCSAT as ping or mangager level adjustment.
1316
// (see parseEXCSAT2())
1317
// For this we just ignore the EXCSAT objects that
1318
// are already set.
1319
// 3) Send of EXCSAT for connection reset. (see parseEXCSAT2())
1320
// This is treated just like ping and will be followed up
1321
// by an ACCSEC request if in fact it is a connection reset.
1322

1323        // If we have already exchanged attributes once just
1324
// process any new manager levels and return (case 2 and 3 above)
1325
if (appRequester != null)
1326        {
1327            parseEXCSAT2();
1328            return;
1329        }
1330
1331        // set up a new Application Requester to store information about the
1332
// application requester for this session
1333

1334        appRequester = new AppRequester();
1335
1336        reader.markCollection();
1337
1338        codePoint = reader.getCodePoint();
1339        while (codePoint != -1)
1340        {
1341            switch (codePoint)
1342            {
1343                // optional
1344
case CodePoint.EXTNAM:
1345                    appRequester.extnam = reader.readString();
1346                    if (SanityManager.DEBUG)
1347                        trace("extName = " + appRequester.extnam);
1348                    if (appRequester.extnam.length() > CodePoint.MAX_NAME)
1349                        tooBig(CodePoint.EXTNAM);
1350                    break;
1351                // optional
1352
case CodePoint.MGRLVLLS:
1353                    parseMGRLVLLS(1);
1354                    break;
1355                // optional
1356
case CodePoint.SPVNAM:
1357                    appRequester.spvnam = reader.readString();
1358                    // This is specified as a null parameter so length should
1359
// be zero
1360
if (appRequester.spvnam != null)
1361                        badObjectLength(CodePoint.SPVNAM);
1362                    break;
1363                // optional
1364
case CodePoint.SRVNAM:
1365                    appRequester.srvnam = reader.readString();
1366                    if (SanityManager.DEBUG)
1367                        trace("serverName = " + appRequester.srvnam);
1368                    if (appRequester.srvnam.length() > CodePoint.MAX_NAME)
1369                        tooBig(CodePoint.SRVNAM);
1370                    break;
1371                // optional
1372
case CodePoint.SRVRLSLV:
1373                    appRequester.srvrlslv = reader.readString();
1374                    if (SanityManager.DEBUG)
1375                        trace("serverlslv = " + appRequester.srvrlslv);
1376                    if (appRequester.srvrlslv.length() > CodePoint.MAX_NAME)
1377                        tooBig(CodePoint.SRVRLSLV);
1378                    break;
1379                // optional
1380
case CodePoint.SRVCLSNM:
1381                    appRequester.srvclsnm = reader.readString();
1382                    if (SanityManager.DEBUG)
1383                        trace("serverClassName = " + appRequester.srvclsnm);
1384                    if (appRequester.srvclsnm.length() > CodePoint.MAX_NAME)
1385                        tooBig(CodePoint.SRVCLSNM);
1386                    break;
1387                default:
1388                    invalidCodePoint(codePoint);
1389            }
1390            codePoint = reader.getCodePoint();
1391        }
1392    }
1393
1394    /**
1395     * Parses EXCSAT2 (Exchange Server Attributes)
1396     * Instance variables
1397     * EXTNAM(External Name) - optional
1398     * MGRLVLLS(Manager Levels) - optional
1399     * SPVNAM(Supervisor Name) - optional
1400     * SRVCLSNM(Server Class Name) - optional
1401     * SRVNAM(Server Name) - optional, ignorable
1402     * SRVRLSLV(Server Product Release Level) - optional, ignorable
1403     *
1404     * @exception DRDAProtocolException
1405     *
1406     * This parses a second occurrence of an EXCSAT command
1407     * The target must ignore the values for extnam, srvclsnm, srvnam and srvrlslv.
1408     * I am also going to ignore spvnam since it should be null anyway.
1409     * Only new managers can be added.
1410     */

1411    private void parseEXCSAT2() throws DRDAProtocolException
1412    {
1413        int codePoint;
1414        reader.markCollection();
1415
1416        codePoint = reader.getCodePoint();
1417        while (codePoint != -1)
1418        {
1419            switch (codePoint)
1420            {
1421                // optional
1422
case CodePoint.EXTNAM:
1423                case CodePoint.SRVNAM:
1424                case CodePoint.SRVRLSLV:
1425                case CodePoint.SRVCLSNM:
1426                case CodePoint.SPVNAM:
1427                    reader.skipBytes();
1428                    break;
1429                // optional
1430
case CodePoint.MGRLVLLS:
1431                    parseMGRLVLLS(2);
1432                    break;
1433                default:
1434                    invalidCodePoint(codePoint);
1435            }
1436            codePoint = reader.getCodePoint();
1437        }
1438    }
1439
1440    /**
1441     * Parse manager levels
1442     * Instance variables
1443     * MGRLVL - repeatable, required
1444     * CODEPOINT
1445     * CCSIDMGR - CCSID Manager
1446     * CMNAPPC - LU 6.2 Conversational Communications Manager
1447     * CMNSYNCPT - SNA LU 6.2 SyncPoint Conversational Communications Manager
1448     * CMNTCPIP - TCP/IP Communication Manager
1449     * DICTIONARY - Dictionary
1450     * RDB - Relational Database
1451     * RSYNCMGR - Resynchronization Manager
1452     * SECMGR - Security Manager
1453     * SQLAM - SQL Application Manager
1454     * SUPERVISOR - Supervisor
1455     * SYNCPTMGR - Sync Point Manager
1456     * VALUE
1457     *
1458     * On the second appearance of this codepoint, it can only add managers
1459     *
1460     * @param time 1 for first time this is seen, 2 for subsequent ones
1461     * @exception DRDAProtocolException
1462     *
1463     */

1464    private void parseMGRLVLLS(int time) throws DRDAProtocolException
1465    {
1466        int manager, managerLevel;
1467        int currentLevel;
1468        // set up vectors to keep track of manager information
1469
unknownManagers = new Vector JavaDoc();
1470        knownManagers = new Vector JavaDoc();
1471        errorManagers = new Vector JavaDoc();
1472        errorManagersLevel = new Vector JavaDoc();
1473        if (SanityManager.DEBUG)
1474            trace("Manager Levels");
1475
1476        while (reader.moreDdmData())
1477        {
1478            manager = reader.readNetworkShort();
1479            managerLevel = reader.readNetworkShort();
1480            if (CodePoint.isKnownManager(manager))
1481            {
1482                knownManagers.addElement(new Integer JavaDoc(manager));
1483                //if the manager level hasn't been set, set it
1484
currentLevel = appRequester.getManagerLevel(manager);
1485                if (currentLevel == appRequester.MGR_LEVEL_UNKNOWN)
1486                    appRequester.setManagerLevel(manager, managerLevel);
1487                else
1488                {
1489                    //if the level is still the same we'll ignore it
1490
if (currentLevel != managerLevel)
1491                    {
1492                        //keep a list of conflicting managers
1493
errorManagers.addElement(new Integer JavaDoc(manager));
1494                        errorManagersLevel.addElement(new Integer JavaDoc (managerLevel));
1495                    }
1496                }
1497
1498            }
1499            else
1500                unknownManagers.addElement(new Integer JavaDoc(manager));
1501            if (SanityManager.DEBUG)
1502               trace("Manager = " + java.lang.Integer.toHexString(manager) +
1503                      " ManagerLevel " + managerLevel);
1504        }
1505        sqlamLevel = appRequester.getManagerLevel(CodePoint.SQLAM);
1506        // did we have any errors
1507
if (errorManagers.size() > 0)
1508        {
1509            Object JavaDoc [] oa = new Object JavaDoc[errorManagers.size()*2];
1510            int j = 0;
1511            for (int i = 0; i < errorManagers.size(); i++)
1512            {
1513                oa[j++] = errorManagers.elementAt(i);
1514                oa[j++] = errorManagersLevel.elementAt(i);
1515            }
1516            throw new DRDAProtocolException(DRDAProtocolException.DRDA_Proto_MGRLVLRM,
1517                                          this, 0,
1518                                          0, oa);
1519        }
1520    }
1521    /**
1522     * Write reply to EXCSAT command
1523     * Instance Variables
1524     * EXTNAM - External Name (optional)
1525     * MGRLVLLS - Manager Level List (optional)
1526     * SRVCLSNM - Server Class Name (optional) - used by JCC
1527     * SRVNAM - Server Name (optional)
1528     * SRVRLSLV - Server Product Release Level (optional)
1529     *
1530     * @exception DRDAProtocolException
1531     */

1532    private void writeEXCSATRD() throws DRDAProtocolException
1533    {
1534        writer.createDssReply();
1535        writer.startDdm(CodePoint.EXCSATRD);
1536        writer.writeScalarString(CodePoint.EXTNAM, server.att_extnam);
1537        //only reply with manager levels if we got sent some
1538
if (knownManagers != null && knownManagers.size() > 0)
1539            writeMGRLEVELS();
1540        writer.writeScalarString(CodePoint.SRVCLSNM, server.att_srvclsnm);
1541        writer.writeScalarString(CodePoint.SRVNAM, server.ATT_SRVNAM);
1542        writer.writeScalarString(CodePoint.SRVRLSLV, server.att_srvrlslv);
1543        writer.endDdmAndDss();
1544    }
1545    /**
1546     * Write manager levels
1547     * The target server must not provide information for any target
1548     * managers unless the source explicitly requests it.
1549     * For each manager class, if the target server's support level
1550     * is greater than or equal to the source server's level, then the source
1551     * server's level is returned for that class if the target server can operate
1552     * at the source's level; otherwise a level 0 is returned. If the target
1553     * server's support level is less than the source server's level, the
1554     * target server's level is returned for that class. If the target server
1555     * does not recognize the code point of a manager class or does not support
1556     * that class, it returns a level of 0. The target server then waits
1557     * for the next command or for the source server to terminate communications.
1558     * When the source server receives EXCSATRD, it must compare each of the entries
1559     * in the mgrlvlls parameter it received to the corresponding entries in the mgrlvlls
1560     * parameter it sent. If any level mismatches, the source server must decide
1561     * whether it can use or adjust to the lower level of target support for that manager
1562     * class. There are no architectural criteria for making this decision.
1563     * The source server can terminate communications or continue at the target
1564     * servers level of support. It can also attempt to use whatever
1565     * commands its user requests while receiving error reply messages for real
1566     * functional mismatches.
1567     * The manager levels the source server specifies or the target server
1568     * returns must be compatible with the manager-level dependencies of the specified
1569     * manangers. Incompatible manager levels cannot be specified.
1570     * Instance variables
1571     * MGRLVL - repeatable, required
1572     * CODEPOINT
1573     * CCSIDMGR - CCSID Manager
1574     * CMNAPPC - LU 6.2 Conversational Communications Manager
1575     * CMNSYNCPT - SNA LU 6.2 SyncPoint Conversational Communications Manager
1576     * CMNTCPIP - TCP/IP Communication Manager
1577     * DICTIONARY - Dictionary
1578     * RDB - Relational Database
1579     * RSYNCMGR - Resynchronization Manager
1580     * SECMGR - Security Manager
1581     * SQLAM - SQL Application Manager
1582     * SUPERVISOR - Supervisor
1583     * SYNCPTMGR - Sync Point Manager
1584     * XAMGR - XA manager
1585     * VALUE
1586     */

1587    private void writeMGRLEVELS() throws DRDAProtocolException
1588    {
1589        int manager;
1590        int appLevel;
1591        int serverLevel;
1592        writer.startDdm(CodePoint.MGRLVLLS);
1593        for (int i = 0; i < knownManagers.size(); i++)
1594        {
1595            manager = ((Integer JavaDoc)knownManagers.elementAt(i)).intValue();
1596            appLevel = appRequester.getManagerLevel(manager);
1597            serverLevel = server.getManagerLevel(manager);
1598            if (serverLevel >= appLevel)
1599            {
1600                //Note appLevel has already been set to 0 if we can't support
1601
//the original app Level
1602
writer.writeCodePoint4Bytes(manager, appLevel);
1603            }
1604            else
1605            {
1606                writer.writeCodePoint4Bytes(manager, serverLevel);
1607                // reset application manager level to server level
1608
appRequester.setManagerLevel(manager, serverLevel);
1609            }
1610        }
1611        // write 0 for all unknown managers
1612
for (int i = 0; i < unknownManagers.size(); i++)
1613        {
1614            manager = ((Integer JavaDoc)unknownManagers.elementAt(i)).intValue();
1615            writer.writeCodePoint4Bytes(manager, 0);
1616        }
1617        writer.endDdm();
1618    }
1619    /**
1620     * Parse Access Security
1621     *
1622     * If the target server supports the SECMEC requested by the application requester
1623     * then a single value is returned and it is identical to the SECMEC value
1624     * in the ACCSEC command. If the target server does not support the SECMEC
1625     * requested, then one or more values are returned and the application requester
1626     * must choose one of these values for the security mechanism.
1627     * We currently support
1628     * - user id and password (default for JCC)
1629     * - encrypted user id and password
1630     * - strong password substitute (USRSSBPWD w/
1631     * Derby network client only)
1632     *
1633     * Instance variables
1634     * SECMGRNM - security manager name - optional
1635     * SECMEC - security mechanism - required
1636     * RDBNAM - relational database name - optional
1637     * SECTKN - security token - optional, (required if sec mech. needs it)
1638     *
1639     * @return security check code - 0 if everything O.K.
1640     */

1641    private int parseACCSEC() throws DRDAProtocolException
1642    {
1643        int securityCheckCode = 0;
1644        int securityMechanism = 0;
1645        byte [] secTokenIn = null;
1646
1647        reader.markCollection();
1648        int codePoint = reader.getCodePoint();
1649        while (codePoint != -1)
1650        {
1651            switch(codePoint)
1652            {
1653                //optional
1654
case CodePoint.SECMGRNM:
1655                    // this is defined to be 0 length
1656
if (reader.getDdmLength() != 0)
1657                        badObjectLength(CodePoint.SECMGRNM);
1658                    break;
1659                //required
1660
case CodePoint.SECMEC:
1661                    checkLength(CodePoint.SECMEC, 2);
1662                    securityMechanism = reader.readNetworkShort();
1663                    if (SanityManager.DEBUG)
1664                        trace("parseACCSEC - Security mechanism = " + securityMechanism);
1665                    
1666                    // if Property.DRDA_PROP_SECURITYMECHANISM has been set, then
1667
// network server only accepts connections which use that
1668
// security mechanism. No other types of connections
1669
// are accepted.
1670
// Make check to see if this property has been set.
1671
// if set, and if the client requested security mechanism
1672
// is not the same, then return a security check code
1673
// that the server does not support/allow this security
1674
// mechanism
1675
if ( (server.getSecurityMechanism() !=
1676                        NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM)
1677                            && securityMechanism != server.getSecurityMechanism())
1678                    {
1679                        securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
1680                        if (SanityManager.DEBUG) {
1681                            trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [1] - " +
1682                                  securityMechanism + " <> " +
1683                                  server.getSecurityMechanism() + "\n");
1684                        }
1685                    }
1686                    else
1687                    {
1688                        // for plain text userid,password USRIDPWD, and USRIDONL
1689
// no need of decryptionManager
1690
if (securityMechanism != CodePoint.SECMEC_USRIDPWD &&
1691                                securityMechanism != CodePoint.SECMEC_USRIDONL)
1692                        {
1693                            // These are the only other mechanisms we understand
1694
if (((securityMechanism != CodePoint.SECMEC_EUSRIDPWD) ||
1695                                 (securityMechanism == CodePoint.SECMEC_EUSRIDPWD &&
1696                                   !server.supportsEUSRIDPWD())
1697                                 ) &&
1698                                (securityMechanism !=
1699                                        CodePoint.SECMEC_USRSSBPWD))
1700                                //securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
1701
{
1702                        securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
1703                        if (SanityManager.DEBUG) {
1704                            trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [2]\n");
1705                        }
1706                    }
1707                            else
1708                            {
1709                                // We delay the initialization and required
1710
// processing for SECMEC_USRSSBPWD as we need
1711
// to ensure the database is booted so that
1712
// we can verify that the current auth scheme
1713
// is set to BUILT-IN or NONE. For this we need
1714
// to have the RDBNAM codepoint available.
1715
//
1716
// See validateSecMecUSRSSBPWD() call below
1717
if (securityMechanism ==
1718                                        CodePoint.SECMEC_USRSSBPWD)
1719                                    break;
1720
1721                                // SECMEC_EUSRIDPWD initialization
1722
try {
1723                                    if (decryptionManager == null)
1724                                        decryptionManager = new DecryptionManager();
1725                                    myPublicKey = decryptionManager.obtainPublicKey();
1726                                } catch (SQLException JavaDoc e) {
1727                                    println2Log(null, session.drdaID, e.getMessage());
1728                                    // Local security service non-retryable error.
1729
securityCheckCode = CodePoint.SECCHKCD_0A;
1730                                }
1731                            }
1732                        }
1733                    }
1734                    break;
1735                //optional (currently required for Cloudscape - needed for
1736
// DERBY-528 as well)
1737
case CodePoint.RDBNAM:
1738                    String JavaDoc dbname = parseRDBNAM();
1739                    Database d = session.getDatabase(dbname);
1740                    if (d == null)
1741                        addDatabase(dbname);
1742                    else
1743                    {
1744                        // reset database for connection re-use
1745
d.reset();
1746                        database = d;
1747                    }
1748                    break;
1749                //optional - depending on security Mechanism
1750
case CodePoint.SECTKN:
1751                    secTokenIn = reader.readBytes();
1752                    break;
1753                default:
1754                    invalidCodePoint(codePoint);
1755            }
1756            codePoint = reader.getCodePoint();
1757        }
1758
1759        // check for required CodePoint's
1760
if (securityMechanism == 0)
1761            missingCodePoint(CodePoint.SECMEC);
1762
1763
1764        // RESOLVE - when we look further into security we might want to
1765
// handle this part of the protocol at the session level without
1766
// requiring a database for when authentication is used but there
1767
// is no database level security
1768
if (database == null)
1769            missingCodePoint(CodePoint.RDBNAM);
1770
1771        database.securityMechanism = securityMechanism;
1772        database.secTokenIn = secTokenIn;
1773
1774        // If security mechanism is SECMEC_USRSSBPWD, then ensure it can be
1775
// used for the database or system based on the client's connection
1776
// URL and its identity.
1777
if (securityCheckCode == 0 &&
1778            (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD))
1779        {
1780            if (SanityManager.DEBUG)
1781                SanityManager.ASSERT((securityCheckCode == 0),
1782                        "SECMEC_USRSSBPWD: securityCheckCode should not " +
1783                        "already be set, found it initialized with " +
1784                        "a value of '" + securityCheckCode + "'.");
1785            securityCheckCode = validateSecMecUSRSSBPWD();
1786        }
1787
1788        // need security token
1789
if (securityCheckCode == 0 &&
1790            (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD ||
1791            database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) &&
1792            database.secTokenIn == null)
1793            securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
1794
1795        // shouldn't have security token
1796
if (securityCheckCode == 0 &&
1797            (database.securityMechanism == CodePoint.SECMEC_USRIDPWD ||
1798            database.securityMechanism == CodePoint.SECMEC_USRIDONL) &&
1799            database.secTokenIn != null)
1800            securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
1801
1802        if (SanityManager.DEBUG)
1803            trace("** ACCSECRD securityCheckCode is: " + securityCheckCode);
1804        
1805        // If the security check was successful set the session state to
1806
// security accesseed. Otherwise go back to attributes exchanged so we
1807
// require another ACCSEC
1808
if (securityCheckCode == 0)
1809            session.setState(session.SECACC);
1810        else
1811            session.setState(session.ATTEXC);
1812
1813        return securityCheckCode;
1814    }
1815
1816    /**
1817     * Parse OPNQRY
1818     * Instance Variables
1819     * RDBNAM - relational database name - optional
1820     * PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
1821     * QRYBLKSZ - Query Block Size - required
1822     * QRYBLKCTL - Query Block Protocol Control - optional
1823     * MAXBLKEXT - Maximum Number of Extra Blocks - optional - default value 0
1824     * OUTOVROPT - Output Override Option
1825     * QRYROWSET - Query Rowset Size - optional - level 7
1826     * MONITOR - Monitor events - optional.
1827     *
1828     * @return RDB Package Name, Consistency Token, and Section Number
1829     * @exception DRDAProtocolException
1830     */

1831    private Pkgnamcsn parseOPNQRY() throws DRDAProtocolException, SQLException JavaDoc
1832    {
1833        Pkgnamcsn pkgnamcsn = null;
1834        boolean gotQryblksz = false;
1835        int blksize = 0;
1836        int qryblkctl = CodePoint.QRYBLKCTL_DEFAULT;
1837        int maxblkext = CodePoint.MAXBLKEXT_DEFAULT;
1838        int qryrowset = CodePoint.QRYROWSET_DEFAULT;
1839        int qryclsimp = DRDAResultSet.QRYCLSIMP_DEFAULT;
1840        int outovropt = CodePoint.OUTOVRFRS;
1841        reader.markCollection();
1842        int codePoint = reader.getCodePoint();
1843        while (codePoint != -1)
1844        {
1845            switch(codePoint)
1846            {
1847                //optional
1848
case CodePoint.RDBNAM:
1849                    setDatabase(CodePoint.OPNQRY);
1850                    break;
1851                //required
1852
case CodePoint.PKGNAMCSN:
1853                    pkgnamcsn = parsePKGNAMCSN();
1854                    break;
1855                //required
1856
case CodePoint.QRYBLKSZ:
1857                    blksize = parseQRYBLKSZ();
1858                    gotQryblksz = true;
1859                    break;
1860                //optional
1861
case CodePoint.QRYBLKCTL:
1862                    qryblkctl = reader.readNetworkShort();
1863                    //The only type of query block control we can specify here
1864
//is forced fixed row
1865
if (qryblkctl != CodePoint.FRCFIXROW)
1866                        invalidCodePoint(qryblkctl);
1867                    if (SanityManager.DEBUG)
1868                        trace("!!qryblkctl = "+Integer.toHexString(qryblkctl));
1869                    gotQryblksz = true;
1870                    break;
1871                //optional
1872
case CodePoint.MAXBLKEXT:
1873                    maxblkext = reader.readSignedNetworkShort();
1874                    if (SanityManager.DEBUG)
1875                        trace("maxblkext = "+maxblkext);
1876                    break;
1877                // optional
1878
case CodePoint.OUTOVROPT:
1879                    outovropt = parseOUTOVROPT();
1880                    break;
1881                //optional
1882
case CodePoint.QRYROWSET:
1883                    //Note minimum for OPNQRY is 0
1884
qryrowset = parseQRYROWSET(0);
1885                    break;
1886                case CodePoint.QRYCLSIMP:
1887                    // Implicitly close non-scrollable cursor
1888
qryclsimp = parseQRYCLSIMP();
1889                    break;
1890                case CodePoint.QRYCLSRLS:
1891                    // Ignore release of read locks. Nothing we can do here
1892
parseQRYCLSRLS();
1893                    break;
1894                // optional
1895
case CodePoint.MONITOR:
1896                    parseMONITOR();
1897                    break;
1898                default:
1899                    invalidCodePoint(codePoint);
1900            }
1901            codePoint = reader.getCodePoint();
1902        }
1903        // check for required variables
1904
if (pkgnamcsn == null)
1905            missingCodePoint(CodePoint.PKGNAMCSN);
1906        if (!gotQryblksz)
1907            missingCodePoint(CodePoint.QRYBLKSZ);
1908
1909        // get the statement we are opening
1910
DRDAStatement stmt = database.getDRDAStatement(pkgnamcsn);
1911        if (stmt == null)
1912        {
1913            //XXX should really throw a SQL Exception here
1914
invalidValue(CodePoint.PKGNAMCSN);
1915        }
1916
1917        // check that this statement is not already open
1918
// commenting this check out for now
1919
// it turns out that JCC doesn't send a close if executeQuery is
1920
// done again without closing the previous result set
1921
// this check can't be done since the second executeQuery should work
1922
//if (stmt.state != DRDAStatement.NOT_OPENED)
1923
//{
1924
// writeQRYPOPRM();
1925
// pkgnamcsn = null;
1926
//}
1927
//else
1928
//{
1929
stmt.setOPNQRYOptions(blksize,qryblkctl,maxblkext,outovropt,
1930                              qryrowset, qryclsimp);
1931        //}
1932

1933        // read the command objects
1934
// for ps with parameter
1935
if (reader.isChainedWithSameID())
1936        {
1937            if (SanityManager.DEBUG)
1938                trace("&&&&&& parsing SQLDTA");
1939            parseOPNQRYobjects(stmt);
1940        }
1941        return pkgnamcsn;
1942    }
1943    /**
1944     * Parse OPNQRY objects
1945     * Objects
1946     * TYPDEFNAM - Data type definition name - optional
1947     * TYPDEFOVR - Type defintion overrides - optional
1948     * SQLDTA- SQL Program Variable Data - optional
1949     *
1950     * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
1951     * sent with the statement. Once the statement is over, the default values
1952     * sent in the ACCRDB are once again in effect. If no values are supplied,
1953     * the values sent in the ACCRDB are used.
1954     * Objects may follow in one DSS or in several DSS chained together.
1955     *
1956     * @throws DRDAProtocolException
1957     * @throws SQLException
1958     */

1959    private void parseOPNQRYobjects(DRDAStatement stmt)
1960        throws DRDAProtocolException, SQLException JavaDoc
1961    {
1962        int codePoint;
1963        do
1964        {
1965            correlationID = reader.readDssHeader();
1966            while (reader.moreDssData())
1967            {
1968                codePoint = reader.readLengthAndCodePoint();
1969                switch(codePoint)
1970                {
1971                    // optional
1972
case CodePoint.TYPDEFNAM:
1973                        setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
1974                        break;
1975                    // optional
1976
case CodePoint.TYPDEFOVR:
1977                        parseTYPDEFOVR(stmt);
1978                        break;
1979                    // optional
1980
case CodePoint.SQLDTA:
1981                        parseSQLDTA(stmt);
1982                        break;
1983                    // optional
1984
case CodePoint.EXTDTA:
1985                        readAndSetAllExtParams(stmt, false);
1986                        break;
1987                    default:
1988                        invalidCodePoint(codePoint);
1989                }
1990            }
1991        } while (reader.isChainedWithSameID());
1992
1993    }
1994    /**
1995     * Parse OUTOVROPT - this indicates whether output description can be
1996     * overridden on just the first CNTQRY or on any CNTQRY
1997     *
1998     * @return output override option
1999     * @exception DRDAProtocolException
2000     */

2001    private int parseOUTOVROPT() throws DRDAProtocolException
2002    {
2003        checkLength(CodePoint.OUTOVROPT, 1);
2004        int outovropt = reader.readUnsignedByte();
2005        if (SanityManager.DEBUG)
2006            trace("output override option: "+outovropt);
2007        if (outovropt != CodePoint.OUTOVRFRS && outovropt != CodePoint.OUTOVRANY)
2008            invalidValue(CodePoint.OUTOVROPT);
2009        return outovropt;
2010    }
2011
2012    /**
2013     * Parse QRYBLSZ - this gives the maximum size of the query blocks that
2014     * can be returned to the requester
2015     *
2016     * @return query block size
2017     * @exception DRDAProtocolException
2018     */

2019    private int parseQRYBLKSZ() throws DRDAProtocolException
2020    {
2021        checkLength(CodePoint.QRYBLKSZ, 4);
2022        int blksize = reader.readNetworkInt();
2023        if (SanityManager.DEBUG)
2024            trace("qryblksz = "+blksize);
2025        if (blksize < CodePoint.QRYBLKSZ_MIN || blksize > CodePoint.QRYBLKSZ_MAX)
2026            invalidValue(CodePoint.QRYBLKSZ);
2027        return blksize;
2028    }
2029    /**
2030     * Parse QRYROWSET - this is the number of rows to return
2031     *
2032     * @param minVal - minimum value
2033     * @return query row set size
2034     * @exception DRDAProtocolException
2035     */

2036    private int parseQRYROWSET(int minVal) throws DRDAProtocolException
2037    {
2038        checkLength(CodePoint.QRYROWSET, 4);
2039        int qryrowset = reader.readNetworkInt();
2040        if (SanityManager.DEBUG)
2041            trace("qryrowset = " + qryrowset);
2042        if (qryrowset < minVal || qryrowset > CodePoint.QRYROWSET_MAX)
2043            invalidValue(CodePoint.QRYROWSET);
2044        return qryrowset;
2045    }
2046
2047    /** Parse a QRYCLSIMP - Implicitly close non-scrollable cursor
2048     * after end of data.
2049     * @return true to close on end of data
2050     */

2051    private int parseQRYCLSIMP() throws DRDAProtocolException
2052    {
2053       
2054        checkLength(CodePoint.QRYCLSIMP, 1);
2055        int qryclsimp = reader.readUnsignedByte();
2056        if (SanityManager.DEBUG)
2057            trace ("qryclsimp = " + qryclsimp);
2058        if (qryclsimp != CodePoint.QRYCLSIMP_SERVER_CHOICE &&
2059            qryclsimp != CodePoint.QRYCLSIMP_YES &&
2060            qryclsimp != CodePoint.QRYCLSIMP_NO )
2061            invalidValue(CodePoint.QRYCLSIMP);
2062        return qryclsimp;
2063    }
2064
2065
2066    private int parseQRYCLSRLS() throws DRDAProtocolException
2067    {
2068        reader.skipBytes();
2069        return 0;
2070    }
2071
2072    /**
2073     * Write a QRYPOPRM - Query Previously opened
2074     * Instance Variables
2075     * SVRCOD - Severity Code - required - 8 ERROR
2076     * RDBNAM - Relational Database Name - required
2077     * PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
2078     *
2079     * @exception DRDAProtocolException
2080     */

2081    private void writeQRYPOPRM() throws DRDAProtocolException
2082    {
2083        writer.createDssReply();
2084        writer.startDdm(CodePoint.QRYPOPRM);
2085        writer.writeScalar2Bytes(CodePoint.SVRCOD, CodePoint.SVRCOD_ERROR);
2086        writeRDBNAM(database.dbName);
2087        writePKGNAMCSN();
2088        writer.endDdmAndDss();
2089    }
2090    /**
2091     * Write a QRYNOPRM - Query Not Opened
2092     * Instance Variables
2093     * SVRCOD - Severity Code - required - 4 Warning 8 ERROR
2094     * RDBNAM - Relational Database Name - required
2095     * PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
2096     *
2097     * @param svrCod Severity Code
2098     * @exception DRDAProtocolException
2099     */

2100    private void writeQRYNOPRM(int svrCod) throws DRDAProtocolException
2101    {
2102        writer.createDssReply();
2103        writer.startDdm(CodePoint.QRYNOPRM);
2104        writer.writeScalar2Bytes(CodePoint.SVRCOD, svrCod);
2105        writeRDBNAM(database.dbName);
2106        writePKGNAMCSN();
2107        writer.endDdmAndDss();
2108    }
2109    /**
2110     * Write a OPNQFLRM - Open Query Failure
2111     * Instance Variables
2112     * SVRCOD - Severity Code - required - 8 ERROR
2113     * RDBNAM - Relational Database Name - required
2114     *
2115     * @param e Exception describing failure
2116     *
2117     * @exception DRDAProtocolException
2118     */

2119    private void writeOPNQFLRM(SQLException JavaDoc e) throws DRDAProtocolException
2120    {
2121        writer.createDssReply();
2122        writer.startDdm(CodePoint.OPNQFLRM);
2123        writer.writeScalar2Bytes(CodePoint.SVRCOD, CodePoint.SVRCOD_ERROR);
2124        writeRDBNAM(database.dbName);
2125        writer.endDdm();
2126        writer.startDdm(CodePoint.SQLCARD);
2127        writeSQLCAGRP(e, getSqlCode(getExceptionSeverity(e)), 0, 0);
2128        writer.endDdmAndDss();
2129    }
2130    /**
2131     * Write PKGNAMCSN
2132     * Instance Variables
2133     * NAMESYMDR - database name - not validated
2134     * RDBCOLID - RDB Collection Identifier
2135     * PKGID - RDB Package Identifier
2136     * PKGCNSTKN - RDB Package Consistency Token
2137     * PKGSN - RDB Package Section Number
2138     *
2139     * There are two possible formats, fixed and extended which includes length
2140     * information for the strings
2141     *
2142     * @throws DRDAProtocolException
2143     */

2144    private void writePKGNAMCSN(byte[] pkgcnstkn) throws DRDAProtocolException
2145    {
2146        writer.startDdm(CodePoint.PKGNAMCSN);
2147        if (rdbnam.length() <= CodePoint.RDBNAM_LEN &&
2148            rdbcolid.length() <= CodePoint.RDBCOLID_LEN &&
2149            pkgid.length() <= CodePoint.PKGID_LEN)
2150        { // if none of RDBNAM, RDBCOLID and PKGID have a length of
2151
// more than 18, use fixed format
2152
writer.writeScalarPaddedString(rdbnam, CodePoint.RDBNAM_LEN);
2153            writer.writeScalarPaddedString(rdbcolid, CodePoint.RDBCOLID_LEN);
2154            writer.writeScalarPaddedString(pkgid, CodePoint.PKGID_LEN);
2155            writer.writeScalarPaddedBytes(pkgcnstkn,
2156                                          CodePoint.PKGCNSTKN_LEN, (byte) 0);
2157            writer.writeShort(pkgsn);
2158        }
2159        else // extended format
2160
{
2161            int len = Math.max(CodePoint.RDBNAM_LEN, rdbnam.length());
2162            writer.writeShort(len);
2163            writer.writeScalarPaddedString(rdbnam, len);
2164            len = Math.max(CodePoint.RDBCOLID_LEN, rdbcolid.length());
2165            writer.writeShort(len);
2166            writer.writeScalarPaddedString(rdbcolid, len);
2167            len = Math.max(CodePoint.PKGID_LEN, pkgid.length());
2168            writer.writeShort(len);
2169            writer.writeScalarPaddedString(pkgid, len);
2170            writer.writeScalarPaddedBytes(pkgcnstkn,
2171                                          CodePoint.PKGCNSTKN_LEN, (byte) 0);
2172            writer.writeShort(pkgsn);
2173        }
2174        writer.endDdm();
2175    }
2176
2177    private void writePKGNAMCSN() throws DRDAProtocolException
2178    {
2179        writePKGNAMCSN(pkgcnstkn.getBytes());
2180    }
2181
2182    /**
2183     * Parse CNTQRY - Continue Query
2184     * Instance Variables
2185     * RDBNAM - Relational Database Name - optional
2186     * PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
2187     * QRYBLKSZ - Query Block Size - required
2188     * QRYRELSCR - Query Relative Scrolling Action - optional
2189     * QRYSCRORN - Query Scroll Orientation - optional - level 7
2190     * QRYROWNBR - Query Row Number - optional
2191     * QRYROWSNS - Query Row Sensitivity - optional - level 7
2192     * QRYBLKRST - Query Block Reset - optional - level 7
2193     * QRYRTNDTA - Query Returns Data - optional - level 7
2194     * QRYROWSET - Query Rowset Size - optional - level 7
2195     * QRYRFRTBL - Query Refresh Answer Set Table - optional
2196     * NBRROW - Number of Fetch or Insert Rows - optional
2197     * MAXBLKEXT - Maximum number of extra blocks - optional
2198     * RTNEXTDTA - Return of EXTDTA Option - optional
2199     * MONITOR - Monitor events - optional.
2200     *
2201     * @return DRDAStatement we are continuing
2202     * @throws DRDAProtocolException
2203     * @throws SQLException
2204     */

2205    private DRDAStatement parseCNTQRY() throws DRDAProtocolException, SQLException JavaDoc
2206    {
2207        byte val;
2208        Pkgnamcsn pkgnamcsn = null;
2209        boolean gotQryblksz = false;
2210        boolean qryrelscr = true;
2211        long qryrownbr = 1;
2212        boolean qryrfrtbl = false;
2213        int nbrrow = 1;
2214        int blksize = 0;
2215        int maxblkext = -1;
2216        long qryinsid;
2217        boolean gotQryinsid = false;
2218        int qryscrorn = CodePoint.QRYSCRREL;
2219        boolean qryrowsns = false;
2220        boolean gotQryrowsns = false;
2221        boolean qryblkrst = false;
2222        boolean qryrtndta = true;
2223        int qryrowset = CodePoint.QRYROWSET_DEFAULT;
2224        int rtnextdta = CodePoint.RTNEXTROW;
2225        reader.markCollection();
2226        int codePoint = reader.getCodePoint();
2227        while (codePoint != -1)
2228        {
2229            switch(codePoint)
2230            {
2231                //optional
2232
case CodePoint.RDBNAM:
2233                    setDatabase(CodePoint.CNTQRY);
2234                    break;
2235                //required
2236
case CodePoint.PKGNAMCSN:
2237                    pkgnamcsn = parsePKGNAMCSN();
2238                    break;
2239                //required
2240
case CodePoint.QRYBLKSZ:
2241                    blksize = parseQRYBLKSZ();
2242                    gotQryblksz = true;
2243                    break;
2244                //optional
2245
case CodePoint.QRYRELSCR:
2246                    qryrelscr = readBoolean(CodePoint.QRYRELSCR);
2247                    if (SanityManager.DEBUG)
2248                        trace("qryrelscr = "+qryrelscr);
2249                    break;
2250                //optional
2251
case CodePoint.QRYSCRORN:
2252                    checkLength(CodePoint.QRYSCRORN, 1);
2253                    qryscrorn = reader.readUnsignedByte();
2254                    if (SanityManager.DEBUG)
2255                        trace("qryscrorn = "+qryscrorn);
2256                    switch (qryscrorn)
2257                    {
2258                        case CodePoint.QRYSCRREL:
2259                        case CodePoint.QRYSCRABS:
2260                        case CodePoint.QRYSCRAFT:
2261                        case CodePoint.QRYSCRBEF:
2262                            break;
2263                        default:
2264                            invalidValue(CodePoint.QRYSCRORN);
2265                    }
2266                    break;
2267                //optional
2268
case CodePoint.QRYROWNBR:
2269                    checkLength(CodePoint.QRYROWNBR, 8);
2270                    qryrownbr = reader.readNetworkLong();
2271                    if (SanityManager.DEBUG)
2272                        trace("qryrownbr = "+qryrownbr);
2273                    break;
2274                //optional
2275
case CodePoint.QRYROWSNS:
2276                    checkLength(CodePoint.QRYROWSNS, 1);
2277                    qryrowsns = readBoolean(CodePoint.QRYROWSNS);
2278                    if (SanityManager.DEBUG)
2279                        trace("qryrowsns = "+qryrowsns);
2280                    gotQryrowsns = true;
2281                    break;
2282                //optional
2283
case CodePoint.QRYBLKRST:
2284                    checkLength(CodePoint.QRYBLKRST, 1);
2285                    qryblkrst = readBoolean(CodePoint.QRYBLKRST);
2286                    if (SanityManager.DEBUG)
2287                        trace("qryblkrst = "+qryblkrst);
2288                    break;
2289                //optional
2290
case CodePoint.QRYRTNDTA:
2291                    qryrtndta = readBoolean(CodePoint.QRYRTNDTA);
2292                    if (SanityManager.DEBUG)
2293                        trace("qryrtndta = "+qryrtndta);
2294                    break;
2295                //optional
2296
case CodePoint.QRYROWSET:
2297                    //Note minimum for CNTQRY is 1
2298
qryrowset = parseQRYROWSET(1);
2299                    if (SanityManager.DEBUG)
2300                        trace("qryrowset = "+qryrowset);
2301                    break;
2302                //optional
2303
case CodePoint.QRYRFRTBL:
2304                    qryrfrtbl = readBoolean(CodePoint.QRYRFRTBL);
2305                    if (SanityManager.DEBUG)
2306                        trace("qryrfrtbl = "+qryrfrtbl);
2307                    break;
2308                //optional
2309
case CodePoint.NBRROW:
2310                    checkLength(CodePoint.NBRROW, 4);
2311                    nbrrow = reader.readNetworkInt();
2312                    if (SanityManager.DEBUG)
2313                        trace("nbrrow = "+nbrrow);
2314                    break;
2315                //optional
2316
case CodePoint.MAXBLKEXT:
2317                    checkLength(CodePoint.MAXBLKEXT, 2);
2318                    maxblkext = reader.readSignedNetworkShort();
2319                    if (SanityManager.DEBUG)
2320                        trace("maxblkext = "+maxblkext);
2321                    break;
2322                //optional
2323
case CodePoint.RTNEXTDTA:
2324                    checkLength(CodePoint.RTNEXTDTA, 1);
2325                    rtnextdta = reader.readUnsignedByte();
2326                    if (rtnextdta != CodePoint.RTNEXTROW &&
2327                            rtnextdta != CodePoint.RTNEXTALL)
2328                        invalidValue(CodePoint.RTNEXTDTA);
2329                    if (SanityManager.DEBUG)
2330                        trace("rtnextdta = "+rtnextdta);
2331                    break;
2332                // required for SQLAM >= 7
2333
case CodePoint.QRYINSID:
2334                    checkLength(CodePoint.QRYINSID, 8);
2335                    qryinsid = reader.readNetworkLong();
2336                    gotQryinsid = true;
2337                    if (SanityManager.DEBUG)
2338                        trace("qryinsid = "+qryinsid);
2339                    break;
2340                // optional
2341
case CodePoint.MONITOR:
2342                    parseMONITOR();
2343                    break;
2344                default:
2345                    invalidCodePoint(codePoint);
2346            }
2347            codePoint = reader.getCodePoint();
2348        }
2349        // check for required variables
2350
if (pkgnamcsn == null)
2351            missingCodePoint(CodePoint.PKGNAMCSN);
2352        if (!gotQryblksz)
2353            missingCodePoint(CodePoint.QRYBLKSZ);
2354        if (sqlamLevel >= MGRLVL_7 && !gotQryinsid)
2355            missingCodePoint(CodePoint.QRYINSID);
2356
2357        // get the statement we are continuing
2358
DRDAStatement stmt = database.getDRDAStatement(pkgnamcsn);
2359        if (stmt == null)
2360        {
2361            //XXX should really throw a SQL Exception here
2362
invalidValue(CodePoint.CNTQRY);
2363        }
2364
2365        if (stmt.rsIsClosed())
2366        {
2367            writeQRYNOPRM(CodePoint.SVRCOD_ERROR);
2368            skipRemainder(true);
2369            return null;
2370        }
2371        stmt.setQueryOptions(blksize,qryrelscr,qryrownbr,qryrfrtbl,nbrrow,maxblkext,
2372                         qryscrorn,qryrowsns,qryblkrst,qryrtndta,qryrowset,
2373                         rtnextdta);
2374
2375        if (reader.isChainedWithSameID())
2376            parseCNTQRYobjects(stmt);
2377        return stmt;
2378    }
2379    /**
2380     * Skip remainder of current DSS and all chained DSS'es
2381     *
2382     * @param onlySkipSameIds True if we _only_ want to skip DSS'es
2383     * that are chained with the SAME id as the current DSS.
2384     * False means skip ALL chained DSSes, whether they're
2385     * chained with same or different ids.
2386     * @exception DRDAProtocolException
2387     */

2388    private void skipRemainder(boolean onlySkipSameIds) throws DRDAProtocolException
2389    {
2390        reader.skipDss();
2391        while (reader.isChainedWithSameID() ||
2392            (!onlySkipSameIds && reader.isChainedWithDiffID()))
2393        {
2394            reader.readDssHeader();
2395            reader.skipDss();
2396        }
2397    }
2398    /**
2399     * Parse CNTQRY objects
2400     * Instance Variables
2401     * OUTOVR - Output Override Descriptor - optional
2402     *
2403     * @param stmt DRDA statement we are working on
2404     * @exception DRDAProtocolException
2405     */

2406    private void parseCNTQRYobjects(DRDAStatement stmt) throws DRDAProtocolException, SQLException JavaDoc
2407    {
2408        int codePoint;
2409        do
2410        {
2411            correlationID = reader.readDssHeader();
2412            while (reader.moreDssData())
2413            {
2414                codePoint = reader.readLengthAndCodePoint();
2415                switch(codePoint)
2416                {
2417                    // optional
2418
case CodePoint.OUTOVR:
2419                        parseOUTOVR(stmt);
2420                        break;
2421                    default:
2422                        invalidCodePoint(codePoint);
2423                }
2424            }
2425        } while (reader.isChainedWithSameID());
2426
2427    }
2428    /**
2429     * Parse OUTOVR - Output Override Descriptor
2430     * This specifies the output format for data to be returned as output to a SQL
2431     * statement or as output from a query.
2432     *
2433     * @param stmt DRDA statement this applies to
2434     * @exception DRDAProtocolException
2435     */

2436    private void parseOUTOVR(DRDAStatement stmt) throws DRDAProtocolException, SQLException JavaDoc
2437    {
2438        boolean first = true;
2439        int numVars;
2440        int dtaGrpLen;
2441        int tripType;
2442        int tripId;
2443        int precision;
2444        int start = 0;
2445        while (true)
2446        {
2447            dtaGrpLen = reader.readUnsignedByte();
2448            tripType = reader.readUnsignedByte();
2449            tripId = reader.readUnsignedByte();
2450            // check if we have reached the end of the data
2451
if (tripType == FdocaConstants.RLO_TRIPLET_TYPE)
2452            {
2453                //read last part of footer
2454
reader.skipBytes();
2455                break;
2456            }
2457            numVars = (dtaGrpLen - 3) / 3;
2458            if (SanityManager.DEBUG)
2459                trace("num of vars is: "+numVars);
2460            int[] outovr_drdaType = null;
2461            if (first)
2462            {
2463                outovr_drdaType = new int[numVars];
2464                first = false;
2465            }
2466            else
2467            {
2468                int[] oldoutovr_drdaType = stmt.getOutovr_drdaType();
2469                int oldlen = oldoutovr_drdaType.length;
2470                // create new array and copy over already read stuff
2471
outovr_drdaType = new int[oldlen + numVars];
2472                System.arraycopy(oldoutovr_drdaType, 0,
2473                                 outovr_drdaType,0,
2474                                 oldlen);
2475                start = oldlen;
2476            }
2477            for (int i = start; i < numVars + start; i++)
2478            {
2479                outovr_drdaType[i] = reader.readUnsignedByte();
2480                if (SanityManager.DEBUG)
2481                    trace("drdaType is: "+ outovr_drdaType[i]);
2482                precision = reader.readNetworkShort();
2483                if (SanityManager.DEBUG)
2484                    trace("drdaLength is: "+precision);
2485                outovr_drdaType[i] |= (precision << 8);
2486            }
2487            stmt.setOutovr_drdaType(outovr_drdaType);
2488        }
2489    }
2490
2491    /**
2492     * Write OPNQRYRM - Open Query Complete
2493     * Instance Variables
2494     * SVRCOD - Severity Code - required
2495     * QRYPRCTYP - Query Protocol Type - required
2496     * SQLCSRHLD - Hold Cursor Position - optional
2497     * QRYATTSCR - Query Attribute for Scrollability - optional - level 7
2498     * QRYATTSNS - Query Attribute for Sensitivity - optional - level 7
2499     * QRYATTUPD - Query Attribute for Updatability -optional - level 7
2500     * QRYINSID - Query Instance Identifier - required - level 7
2501     * SRVDGN - Server Diagnostic Information - optional
2502     *
2503     * @param isDssObject - return as a DSS object (part of a reply)
2504     * @param stmt - DRDA statement we are processing
2505     *
2506     * @exception DRDAProtocolException
2507     */

2508    private void writeOPNQRYRM(boolean isDssObject, DRDAStatement stmt)
2509        throws DRDAProtocolException, SQLException JavaDoc
2510    {
2511        if (SanityManager.DEBUG)
2512            trace("WriteOPNQRYRM");
2513
2514        if (isDssObject)
2515            writer.createDssObject();
2516        else
2517            writer.createDssReply();
2518        writer.startDdm(CodePoint.OPNQRYRM);
2519        writer.writeScalar2Bytes(CodePoint.SVRCOD,CodePoint.SVRCOD_INFO);
2520
2521        // There is currently a problem specifying LMTBLKPRC for LOBs with JCC
2522
// JCC will throw an ArrayOutOfBounds exception. Once this is fixed, we
2523
// don't need to pass the two arguments for getQryprctyp.
2524
int prcType = stmt.getQryprctyp();
2525        if (SanityManager.DEBUG)
2526            trace("sending QRYPRCTYP: " + prcType);
2527        writer.writeScalar2Bytes(CodePoint.QRYPRCTYP, prcType);
2528
2529        //pass the SQLCSRHLD codepoint only if statement producing the ResultSet has
2530
//hold cursors over commit set. In case of stored procedures which use server-side
2531
//JDBC, the holdability of the ResultSet will be the holdability of the statement
2532
//in the stored procedure, not the holdability of the calling statement.
2533
if (stmt.getCurrentDrdaResultSet().withHoldCursor == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT)
2534            writer.writeScalar1Byte(CodePoint.SQLCSRHLD, CodePoint.TRUE);
2535        if (sqlamLevel >= MGRLVL_7)
2536        {
2537            writer.writeScalarHeader(CodePoint.QRYINSID, 8);
2538            //This is implementer defined. DB2 uses this for the nesting level
2539
//of the query. A query from an application would be nesting level 0,
2540
//from a stored procedure, nesting level 1, from a recursive call of
2541
//a stored procedure, nesting level 2, etc.
2542
writer.writeInt(0);
2543            //This is a unique sequence number per session
2544
writer.writeInt(session.qryinsid++);
2545            //Write the scroll attributes if they are set
2546
if (stmt.isScrollable())
2547            {
2548                writer.writeScalar1Byte(CodePoint.QRYATTSCR, CodePoint.TRUE);
2549                if ((stmt.getConcurType() == ResultSet.CONCUR_UPDATABLE) &&
2550                        (stmt.getResultSet().getType() ==
2551                         ResultSet.TYPE_SCROLL_INSENSITIVE)) {
2552                    writer.writeScalar1Byte(CodePoint.QRYATTSNS,
2553                                            CodePoint.QRYSNSSTC);
2554                } else {
2555                    writer.writeScalar1Byte(CodePoint.QRYATTSNS,
2556                                            CodePoint.QRYINS);
2557                }
2558            }
2559            if (stmt.getConcurType() == ResultSet.CONCUR_UPDATABLE) {
2560                if (stmt.getResultSet() != null) {
2561                    // Resultset concurrency can be less than statement
2562
// concurreny if the underlying language resultset
2563
// is not updatable.
2564
if (stmt.getResultSet().getConcurrency() ==
2565                        ResultSet.CONCUR_UPDATABLE) {
2566                        writer.writeScalar1Byte(CodePoint.QRYATTUPD,
2567                                                CodePoint.QRYUPD);
2568                    } else {
2569                        writer.writeScalar1Byte(CodePoint.QRYATTUPD,
2570                                                CodePoint.QRYRDO);
2571                    }
2572                } else {
2573                    writer.writeScalar1Byte(CodePoint.QRYATTUPD,
2574                                            CodePoint.QRYUPD);
2575                }
2576            } else {
2577                writer.writeScalar1Byte(CodePoint.QRYATTUPD, CodePoint.QRYRDO);
2578            }
2579        }
2580        writer.endDdmAndDss ();
2581    }
2582    /**
2583     * Write ENDQRYRM - query process has terminated in such a manner that the
2584     * query or result set is now closed. It cannot be resumed with the CNTQRY
2585     * command or closed with the CLSQRY command
2586     * @param svrCod Severity code - WARNING or ERROR
2587     * @exception DRDAProtocolException
2588     */

2589    private void writeENDQRYRM(int svrCod) throws DRDAProtocolException
2590    {
2591        writer.createDssReply();
2592        writer.startDdm(CodePoint.ENDQRYRM);
2593        writer.writeScalar2Bytes(CodePoint.SVRCOD,svrCod);
2594        writer.endDdmAndDss();
2595    }
2596/**
2597     * Write ABNUOWRM - query process has terminated in an error condition
2598     * such as deadlock or lock timeout.
2599     * Severity code is always error
2600     * * @exception DRDAProtocolException
2601     */

2602    private void writeABNUOWRM() throws DRDAProtocolException
2603    {
2604        writer.createDssReply();
2605        writer.startDdm(CodePoint.ABNUOWRM);
2606        writer.writeScalar2Bytes(CodePoint.SVRCOD,CodePoint.SVRCOD_ERROR);
2607        writeRDBNAM(database.dbName);
2608        writer.endDdmAndDss();
2609    }
2610    /**
2611     * Parse database name
2612     *
2613     * @return database name
2614     *
2615     * @exception DRDAProtocolException
2616     */

2617    private String JavaDoc parseRDBNAM() throws DRDAProtocolException
2618    {
2619        String JavaDoc name;
2620        byte [] rdbName = reader.readBytes();
2621        if (rdbName.length == 0)
2622        {
2623            // throw RDBNFNRM
2624
rdbNotFound(null);
2625        }
2626        //SQLAM level 7 allows db name up to 255, level 6 fixed len 18
2627
if (rdbName.length < CodePoint.RDBNAM_LEN || rdbName.length > CodePoint.MAX_NAME)
2628            badObjectLength(CodePoint.RDBNAM);
2629        name = reader.convertBytes(rdbName);
2630        // trim trailing blanks from the database name
2631
name = name.trim();
2632        if (SanityManager.DEBUG)
2633            trace("RdbName " + name);
2634        return name;
2635    }
2636
2637    /**
2638     * Write ACCSECRD
2639     * If the security mechanism is known, we just send it back along with
2640     * the security token if encryption is going to be used.
2641     * If the security mechanism is not known, we send a list of the ones
2642     * we know.
2643     * Instance Variables
2644     * SECMEC - security mechanism - required
2645     * SECTKN - security token - optional (required if security mechanism
2646     * uses encryption)
2647     * SECCHKCD - security check code - error occurred in processing ACCSEC
2648     *
2649     * @param securityCheckCode
2650     *
2651     * @exception DRDAProtocolException
2652     */

2653    private void writeACCSECRD(int securityCheckCode)
2654        throws DRDAProtocolException
2655    {
2656        writer.createDssReply();
2657        writer.startDdm(CodePoint.ACCSECRD);
2658
2659        if (securityCheckCode != CodePoint.SECCHKCD_NOTSUPPORTED)
2660            writer.writeScalar2Bytes(CodePoint.SECMEC, database.securityMechanism);
2661        else
2662        {
2663            // if server doesnt recognize or allow the client requested security mechanism,
2664
// then need to return the list of security mechanisms supported/allowed by the server
2665

2666            // check if server is set to accept connections from client at a certain
2667
// security mechanism, if so send only the security mechanism that the
2668
// server will accept, to the client
2669
if ( server.getSecurityMechanism() != NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM )
2670                writer.writeScalar2Bytes(CodePoint.SECMEC, server.getSecurityMechanism());
2671            else
2672            {
2673                // note: per the DDM manual , ACCSECRD response is of
2674
// form SECMEC (value{value..})
2675
// Need to fix the below to send a list of supported security
2676
// mechanisms for value of one SECMEC codepoint (JIRA 926)
2677
// these are the ones we know about
2678
writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRIDPWD);
2679                // include EUSRIDPWD in the list of supported secmec only if
2680
// server can truely support it in the jvm that is running in
2681
if ( server.supportsEUSRIDPWD())
2682                    writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_EUSRIDPWD);
2683                writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRIDONL);
2684                writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRSSBPWD);
2685            }
2686        }
2687
2688        if (securityCheckCode != 0)
2689        {
2690            writer.writeScalar1Byte(CodePoint.SECCHKCD, securityCheckCode);
2691        }
2692        else
2693        {
2694            // we need to send back the key if encryption is being used
2695
if (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD)
2696                writer.writeScalarBytes(CodePoint.SECTKN, myPublicKey);
2697            else if (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
2698                writer.writeScalarBytes(CodePoint.SECTKN, myTargetSeed);
2699        }
2700        writer.endDdmAndDss ();
2701
2702        if (securityCheckCode != 0) {
2703        // then we have an error and so can ignore the rest of the
2704
// DSS request chain.
2705
skipRemainder(false);
2706        }
2707
2708        finalizeChain();
2709    }
2710
2711    /**
2712     * Parse security check
2713     * Instance Variables
2714     * SECMGRNM - security manager name - optional, ignorable
2715     * SECMEC - security mechanism - required
2716     * SECTKN - security token - optional, (required if encryption used)
2717     * PASSWORD - password - optional, (required if security mechanism uses it)
2718     * NEWPASSWORD - new password - optional, (required if sec mech. uses it)
2719     * USRID - user id - optional, (required if sec mec. uses it)
2720     * RDBNAM - database name - optional (required if databases can have own sec.)
2721     *
2722     *
2723     * @return security check code
2724     * @exception DRDAProtocolException
2725     */

2726    private int parseSECCHK() throws DRDAProtocolException
2727    {
2728        int codePoint, securityCheckCode = 0;
2729        int securityMechanism = 0;
2730        databaseAccessException = null;
2731        reader.markCollection();
2732        codePoint = reader.getCodePoint();
2733        while (codePoint != -1)
2734        {
2735            switch (codePoint)
2736            {
2737                //optional, ignorable
2738
case CodePoint.SECMGRNM:
2739                    reader.skipBytes();
2740                    break;
2741                //required
2742
case CodePoint.SECMEC:
2743                    checkLength(CodePoint.SECMEC, 2);
2744                    securityMechanism = reader.readNetworkShort();
2745                    if (SanityManager.DEBUG)
2746                        trace("parseSECCHK - Security mechanism = " + securityMechanism);
2747                    //RESOLVE - spec is not clear on what should happen
2748
//in this case
2749
if (securityMechanism != database.securityMechanism)
2750                        invalidValue(CodePoint.SECMEC);
2751                    break;
2752                //optional - depending on security Mechanism
2753
case CodePoint.SECTKN:
2754                    if ((database.securityMechanism !=
2755                                        CodePoint.SECMEC_EUSRIDPWD) &&
2756                        (database.securityMechanism !=
2757                                        CodePoint.SECMEC_USRSSBPWD))
2758                    {
2759                        securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
2760                        reader.skipBytes();
2761                    }
2762                    else if (database.securityMechanism ==
2763                                                CodePoint.SECMEC_EUSRIDPWD)
2764                    {
2765                        if (database.decryptedUserId == null)
2766                        {
2767                            try {
2768                                database.decryptedUserId =
2769                                    reader.readEncryptedString(
2770                                                decryptionManager,
2771                                                database.securityMechanism,
2772                                                myPublicKey,
2773                                                database.secTokenIn);
2774                            } catch (SQLException JavaDoc se) {
2775                                println2Log(database.dbName, session.drdaID,
2776                                            se.getMessage());
2777                                if (securityCheckCode == 0)
2778                                    //userid invalid
2779
securityCheckCode = CodePoint.SECCHKCD_13;
2780                            }
2781                            database.userId = database.decryptedUserId;
2782                            if (SanityManager.DEBUG)
2783                                trace("**decrypted userid is: "+database.userId);
2784                        }
2785                        else if (database.decryptedPassword == null)
2786                        {
2787                            try {
2788                                database.decryptedPassword =
2789                                    reader.readEncryptedString(
2790                                            decryptionManager,
2791                                            database.securityMechanism,
2792                                            myPublicKey,
2793                                            database.secTokenIn);
2794                            } catch (SQLException JavaDoc se) {
2795                                println2Log(database.dbName, session.drdaID,
2796                                            se.getMessage());
2797                                if (securityCheckCode == 0)
2798                                    //password invalid
2799
securityCheckCode = CodePoint.SECCHKCD_0F;
2800                            }
2801                            database.password = database.decryptedPassword;
2802                            if (SanityManager.DEBUG)
2803                                trace("**decrypted password is: " +
2804                                      database.password);
2805                        }
2806                    }
2807                    else if (database.securityMechanism ==
2808                                                CodePoint.SECMEC_USRSSBPWD)
2809                    {
2810                        if (database.passwordSubstitute == null)
2811                        {
2812                            database.passwordSubstitute = reader.readBytes();
2813                            if (SanityManager.DEBUG)
2814                                trace("** Substitute Password is:" +
2815                                      DecryptionManager.toHexString(
2816                                        database.passwordSubstitute, 0,
2817                                        database.passwordSubstitute.length));
2818                            database.password =
2819                                DecryptionManager.toHexString(
2820                                    database.passwordSubstitute, 0,
2821                                    database.passwordSubstitute.length);
2822                        }
2823                    }
2824                    else
2825                    {
2826                        tooMany(CodePoint.SECTKN);
2827                    }
2828                    break;
2829                //optional - depending on security Mechanism
2830
case CodePoint.PASSWORD:
2831                    database.password = reader.readString();
2832                    if (SanityManager.DEBUG) trace("PASSWORD " + database.password);
2833                    break;
2834                //optional - depending on security Mechanism
2835
//we are not supporting this method so we'll skip bytes
2836
case CodePoint.NEWPASSWORD:
2837                    reader.skipBytes();
2838                    break;
2839                //optional - depending on security Mechanism
2840
case CodePoint.USRID:
2841                    database.userId = reader.readString();
2842                    if (SanityManager.DEBUG) trace("USERID " + database.userId);
2843                    break;
2844                //optional - depending on security Mechanism
2845
case CodePoint.RDBNAM:
2846                    String JavaDoc dbname = parseRDBNAM();
2847                    if (database != null)
2848                    {
2849                        if (!database.dbName.equals(dbname))
2850                            rdbnamMismatch(CodePoint.SECCHK);
2851                    }
2852                    else
2853                    {
2854                        // we should already have added the database in ACCSEC
2855
// added code here in case we make the SECMEC session rather
2856
// than database wide
2857
addDatabase(dbname);
2858                    }
2859                    break;
2860                default:
2861                    invalidCodePoint(codePoint);
2862
2863            }
2864            codePoint = reader.getCodePoint();
2865        }
2866        // check for SECMEC which is required
2867
if (securityMechanism == 0)
2868            missingCodePoint(CodePoint.SECMEC);
2869
2870        //check if we have a userid and password when we need it
2871
if (securityCheckCode == 0 &&
2872           (database.securityMechanism == CodePoint.SECMEC_USRIDPWD||
2873            database.securityMechanism == CodePoint.SECMEC_USRIDONL ))
2874        {
2875            if (database.userId == null)
2876                securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
2877            else if (database.securityMechanism == CodePoint.SECMEC_USRIDPWD)
2878            {
2879                if (database.password == null)
2880                securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
2881            }
2882            //Note, we'll ignore encryptedUserId and encryptedPassword if they
2883
//are also set
2884
}
2885
2886        if (securityCheckCode == 0 &&
2887                database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
2888        {
2889            if (database.userId == null)
2890                securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
2891            else if (database.passwordSubstitute == null)
2892                securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
2893        }
2894
2895        if (securityCheckCode == 0 &&
2896                database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD)
2897        {
2898            if (database.decryptedUserId == null)
2899                securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
2900            else if (database.decryptedPassword == null)
2901                securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
2902        }
2903        // RESOLVE - when we do security we need to decrypt encrypted userid & password
2904
// before proceeding
2905

2906        // verify userid and password, if we haven't had any errors thus far.
2907
if ((securityCheckCode == 0) && (databaseAccessException == null))
2908        {
2909            securityCheckCode = verifyUserIdPassword();
2910        }
2911
2912        // Security all checked
2913
if (securityCheckCode == 0)
2914            session.setState(session.CHKSEC);
2915        
2916        return securityCheckCode;
2917
2918    }
2919    /**
2920     * Write security check reply
2921     * Instance variables
2922     * SVRCOD - serverity code - required
2923     * SECCHKCD - security check code - required
2924     * SECTKN - security token - optional, ignorable
2925     * SVCERRNO - security service error number
2926     * SRVDGN - Server Diagnostic Information
2927     *
2928     * @exception DRDAProtocolException
2929     */

2930    private void writeSECCHKRM(int securityCheckCode) throws DRDAProtocolException
2931    {
2932        writer.createDssReply();
2933        writer.startDdm(CodePoint.SECCHKRM);
2934        writer.writeScalar2Bytes(CodePoint.SVRCOD, svrcodFromSecchkcd(securityCheckCode));
2935        writer.writeScalar1Byte(CodePoint.SECCHKCD, securityCheckCode);
2936        writer.endDdmAndDss ();
2937
2938        if (securityCheckCode != 0) {
2939        // then we have an error and are going to end up ignoring the rest
2940
// of the DSS request chain.
2941
skipRemainder(false);
2942        }
2943
2944        finalizeChain();
2945
2946    }
2947    /**
2948     * Calculate SVRCOD value from SECCHKCD
2949     *
2950     * @param securityCheckCode
2951     * @return SVRCOD value
2952     */

2953    private int svrcodFromSecchkcd(int securityCheckCode)
2954    {
2955        if (securityCheckCode == 0 || securityCheckCode == 2 ||
2956            securityCheckCode == 5 || securityCheckCode == 8)
2957            return CodePoint.SVRCOD_INFO;
2958        else
2959            return CodePoint.SVRCOD_ERROR;
2960    }
2961    /**
2962     * Parse access RDB
2963     * Instance variables
2964     * RDBACCCL - RDB Access Manager Class - required must be SQLAM
2965     * CRRTKN - Correlation Token - required
2966     * RDBNAM - Relational database name -required
2967     * PRDID - Product specific identifier - required
2968     * TYPDEFNAM - Data Type Definition Name -required
2969     * TYPDEFOVR - Type definition overrides -required
2970     * RDBALWUPD - RDB Allow Updates optional
2971     * PRDDTA - Product Specific Data - optional - ignorable
2972     * STTDECDEL - Statement Decimal Delimiter - optional
2973     * STTSTRDEL - Statement String Delimiter - optional
2974     * TRGDFTRT - Target Default Value Return - optional
2975     *
2976     * @return severity code
2977     *
2978     * @exception DRDAProtocolException
2979     */

2980    private int parseACCRDB() throws DRDAProtocolException
2981    {
2982        int codePoint;
2983        int svrcod = 0;
2984        copyToRequired(ACCRDB_REQUIRED);
2985        reader.markCollection();
2986        codePoint = reader.getCodePoint();
2987        while (codePoint != -1)
2988        {
2989            switch (codePoint)
2990            {
2991                //required
2992
case CodePoint.RDBACCCL:
2993                    checkLength(CodePoint.RDBACCCL, 2);
2994                    int sqlam = reader.readNetworkShort();
2995                    if (SanityManager.DEBUG)
2996                        trace("RDBACCCL = " + sqlam);
2997                    // required to be SQLAM
2998

2999                    if (sqlam != CodePoint.SQLAM)
3000                        invalidValue(CodePoint.RDBACCCL);
3001                    removeFromRequired(CodePoint.RDBACCCL);
3002                    break;
3003                //required
3004
case CodePoint.CRRTKN:
3005                    database.crrtkn = reader.readBytes();
3006                    if (SanityManager.DEBUG)
3007                        trace("crrtkn " + convertToHexString(database.crrtkn));
3008                    removeFromRequired(CodePoint.CRRTKN);
3009                    int l = database.crrtkn.length;
3010                    if (l > CodePoint.MAX_NAME)
3011                        tooBig(CodePoint.CRRTKN);
3012                    // the format of the CRRTKN is defined in the DRDA reference
3013
// x.yz where x is 1 to 8 bytes (variable)
3014
// y is 1 to 8 bytes (variable)
3015
// x is 6 bytes fixed
3016
// size is variable between 9 and 23
3017
if (l < 9 || l > 23)
3018                        invalidValue(CodePoint.CRRTKN);
3019                    byte[] part1 = new byte[l - 6];
3020                    for (int i = 0; i < part1.length; i++)
3021                        part1[i] = database.crrtkn[i];
3022                    long time = SignedBinary.getLong(database.crrtkn,
3023                            l-8, SignedBinary.BIG_ENDIAN); // as "long" as unique
3024
session.drdaID = reader.convertBytes(part1) +
3025                                    time + leftBrace + session.connNum + rightBrace;
3026                    if (SanityManager.DEBUG)
3027                        trace("******************************************drdaID is: " + session.drdaID);
3028                    database.setDrdaID(session.drdaID);
3029    
3030                    break;
3031                //required
3032
case CodePoint.RDBNAM:
3033                    String JavaDoc dbname = parseRDBNAM();
3034                    if (database != null)
3035                    {
3036                        if (!database.dbName.equals(dbname))
3037                            rdbnamMismatch(CodePoint.ACCRDB);
3038                    }
3039                    else
3040                    {
3041                        //first time we have seen a database name
3042
Database d = session.getDatabase(dbname);
3043                        if (d == null)
3044                            addDatabase(dbname);
3045                        else
3046                        {
3047                            database = d;
3048                            database.accessCount++;
3049                        }
3050                    }
3051                    removeFromRequired(CodePoint.RDBNAM);
3052                    break;
3053                //required
3054
case CodePoint.PRDID:
3055                    appRequester.setClientVersion(reader.readString());
3056                    if (SanityManager.DEBUG)
3057                        trace("prdId " + appRequester.prdid);
3058                    if (appRequester.prdid.length() > CodePoint.PRDID_MAX)
3059                        tooBig(CodePoint.PRDID);
3060
3061                    /* If JCC version is 1.5 or later, send SQLWarning on CNTQRY */
3062                    if (((appRequester.getClientType() == appRequester.JCC_CLIENT) &&
3063                        (appRequester.greaterThanOrEqualTo(1, 5, 0))) ||
3064                       (appRequester.getClientType() == appRequester.DNC_CLIENT))
3065                    {
3066                        sendWarningsOnCNTQRY = true;
3067                    }
3068                    else sendWarningsOnCNTQRY = false;
3069
3070                    // The client can not request DIAGLVL because when run with
3071
// an older server it will cause an exception. Older version
3072
// of the server do not recognize requests for DIAGLVL.
3073
if ((appRequester.getClientType() == appRequester.DNC_CLIENT) &&
3074                            appRequester.greaterThanOrEqualTo(10, 2, 0)) {
3075                        diagnosticLevel = CodePoint.DIAGLVL1;
3076                    }
3077
3078                    removeFromRequired(CodePoint.PRDID);
3079                    break;
3080                //required
3081
case CodePoint.TYPDEFNAM:
3082                    setStmtOrDbByteOrder(true, null, parseTYPDEFNAM());
3083                    removeFromRequired(CodePoint.TYPDEFNAM);
3084                    break;
3085                //required
3086
case CodePoint.TYPDEFOVR:
3087                    parseTYPDEFOVR(null);
3088                    removeFromRequired(CodePoint.TYPDEFOVR);
3089                    break;
3090                //optional
3091
case CodePoint.RDBALWUPD:
3092                    checkLength(CodePoint.RDBALWUPD, 1);
3093                    database.rdbAllowUpdates = readBoolean(CodePoint.RDBALWUPD);
3094                    if (SanityManager.DEBUG)
3095                        trace("rdbAllowUpdates = "+database.rdbAllowUpdates);
3096                    break;
3097                //optional, ignorable
3098
case CodePoint.PRDDTA:
3099                    // check that it fits in maximum but otherwise ignore for now
3100
if (reader.getDdmLength() > CodePoint.MAX_NAME)
3101                        tooBig(CodePoint.PRDDTA);
3102                    reader.skipBytes();
3103                    break;
3104                case CodePoint.TRGDFTRT:
3105                    byte b = reader.readByte();
3106                    if (b == 0xF1)
3107                        database.sendTRGDFTRT = true;
3108                    break;
3109                //optional - not used in JCC so skip for now
3110
case CodePoint.STTDECDEL:
3111                case CodePoint.STTSTRDEL:
3112                    codePointNotSupported(codePoint);
3113                    break;
3114                default:
3115                    invalidCodePoint(codePoint);
3116            }
3117            codePoint = reader.getCodePoint();
3118        }
3119        checkRequired(CodePoint.ACCRDB);
3120        // check that we can support the double-byte and mixed-byte CCSIDS
3121
// set svrcod to warning if they are not supported
3122
if ((database.ccsidDBC != 0 && !server.supportsCCSID(database.ccsidDBC)) ||
3123                (database.ccsidMBC != 0 && !server.supportsCCSID(database.ccsidMBC)))
3124            svrcod = CodePoint.SVRCOD_WARNING;
3125        return svrcod;
3126    }
3127    /**
3128     * Parse TYPDEFNAM
3129     *
3130     * @return typdefnam
3131     * @exception DRDAProtocolException
3132     */

3133    private String JavaDoc parseTYPDEFNAM() throws DRDAProtocolException
3134    {
3135        String JavaDoc typDefNam = reader.readString();
3136        if (SanityManager.DEBUG) trace("typeDefName " + typDefNam);
3137        if (typDefNam.length() > CodePoint.MAX_NAME)
3138            tooBig(CodePoint.TYPDEFNAM);
3139        checkValidTypDefNam(typDefNam);
3140        // check if the typedef is one we support
3141
if (!typDefNam.equals(CodePoint.TYPDEFNAM_QTDSQLASC) &&
3142            !typDefNam.equals(CodePoint.TYPDEFNAM_QTDSQLJVM) &&
3143            !typDefNam.equals(CodePoint.TYPDEFNAM_QTDSQLX86))
3144            valueNotSupported(CodePoint.TYPDEFNAM);
3145        return typDefNam;
3146    }
3147
3148    /**
3149     * Set a statement or the database' byte order, depending on the arguments
3150     *
3151     * @param setDatabase if true, set database' byte order, otherwise set statement's
3152     * @param stmt DRDAStatement, used when setDatabase is false
3153     * @param typDefNam TYPDEFNAM value
3154     */

3155    private void setStmtOrDbByteOrder(boolean setDatabase, DRDAStatement stmt, String JavaDoc typDefNam)
3156    {
3157        int byteOrder = (typDefNam.equals(CodePoint.TYPDEFNAM_QTDSQLX86) ?
3158                            SignedBinary.LITTLE_ENDIAN : SignedBinary.BIG_ENDIAN);
3159        if (setDatabase)
3160        {
3161            database.typDefNam = typDefNam;
3162            database.byteOrder = byteOrder;
3163        }
3164        else
3165        {
3166            stmt.typDefNam = typDefNam;
3167            stmt.byteOrder = byteOrder;
3168        }
3169    }
3170
3171    /**
3172     * Write Access to RDB Completed
3173     * Instance Variables
3174     * SVRCOD - severity code - 0 info, 4 warning -required
3175     * PRDID - product specific identifier -required
3176     * TYPDEFNAM - type definition name -required
3177     * TYPDEFOVR - type definition overrides - required
3178     * RDBINTTKN - token which can be used to interrupt DDM commands - optional
3179     * CRRTKN - correlation token - only returned if we didn't get one from requester
3180     * SRVDGN - server diagnostic information - optional
3181     * PKGDFTCST - package default character subtype - optional
3182     * USRID - User ID at the target system - optional
3183     * SRVLST - Server List
3184     *
3185     * @exception DRDAProtocolException
3186     */

3187    private void writeACCRDBRM(int svrcod) throws DRDAProtocolException
3188    {
3189        writer.createDssReply();
3190        writer.startDdm(CodePoint.ACCRDBRM);
3191        writer.writeScalar2Bytes(CodePoint.SVRCOD, svrcod);
3192        writer.writeScalarString(CodePoint.PRDID, server.prdId);
3193        //TYPDEFNAM -required - JCC doesn't support QTDSQLJVM so for now we
3194
// just use ASCII, though we should eventually be able to use QTDSQLJVM
3195
// at level 7
3196
writer.writeScalarString(CodePoint.TYPDEFNAM,
3197                                 CodePoint.TYPDEFNAM_QTDSQLASC);
3198        writeTYPDEFOVR();
3199        writer.endDdmAndDss ();
3200        finalizeChain();
3201    }
3202    
3203    private void writeTYPDEFOVR() throws DRDAProtocolException
3204    {
3205        //TYPDEFOVR - required - only single byte and mixed byte are specified
3206
writer.startDdm(CodePoint.TYPDEFOVR);
3207        writer.writeScalar2Bytes(CodePoint.CCSIDSBC, server.CCSIDSBC);
3208        writer.writeScalar2Bytes(CodePoint.CCSIDMBC, server.CCSIDMBC);
3209        // PKGDFTCST - Send character subtype and userid if requested
3210
if (database.sendTRGDFTRT)
3211        {
3212            // default to multibyte character
3213
writer.startDdm(CodePoint.PKGDFTCST);
3214            writer.writeShort(CodePoint.CSTMBCS);
3215            writer.endDdm();
3216            // userid
3217
writer.startDdm(CodePoint.USRID);
3218            writer.writeString(database.userId);
3219            writer.endDdm();
3220        }
3221        writer.endDdm();
3222
3223    }
3224    
3225    /**
3226     * Parse Type Defintion Overrides
3227     * TYPDEF Overrides specifies the Coded Character SET Identifiers (CCSIDs)
3228     * that are in a named TYPDEF.
3229     * Instance Variables
3230     * CCSIDSBC - CCSID for Single-Byte - optional
3231     * CCSIDDBC - CCSID for Double-Byte - optional
3232     * CCSIDMBC - CCSID for Mixed-byte characters -optional
3233     *
3234     * @param st Statement this TYPDEFOVR applies to
3235     *
3236     * @exception DRDAProtocolException
3237     */

3238    private void parseTYPDEFOVR(DRDAStatement st) throws DRDAProtocolException
3239    {
3240        int codePoint;
3241        int ccsidSBC = 0;
3242        int ccsidDBC = 0;
3243        int ccsidMBC = 0;
3244        String JavaDoc ccsidSBCEncoding = null;
3245        String JavaDoc ccsidDBCEncoding = null;
3246        String JavaDoc ccsidMBCEncoding = null;
3247
3248        reader.markCollection();
3249
3250        codePoint = reader.getCodePoint();
3251        // at least one of the following instance variable is required
3252
// if the TYPDEFOVR is specified in a command object
3253
if (codePoint == -1 && st != null)
3254            missingCodePoint(CodePoint.CCSIDSBC);
3255
3256        while (codePoint != -1)
3257        {
3258            switch (codePoint)
3259            {
3260                case CodePoint.CCSIDSBC:
3261                    checkLength(CodePoint.CCSIDSBC, 2);
3262                    ccsidSBC = reader.readNetworkShort();
3263                    try {
3264                        ccsidSBCEncoding =
3265                            CharacterEncodings.getJavaEncoding(ccsidSBC);
3266                    } catch (Exception JavaDoc e) {
3267                        valueNotSupported(CodePoint.CCSIDSBC);
3268                    }
3269                    if (SanityManager.DEBUG)
3270                        trace("ccsidsbc = " + ccsidSBC + " encoding = " + ccsidSBCEncoding);
3271                    break;
3272                case CodePoint.CCSIDDBC:
3273                    checkLength(CodePoint.CCSIDDBC, 2);
3274                    ccsidDBC = reader.readNetworkShort();
3275                    try {
3276                        ccsidDBCEncoding =
3277                            CharacterEncodings.getJavaEncoding(ccsidDBC);
3278                    } catch (Exception JavaDoc e) {
3279                        // we write a warning later for this so no error
3280
// unless for a statement
3281
ccsidDBCEncoding = null;
3282                        if (st != null)
3283                            valueNotSupported(CodePoint.CCSIDSBC);
3284                    }
3285                    if (SanityManager.DEBUG)
3286                        trace("ccsiddbc = " + ccsidDBC + " encoding = " + ccsidDBCEncoding);
3287                    break;
3288                case CodePoint.CCSIDMBC:
3289                    checkLength(CodePoint.CCSIDMBC, 2);
3290                    ccsidMBC = reader.readNetworkShort();
3291                    try {
3292                        ccsidMBCEncoding =
3293                            CharacterEncodings.getJavaEncoding(ccsidMBC);
3294                    } catch (Exception JavaDoc e) {
3295                        // we write a warning later for this so no error
3296
ccsidMBCEncoding = null;
3297                        if (st != null)
3298                            valueNotSupported(CodePoint.CCSIDMBC);
3299                    }
3300                    if (SanityManager.DEBUG)
3301                        trace("ccsidmbc = " + ccsidMBC + " encoding = " + ccsidMBCEncoding);
3302                    break;
3303                default:
3304                    invalidCodePoint(codePoint);
3305
3306            }
3307            codePoint = reader.getCodePoint();
3308        }
3309        if (st == null)
3310        {
3311            if (ccsidSBC != 0)
3312            {
3313                database.ccsidSBC = ccsidSBC;
3314                database.ccsidSBCEncoding = ccsidSBCEncoding;
3315            }
3316            if (ccsidDBC != 0)
3317            {
3318                database.ccsidDBC = ccsidDBC;
3319                database.ccsidDBCEncoding = ccsidDBCEncoding;
3320            }
3321            if (ccsidMBC != 0)
3322            {
3323                database.ccsidMBC = ccsidMBC;
3324                database.ccsidMBCEncoding = ccsidMBCEncoding;
3325            }
3326        }
3327        else
3328        {
3329            if (ccsidSBC != 0)
3330            {
3331                st.ccsidSBC = ccsidSBC;
3332                st.ccsidSBCEncoding = ccsidSBCEncoding;
3333            }
3334            if (ccsidDBC != 0)
3335            {
3336                st.ccsidDBC = ccsidDBC;
3337                st.ccsidDBCEncoding = ccsidDBCEncoding;
3338            }
3339            if (ccsidMBC != 0)
3340            {
3341                st.ccsidMBC = ccsidMBC;
3342                st.ccsidMBCEncoding = ccsidMBCEncoding;
3343            }
3344        }
3345    }
3346    /**
3347     * Parse PRPSQLSTT - Prepare SQL Statement
3348     * Instance Variables
3349     * RDBNAM - Relational Database Name - optional
3350     * PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number - required
3351     * RTNSQLDA - Return SQL Descriptor Area - optional
3352     * MONITOR - Monitor events - optional.
3353     *
3354     * @return return 0 - don't return sqlda, 1 - return input sqlda,
3355     * 2 - return output sqlda
3356     * @throws DRDAProtocolException
3357     * @throws SQLException
3358     */

3359    private int parsePRPSQLSTT() throws DRDAProtocolException,SQLException JavaDoc
3360    {
3361        int codePoint;
3362        boolean rtnsqlda = false;
3363        boolean rtnOutput = true; // Return output SQLDA is default
3364
String JavaDoc typdefnam;
3365        Pkgnamcsn pkgnamcsn = null;
3366
3367        DRDAStatement stmt = null;
3368        Database databaseToSet = null;
3369
3370        reader.markCollection();
3371
3372        codePoint = reader.getCodePoint();
3373        while (codePoint != -1)
3374        {
3375            switch (codePoint)
3376            {
3377                // optional
3378
case CodePoint.RDBNAM:
3379                    setDatabase(CodePoint.PRPSQLSTT);
3380                    databaseToSet = database;
3381                    break;
3382                // required
3383
case CodePoint.PKGNAMCSN:
3384                    pkgnamcsn = parsePKGNAMCSN();
3385                    break;
3386                //optional
3387
case CodePoint.RTNSQLDA:
3388                // Return SQLDA with description of statement
3389
rtnsqlda = readBoolean(CodePoint.RTNSQLDA);
3390                    break;
3391                //optional
3392
case CodePoint.TYPSQLDA:
3393                    rtnOutput = parseTYPSQLDA();
3394                    break;
3395                //optional
3396
case CodePoint.MONITOR:
3397                    parseMONITOR();
3398                    break;
3399                default:
3400                    invalidCodePoint(codePoint);
3401
3402            }
3403            codePoint = reader.getCodePoint();
3404        }
3405
3406        stmt = database.newDRDAStatement(pkgnamcsn);
3407        String JavaDoc sqlStmt = parsePRPSQLSTTobjects(stmt);
3408        if (databaseToSet != null)
3409            stmt.setDatabase(database);
3410        stmt.explicitPrepare(sqlStmt);
3411        // set the statement as the current statement
3412
database.setCurrentStatement(stmt);
3413
3414        if (!rtnsqlda)
3415            return 0;
3416        else if (rtnOutput)
3417            return 2;
3418        else
3419            return 1;
3420    }
3421    /**
3422     * Parse PRPSQLSTT objects
3423     * Objects
3424     * TYPDEFNAM - Data type definition name - optional
3425     * TYPDEFOVR - Type defintion overrides - optional
3426     * SQLSTT - SQL Statement required
3427     * SQLATTR - Cursor attributes on prepare - optional - level 7
3428     *
3429     * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
3430     * sent with the statement. Once the statement is over, the default values
3431     * sent in the ACCRDB are once again in effect. If no values are supplied,
3432     * the values sent in the ACCRDB are used.
3433     * Objects may follow in one DSS or in several DSS chained together.
3434     *
3435     * @return SQL statement
3436     * @throws DRDAProtocolException
3437     * @throws SQLException
3438     */

3439    private String JavaDoc parsePRPSQLSTTobjects(DRDAStatement stmt)
3440        throws DRDAProtocolException, SQLException JavaDoc
3441    {
3442        String JavaDoc sqlStmt = null;
3443        int codePoint;
3444        do
3445        {
3446            correlationID = reader.readDssHeader();
3447            while (reader.moreDssData())
3448            {
3449                codePoint = reader.readLengthAndCodePoint();
3450                switch(codePoint)
3451                {
3452                    // required
3453
case CodePoint.SQLSTT:
3454                        sqlStmt = parseEncodedString();
3455                        if (SanityManager.DEBUG)
3456                            trace("sqlStmt = " + sqlStmt);
3457                        break;
3458                    // optional
3459
case CodePoint.TYPDEFNAM:
3460                        setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
3461                        break;
3462                    // optional
3463
case CodePoint.TYPDEFOVR:
3464                        parseTYPDEFOVR(stmt);
3465                        break;
3466                    // optional
3467
case CodePoint.SQLATTR:
3468                        parseSQLATTR(stmt);
3469                        break;
3470                    default:
3471                        invalidCodePoint(codePoint);
3472                }
3473            }
3474        } while (reader.isChainedWithSameID());
3475        if (sqlStmt == null)
3476            missingCodePoint(CodePoint.SQLSTT);
3477
3478        return sqlStmt;
3479    }
3480
3481    /**
3482     * Parse TYPSQLDA - Type of the SQL Descriptor Area
3483     *
3484     * @return true if for output; false otherwise
3485     * @exception DRDAProtocolException
3486     */

3487    private boolean parseTYPSQLDA() throws DRDAProtocolException
3488    {
3489        checkLength(CodePoint.TYPSQLDA, 1);
3490        byte sqldaType = reader.readByte();
3491        if (SanityManager.DEBUG)
3492            trace("typSQLDa " + sqldaType);
3493        if (sqldaType == CodePoint.TYPSQLDA_STD_OUTPUT ||
3494                sqldaType == CodePoint.TYPSQLDA_LIGHT_OUTPUT ||
3495                sqldaType == CodePoint.TYPSQLDA_X_OUTPUT)
3496            return true;
3497        else if (sqldaType == CodePoint.TYPSQLDA_STD_INPUT ||
3498                     sqldaType == CodePoint.TYPSQLDA_LIGHT_INPUT ||
3499                     sqldaType == CodePoint.TYPSQLDA_X_INPUT)
3500                return false;
3501        else
3502            invalidValue(CodePoint.TYPSQLDA);
3503
3504        // shouldn't get here but have to shut up compiler
3505
return false;
3506    }
3507    /**
3508     * Parse SQLATTR - Cursor attributes on prepare
3509     * This is an encoded string. Can have combination of following, eg INSENSITIVE SCROLL WITH HOLD
3510     * Possible strings are
3511     * SENSITIVE DYNAMIC SCROLL [FOR UPDATE]
3512     * SENSITIVE STATIC SCROLL [FOR UPDATE]
3513     * INSENSITIVE SCROLL
3514     * FOR UPDATE
3515     * WITH HOLD
3516     *
3517     * @param stmt DRDAStatement
3518     * @exception DRDAProtocolException
3519     */

3520    protected void parseSQLATTR(DRDAStatement stmt) throws DRDAProtocolException
3521    {
3522        String JavaDoc attrs = parseEncodedString();
3523        if (SanityManager.DEBUG)
3524            trace("sqlattr = '" + attrs+"'");
3525        //let Cloudscape handle any errors in the types it doesn't support
3526
//just set the attributes
3527

3528        boolean validAttribute = false;
3529        if (attrs.indexOf("INSENSITIVE SCROLL") != -1 || attrs.indexOf("SCROLL INSENSITIVE") != -1) //CLI
3530
{
3531            stmt.scrollType = ResultSet.TYPE_SCROLL_INSENSITIVE;
3532            stmt.concurType = ResultSet.CONCUR_READ_ONLY;
3533            validAttribute = true;
3534        }
3535        if ((attrs.indexOf("SENSITIVE DYNAMIC SCROLL") != -1) || (attrs.indexOf("SENSITIVE STATIC SCROLL") != -1))
3536        {
3537            stmt.scrollType = ResultSet.TYPE_SCROLL_SENSITIVE;
3538            validAttribute = true;
3539        }
3540
3541        if ((attrs.indexOf("FOR UPDATE") != -1))
3542        {
3543            validAttribute = true;
3544            stmt.concurType = ResultSet.CONCUR_UPDATABLE;
3545        }
3546
3547        if (attrs.indexOf("WITH HOLD") != -1)
3548        {
3549            stmt.withHoldCursor = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
3550            validAttribute = true;
3551        }
3552
3553        if (!validAttribute)
3554        {
3555            invalidValue(CodePoint.SQLATTR);
3556        }
3557    }
3558
3559    /**
3560     * Parse DSCSQLSTT - Describe SQL Statement previously prepared
3561     * Instance Variables
3562     * TYPSQLDA - sqlda type expected (output or input)
3563     * RDBNAM - relational database name - optional
3564     * PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
3565     * MONITOR - Monitor events - optional.
3566     *
3567     * @return expect "output sqlda" or not
3568     * @throws DRDAProtocolException
3569     * @throws SQLException
3570     */

3571    private boolean parseDSCSQLSTT() throws DRDAProtocolException,SQLException JavaDoc
3572    {
3573        int codePoint;
3574        boolean rtnOutput = true; // default
3575
Pkgnamcsn pkgnamcsn = null;
3576        reader.markCollection();
3577
3578        codePoint = reader.getCodePoint();
3579        while (codePoint != -1)
3580        {
3581            switch (codePoint)
3582            {
3583                // optional
3584
case CodePoint.TYPSQLDA:
3585                    rtnOutput = parseTYPSQLDA();
3586                    break;
3587                // optional
3588
case CodePoint.RDBNAM:
3589                    setDatabase(CodePoint.DSCSQLSTT);
3590                    break;
3591                // required
3592
case CodePoint.PKGNAMCSN:
3593                    pkgnamcsn = parsePKGNAMCSN();
3594                    DRDAStatement stmt = database.getDRDAStatement(pkgnamcsn);
3595                    if (stmt == null)
3596                    {
3597                        invalidValue(CodePoint.PKGNAMCSN);
3598                    }
3599                    break;
3600                //optional
3601
case CodePoint.MONITOR:
3602                    parseMONITOR();
3603                    break;
3604                default:
3605                    invalidCodePoint(codePoint);
3606            }
3607            codePoint = reader.getCodePoint();
3608        }
3609        if (pkgnamcsn == null)
3610            missingCodePoint(CodePoint.PKGNAMCSN);
3611        return rtnOutput;
3612    }
3613
3614    /**
3615     * Parse EXCSQLSTT - Execute non-cursor SQL Statement previously prepared
3616     * Instance Variables
3617     * RDBNAM - relational database name - optional
3618     * PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
3619     * OUTEXP - Output expected
3620     * NBRROW - Number of rows to be inserted if it's an insert
3621     * PRCNAM - procedure name if specified by host variable, not needed for Cloudscape
3622     * QRYBLKSZ - query block size
3623     * MAXRSLCNT - max resultset count
3624     * MAXBLKEXT - Max number of extra blocks
3625     * RSLSETFLG - resultset flag
3626     * RDBCMTOK - RDB Commit Allowed - optional
3627     * OUTOVROPT - output override option
3628     * QRYROWSET - Query Rowset Size - Level 7
3629     * MONITOR - Monitor events - optional.
3630     *
3631     * @throws DRDAProtocolException
3632     * @throws SQLException
3633     */

3634    private void parseEXCSQLSTT() throws DRDAProtocolException,SQLException JavaDoc
3635    {
3636        int codePoint;
3637        String JavaDoc strVal;
3638        reader.markCollection();
3639
3640        codePoint = reader.getCodePoint();
3641        boolean outputExpected = false;
3642        Pkgnamcsn pkgnamcsn = null;
3643        int numRows = 1; // default value
3644
int blkSize = 0;
3645        int maxrslcnt = 0; // default value
3646
int maxblkext = CodePoint.MAXBLKEXT_DEFAULT;
3647        int qryrowset = CodePoint.QRYROWSET_DEFAULT;
3648        int outovropt = CodePoint.OUTOVRFRS;
3649        byte [] rslsetflg = null;
3650        String JavaDoc procName = null;
3651
3652        while (codePoint != -1)
3653        {
3654            switch (codePoint)
3655            {
3656                // optional
3657
case CodePoint.RDBNAM:
3658                    setDatabase(CodePoint.EXCSQLSTT);
3659                    break;
3660                // required
3661
case CodePoint.PKGNAMCSN:
3662                    pkgnamcsn = parsePKGNAMCSN();
3663                    break;
3664                // optional
3665
case CodePoint.OUTEXP:
3666                    outputExpected = readBoolean(CodePoint.OUTEXP);
3667                    if (SanityManager.DEBUG)
3668                        trace("outexp = "+ outputExpected);
3669                    break;
3670                // optional
3671
case CodePoint.NBRROW:
3672                    checkLength(CodePoint.NBRROW, 4);
3673                    numRows = reader.readNetworkInt();
3674                    if (SanityManager.DEBUG)
3675                        trace("# of rows: "+numRows);
3676                    break;
3677                // optional
3678
case CodePoint.PRCNAM:
3679                    procName = reader.readString();
3680                    if (SanityManager.DEBUG)
3681                        trace("Procedure Name = " + procName);
3682                    break;
3683                // optional
3684
case CodePoint.QRYBLKSZ:
3685                    blkSize = parseQRYBLKSZ();
3686                    break;
3687                // optional
3688
case CodePoint.MAXRSLCNT:
3689                    // this is the maximum result set count
3690
// values are 0 - requester is not capabable of receiving result
3691
// sets as reply data in the response to EXCSQLSTT
3692
// -1 - requester is able to receive all result sets
3693
checkLength(CodePoint.MAXRSLCNT, 2);
3694                    maxrslcnt = reader.readNetworkShort();
3695                    if (SanityManager.DEBUG)
3696                        trace("max rs count: "+maxrslcnt);
3697                    break;
3698                // optional
3699
case CodePoint.MAXBLKEXT:
3700                    // number of extra qury blocks of answer set data per result set
3701
// 0 - no extra query blocks
3702
// -1 - can receive entire result set
3703
checkLength(CodePoint.MAXBLKEXT, 2);
3704                    maxblkext = reader.readNetworkShort();
3705                    if (SanityManager.DEBUG)
3706                        trace("max extra blocks: "+maxblkext);
3707                    break;
3708                // optional
3709
case CodePoint.RSLSETFLG:
3710                    //Result set flags
3711
rslsetflg = reader.readBytes();
3712                    for (int i=0;i<rslsetflg.length;i++)
3713                        if (SanityManager.DEBUG)
3714                            trace("rslsetflg: "+rslsetflg[i]);
3715                    break;
3716                // optional
3717
case CodePoint.RDBCMTOK:
3718                    parseRDBCMTOK();
3719                    break;
3720                // optional
3721
case CodePoint.OUTOVROPT:
3722                    outovropt = parseOUTOVROPT();
3723                    break;
3724                // optional
3725
case CodePoint.QRYROWSET:
3726                    //Note minimum for OPNQRY is 0, we'll assume it is the same
3727
//for EXCSQLSTT though the standard doesn't say
3728
qryrowset = parseQRYROWSET(0);
3729                    break;
3730                //optional
3731
case CodePoint.MONITOR:
3732                    parseMONITOR();
3733                    break;
3734                default:
3735                    invalidCodePoint(codePoint);
3736            }
3737            codePoint = reader.getCodePoint();
3738        }
3739
3740        if (pkgnamcsn == null)
3741            missingCodePoint(CodePoint.PKGNAMCSN);
3742
3743        DRDAStatement stmt;
3744        boolean needPrepareCall = false;
3745
3746        stmt = database.getDRDAStatement(pkgnamcsn);
3747        boolean isProcedure = (procName !=null ||
3748                               (stmt != null &&
3749                                stmt.wasExplicitlyPrepared() &&
3750                                stmt.isCall));
3751
3752        if (isProcedure) // stored procedure call
3753
{
3754            if ( stmt == null || !(stmt.wasExplicitlyPrepared()))
3755            {
3756                stmt = database.newDRDAStatement(pkgnamcsn);
3757                stmt.setQryprctyp(CodePoint.QRYBLKCTL_DEFAULT);
3758                needPrepareCall = true;
3759            }
3760                
3761            stmt.procName = procName;
3762            stmt.outputExpected = outputExpected;
3763        }
3764        else
3765        {
3766            // we can't find the statement
3767
if (stmt == null)
3768            {
3769                invalidValue(CodePoint.PKGNAMCSN);
3770            }
3771            stmt.setQryprctyp(CodePoint.QRYBLKCTL_DEFAULT);
3772        }
3773
3774        stmt.nbrrow = numRows;
3775        stmt.qryrowset = qryrowset;
3776        stmt.blksize = blkSize;
3777        stmt.maxblkext = maxblkext;
3778        stmt.maxrslcnt = maxrslcnt;
3779        stmt.outovropt = outovropt;
3780        stmt.rslsetflg = rslsetflg;
3781        if (pendingStatementTimeout >= 0) {
3782            stmt.getPreparedStatement().setQueryTimeout(pendingStatementTimeout);
3783            pendingStatementTimeout = -1;
3784        }
3785 
3786    
3787        // set the statement as the current statement
3788
database.setCurrentStatement(stmt);
3789        
3790        boolean hasResultSet;
3791        if (reader.isChainedWithSameID())
3792        {
3793            hasResultSet = parseEXCSQLSTTobjects(stmt);
3794        } else
3795        {
3796            if (isProcedure && (needPrepareCall))
3797            {
3798                // if we had parameters the callable statement would
3799
// be prepared with parseEXCQLSTTobjects, otherwise we
3800
// have to do it here
3801
String JavaDoc prepareString = "call " + stmt.procName +"()";
3802                if (SanityManager.DEBUG)
3803                    trace ("$$$prepareCall is: "+prepareString);
3804                database.getConnection().clearWarnings();
3805                CallableStatement JavaDoc cs = (CallableStatement JavaDoc) stmt.prepare(prepareString);
3806            }
3807            stmt.ps.clearWarnings();
3808            hasResultSet = stmt.execute();
3809        }
3810        
3811        
3812        ResultSet JavaDoc rs = null;
3813        if (hasResultSet)
3814        {
3815            rs = stmt.getResultSet();
3816        }
3817        // temp until ps.execute() return value fixed
3818
hasResultSet = (rs != null);
3819        int numResults = 0;
3820        if (hasResultSet)
3821        {
3822            numResults = stmt.getNumResultSets();
3823            writeRSLSETRM(stmt);
3824        }
3825
3826        // First of all, we send if there really are output params. Otherwise
3827
// CLI (.Net driver) fails. DRDA spec (page 151,152) says send SQLDTARD
3828
// if server has output param data to send.
3829
boolean sendSQLDTARD = stmt.hasOutputParams() && outputExpected;
3830        if (isProcedure)
3831        {
3832            if (sendSQLDTARD) {
3833                writer.createDssObject();
3834                writer.startDdm(CodePoint.SQLDTARD);
3835                writer.startDdm(CodePoint.FDODSC);
3836                writeQRYDSC(stmt, true);
3837                writer.endDdm();
3838                writer.startDdm(CodePoint.FDODTA);
3839                writeFDODTA(stmt);
3840                writer.endDdm();
3841                writer.endDdmAndDss();
3842            }
3843            else if (hasResultSet)
3844            // DRDA spec says that we MUST return either an
3845
// SQLDTARD or an SQLCARD--the former when we have
3846
// output parameters, the latter when we don't.
3847
// If we have a result set, then we have to write
3848
// the SQLCARD _now_, since it is expected before
3849
// we send the result set info below; if we don't
3850
// have a result set and we don't send SQLDTARD,
3851
// then we can wait until we reach the call to
3852
// checkWarning() below, which will write an
3853
// SQLCARD for us.
3854
writeNullSQLCARDobject();
3855        }
3856        
3857        //We need to marke that params are finished so that we know we
3858
// are ready to send resultset info.
3859
stmt.finishParams();
3860            
3861        PreparedStatement JavaDoc ps = stmt.getPreparedStatement();
3862        int rsNum = 0;
3863        do {
3864        if (hasResultSet)
3865        {
3866            stmt.setCurrentDrdaResultSet(rsNum);
3867            //indicate that we are going to return data
3868
stmt.setQryrtndta(true);
3869            if (! isProcedure)
3870                checkWarning(null, ps, null, -1, true, true);
3871            if (rsNum == 0)
3872                writeSQLRSLRD(stmt);
3873            writeOPNQRYRM(true, stmt);
3874            writeSQLCINRD(stmt);
3875            writeQRYDSC(stmt, false);
3876            stmt.rsSuspend();
3877
3878            /* Currently, if LMTBLKPRC is used, a pre-condition is that no lob columns.
3879             * But in the future, when we do support LOB in LMTBLKPRC, the drda spec still
3880             * does not allow LOB to be sent with OPNQRYRM. So this "if" here will have
3881             * to add "no lob columns".
3882             */

3883            if (stmt.getQryprctyp() == CodePoint.LMTBLKPRC)
3884                writeQRYDTA(stmt);
3885        }
3886        else if (! sendSQLDTARD)
3887        {
3888            int updateCount = ps.getUpdateCount();
3889            if (false && (database.RDBUPDRM_sent == false) &&
3890                ! isProcedure)
3891            {
3892                writeRDBUPDRM();
3893            }
3894
3895            checkWarning(database.getConnection(), stmt.ps, null, updateCount, true, true);
3896        }
3897
3898        } while(hasResultSet && (++rsNum < numResults));
3899        
3900        return; // we are done
3901
}
3902
3903
3904    /**
3905     * Parse RDBCMTOK - tells the database whether to allow commits or rollbacks
3906     * to be executed as part of the command
3907     * Since we don't have a SQL commit or rollback command, we will just ignore
3908     * this for now
3909     *
3910     * @exception DRDAProtocolException
3911     */

3912    private void parseRDBCMTOK() throws DRDAProtocolException
3913    {
3914        boolean rdbcmtok = readBoolean(CodePoint.RDBCMTOK);
3915        if (SanityManager.DEBUG)
3916            trace("rdbcmtok = " + rdbcmtok);
3917    }
3918
3919    /**
3920     * Parse EXCSQLSTT command objects
3921     * Command Objects
3922     * TYPDEFNAM - Data Type Definition Name - optional
3923     * TYPDEFOVR - TYPDEF Overrides -optional
3924     * SQLDTA - optional, variable data, specified if prpared statement has input parameters
3925     * EXTDTA - optional, externalized FD:OCA data
3926     * OUTOVR - output override descriptor, not allowed for stored procedure calls
3927     *
3928     * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
3929     * sent with the statement. Once the statement is over, the default values
3930     * sent in the ACCRDB are once again in effect. If no values are supplied,
3931     * the values sent in the ACCRDB are used.
3932     * Objects may follow in one DSS or in several DSS chained together.
3933     *
3934     * @param stmt the DRDAStatement to execute
3935     * @throws DRDAProtocolException
3936     * @throws SQLException
3937     */

3938    private boolean parseEXCSQLSTTobjects(DRDAStatement stmt) throws DRDAProtocolException, SQLException JavaDoc
3939    {
3940        int codePoint;
3941        boolean gotSQLDTA = false, gotEXTDTA = false;
3942        boolean result = false;
3943        do
3944        {
3945            correlationID = reader.readDssHeader();
3946            while (reader.moreDssData())
3947            {
3948                codePoint = reader.readLengthAndCodePoint();
3949                switch(codePoint)
3950                {
3951                    // optional
3952
case CodePoint.TYPDEFNAM:
3953                        setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
3954                        stmt.setTypDefValues();
3955                        break;
3956                    // optional
3957
case CodePoint.TYPDEFOVR:
3958                        parseTYPDEFOVR(stmt);
3959                        stmt.setTypDefValues();
3960                        break;
3961                    // required
3962
case CodePoint.SQLDTA:
3963                        parseSQLDTA(stmt);
3964                        gotSQLDTA = true;
3965                        break;
3966                    // optional
3967
case CodePoint.EXTDTA:
3968                        readAndSetAllExtParams(stmt, true);
3969                        stmt.ps.clearWarnings();
3970                        result = stmt.execute();
3971                        gotEXTDTA = true;
3972                        break;
3973                    // optional
3974
case CodePoint.OUTOVR:
3975                        parseOUTOVR(stmt);
3976                        break;
3977                    default:
3978                        invalidCodePoint(codePoint);
3979                }
3980            }
3981        } while (reader.isChainedWithSameID());
3982
3983        // SQLDTA is required
3984
if (! gotSQLDTA)
3985            missingCodePoint(CodePoint.SQLDTA);
3986        
3987        if (! gotEXTDTA) {
3988            stmt.ps.clearWarnings();
3989            result = stmt.execute();
3990        }
3991        
3992        return result;
3993    }
3994
3995    /**
3996     * Write SQLCINRD - result set column information
3997     *
3998     * @throws DRDAProtocolException
3999     * @throws SQLException
4000     */

4001    private void writeSQLCINRD(DRDAStatement stmt) throws DRDAProtocolException,SQLException JavaDoc
4002    {
4003        ResultSet JavaDoc rs = null;
4004        // todo ps is never used or closed - could this be a memory leak?
4005
PreparedStatement JavaDoc ps = stmt.getPreparedStatement();
4006        
4007        if (!stmt.needsToSendParamData)
4008            rs = stmt.getResultSet();
4009
4010        writer.createDssObject();
4011        writer.startDdm(CodePoint.SQLCINRD);
4012        if (sqlamLevel >= MGRLVL_7)
4013            writeSQLDHROW (stmt);
4014
4015        ResultSetMetaData JavaDoc rsmeta = rs.getMetaData();
4016        int ncols = rsmeta.getColumnCount();
4017        writer.writeShort(ncols); // num of columns
4018
if (sqlamLevel >= MGRLVL_7)
4019        {
4020            for (int i = 0; i < ncols; i++)
4021                writeSQLDAGRP (rsmeta, null, i, true);
4022        }
4023        else
4024        {
4025            for (int i = 0; i < ncols; i++)
4026            {
4027                writeVCMorVCS(rsmeta.getColumnName(i+1));
4028                writeVCMorVCS(rsmeta.getColumnLabel(i+1));
4029                writeVCMorVCS(null);
4030            }
4031        }
4032        writer.endDdmAndDss();
4033    }
4034
4035    /**
4036     * Write SQLRSLRD - result set reply data
4037     *
4038     * @throws DRDAProtocolException
4039     * @throws SQLException
4040     */

4041    private void writeSQLRSLRD(DRDAStatement stmt) throws DRDAProtocolException,SQLException JavaDoc
4042    {
4043        int numResults = stmt.getNumResultSets();
4044
4045        writer.createDssObject();
4046        writer.startDdm(CodePoint.SQLRSLRD);
4047        writer.writeShort(numResults); // num of result sets
4048

4049        for (int i = 0; i < numResults; i ++)
4050            {
4051                writer.writeInt(i); // rsLocator
4052
writeVCMorVCS(stmt.getResultSetCursorName(i));
4053                writer.writeInt(1); // num of rows XXX resolve, it doesn't matter for now
4054

4055            }
4056        writer.endDdmAndDss();
4057    }
4058
4059    /**
4060     * Write RSLSETRM
4061     * Instance variables
4062     * SVRCOD - Severity code - Information only - required
4063     * PKGSNLST - list of PKGNAMCSN -required
4064     * SRVDGN - Server Diagnostic Information -optional
4065     *
4066     * @throws DRDAProtocolException
4067     * @throws SQLException
4068     */

4069    private void writeRSLSETRM(DRDAStatement stmt) throws DRDAProtocolException,SQLException JavaDoc
4070    {
4071        int numResults = stmt.getNumResultSets();
4072        writer.createDssReply();
4073        writer.startDdm(CodePoint.RSLSETRM);
4074        writer.writeScalar2Bytes(CodePoint.SVRCOD, 0);
4075        writer.startDdm(CodePoint.PKGSNLST);
4076        
4077        for (int i = 0; i < numResults; i++)
4078            writePKGNAMCSN(stmt.getResultSetPkgcnstkn(i).getBytes());
4079        writer.endDdm();
4080        writer.endDdmAndDss();
4081    }
4082
4083    
4084    /**
4085     * Parse SQLDTA - SQL program variable data
4086     * and handle exception.
4087     * @see #parseSQLDTA_work
4088     */

4089
4090    private void parseSQLDTA(DRDAStatement stmt) throws DRDAProtocolException,SQLException JavaDoc
4091    {
4092        try {
4093            parseSQLDTA_work(stmt);
4094        }
4095        catch (SQLException JavaDoc se)
4096        {
4097            skipRemainder(true);
4098            throw se;
4099        }
4100    }
4101    
4102    /**
4103     * Parse SQLDTA - SQL program variable data
4104     * Instance Variables
4105     * FDODSC - FD:OCA data descriptor - required
4106     * FDODTA - FD:OCA data - optional
4107     *
4108     * @throws DRDAProtocolException
4109     * @throws SQLException
4110     */

4111    private void parseSQLDTA_work(DRDAStatement stmt) throws DRDAProtocolException,SQLException JavaDoc
4112    {
4113        String JavaDoc strVal;
4114        PreparedStatement JavaDoc ps = stmt.getPreparedStatement();
4115        int codePoint;
4116        EngineParameterMetaData pmeta = null;
4117        Vector JavaDoc paramDrdaTypes = new Vector JavaDoc();
4118        Vector JavaDoc paramLens = new Vector JavaDoc();
4119        ArrayList JavaDoc paramExtPositions = null;
4120        int numVars = 0;
4121        boolean rtnParam = false;
4122
4123        reader.markCollection();
4124        codePoint = reader.getCodePoint();
4125        while (codePoint != -1)
4126        {
4127                switch (codePoint)
4128                {
4129                    // required
4130
case CodePoint.FDODSC:
4131                        while (reader.getDdmLength() > 6) //we get parameter info til last 6 byte
4132
{
4133                        int dtaGrpLen = reader.readUnsignedByte();
4134                        int numVarsInGrp = (dtaGrpLen - 3) / 3;
4135                        if (SanityManager.DEBUG)
4136                            trace("num of vars in this group is: "+numVarsInGrp);
4137                        reader.readByte(); // tripletType
4138
reader.readByte(); // id
4139
for (int j = 0; j < numVarsInGrp; j++)
4140                        {
4141                            paramDrdaTypes.addElement(new Byte JavaDoc(reader.readByte()));
4142                            if (SanityManager.DEBUG)
4143                                trace("drdaType is: "+ "0x" +
4144                                      Integer.toHexString(((Byte JavaDoc ) paramDrdaTypes.lastElement()).byteValue()));
4145                            int drdaLength = reader.readNetworkShort();
4146                            if (SanityManager.DEBUG)
4147                                trace("drdaLength is: "+drdaLength);
4148                            paramLens.addElement(new Integer JavaDoc(drdaLength));
4149                        }
4150                    }
4151                    numVars = paramDrdaTypes.size();
4152                    if (SanityManager.DEBUG)
4153                        trace("numVars = " + numVars);
4154                    if (ps == null) // it is a CallableStatement under construction
4155
{
4156                        String JavaDoc marks = "(?"; // construct parameter marks
4157
for (int i = 1; i < numVars; i++)
4158                            marks += ", ?";
4159                        String JavaDoc prepareString = "call " + stmt.procName + marks + ")";
4160                        if (SanityManager.DEBUG)
4161                            trace ("$$ prepareCall is: "+prepareString);
4162                        CallableStatement JavaDoc cs = null;
4163                        try {
4164                            cs = (CallableStatement JavaDoc)
4165                                stmt.prepare(prepareString);
4166                            stmt.registerAllOutParams();
4167                        } catch (SQLException JavaDoc se) {
4168                            if (! stmt.outputExpected ||
4169                                (!se.getSQLState().equals(SQLState.LANG_NO_METHOD_FOUND)))
4170                                throw se;
4171                            if (SanityManager.DEBUG)
4172                                trace("****** second try with return parameter...");
4173                            // Save first SQLException most likely suspect
4174
if (numVars == 1)
4175                                prepareString = "? = call " + stmt.procName +"()";
4176                            else
4177                                prepareString = "? = call " + stmt.procName +"("+marks.substring(3) + ")";
4178                            if (SanityManager.DEBUG)
4179                                trace ("$$ prepareCall is: "+prepareString);
4180                            try {
4181                                cs = (CallableStatement JavaDoc) stmt.prepare(prepareString);
4182                            } catch (SQLException JavaDoc se2)
4183                            {
4184                                // The first exception is the most likely suspect
4185
throw se;
4186                            }
4187                            rtnParam = true;
4188                        }
4189                        ps = cs;
4190                        stmt.ps = ps;
4191                    }
4192
4193                    pmeta = stmt.getParameterMetaData();
4194
4195                    reader.readBytes(6); // descriptor footer
4196
break;
4197                // optional
4198
case CodePoint.FDODTA:
4199                    reader.readByte(); // row indicator
4200
for (int i = 0; i < numVars; i++)
4201                    {
4202                    
4203                        if ((((Byte JavaDoc)paramDrdaTypes.elementAt(i)).byteValue() & 0x1) == 0x1) // nullable
4204
{
4205                            int nullData = reader.readUnsignedByte();
4206                            if ((nullData & 0xFF) == FdocaConstants.NULL_DATA)
4207                            {
4208                                if (SanityManager.DEBUG)
4209                                    trace("******param null");
4210                                if (pmeta.getParameterMode(i + 1)
4211                                    != JDBC30Translation.PARAMETER_MODE_OUT )
4212                                        ps.setNull(i+1, pmeta.getParameterType(i+1));
4213                                if (stmt.isOutputParam(i+1))
4214                                    stmt.registerOutParam(i+1);
4215                                continue;
4216                            }
4217                        }
4218
4219                        // not null, read and set it
4220
paramExtPositions = readAndSetParams(i, stmt,
4221                                                             ((Byte JavaDoc)paramDrdaTypes.elementAt(i)).byteValue(),
4222                                                             pmeta,
4223                                                             paramExtPositions,
4224                                                             ((Integer JavaDoc)(paramLens.elementAt(i))).intValue());
4225                    }
4226                    stmt.cliParamExtPositions = paramExtPositions;
4227                    stmt.cliParamDrdaTypes = paramDrdaTypes;
4228                    stmt.cliParamLens = paramLens;
4229                    break;
4230                case CodePoint.EXTDTA:
4231                    readAndSetAllExtParams(stmt, false);
4232                    break;
4233                default:
4234                    invalidCodePoint(codePoint);
4235
4236            }
4237                codePoint = reader.getCodePoint();
4238        }
4239
4240
4241    }
4242
4243    private int getByteOrder()
4244    {
4245        DRDAStatement stmt = database.getCurrentStatement();
4246        return ((stmt != null && stmt.typDefNam != null) ? stmt.byteOrder : database.byteOrder);
4247    }
4248
4249    /**
4250     * Read different types of input parameters and set them in PreparedStatement
4251     * @param i index of the parameter
4252     * @param stmt drda statement
4253     * @param drdaType drda type of the parameter
4254     * @param pmeta parameter meta data
4255     * @param paramExtPositions ArrayList of parameters with extdta
4256     * @param paramLenNumBytes Number of bytes for encoding LOB Length
4257     *
4258     * @return updated paramExtPositions
4259     * @throws DRDAProtocolException
4260     * @throws SQLException
4261     */

4262    private ArrayList JavaDoc readAndSetParams(int i, DRDAStatement stmt, int
4263                                       drdaType, EngineParameterMetaData pmeta,
4264                                       ArrayList JavaDoc paramExtPositions,
4265                                       int paramLenNumBytes)
4266                throws DRDAProtocolException, SQLException JavaDoc
4267    {
4268        PreparedStatement JavaDoc ps = stmt.getPreparedStatement();
4269        // mask out null indicator
4270
drdaType = ((drdaType | 0x01) & 0x000000ff);
4271
4272        if (ps instanceof CallableStatement JavaDoc)
4273        {
4274            if (stmt.isOutputParam(i+1))
4275            {
4276                CallableStatement JavaDoc cs = (CallableStatement JavaDoc) ps;
4277                cs.registerOutParameter(i+1, stmt.getOutputParamType(i+1));
4278            }
4279        }
4280
4281        switch (drdaType)
4282        {
4283            case DRDAConstants.DRDA_TYPE_NSMALL:
4284            {
4285                short paramVal = (short) reader.readShort(getByteOrder());
4286                if (SanityManager.DEBUG)
4287                    trace("short parameter value is: "+paramVal);
4288                // DB2 does not have a BOOLEAN java.sql.bit type, it's sent as small
4289
if (pmeta.getParameterType(i+1) == JDBC30Translation.BOOLEAN)
4290                    ps.setBoolean(i+1, (paramVal == 1));
4291                else
4292                    ps.setShort(i+1, paramVal);
4293                break;
4294            }
4295            case DRDAConstants.DRDA_TYPE_NINTEGER:
4296            {
4297                int paramVal = reader.readInt(getByteOrder());
4298                if (SanityManager.DEBUG)
4299                    trace("integer parameter value is: "+paramVal);
4300                ps.setInt(i+1, paramVal);
4301                break;
4302            }
4303            case DRDAConstants.DRDA_TYPE_NINTEGER8:
4304            {
4305                long paramVal = reader.readLong(getByteOrder());
4306                if (SanityManager.DEBUG)
4307                    trace("parameter value is: "+paramVal);
4308                ps.setLong(i+1, paramVal);
4309                break;
4310            }
4311            case DRDAConstants.DRDA_TYPE_NFLOAT4:
4312            {
4313                float paramVal = reader.readFloat(getByteOrder());
4314                if (SanityManager.DEBUG)
4315                    trace("parameter value is: "+paramVal);
4316                ps.setFloat(i+1, paramVal);
4317                break;
4318            }
4319            case DRDAConstants.DRDA_TYPE_NFLOAT8:
4320            {
4321                double paramVal = reader.readDouble(getByteOrder());
4322                if (SanityManager.DEBUG)
4323                    trace("nfloat8 parameter value is: "+paramVal);
4324                ps.setDouble(i+1, paramVal);
4325                break;
4326            }
4327            case DRDAConstants.DRDA_TYPE_NDECIMAL:
4328            {
4329                int precision = (paramLenNumBytes >> 8) & 0xff;
4330                int scale = paramLenNumBytes & 0xff;
4331                BigDecimal JavaDoc paramVal = reader.readBigDecimal(precision, scale);
4332                if (SanityManager.DEBUG)
4333                    trace("ndecimal parameter value is: "+paramVal);
4334                ps.setBigDecimal(i+1, paramVal);
4335                break;
4336            }
4337            case DRDAConstants.DRDA_TYPE_NDATE:
4338            {
4339                String JavaDoc paramVal = reader.readStringData(10).trim(); //parameter may be char value
4340
if (SanityManager.DEBUG)
4341                    trace("ndate parameter value is: \""+paramVal+"\"");
4342                try {
4343                    ps.setDate(i+1, java.sql.Date.valueOf(paramVal));
4344                } catch (java.lang.IllegalArgumentException JavaDoc e) {
4345                    // Just use SQLSTATE as message since, if user wants to
4346
// retrieve it, the message will be looked up by the
4347
// sqlcamessage() proc, which will get the localized
4348
// message based on SQLSTATE, and will ignore the
4349
// the message we use here...
4350
throw new SQLException JavaDoc(SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4351                        SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(0,5));
4352                }
4353                break;
4354            }
4355            case DRDAConstants.DRDA_TYPE_NTIME:
4356            {
4357                String JavaDoc paramVal = reader.readStringData(8).trim(); //parameter may be char value
4358
if (SanityManager.DEBUG)
4359                    trace("ntime parameter value is: "+paramVal);
4360                try {
4361                    ps.setTime(i+1, java.sql.Time.valueOf(paramVal));
4362                } catch (java.lang.IllegalArgumentException JavaDoc e) {
4363                    throw new SQLException JavaDoc(SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4364                        SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(0,5));
4365                }
4366                break;
4367            }
4368            case DRDAConstants.DRDA_TYPE_NTIMESTAMP:
4369            {
4370                // JCC represents ts in a slightly different format than Java standard, so
4371
// we do the conversion to Java standard here.
4372
String JavaDoc paramVal = reader.readStringData(26).trim(); //parameter may be char value
4373
if (SanityManager.DEBUG)
4374                    trace("ntimestamp parameter value is: "+paramVal);
4375                try {
4376                    String JavaDoc tsString = paramVal.substring(0,10) + " " +
4377                        paramVal.substring(11,19).replace('.', ':') +
4378                        paramVal.substring(19);
4379                    if (SanityManager.DEBUG)
4380                        trace("tsString is: "+tsString);
4381                    ps.setTimestamp(i+1, java.sql.Timestamp.valueOf(tsString));
4382                } catch (java.lang.IllegalArgumentException JavaDoc e1) {
4383                // thrown by Timestamp.valueOf(...) for bad syntax...
4384
throw new SQLException JavaDoc(SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4385                        SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(0,5));
4386                } catch (java.lang.StringIndexOutOfBoundsException JavaDoc e2) {
4387                // can be thrown by substring(...) if syntax is invalid...
4388
throw new SQLException JavaDoc(SQLState.LANG_DATE_SYNTAX_EXCEPTION,
4389                        SQLState.LANG_DATE_SYNTAX_EXCEPTION.substring(0,5));
4390                }
4391                break;
4392            }
4393            case DRDAConstants.DRDA_TYPE_NCHAR:
4394            case DRDAConstants.DRDA_TYPE_NVARCHAR:
4395            case DRDAConstants.DRDA_TYPE_NLONG:
4396            case DRDAConstants.DRDA_TYPE_NVARMIX:
4397            case DRDAConstants.DRDA_TYPE_NLONGMIX:
4398            {
4399                String JavaDoc paramVal = reader.readLDStringData(stmt.ccsidMBCEncoding);
4400                if (SanityManager.DEBUG)
4401                    trace("char/varchar parameter value is: "+paramVal);
4402                ps.setString(i+1, paramVal);
4403                break;
4404            }
4405            case DRDAConstants.DRDA_TYPE_NFIXBYTE:
4406            {
4407                byte[] paramVal = reader.readBytes();
4408                if (SanityManager.DEBUG)
4409                    trace("fix bytes parameter value is: "+ convertToHexString(paramVal));
4410                ps.setBytes(i+1, paramVal);
4411                break;
4412            }
4413            case DRDAConstants.DRDA_TYPE_NVARBYTE:
4414            case DRDAConstants.DRDA_TYPE_NLONGVARBYTE:
4415            {
4416                int length = reader.readNetworkShort(); //protocol control data always follows big endian
4417
if (SanityManager.DEBUG)
4418                    trace("===== binary param length is: " + length);
4419                byte[] paramVal = reader.readBytes(length);
4420                ps.setBytes(i+1, paramVal);
4421                break;
4422            }
4423            case DRDAConstants.DRDA_TYPE_NLOBBYTES:
4424            case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
4425            case DRDAConstants.DRDA_TYPE_NLOBCSBCS:
4426            case DRDAConstants.DRDA_TYPE_NLOBCDBCS:
4427             {
4428                 long length = readLobLength(paramLenNumBytes);
4429                 if (length != 0) //can be -1 for CLI if "data at exec" mode, see clifp/exec test
4430
{
4431                    if (paramExtPositions == null)
4432                         paramExtPositions = new ArrayList JavaDoc();
4433                    paramExtPositions.add(new Integer JavaDoc(i));
4434                 }
4435                 else /* empty */
4436                 {
4437                    if (drdaType == DRDAConstants.DRDA_TYPE_NLOBBYTES)
4438                        ps.setBytes(i+1, new byte[0]);
4439                    else
4440                        ps.setString(i+1, "");
4441                 }
4442                 break;
4443             }
4444            default:
4445                {
4446                String JavaDoc paramVal = reader.readLDStringData(stmt.ccsidMBCEncoding);
4447                if (SanityManager.DEBUG)
4448                    trace("default type parameter value is: "+paramVal);
4449                ps.setObject(i+1, paramVal);
4450            }
4451        }
4452        return paramExtPositions;
4453    }
4454
4455    private long readLobLength(int extLenIndicator)
4456        throws DRDAProtocolException
4457    {
4458        switch (extLenIndicator)
4459        {
4460            case 0x8002:
4461                return (long) reader.readNetworkShort();
4462            case 0x8004:
4463                return (long) reader.readNetworkInt();
4464            case 0x8006:
4465                return (long) reader.readNetworkSixByteLong();
4466            case 0x8008:
4467                return (long) reader.readNetworkLong();
4468            default:
4469                throwSyntaxrm(CodePoint.SYNERRCD_INCORRECT_EXTENDED_LEN, extLenIndicator);
4470                return 0L;
4471        }
4472        
4473
4474
4475    }
4476    
4477
4478    private void readAndSetAllExtParams(final DRDAStatement stmt, final boolean streamLOB)
4479        throws SQLException JavaDoc, DRDAProtocolException
4480    {
4481        int numExt = stmt.cliParamExtPositions.size();
4482        for (int i = 0; i < stmt.cliParamExtPositions.size(); i++)
4483                    {
4484                        int paramPos = ((Integer JavaDoc) (stmt.cliParamExtPositions).get(i)).intValue();
4485                        final boolean doStreamLOB = (streamLOB && i == numExt -1);
4486                        readAndSetExtParam(paramPos,
4487                                           stmt,
4488                                           ((Byte JavaDoc)stmt.cliParamDrdaTypes.elementAt(paramPos)).intValue(),
4489                                           ((Integer JavaDoc)(stmt.cliParamLens.elementAt(paramPos))).intValue(),
4490                                           doStreamLOB);
4491                        // Each extdta in it's own dss
4492
if (i < numExt -1)
4493                        {
4494                            correlationID = reader.readDssHeader();
4495                            int codePoint = reader.readLengthAndCodePoint();
4496                        }
4497                    }
4498
4499    }
4500    
4501
4502    /**
4503     * Read different types of input parameters and set them in PreparedStatement
4504     * @param i index of the parameter
4505     * @param stmt associated ps
4506     * @param drdaType drda type of the parameter
4507     *
4508     * @throws DRDAProtocolException
4509     * @throws SQLException
4510     */

4511    private void readAndSetExtParam( int i, DRDAStatement stmt,
4512                                     int drdaType, int extLen, boolean streamLOB)
4513                throws DRDAProtocolException, SQLException JavaDoc
4514        {
4515            PreparedStatement JavaDoc ps = stmt.getPreparedStatement();
4516            drdaType = (drdaType & 0x000000ff); // need unsigned value
4517
boolean checkNullability = false;
4518            if (sqlamLevel >= MGRLVL_7 &&
4519                FdocaConstants.isNullable(drdaType))
4520                checkNullability = true;
4521    
4522            try {
4523                final byte[] paramBytes;
4524                final String JavaDoc paramString;
4525                
4526                switch (drdaType)
4527                {
4528                    case DRDAConstants.DRDA_TYPE_LOBBYTES:
4529                    case DRDAConstants.DRDA_TYPE_NLOBBYTES:
4530                        paramString = "";
4531                        final boolean useSetBinaryStream =
4532                            stmt.getParameterMetaData().getParameterType(i+1)==Types.BLOB;
4533                        
4534                        if (streamLOB && useSetBinaryStream) {
4535                            paramBytes = null;
4536                            final EXTDTAReaderInputStream stream =
4537                                reader.getEXTDTAReaderInputStream(checkNullability);
4538                            if (stream==null) {
4539                                ps.setBytes(i+1, null);
4540                            } else {
4541                                ps.setBinaryStream(i+1, stream, (int) stream.getLength());
4542                            }
4543                            
4544                            if (SanityManager.DEBUG) {
4545                                if (stream==null) {
4546                                    trace("parameter value : NULL");
4547                                } else {
4548                                    trace("parameter value will be streamed");
4549                                }
4550                            }
4551                        } else {
4552                            paramBytes = reader.getExtData(checkNullability);
4553                            if (paramBytes==null || !useSetBinaryStream) {
4554                                ps.setBytes(i+1, paramBytes);
4555                            } else {
4556                                ps.setBinaryStream(i+1, new ByteArrayInputStream JavaDoc(paramBytes),
4557                                                   paramBytes.length);
4558                            }
4559                            if (SanityManager.DEBUG) {
4560                                if (paramBytes==null) {
4561                                    trace("parameter value : NULL");
4562                                } else {
4563                                    trace("parameter value is a LOB with length:" +
4564                                          paramBytes.length);
4565                                }
4566                            }
4567                        }
4568                        break;
4569                    case DRDAConstants.DRDA_TYPE_LOBCSBCS:
4570                    case DRDAConstants.DRDA_TYPE_NLOBCSBCS:
4571                        paramBytes = reader.getExtData(checkNullability);
4572                        paramString = new String JavaDoc(paramBytes, stmt.ccsidSBCEncoding);
4573                        if (SanityManager.DEBUG)
4574                            trace("parameter value is: "+ paramString);
4575                        ps.setString(i+1,paramString);
4576                        break;
4577                    case DRDAConstants.DRDA_TYPE_LOBCDBCS:
4578                    case DRDAConstants.DRDA_TYPE_NLOBCDBCS:
4579                        paramBytes = reader.getExtData(checkNullability);
4580                        paramString = new String JavaDoc(paramBytes, stmt.ccsidDBCEncoding );
4581                        if (SanityManager.DEBUG)
4582                            trace("parameter value is: "+ paramString);
4583                        ps.setString(i+1,paramString);
4584                        break;
4585                    case DRDAConstants.DRDA_TYPE_LOBCMIXED:
4586                    case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
4587                        paramBytes = reader.getExtData(checkNullability);
4588                        paramString = new String JavaDoc(paramBytes, stmt.ccsidMBCEncoding);
4589                        if (SanityManager.DEBUG)
4590                            trace("parameter value is: "+ paramString);
4591                        ps.setString(i+1,paramString);
4592                        break;
4593                    default:
4594                        paramBytes = null;
4595                        paramString = "";
4596
4597                        invalidValue(drdaType);
4598                }
4599                 
4600            }
4601            catch (java.io.UnsupportedEncodingException JavaDoc e) {
4602                throw new SQLException JavaDoc (e.getMessage());
4603            }
4604        }
4605
4606    /**
4607     * Parse EXCSQLIMM - Execute Immediate Statement
4608     * Instance Variables
4609     * RDBNAM - relational database name - optional
4610     * PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
4611     * RDBCMTOK - RDB Commit Allowed - optional
4612     * MONITOR - Monitor Events - optional
4613     *
4614     * Command Objects
4615     * TYPDEFNAM - Data Type Definition Name - optional
4616     * TYPDEFOVR - TYPDEF Overrides -optional
4617     * SQLSTT - SQL Statement -required
4618     *
4619     * @return update count
4620     * @throws DRDAProtocolException
4621     * @throws SQLException
4622     */

4623    private int parseEXCSQLIMM() throws DRDAProtocolException,SQLException JavaDoc
4624    {
4625        int codePoint;
4626        reader.markCollection();
4627        Pkgnamcsn pkgnamcsn = null;
4628        codePoint = reader.getCodePoint();
4629        while (codePoint != -1)
4630        {
4631            switch (codePoint)
4632            {
4633                // optional
4634
case CodePoint.RDBNAM:
4635                    setDatabase(CodePoint.EXCSQLIMM);
4636                    break;
4637                // required
4638
case CodePoint.PKGNAMCSN:
4639                    pkgnamcsn = parsePKGNAMCSN();
4640                    break;
4641                case CodePoint.RDBCMTOK:
4642                    parseRDBCMTOK();
4643                    break;
4644                //optional
4645
case CodePoint.MONITOR:
4646                    parseMONITOR();
4647                    break;
4648                default:
4649                    invalidCodePoint(codePoint);
4650
4651            }
4652            codePoint = reader.getCodePoint();
4653        }
4654        DRDAStatement drdaStmt = database.getDefaultStatement(pkgnamcsn);
4655        // initialize statement for reuse
4656
drdaStmt.initialize();
4657        String JavaDoc sqlStmt = parseEXECSQLIMMobjects();
4658        Statement JavaDoc statement = drdaStmt.getStatement();
4659        statement.clearWarnings();
4660        if (pendingStatementTimeout >= 0) {
4661            statement.setQueryTimeout(pendingStatementTimeout);
4662            pendingStatementTimeout = -1;
4663        }
4664        int updCount = statement.executeUpdate(sqlStmt);
4665        return updCount;
4666    }
4667
4668    /**
4669     * Parse EXCSQLSET - Execute Set SQL Environment
4670     * Instance Variables
4671     * RDBNAM - relational database name - optional
4672     * PKGNAMCT - RDB Package Name, Consistency Token - optional
4673     * MONITOR - Monitor Events - optional
4674     *
4675     * Command Objects
4676     * TYPDEFNAM - Data Type Definition Name - required
4677     * TYPDEFOVR - TYPDEF Overrides - required
4678     * SQLSTT - SQL Statement - required (at least one; may be more)
4679     *
4680     * @throws DRDAProtocolException
4681     * @throws SQLException
4682     */

4683    private boolean parseEXCSQLSET() throws DRDAProtocolException,SQLException JavaDoc
4684    {
4685
4686        int codePoint;
4687        reader.markCollection();
4688
4689
4690        codePoint = reader.getCodePoint();
4691        while (codePoint != -1)
4692        {
4693            switch (codePoint)
4694            {
4695                // optional
4696
case CodePoint.RDBNAM:
4697                    setDatabase(CodePoint.EXCSQLSET);
4698                    break;
4699                // optional
4700
case CodePoint.PKGNAMCT:
4701                    // we are going to ignore this for EXCSQLSET
4702
// since we are just going to reuse an existing statement
4703
String JavaDoc pkgnamct = parsePKGNAMCT();
4704                    break;
4705                // optional
4706
case CodePoint.MONITOR:
4707                    parseMONITOR();
4708                    break;
4709                // required
4710
case CodePoint.PKGNAMCSN:
4711                    // we are going to ignore this for EXCSQLSET.
4712
// since we are just going to reuse an existing statement.
4713
// NOTE: This codepoint is not in the DDM spec for 'EXCSQLSET',
4714
// but since it DOES get sent by jcc1.2, we have to have
4715
// a case for it...
4716
Pkgnamcsn pkgnamcsn = parsePKGNAMCSN();
4717                    break;
4718                default:
4719                    invalidCodePoint(codePoint);
4720
4721            }
4722            codePoint = reader.getCodePoint();
4723        }
4724
4725        parseEXCSQLSETobjects();
4726        return true;
4727    }
4728
4729    /**
4730     * Parse EXCSQLIMM objects
4731     * Objects
4732     * TYPDEFNAM - Data type definition name - optional
4733     * TYPDEFOVR - Type defintion overrides
4734     * SQLSTT - SQL Statement required
4735     *
4736     * If TYPDEFNAM and TYPDEFOVR are supplied, they apply to the objects
4737     * sent with the statement. Once the statement is over, the default values
4738     * sent in the ACCRDB are once again in effect. If no values are supplied,
4739     * the values sent in the ACCRDB are used.
4740     * Objects may follow in one DSS or in several DSS chained together.
4741     *
4742     * @return SQL Statement
4743     * @throws DRDAProtocolException
4744     * @throws SQLException
4745     */

4746    private String JavaDoc parseEXECSQLIMMobjects() throws DRDAProtocolException, SQLException JavaDoc
4747    {
4748        String JavaDoc sqlStmt = null;
4749        int codePoint;
4750        DRDAStatement stmt = database.getDefaultStatement();
4751        do
4752        {
4753            correlationID = reader.readDssHeader();
4754            while (reader.moreDssData())
4755            {
4756                codePoint = reader.readLengthAndCodePoint();
4757                switch(codePoint)
4758                {
4759                    // optional
4760
case CodePoint.TYPDEFNAM:
4761                        setStmtOrDbByteOrder(false, stmt, parseTYPDEFNAM());
4762                        break;
4763                    // optional
4764
case CodePoint.TYPDEFOVR:
4765                        parseTYPDEFOVR(stmt);
4766                        break;
4767                    // required
4768
case CodePoint.SQLSTT:
4769                        sqlStmt = parseEncodedString();
4770                        if (SanityManager.DEBUG)
4771                            trace("sqlStmt = " + sqlStmt);
4772                        break;
4773                    default:
4774                        invalidCodePoint(codePoint);
4775                }
4776            }
4777        } while (reader.isChainedWithSameID());
4778
4779        // SQLSTT is required
4780
if (sqlStmt == null)
4781            missingCodePoint(CodePoint.SQLSTT);
4782        return sqlStmt;
4783    }
4784
4785    /**
4786     * Parse EXCSQLSET objects
4787     * Objects
4788     * TYPDEFNAM - Data type definition name - optional
4789     * TYPDEFOVR - Type defintion overrides - optional
4790     * SQLSTT - SQL Statement - required (a list of at least one)
4791     *
4792     * Objects may follow in one DSS or in several DSS chained together.
4793     *
4794     * @throws DRDAProtocolException
4795     * @throws SQLException
4796     */

4797    private void parseEXCSQLSETobjects()
4798        throws DRDAProtocolException, SQLException JavaDoc
4799    {
4800
4801        boolean gotSqlStt = false;
4802        boolean hadUnrecognizedStmt = false;
4803
4804        String JavaDoc sqlStmt = null;
4805        int codePoint;
4806        DRDAStatement drdaStmt = database.getDefaultStatement();
4807        drdaStmt.initialize();
4808
4809        do
4810        {
4811            correlationID = reader.readDssHeader();
4812            while (reader.moreDssData())
4813            {
4814
4815                codePoint = reader.readLengthAndCodePoint();
4816
4817                switch(codePoint)
4818                {
4819                    // optional
4820
case CodePoint.TYPDEFNAM:
4821                        setStmtOrDbByteOrder(false, drdaStmt, parseTYPDEFNAM());
4822                        break;
4823                    // optional
4824
case CodePoint.TYPDEFOVR:
4825                        parseTYPDEFOVR(drdaStmt);
4826                        break;
4827                    // required
4828
case CodePoint.SQLSTT:
4829                        sqlStmt = parseEncodedString();
4830                        if (sqlStmt != null)
4831                        // then we have at least one SQL Statement.
4832
gotSqlStt = true;
4833
4834                        if (sqlStmt.startsWith(TIMEOUT_STATEMENT)) {
4835                            String JavaDoc timeoutString = sqlStmt.substring(TIMEOUT_STATEMENT.length());
4836                            pendingStatementTimeout = Integer.valueOf(timeoutString).intValue();
4837                            break;
4838                        }
4839
4840                        if (canIgnoreStmt(sqlStmt)) {
4841                        // We _know_ Cloudscape doesn't recognize this
4842
// statement; don't bother trying to execute it.
4843
// NOTE: at time of writing, this only applies
4844
// to "SET CLIENT" commands, and it was decided
4845
// that throwing a Warning for these commands
4846
// would confuse people, so even though the DDM
4847
// spec says to do so, we choose not to (but
4848
// only for SET CLIENT cases). If this changes
4849
// at some point in the future, simply remove
4850
// the follwing line; we will then throw a
4851
// warning.
4852
// hadUnrecognizedStmt = true;
4853
break;
4854                        }
4855
4856                        if (SanityManager.DEBUG)
4857                            trace("sqlStmt = " + sqlStmt);
4858
4859                        // initialize statement for reuse
4860
drdaStmt.initialize();
4861                        drdaStmt.getStatement().clearWarnings();
4862                        try {
4863                            drdaStmt.getStatement().executeUpdate(sqlStmt);
4864                        } catch (SQLException JavaDoc e) {
4865
4866                            // if this is a syntax error, then we take it
4867
// to mean that the given SET statement is not
4868
// recognized; take note (so we can throw a
4869
// warning later), but don't interfere otherwise.
4870
if (e.getSQLState().equals(SYNTAX_ERR))
4871                                hadUnrecognizedStmt = true;
4872                            else
4873                            // something else; assume it's serious.
4874
throw e;
4875                        }
4876                        break;
4877                    default:
4878                        invalidCodePoint(codePoint);
4879                }
4880            }
4881
4882        } while (reader.isChainedWithSameID());
4883
4884        // SQLSTT is required.
4885
if (!gotSqlStt)
4886            missingCodePoint(CodePoint.SQLSTT);
4887
4888        // Now that we've processed all SET statements (assuming no
4889
// severe exceptions), check for warnings and, if we had any,
4890
// note this in the SQLCARD reply object (but DON'T cause the
4891
// EXCSQLSET statement to fail).
4892
if (hadUnrecognizedStmt) {
4893            SQLWarning JavaDoc warn = new SQLWarning JavaDoc("One or more SET statements " +
4894                "not recognized.", "01000");
4895            throw warn;
4896        } // end if.
4897

4898        return;
4899    }
4900
4901    private boolean canIgnoreStmt(String JavaDoc stmt)
4902    {
4903        if (stmt.indexOf("SET CLIENT") != -1)
4904            return true;
4905        return false;
4906    }
4907
4908    /**
4909     * Write RDBUPDRM
4910     * Instance variables
4911     * SVRCOD - Severity code - Information only - required
4912     * RDBNAM - Relational database name -required
4913     * SRVDGN - Server Diagnostic Information -optional
4914     *
4915     * @exception DRDAProtocolException
4916     */

4917    private void writeRDBUPDRM() throws DRDAProtocolException
4918    {
4919        database.RDBUPDRM_sent = true;
4920        writer.createDssReply();
4921        writer.startDdm(CodePoint.RDBUPDRM);
4922        writer.writeScalar2Bytes(CodePoint.SVRCOD, CodePoint.SVRCOD_INFO);
4923        writeRDBNAM(database.dbName);
4924        writer.endDdmAndDss();
4925    }
4926
4927
4928    private String JavaDoc parsePKGNAMCT() throws DRDAProtocolException
4929    {
4930        reader.skipBytes();
4931        return null;
4932    }
4933
4934    /**
4935     * Parse PKGNAMCSN - RDB Package Name, Consistency Token, and Section Number
4936     * Instance Variables
4937     * NAMESYMDR - database name - not validated
4938     * RDBCOLID - RDB Collection Identifier
4939     * PKGID - RDB Package Identifier
4940     * PKGCNSTKN - RDB Package Consistency Token
4941     * PKGSN - RDB Package Section Number
4942     *
4943     * @return <code>Pkgnamcsn</code> value
4944     * @throws DRDAProtocolException
4945     */

4946    private Pkgnamcsn parsePKGNAMCSN() throws DRDAProtocolException
4947    {
4948        if (reader.getDdmLength() == CodePoint.PKGNAMCSN_LEN)
4949        {
4950            // This is a scalar object with the following fields
4951
reader.readString(rdbnam, CodePoint.RDBNAM_LEN, true);
4952            if (SanityManager.DEBUG)
4953                trace("rdbnam = " + rdbnam);
4954
4955            reader.readString(rdbcolid, CodePoint.RDBCOLID_LEN, true);
4956            if (SanityManager.DEBUG)
4957                trace("rdbcolid = " + rdbcolid);
4958
4959            reader.readString(pkgid, CodePoint.PKGID_LEN, true);
4960            if (SanityManager.DEBUG)
4961                trace("pkgid = " + pkgid);
4962
4963            // we need to use the same UCS2 encoding, as this can be
4964
// bounced back to jcc (or keep the byte array)
4965
reader.readString(pkgcnstkn, CodePoint.PKGCNSTKN_LEN, false);
4966            if (SanityManager.DEBUG)
4967                trace("pkgcnstkn = " + pkgcnstkn);
4968
4969            pkgsn = reader.readNetworkShort();
4970            if (SanityManager.DEBUG)
4971                trace("pkgsn = " + pkgsn);
4972        }
4973        else // extended format
4974
{
4975            int length = reader.readNetworkShort();
4976            if (length < CodePoint.RDBNAM_LEN || length > CodePoint.MAX_NAME)
4977                badObjectLength(CodePoint.RDBNAM);
4978            reader.readString(rdbnam, length, true);
4979            if (SanityManager.DEBUG)
4980                trace("rdbnam = " + rdbnam);
4981
4982            //RDBCOLID can be variable length in this format
4983
length = reader.readNetworkShort();
4984            reader.readString(rdbcolid, length, true);
4985            if (SanityManager.DEBUG)
4986                trace("rdbcolid = " + rdbcolid);
4987
4988            length = reader.readNetworkShort();
4989            if (length != CodePoint.PKGID_LEN)
4990                badObjectLength(CodePoint.PKGID);
4991            reader.readString(pkgid, CodePoint.PKGID_LEN, true);
4992            if (SanityManager.DEBUG)
4993                trace("pkgid = " + pkgid);
4994
4995            reader.readString(pkgcnstkn, CodePoint.PKGCNSTKN_LEN, false);
4996            if (SanityManager.DEBUG)
4997                trace("pkgcnstkn = " + pkgcnstkn);
4998
4999            pkgsn = reader.readNetworkShort();
5000            if (SanityManager.DEBUG)
5001                trace("pkgsn = " + pkgsn);
5002        }
5003
5004        // In most cases, the pkgnamcsn object is equal to the
5005
// previously returned object. To avoid allocation of a new
5006
// object in these cases, we first check to see if the old
5007
// object can be reused.
5008
if ((prevPkgnamcsn == null) ||
5009            rdbnam.wasModified() ||
5010            rdbcolid.wasModified() ||
5011            pkgid.wasModified() ||
5012            pkgcnstkn.wasModified() ||
5013            (prevPkgnamcsn.getPkgsn() != pkgsn))
5014        {
5015            // The byte array returned by pkgcnstkn.getBytes() might
5016
// be modified by DDMReader.readString() later, so we have
5017
// to create a copy of the array.
5018
byte[] token = new byte[pkgcnstkn.length()];
5019            System.arraycopy(pkgcnstkn.getBytes(), 0, token, 0, token.length);
5020
5021            prevPkgnamcsn =
5022                new Pkgnamcsn(rdbnam.toString(), rdbcolid.toString(),
5023                              pkgid.toString(), pkgsn,
5024                              new ConsistencyToken(token));
5025        }
5026
5027        return prevPkgnamcsn;
5028    }
5029
5030    /**
5031     * Parse SQLSTT Dss
5032     * @exception DRDAProtocolException
5033     */

5034    private String JavaDoc parseSQLSTTDss() throws DRDAProtocolException
5035    {
5036        correlationID = reader.readDssHeader();
5037        int codePoint = reader.readLengthAndCodePoint();
5038        String JavaDoc strVal = parseEncodedString();
5039        if (SanityManager.DEBUG)
5040            trace("SQL Statement = " + strVal);
5041        return strVal;
5042    }
5043
5044    /**
5045     * Parse an encoded data string from the Application Requester
5046     *
5047     * @return string value
5048     * @exception DRDAProtocolException
5049     */

5050    private String JavaDoc parseEncodedString() throws DRDAProtocolException
5051    {
5052        if (sqlamLevel < 7)
5053            return parseVCMorVCS();
5054        else
5055            return parseNOCMorNOCS();
5056    }
5057
5058    /**
5059     * Parse variable character mixed byte or variable character single byte
5060     * Format
5061     * I2 - VCM Length
5062     * N bytes - VCM value
5063     * I2 - VCS Length
5064     * N bytes - VCS value
5065     * Only 1 of VCM length or VCS length can be non-zero
5066     *
5067     * @return string value
5068     */

5069    private String JavaDoc parseVCMorVCS() throws DRDAProtocolException
5070    {
5071        String JavaDoc strVal = null;
5072        int vcm_length = reader.readNetworkShort();
5073        if (vcm_length > 0)
5074            strVal = parseCcsidMBC(vcm_length);
5075        int vcs_length = reader.readNetworkShort();
5076        if (vcs_length > 0)
5077        {
5078            if (strVal != null)
5079                agentError ("Both VCM and VCS have lengths > 0");
5080            strVal = parseCcsidSBC(vcs_length);
5081        }
5082        return strVal;
5083    }
5084    /**
5085     * Parse nullable character mixed byte or nullable character single byte
5086     * Format
5087     * 1 byte - null indicator
5088     * I4 - mixed character length
5089     * N bytes - mixed character string
5090     * 1 byte - null indicator
5091     * I4 - single character length
5092     * N bytes - single character length string
5093     *
5094     * @return string value
5095     * @exception DRDAProtocolException
5096     */

5097    private String JavaDoc parseNOCMorNOCS() throws DRDAProtocolException
5098    {
5099        byte nocm_nullByte = reader.readByte();
5100        String JavaDoc strVal = null;
5101        int length;
5102        if (nocm_nullByte != NULL_VALUE)
5103        {
5104            length = reader.readNetworkInt();
5105            strVal = parseCcsidMBC(length);
5106        }
5107        byte nocs_nullByte = reader.readByte();
5108        if (nocs_nullByte != NULL_VALUE)
5109        {
5110            if (strVal != null)
5111                agentError("Both CM and CS are non null");
5112            length = reader.readNetworkInt();
5113            strVal = parseCcsidSBC(length);
5114        }
5115        return strVal;
5116    }
5117    /**
5118     * Parse mixed character string
5119     *
5120     * @return string value
5121     * @exception DRDAProtocolException
5122     */

5123    private String JavaDoc parseCcsidMBC(int length) throws DRDAProtocolException
5124    {
5125        String JavaDoc strVal = null;
5126        DRDAStatement currentStatement;
5127
5128        currentStatement = database.getCurrentStatement();
5129        if (currentStatement == null)
5130        {
5131            currentStatement = database.getDefaultStatement();
5132            currentStatement.initialize();
5133        }
5134        String JavaDoc ccsidMBCEncoding = currentStatement.ccsidMBCEncoding;
5135
5136        if (length == 0)
5137            return null;
5138        byte [] byteStr = reader.readBytes(length);
5139        if (ccsidMBCEncoding != null)
5140        {
5141            try {
5142                strVal = new String JavaDoc(byteStr, 0, length, ccsidMBCEncoding);
5143            } catch (UnsupportedEncodingException JavaDoc e) {
5144                agentError("Unsupported encoding " + ccsidMBCEncoding +
5145                    "in parseCcsidMBC");
5146            }
5147        }
5148        else
5149            agentError("Attempt to decode mixed byte string without CCSID being set");
5150        return strVal;
5151    }
5152    /**
5153     * Parse single byte character string
5154     *
5155     * @return string value
5156     * @exception DRDAProtocolException
5157     */

5158    private String JavaDoc parseCcsidSBC(int length) throws DRDAProtocolException
5159    {
5160        String JavaDoc strVal = null;
5161        DRDAStatement currentStatement;
5162        
5163        currentStatement = database.getCurrentStatement();
5164        if (currentStatement == null)
5165        {
5166            currentStatement = database.getDefaultStatement();
5167            currentStatement.initialize();
5168        }
5169        String JavaDoc ccsidSBCEncoding = currentStatement.ccsidSBCEncoding;
5170        System.out.println("ccsidSBCEncoding - " + ccsidSBCEncoding);
5171        
5172        if (length == 0)
5173            return null;
5174        byte [] byteStr = reader.readBytes(length);
5175        if (ccsidSBCEncoding != null)
5176        {
5177            try {
5178                strVal = new String JavaDoc(byteStr, 0, length, ccsidSBCEncoding);
5179            } catch (UnsupportedEncodingException JavaDoc e) {
5180                agentError("Unsupported encoding " + ccsidSBCEncoding +
5181                    "in parseCcsidSBC");
5182            }
5183        }
5184        else
5185            agentError("Attempt to decode single byte string without CCSID being set");
5186        return strVal;
5187    }
5188    /**
5189     * Parse CLSQRY
5190     * Instance Variables
5191     * RDBNAM - relational database name - optional
5192     * PKGNAMCSN - RDB Package Name, Consistency Token and Section Number - required
5193     * QRYINSID - Query Instance Identifier - required - level 7
5194     * MONITOR - Monitor events - optional.
5195     *
5196     * @return DRDAstatement being closed
5197     * @throws DRDAProtocolException
5198     * @throws SQLException
5199     */

5200    private DRDAStatement parseCLSQRY() throws DRDAProtocolException, SQLException JavaDoc
5201    {
5202        Pkgnamcsn pkgnamcsn = null;
5203        reader.markCollection();
5204        long qryinsid = 0;
5205        boolean gotQryinsid = false;
5206
5207        int codePoint = reader.getCodePoint();
5208        while (codePoint != -1)
5209        {
5210            switch (codePoint)
5211            {
5212                // optional
5213
case CodePoint.RDBNAM:
5214                    setDatabase(CodePoint.CLSQRY);
5215                    break;
5216                    // required
5217
case CodePoint.PKGNAMCSN:
5218                    pkgnamcsn = parsePKGNAMCSN();
5219                    break;
5220                case CodePoint.QRYINSID:
5221                    qryinsid = reader.readNetworkLong();
5222                    gotQryinsid = true;
5223                    break;
5224                // optional
5225
case CodePoint.MONITOR:
5226                    parseMONITOR();
5227                    break;
5228                default:
5229                    invalidCodePoint(codePoint);
5230            }
5231            codePoint = reader.getCodePoint();
5232        }
5233        // check for required variables
5234
if (pkgnamcsn == null)
5235            missingCodePoint(CodePoint.PKGNAMCSN);
5236        if (sqlamLevel >= MGRLVL_7 && !gotQryinsid)
5237            missingCodePoint(CodePoint.QRYINSID);
5238
5239        DRDAStatement stmt = database.getDRDAStatement(pkgnamcsn);
5240        if (stmt == null)
5241        {
5242            //XXX should really throw a SQL Exception here
5243
invalidValue(CodePoint.PKGNAMCSN);
5244        }
5245
5246        if (stmt.wasExplicitlyClosed())
5247        {
5248            // JCC still sends a CLSQRY even though we have
5249
// implicitly closed the resultSet.
5250
// Then complains if we send the writeQRYNOPRM
5251
// So for now don't send it
5252
// Also metadata calls seem to get bound to the same
5253
// PGKNAMCSN, so even for explicit closes we have
5254
// to ignore.
5255
//writeQRYNOPRM(CodePoint.SVRCOD_ERROR);
5256
pkgnamcsn = null;
5257        }
5258
5259        stmt.CLSQRY();
5260       
5261        return stmt;
5262    }
5263
5264    /**
5265     * Parse MONITOR
5266     * DRDA spec says this is optional. Since we
5267     * don't currently support it, we just ignore.
5268     */

5269    private void parseMONITOR()
5270        throws DRDAProtocolException
5271    {
5272
5273        // Just ignore it.
5274
reader.skipBytes();
5275        return;
5276
5277    }
5278
5279    private void writeSQLCARDs(SQLException JavaDoc e, int updateCount)
5280                                    throws DRDAProtocolException
5281    {
5282        writeSQLCARDs(e, updateCount, false);
5283    }
5284
5285    private void writeSQLCARDs(SQLException JavaDoc e, int updateCount, boolean sendSQLERRRM)
5286                                    throws DRDAProtocolException
5287    {
5288
5289        int severity = CodePoint.SVRCOD_INFO;
5290        if (e == null)
5291        {
5292            writeSQLCARD(e,severity, updateCount, 0);
5293            return;
5294        }
5295
5296        // instead of writing a chain of sql error or warning, we send the first one, this is
5297
// jcc/db2 limitation, see beetle 4629
5298

5299        // If it is a real SQL Error write a SQLERRRM first
5300
severity = getExceptionSeverity(e);
5301        if (severity > CodePoint.SVRCOD_ERROR)
5302        {
5303            // For a session ending error > CodePoint.SRVCOD_ERROR you cannot
5304
// send a SQLERRRM. A CMDCHKRM is required. In XA if there is a
5305
// lock timeout it ends the whole session. I am not sure this
5306
// is the correct behaviour but if it occurs we have to send
5307
// a CMDCHKRM instead of SQLERRM
5308
writeCMDCHKRM(severity);
5309        }
5310        else if (sendSQLERRRM)
5311        {
5312            writeSQLERRRM(severity);
5313        }
5314        writeSQLCARD(e,severity, updateCount, 0);
5315    }
5316
5317    private int getSqlCode(int severity)
5318    {
5319        if (severity == CodePoint.SVRCOD_WARNING) // warning
5320
return 100; //CLI likes it
5321
else if (severity == CodePoint.SVRCOD_INFO)
5322            return 0;
5323        else
5324            return -1;
5325    }
5326
5327    private void writeSQLCARD(SQLException JavaDoc e,int severity,
5328        int updateCount, long rowCount ) throws DRDAProtocolException
5329    {
5330        writer.createDssObject();
5331        writer.startDdm(CodePoint.SQLCARD);
5332        writeSQLCAGRP(e, getSqlCode(severity), updateCount, rowCount);
5333        writer.endDdmAndDss();
5334
5335        // If we have a shutdown exception, restart the server.
5336
if (e != null) {
5337            String JavaDoc sqlState = e.getSQLState();
5338            if (sqlState.regionMatches(0,
5339              SQLState.CLOUDSCAPE_SYSTEM_SHUTDOWN, 0, 5)) {
5340            // then we're here because of a shutdown exception;
5341
// "clean up" by restarting the server.
5342
try {
5343                    server.startNetworkServer();
5344                } catch (Exception JavaDoc restart)
5345                // any error messages should have already been printed,
5346
// so we ignore this exception here.
5347
{}
5348            }
5349        }
5350
5351    }
5352
5353    /**
5354     * Write a null SQLCARD as an object
5355     *
5356     * @exception DRDAProtocolException
5357     */

5358    private void writeNullSQLCARDobject()
5359        throws DRDAProtocolException
5360    {
5361        writer.createDssObject();
5362        writer.startDdm(CodePoint.SQLCARD);
5363        writeSQLCAGRP(nullSQLState, 0, 0, 0);
5364        writer.endDdmAndDss();
5365    }
5366    /**
5367     * Write SQLERRRM
5368     *
5369     * Instance Variables
5370     * SVRCOD - Severity Code - required
5371     *
5372     * @param severity severity of error
5373     *
5374     * @exception DRDAProtocolException
5375     */

5376    private void writeSQLERRRM(int severity) throws DRDAProtocolException
5377    {
5378        writer.createDssReply();
5379        writer.startDdm(CodePoint.SQLERRRM);
5380        writer.writeScalar2Bytes(CodePoint.SVRCOD, severity);
5381        writer.endDdmAndDss ();
5382
5383    }
5384
5385    /**
5386     * Write CMDCHKRM
5387     *
5388     * Instance Variables
5389     * SVRCOD - Severity Code - required
5390     *
5391     * @param severity severity of error
5392     *
5393     * @exception DRDAProtocolException
5394     */

5395    private void writeCMDCHKRM(int severity) throws DRDAProtocolException
5396    {
5397        writer.createDssReply();
5398        writer.startDdm(CodePoint.CMDCHKRM);
5399        writer.writeScalar2Bytes(CodePoint.SVRCOD, severity);
5400        writer.endDdmAndDss ();
5401
5402    }
5403
5404    /**
5405     * Translate from Cloudscape exception severity to SVRCOD
5406     *
5407     * @param e SQLException
5408     */

5409    private int getExceptionSeverity (SQLException JavaDoc e)
5410    {
5411        int severity= CodePoint.SVRCOD_INFO;
5412
5413        if (e == null)
5414            return severity;
5415
5416        int ec = e.getErrorCode();
5417        switch (ec)
5418        {
5419            case ExceptionSeverity.STATEMENT_SEVERITY:
5420            case ExceptionSeverity.TRANSACTION_SEVERITY:
5421                severity = CodePoint.SVRCOD_ERROR;
5422                break;
5423            case ExceptionSeverity.WARNING_SEVERITY:
5424                severity = CodePoint.SVRCOD_WARNING;
5425                break;
5426            case ExceptionSeverity.SESSION_SEVERITY:
5427            case ExceptionSeverity.DATABASE_SEVERITY:
5428            case ExceptionSeverity.SYSTEM_SEVERITY:
5429                severity = CodePoint.SVRCOD_SESDMG;
5430                break;
5431            default:
5432                String JavaDoc sqlState = e.getSQLState();
5433                if (sqlState != null && sqlState.startsWith("01")) // warning
5434
severity = CodePoint.SVRCOD_WARNING;
5435                else
5436                    severity = CodePoint.SVRCOD_ERROR;
5437        }
5438
5439        return severity;
5440
5441    }
5442    /**
5443     * Write SQLCAGRP
5444     *
5445     * SQLCAGRP : FDOCA EARLY GROUP
5446     * SQL Communcations Area Group Description
5447     *
5448     * FORMAT FOR SQLAM <= 6
5449     * SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5450     * SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5451     * SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5452     * SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5453     *
5454     * FORMAT FOR SQLAM >= 7
5455     * SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5456     * SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5457     * SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5458     * SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5459     * SQLDIAGGRP; DRDA TYPE N-GDA; ENVLID 0x56; Length Override 0
5460     *
5461     * @param e SQLException encountered
5462     * @param sqlcode sqlcode
5463     *
5464     * @exception DRDAProtocolException
5465     */

5466    private void writeSQLCAGRP(SQLException JavaDoc e, int sqlcode, int updateCount,
5467            long rowCount) throws DRDAProtocolException
5468    {
5469        if (e == null) {
5470            // Forwarding to the optimized version when there is no
5471
// exception object
5472
writeSQLCAGRP(nullSQLState, sqlcode, updateCount, rowCount);
5473            return;
5474        }
5475
5476        if (rowCount < 0 && updateCount < 0)
5477        {
5478            writer.writeByte(CodePoint.NULLDATA);
5479            return;
5480        }
5481            
5482        if (SanityManager.DEBUG && server.debugOutput && sqlcode < 0) {
5483            trace("handle SQLException here");
5484            trace("reason is: "+e.getMessage());
5485            trace("SQLState is: "+e.getSQLState());
5486            trace("vendorCode is: "+e.getErrorCode());
5487            trace("nextException is: "+e.getNextException());
5488            server.consoleExceptionPrint(e);
5489            trace("wrapping SQLException into SQLCARD...");
5490        }
5491        
5492        //null indicator
5493
writer.writeByte(0);
5494
5495        // SQLCODE
5496
writer.writeInt(sqlcode);
5497
5498        // SQLSTATE
5499
writer.writeString(e.getSQLState());
5500
5501        // SQLERRPROC
5502
// Write the byte[] constant rather than the string, for efficiency
5503
writer.writeBytes(server.prdIdBytes_);
5504
5505        // SQLCAXGRP
5506
writeSQLCAXGRP(updateCount, rowCount, buildSqlerrmc(e), e.getNextException());
5507    }
5508
5509    /**
5510     * Same as writeSQLCAGRP, but optimized for the case
5511         * when there is no real exception, i.e. the exception is null, or "End
5512         * of data"
5513     *
5514     * SQLCAGRP : FDOCA EARLY GROUP
5515     * SQL Communcations Area Group Description
5516     *
5517     * FORMAT FOR SQLAM <= 6
5518     * SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5519     * SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5520     * SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5521     * SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5522     *
5523     * FORMAT FOR SQLAM >= 7
5524     * SQLCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5525     * SQLSTATE; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5526     * SQLERRPROC; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5527     * SQLCAXGRP; DRDA TYPE N-GDA; ENVLID 0x52; Length Override 0
5528     * SQLDIAGGRP; DRDA TYPE N-GDA; ENVLID 0x56; Length Override 0
5529     *
5530     * @param sqlState SQLState (already converted to UTF8)
5531     * @param sqlcode sqlcode
5532         * @param updateCount
5533         * @param rowCount
5534     *
5535     * @exception DRDAProtocolException
5536     */

5537
5538    private void writeSQLCAGRP(byte[] sqlState, int sqlcode,
5539                               int updateCount, long rowCount) throws DRDAProtocolException
5540    {
5541        if (rowCount < 0 && updateCount < 0) {
5542            writer.writeByte(CodePoint.NULLDATA);
5543            return;
5544        }
5545        
5546        //null indicator
5547
writer.writeByte(0);
5548        
5549        // SQLCODE
5550
writer.writeInt(sqlcode);
5551
5552        // SQLSTATE
5553
writer.writeBytes(sqlState);
5554
5555        // SQLERRPROC
5556
writer.writeBytes(server.prdIdBytes_);
5557
5558        // SQLCAXGRP (Uses null as sqlerrmc since there is no error)
5559
writeSQLCAXGRP(updateCount, rowCount, null, null);
5560    }
5561    
5562    
5563    // Delimiters for SQLERRMC values.
5564
// The token delimiter value will be used to parse the MessageId from the
5565
// SQLERRMC in MessageService.getLocalizedMessage and the MessageId will be
5566
// used to retrive the localized message. If this delimiter value is changed
5567
// please make sure to make appropriate changes in
5568
// MessageService.getLocalizedMessage that gets called from
5569
// SystemProcedures.SQLCAMESSAGE
5570
/**
5571     * <code>SQLERRMC_TOKEN_DELIMITER</code> separates message argument tokens
5572     */

5573    private static String JavaDoc SQLERRMC_TOKEN_DELIMITER = new String JavaDoc(new char[] {(char)20});
5574
5575    /**
5576     * <code>SQLERRMC_PREFORMATTED_MESSAGE_DELIMITER</code>, When full message text is
5577     * sent for severe errors. This value separates the messages.
5578     */

5579    private static String JavaDoc SQLERRMC_PREFORMATTED_MESSAGE_DELIMITER = new String JavaDoc("::");
5580    
5581    /**
5582     * Create error message or message argements to return to client.
5583     * The SQLERRMC will normally be passed back to the server in a call
5584     * to the SYSIBM.SQLCAMESSAGE but for severe exceptions the stored procedure
5585     * call cannot be made. So for Severe messages we will just send the message text.
5586     *
5587     * This method will also truncate the value according the client capacity.
5588     * CCC can only handle 70 characters.
5589     *
5590     * Server sends the sqlerrmc using UTF8 encoding to the client.
5591     * To get the message, client sends back information to the server
5592     * calling SYSIBM.SQLCAMESSAGE (see Sqlca.getMessage). Several parameters
5593     * are sent to this procedure including the locale, the sqlerrmc that the
5594     * client received from the server.
5595     * On server side, the procedure SQLCAMESSAGE in SystemProcedures then calls
5596     * the MessageService.getLocalizedMessage to retrieve the localized error message.
5597     * In MessageService.getLocalizedMessage the sqlerrmc that is passed in,
5598     * is parsed to retrieve the message id. The value it uses to parse the MessageId
5599     * is char value of 20, otherwise it uses the entire sqlerrmc as the message id.
5600     * This messageId is then used to retrieve the localized message if present, to
5601     * the client.
5602     *
5603     * @param se SQLException to build SQLERRMC
5604     *
5605     * @return String which is either the message arguments to be passed to
5606     * SYSIBM.SQLCAMESSAGE or just message text for severe errors.
5607     */

5608    private String JavaDoc buildSqlerrmc (SQLException JavaDoc se)
5609    {
5610        boolean severe = (se.getErrorCode() >= ExceptionSeverity.SESSION_SEVERITY);
5611        String JavaDoc sqlerrmc = null;
5612
5613        // get exception which carries Derby messageID and args, per DERBY-1178
5614
se = Util.getExceptionFactory().getArgumentFerry( se );
5615        
5616        if (se instanceof EmbedSQLException && ! severe)
5617            sqlerrmc = buildTokenizedSqlerrmc((EmbedSQLException) se);
5618        else {
5619            // If this is not an EmbedSQLException or is a severe excecption where
5620
// we have no hope of succussfully calling the SYSIBM.SQLCAMESSAGE send
5621
// preformatted message using the server locale
5622
sqlerrmc = buildPreformattedSqlerrmc(se);
5623            }
5624            // Truncate the sqlerrmc to a length that the client can support.
5625
int maxlen = (sqlerrmc == null) ? -1 : Math.min(sqlerrmc.length(),
5626                    appRequester.supportedMessageParamLength());
5627            if ((maxlen >= 0) && (sqlerrmc.length() > maxlen))
5628            // have to truncate so the client can handle it.
5629
sqlerrmc = sqlerrmc.substring(0, maxlen);
5630            return sqlerrmc;
5631        }
5632
5633    /**
5634     * Build preformatted SQLException text
5635     * for severe exceptions or SQLExceptions that are not EmbedSQLExceptions.
5636     * Just send the message text localized to the server locale.
5637     *
5638     * @param se SQLException for which to build SQLERRMC
5639     * @return preformated message text
5640     * with messages separted by SQLERRMC_PREFORMATED_MESSAGE_DELIMITER
5641     *
5642     */

5643    private String JavaDoc buildPreformattedSqlerrmc(SQLException JavaDoc se) {
5644        if (se == null)
5645            return "";
5646        
5647        StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
5648         // String buffer to build up message
5649
do {
5650            sb.append(se.getLocalizedMessage());
5651            se = se.getNextException();
5652            if (se != null)
5653                sb.append(SQLERRMC_PREFORMATTED_MESSAGE_DELIMITER +
5654                        "SQLSTATE: " + se.getSQLState());
5655        } while (se != null);
5656        return sb.toString();
5657    }
5658
5659    /**
5660     * Build Tokenized SQLERRMC to just send the tokenized arguments to the client.
5661     * for a Derby SQLException
5662     * Message argument tokens are separated by SQLERRMC_TOKEN_DELIMITER
5663     * Multiple messages are separated by SystemProcedures.SQLERRMC_MESSAGE_DELIMITER
5664     *
5665     * ...
5666     * @param se SQLException to print
5667     *
5668     */

5669    private String JavaDoc buildTokenizedSqlerrmc(EmbedSQLException se) {
5670        
5671        String JavaDoc sqlerrmc = "";
5672        do {
5673            String JavaDoc messageId = se.getMessageId();
5674            // arguments are variable part of a message
5675
Object JavaDoc[] args = se.getArguments();
5676            for (int i = 0; args != null && i < args.length; i++)
5677                sqlerrmc += args[i] + SQLERRMC_TOKEN_DELIMITER;
5678            sqlerrmc += messageId;
5679            se = (EmbedSQLException) se.getNextException();
5680            if (se != null)
5681            {
5682                sqlerrmc += SystemProcedures.SQLERRMC_MESSAGE_DELIMITER + se.getSQLState() + ":";
5683            }
5684        } while (se != null);
5685        return sqlerrmc;
5686    }
5687
5688    
5689    /**
5690     * Write SQLCAXGRP
5691     *
5692     * SQLCAXGRP : EARLY FDOCA GROUP
5693     * SQL Communications Area Exceptions Group Description
5694     *
5695     * FORMAT FOR SQLAM <= 6
5696     * SQLRDBNME; DRDA TYPE FCS; ENVLID 0x30; Length Override 18
5697     * SQLERRD1; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5698     * SQLERRD2; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5699     * SQLERRD3; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5700     * SQLERRD4; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5701     * SQLERRD5; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5702     * SQLERRD6; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5703     * SQLWARN0; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5704     * SQLWARN1; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5705     * SQLWARN2; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5706     * SQLWARN3; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5707     * SQLWARN4; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5708     * SQLWARN5; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5709     * SQLWARN6; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5710     * SQLWARN7; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5711     * SQLWARN8; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5712     * SQLWARN9; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5713     * SQLWARNA; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5714     * SQLERRMSG_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 70
5715     * SQLERRMSG_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 70
5716     *
5717     * FORMAT FOR SQLAM >= 7
5718     * SQLERRD1; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5719     * SQLERRD2; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5720     * SQLERRD3; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5721     * SQLERRD4; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5722     * SQLERRD5; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5723     * SQLERRD6; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5724     * SQLWARN0; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5725     * SQLWARN1; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5726     * SQLWARN2; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5727     * SQLWARN3; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5728     * SQLWARN4; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5729     * SQLWARN5; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5730     * SQLWARN6; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5731     * SQLWARN7; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5732     * SQLWARN8; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5733     * SQLWARN9; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5734     * SQLWARNA; DRDA TYPE FCS; ENVLID 0x30; Length Override 1
5735     * SQLRDBNAME; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
5736     * SQLERRMSG_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 70
5737     * SQLERRMSG_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 70
5738     * @param nextException SQLException encountered
5739     * @param sqlerrmc sqlcode
5740     *
5741     * @exception DRDAProtocolException
5742     */

5743    private void writeSQLCAXGRP(int updateCount, long rowCount, String JavaDoc sqlerrmc,
5744                SQLException JavaDoc nextException) throws DRDAProtocolException
5745    {
5746        writer.writeByte(0); // SQLCAXGRP INDICATOR
5747
if (sqlamLevel < 7)
5748        {
5749            writeRDBNAM(database.dbName);
5750            writeSQLCAERRWARN(updateCount, rowCount);
5751        }
5752        else
5753        {
5754            // SQL ERRD1 - D6, WARN0-WARNA (35 bytes)
5755
writeSQLCAERRWARN(updateCount, rowCount);
5756            writer.writeShort(0); //CCC on Win does not take RDBNAME
5757
}
5758        writeVCMorVCS(sqlerrmc);
5759        if (sqlamLevel >=7)
5760            writeSQLDIAGGRP(nextException);
5761    }
5762
5763    /**
5764     * Write the ERR and WARN part of the SQLCA
5765     *
5766     * @param updateCount
5767     * @param rowCount
5768     */

5769    private void writeSQLCAERRWARN(int updateCount, long rowCount)
5770    {
5771        // SQL ERRD1 - ERRD2 - row Count
5772
writer.writeInt((int)((rowCount>>>32)));
5773        writer.writeInt((int)(rowCount & 0x0000000ffffffffL));
5774        // SQL ERRD3 - updateCount
5775
writer.writeInt(updateCount);
5776        // SQL ERRD4 - D6 (12 bytes)
5777
writer.writeBytes(errD4_D6); // byte[] constant
5778
// WARN0-WARNA (11 bytes)
5779
writer.writeBytes(warn0_warnA); // byte[] constant
5780
}
5781
5782    /**
5783     * Write SQLDIAGGRP: SQL Diagnostics Group Description - Identity 0xD1
5784     * Nullable Group
5785     * SQLDIAGSTT; DRDA TYPE N-GDA; ENVLID 0xD3; Length Override 0
5786     * SQLDIAGCN; DRFA TYPE N-RLO; ENVLID 0xF6; Length Override 0
5787     * SQLDIAGCI; DRDA TYPE N-RLO; ENVLID 0xF5; Length Override 0
5788     */

5789    private void writeSQLDIAGGRP(SQLException JavaDoc nextException)
5790        throws DRDAProtocolException
5791    {
5792        // for now we only want to send ROW_DELETED and ROW_UPDATED warnings
5793
// as extended diagnostics
5794
// move to first ROW_DELETED or ROW_UPDATED exception. These have been
5795
// added to the end of the warning chain.
5796
while (
5797                nextException != null &&
5798                nextException.getSQLState() != SQLState.ROW_UPDATED &&
5799                nextException.getSQLState() != SQLState.ROW_DELETED) {
5800            nextException = nextException.getNextException();
5801        }
5802
5803        if ((nextException == null) ||
5804                (diagnosticLevel == CodePoint.DIAGLVL0)) {
5805            writer.writeByte(CodePoint.NULLDATA);
5806            return;
5807        }
5808        writer.writeByte(0); // SQLDIAGGRP indicator
5809

5810        writeSQLDIAGSTT();
5811        writeSQLDIAGCI(nextException);
5812        writeSQLDIAGCN();
5813    }
5814
5815    /*
5816     * writeSQLDIAGSTT: Write NULLDATA for now
5817     */

5818    private void writeSQLDIAGSTT()
5819        throws DRDAProtocolException
5820    {
5821        writer.writeByte(CodePoint.NULLDATA);
5822        return;
5823    }
5824
5825    /**
5826     * writeSQLDIAGCI: SQL Diagnostics Condition Information Array - Identity 0xF5
5827     * SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
5828     * SQLDCIROW; ROW LID 0xE5; ELEMENT TAKEN 0(all); REP FACTOR 0(all)
5829     */

5830    private void writeSQLDIAGCI(SQLException JavaDoc nextException)
5831        throws DRDAProtocolException
5832    {
5833        SQLException JavaDoc se = nextException;
5834        long rowNum = 1;
5835
5836        /* Write the number of next exceptions to expect */
5837        writeSQLNUMROW(se);
5838
5839        while (se != null)
5840        {
5841            String JavaDoc sqlState = se.getSQLState();
5842
5843            // SQLCode > 0 -> Warning
5844
// SQLCode = 0 -> Info
5845
// SQLCode < 0 -> Error
5846
int severity = getExceptionSeverity(se);
5847            int sqlCode = -1;
5848            if (severity == CodePoint.SVRCOD_WARNING)
5849                sqlCode = 1;
5850            else if (severity == CodePoint.SVRCOD_INFO)
5851                sqlCode = 0;
5852
5853            String JavaDoc sqlerrmc = "";
5854            if (diagnosticLevel == CodePoint.DIAGLVL1) {
5855                sqlerrmc = se.getLocalizedMessage();
5856            }
5857
5858            // arguments are variable part of a message
5859
// only send arguments for diagnostic level 0
5860
if (diagnosticLevel == CodePoint.DIAGLVL0) {
5861                // we are only able to get arguments of EmbedSQLException
5862
if (se instanceof EmbedSQLException) {
5863                    Object JavaDoc[] args = ((EmbedSQLException)se).getArguments();
5864                    for (int i = 0; args != null && i < args.length; i++)
5865                        sqlerrmc += args[i].toString() + SQLERRMC_TOKEN_DELIMITER;
5866                }
5867            }
5868
5869            String JavaDoc dbname = null;
5870            if (database != null)
5871                dbname = database.dbName;
5872
5873            writeSQLDCROW(rowNum++, sqlCode, sqlState, dbname, sqlerrmc);
5874
5875            se = se.getNextException();
5876        }
5877            
5878        return;
5879    }
5880
5881    /**
5882     * writeSQLNUMROW: Writes SQLNUMROW : FDOCA EARLY ROW
5883     * SQL Number of Elements Row Description
5884     * FORMAT FOR SQLAM LEVELS
5885     * SQLNUMGRP; GROUP LID 0x58; ELEMENT TAKEN 0(all); REP FACTOR 1
5886     */

5887    private void writeSQLNUMROW(SQLException JavaDoc nextException)
5888         throws DRDAProtocolException
5889    {
5890        writeSQLNUMGRP(nextException);
5891    }
5892
5893    /**
5894     * writeSQLNUMGRP: Writes SQLNUMGRP : FDOCA EARLY GROUP
5895     * SQL Number of Elements Group Description
5896     * FORMAT FOR ALL SQLAM LEVELS
5897     * SQLNUM; DRDA TYPE I2; ENVLID 0x04; Length Override 2
5898     */

5899    private void writeSQLNUMGRP(SQLException JavaDoc nextException)
5900         throws DRDAProtocolException
5901    {
5902        int i=0;
5903        SQLException JavaDoc se;
5904
5905        /* Count the number of chained exceptions to be sent */
5906        for (se = nextException; se != null; se = se.getNextException()) i++;
5907        writer.writeShort(i);
5908    }
5909
5910    /**
5911     * writeSQLDCROW: SQL Diagnostics Condition Row - Identity 0xE5
5912     * SQLDCGRP; GROUP LID 0xD5; ELEMENT TAKEN 0(all); REP FACTOR 1
5913     */

5914    private void writeSQLDCROW(long rowNum, int sqlCode, String JavaDoc sqlState, String JavaDoc dbname,
5915         String JavaDoc sqlerrmc) throws DRDAProtocolException
5916    {
5917        writeSQLDCGRP(rowNum, sqlCode, sqlState, dbname, sqlerrmc);
5918    }
5919
5920    /**
5921     * writeSQLDCGRP: SQL Diagnostics Condition Group Description
5922     *
5923     * SQLDCCODE; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5924     * SQLDCSTATE; DRDA TYPE FCS; ENVLID Ox30; Lengeh Override 5
5925     * SQLDCREASON; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5926     * SQLDCLINEN; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5927     * SQLDCROWN; DRDA TYPE FD; ENVLID 0x0E; Lengeh Override 31
5928     * SQLDCER01; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5929     * SQLDCER02; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5930     * SQLDCER03; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5931     * SQLDCER04; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5932     * SQLDCPART; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5933     * SQLDCPPOP; DRDA TYPE I4; ENVLID 0x02; Length Override 4
5934     * SQLDCMSGID; DRDA TYPE FCS; ENVLID 0x30; Length Override 10
5935     * SQLDCMDE; DRDA TYPE FCS; ENVLID 0x30; Length Override 8
5936     * SQLDCPMOD; DRDA TYPE FCS; ENVLID 0x30; Length Override 5
5937     * SQLDCRDB; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
5938     * SQLDCTOKS; DRDA TYPE N-RLO; ENVLID 0xF7; Length Override 0
5939     * SQLDCMSG_m; DRDA TYPE NVMC; ENVLID 0x3F; Length Override 32672
5940     * SQLDCMSG_S; DRDA TYPE NVCS; ENVLID 0x33; Length Override 32672
5941     * SQLDCCOLN_m; DRDA TYPE NVCM ; ENVLID 0x3F; Length Override 255
5942     * SQLDCCOLN_s; DRDA TYPE NVCS; ENVLID 0x33; Length Override 255
5943     * SQLDCCURN_m; DRDA TYPE NVCM; ENVLID 0x3F; Length Override 255
5944     * SQLDCCURN_s; DRDA TYPE NVCS; ENVLID 0x33; Length Override 255
5945     * SQLDCPNAM_m; DRDA TYPE NVCM; ENVLID 0x3F; Length Override 255
5946     * SQLDCPNAM_s; DRDA TYPE NVCS; ENVLID 0x33; Length Override 255
5947     * SQLDCXGRP; DRDA TYPE N-GDA; ENVLID 0xD3; Length Override 1
5948     */

5949    private void writeSQLDCGRP(long rowNum, int sqlCode, String JavaDoc sqlState, String JavaDoc dbname,
5950         String JavaDoc sqlerrmc) throws DRDAProtocolException
5951    {
5952        // SQLDCCODE
5953
writer.writeInt(sqlCode);
5954
5955        // SQLDCSTATE
5956
writer.writeString(sqlState);
5957
5958
5959        writer.writeInt(0); // REASON_CODE
5960
writer.writeInt(0); // LINE_NUMBER
5961
writer.writeLong(rowNum); // ROW_NUMBER
5962

5963        byte[] byteArray = new byte[1];
5964        writer.writeScalarPaddedBytes(byteArray, 47, (byte) 0);
5965
5966        writer.writeShort(0); // CCC on Win does not take RDBNAME
5967
writer.writeByte(CodePoint.NULLDATA); // MESSAGE_TOKENS
5968
writer.writeLDString(sqlerrmc); // MESSAGE_TEXT
5969

5970        writeVCMorVCS(null); // COLUMN_NAME
5971
writeVCMorVCS(null); // PARAMETER_NAME
5972
writeVCMorVCS(null); // EXTENDED_NAME
5973
writer.writeByte(CodePoint.NULLDATA); // SQLDCXGRP
5974
}
5975
5976    /*
5977     * writeSQLDIAGCN: Write NULLDATA for now
5978     */

5979    private void writeSQLDIAGCN()
5980        throws DRDAProtocolException
5981    {
5982        writer.writeByte(CodePoint.NULLDATA);
5983        return;
5984    }
5985
5986    /**
5987     * Write SQLDARD
5988     *
5989     * SQLDARD : FDOCA EARLY ARRAY
5990     * SQL Descriptor Area Row Description with SQL Communications Area
5991     *
5992     * FORMAT FOR SQLAM <= 6
5993     * SQLCARD; ROW LID 0x64; ELEMENT TAKEN 0(all); REP FACTOR 1
5994     * SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
5995     * SQLDAROW; ROW LID 0x60; ELEMENT TAKEN 0(all); REP FACTOR 0(all)
5996     *
5997     * FORMAT FOR SQLAM >= 7
5998     * SQLCARD; ROW LID 0x64; ELEMENT TAKEN 0(all); REP FACTOR 1
5999     * SQLDHROW; ROW LID 0xE0; ELEMENT TAKEN 0(all); REP FACTOR 1
6000     * SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
6001     *
6002     * @param stmt prepared statement
6003     *
6004     * @throws DRDAProtocolException
6005     * @throws SQLException
6006     */

6007    private void writeSQLDARD(DRDAStatement stmt, boolean rtnOutput, SQLException JavaDoc e) throws DRDAProtocolException, SQLException JavaDoc
6008    {
6009        PreparedStatement JavaDoc ps = stmt.getPreparedStatement();
6010        ResultSetMetaData JavaDoc rsmeta = ps.getMetaData();
6011        EngineParameterMetaData pmeta = stmt.getParameterMetaData();
6012        int numElems = 0;
6013        if (e == null || e instanceof SQLWarning JavaDoc)
6014        {
6015            if (rtnOutput && (rsmeta != null))
6016                numElems = rsmeta.getColumnCount();
6017            else if ((! rtnOutput) && (pmeta != null))
6018                numElems = pmeta.getParameterCount();
6019        }
6020
6021        writer.createDssObject();
6022
6023        // all went well we will just write a null SQLCA
6024
writer.startDdm(CodePoint.SQLDARD);
6025        writeSQLCAGRP(e, getSqlCode(getExceptionSeverity(e)), 0, 0);
6026
6027        if (sqlamLevel >= MGRLVL_7)
6028            writeSQLDHROW (stmt);
6029
6030        //SQLNUMROW
6031
if (SanityManager.DEBUG)
6032            trace("num Elements = " + numElems);
6033        writer.writeShort(numElems);
6034
6035        for (int i=0; i < numElems; i++)
6036            writeSQLDAGRP (rsmeta, pmeta, i, rtnOutput);
6037        writer.endDdmAndDss();
6038
6039    }
6040    /**
6041     * Write QRYDSC - Query Answer Set Description
6042     *
6043     * @param stmt DRDAStatement we are working on
6044     * @param FDODSConly simply the FDODSC, without the wrap
6045     *
6046     * Instance Variables
6047     * SQLDTAGRP - required
6048     *
6049     * Only 84 columns can be sent in a single QRYDSC. If there are more columns
6050     * they must be sent in subsequent QRYDSC.
6051     * If the QRYDSC will not fit into the current block, as many columns as can
6052     * fit are sent and then the remaining are sent in the following blocks.
6053     *
6054     * @throws DRDAProtocolException
6055     * @throws SQLException
6056     */

6057    private void writeQRYDSC(DRDAStatement stmt, boolean FDODSConly)
6058        throws DRDAProtocolException, SQLException JavaDoc
6059    {
6060
6061        ResultSet JavaDoc rs = null;
6062        ResultSetMetaData JavaDoc rsmeta = null;
6063        EngineParameterMetaData pmeta = null;
6064        if (!stmt.needsToSendParamData)
6065            rs = stmt.getResultSet();
6066        if (rs == null) // this is a CallableStatement, use parameter meta data
6067
pmeta = stmt.getParameterMetaData();
6068        else
6069            rsmeta = rs.getMetaData();
6070
6071        int numCols = (rsmeta != null ? rsmeta.getColumnCount() : pmeta.getParameterCount());
6072        int numGroups = 1;
6073        int colStart = 1;
6074        int colEnd = numCols;
6075        int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize() : CodePoint.QRYBLKSZ_MAX;
6076
6077        // check for remaining space in current query block
6078
// Need to mod with blksize so remaining doesn't go negative. 4868
6079
int remaining = blksize - (writer.getDSSLength() % blksize) - (3 +
6080                FdocaConstants.SQLCADTA_SQLDTARD_RLO_SIZE);
6081
6082
6083        // calcuate how may columns can be sent in the current query block
6084
int firstcols = remaining/FdocaConstants.SQLDTAGRP_COL_DSC_SIZE;
6085
6086        // check if it doesn't all fit into the first block and
6087
// under FdocaConstants.MAX_VARS_IN_NGDA
6088
if (firstcols < numCols || numCols > FdocaConstants.MAX_VARS_IN_NGDA)
6089        {
6090            // we are limited to FdocaConstants.MAX_VARS_IN_NGDA
6091
if (firstcols > FdocaConstants.MAX_VARS_IN_NGDA)
6092            {
6093                if (SanityManager.DEBUG)
6094                    SanityManager.ASSERT(numCols > FdocaConstants.MAX_VARS_IN_NGDA,
6095                        "Number of columns " + numCols +
6096                        " is less than MAX_VARS_IN_NGDA");
6097                numGroups = numCols/FdocaConstants.MAX_VARS_IN_NGDA;
6098                // some left over
6099
if (FdocaConstants.MAX_VARS_IN_NGDA * numGroups < numCols)
6100                    numGroups++;
6101                colEnd = FdocaConstants.MAX_VARS_IN_NGDA;
6102            }
6103            else
6104            {
6105                colEnd = firstcols;
6106                numGroups += (numCols-firstcols)/FdocaConstants.MAX_VARS_IN_NGDA;
6107                if (FdocaConstants.MAX_VARS_IN_NGDA * numGroups < numCols)
6108                    numGroups++;
6109            }
6110        }
6111
6112        if (! FDODSConly)
6113        {
6114            writer.createDssObject();
6115            writer.startDdm(CodePoint.QRYDSC);
6116        }
6117
6118        for (int i = 0; i < numGroups; i++)
6119        {
6120            writeSQLDTAGRP(stmt, rsmeta, pmeta, colStart, colEnd,
6121                            (i == 0 ? true : false));
6122            colStart = colEnd + 1;
6123            // 4868 - Limit range to MAX_VARS_IN_NGDA (used to have extra col)
6124
colEnd = colEnd + FdocaConstants.MAX_VARS_IN_NGDA;
6125            if (colEnd > numCols)
6126                colEnd = numCols;
6127        }
6128        writer.writeBytes(FdocaConstants.SQLCADTA_SQLDTARD_RLO);
6129        if (! FDODSConly)
6130            writer.endDdmAndDss();
6131    }
6132    /**
6133     * Write SQLDTAGRP
6134     * SQLDAGRP : Late FDOCA GROUP
6135     * SQL Data Value Group Descriptor
6136     * LENGTH - length of the SQLDTAGRP
6137     * TRIPLET_TYPE - NGDA for first, CPT for following
6138     * ID - SQLDTAGRP_LID for first, NULL_LID for following
6139     * For each column
6140     * DRDA TYPE
6141     * LENGTH OVERRIDE
6142     * For numeric/decimal types
6143     * PRECISON
6144     * SCALE
6145     * otherwise
6146     * LENGTH or DISPLAY_WIDTH
6147     *
6148     * @param stmt drda statement
6149     * @param rsmeta resultset meta data
6150     * @param pmeta parameter meta data for CallableStatement
6151     * @param colStart starting column for group to send
6152     * @param colEnd end column to send
6153     * @param first is this the first group
6154     *
6155     * @throws DRDAProtocolException
6156     * @throws SQLException
6157     */

6158    private void writeSQLDTAGRP(DRDAStatement stmt, ResultSetMetaData JavaDoc rsmeta,
6159                                EngineParameterMetaData pmeta,
6160                                int colStart, int colEnd, boolean first)
6161        throws DRDAProtocolException, SQLException JavaDoc
6162    {
6163
6164        int length = (FdocaConstants.SQLDTAGRP_COL_DSC_SIZE *
6165                    ((colEnd+1) - colStart)) + 3;
6166        writer.writeByte(length);
6167        if (first)
6168        {
6169
6170            writer.writeByte(FdocaConstants.NGDA_TRIPLET_TYPE);
6171            writer.writeByte(FdocaConstants.SQLDTAGRP_LID);
6172        }
6173        else
6174        {
6175            //continued
6176
writer.writeByte(FdocaConstants.CPT_TRIPLET_TYPE);
6177            writer.writeByte(FdocaConstants.NULL_LID);
6178
6179        }
6180
6181                           
6182
6183        boolean hasRs = (rsmeta != null); // if don't have result, then we look at parameter meta
6184

6185        for (int i = colStart; i <= colEnd; i++)
6186        {
6187            boolean nullable = (hasRs ? (rsmeta.isNullable(i) == rsmeta.columnNullable) :
6188                                                 (pmeta.isNullable(i) == JDBC30Translation.PARAMETER_NULLABLE));
6189            int colType = (hasRs ? rsmeta.getColumnType(i) : pmeta.getParameterType(i));
6190            int[] outlen = {-1};
6191            int drdaType =
6192                (hasRs ?FdocaConstants.mapJdbcTypeToDrdaType(colType,nullable,outlen):
6193                 stmt.getParamDRDAType(i));
6194
6195            boolean isDecimal = ((drdaType | 1) == DRDAConstants.DRDA_TYPE_NDECIMAL);
6196            int precision = 0, scale = 0;
6197            if (hasRs)
6198            {
6199                precision = rsmeta.getPrecision(i);
6200                scale = rsmeta.getScale(i);
6201                stmt.setRsDRDAType(i,drdaType);
6202                stmt.setRsPrecision(i, precision);
6203                stmt.setRsScale(i,scale);
6204            }
6205
6206            else if (isDecimal)
6207            {
6208                if (stmt.isOutputParam(i))
6209                    ((CallableStatement JavaDoc) stmt.ps).registerOutParameter(i,Types.DECIMAL);
6210                precision = pmeta.getPrecision(i);
6211                scale = pmeta.getScale(i);
6212
6213            }
6214
6215            if (SanityManager.DEBUG)
6216                trace("jdbcType=" + colType + " \tdrdaType=" + Integer.toHexString(drdaType));
6217
6218            // Length or precision and scale for decimal values.
6219
writer.writeByte(drdaType);
6220            if (isDecimal)
6221            {
6222                writer.writeByte(precision);
6223                writer.writeByte(scale);
6224            }
6225            else if (outlen[0] != -1)
6226                writer.writeShort(outlen[0]);
6227            else if (hasRs)
6228                writer.writeShort(rsmeta.getColumnDisplaySize(i));
6229            else
6230                writer.writeShort(stmt.getParamLen(i));
6231        }
6232    }
6233
6234
6235
6236    //pass PreparedStatement here so we can send correct holdability on the wire for jdk1.3 and higher
6237
//For jdk1.3, we provide hold cursor support through reflection.
6238
private void writeSQLDHROW (DRDAStatement stmt) throws DRDAProtocolException,SQLException JavaDoc
6239    {
6240        if (JVMInfo.JDK_ID < 2) //write null indicator for SQLDHROW because there is no holdability support prior to jdk1.3
6241
{
6242            writer.writeByte(CodePoint.NULLDATA);
6243            return;
6244        }
6245
6246        writer.writeByte(0); // SQLDHROW INDICATOR
6247

6248        //SQLDHOLD
6249
writer.writeShort(stmt.getResultSetHoldability());
6250        
6251        //SQLDRETURN
6252
writer.writeShort(0);
6253        //SQLDSCROLL
6254
writer.writeShort(0);
6255        //SQLDSENSITIVE
6256
writer.writeShort(0);
6257        //SQLDFCODE
6258
writer.writeShort(0);
6259        //SQLDKEYTYPE
6260
writer.writeShort(0);
6261        //SQLRDBNAME
6262
writer.writeShort(0); //CCC on Windows somehow does not take any dbname
6263
//SQLDSCHEMA
6264
writeVCMorVCS(null);
6265
6266    }
6267
6268    /**
6269     * Write QRYDTA - Query Answer Set Data
6270     * Contains some or all of the answer set data resulting from a query
6271     * If the client is not using rowset processing, this routine attempts
6272     * to pack as much data into the QRYDTA as it can. This may result in
6273     * splitting the last row across the block, in which case when the
6274     * client calls CNTQRY we will return the remainder of the row.
6275     *
6276     * Splitting a QRYDTA block is expensive, for several reasons:
6277     * - extra logic must be run, on both client and server side
6278     * - more network round-trips are involved
6279     * - the QRYDTA block which contains the continuation of the split
6280     * row is generally wasteful, since it contains the remainder of
6281     * the split row but no additional rows.
6282     * Since splitting is expensive, the server makes some attempt to
6283     * avoid it. Currently, the server's algorithm for this is to
6284     * compute the length of the current row, and to stop trying to pack
6285     * more rows into this buffer if another row of that length would
6286     * not fit. However, since rows can vary substantially in length,
6287     * this algorithm is often ineffective at preventing splits. For
6288     * example, if a short row near the end of the buffer is then
6289     * followed by a long row, that long row will be split. It is possible
6290     * to improve this algorithm substantially:
6291     * - instead of just using the length of the previous row as a guide
6292     * for whether to attempt packing another row in, use some sort of
6293     * overall average row size computed over multiple rows (e.g., all
6294     * the rows we've placed into this QRYDTA block, or all the rows
6295     * we've process for this result set)
6296     * - when we discover that the next row will not fit, rather than
6297     * splitting the row across QRYDTA blocks, if it is relatively
6298     * small, we could just hold the entire row in a buffer to place
6299     * it entirely into the next QRYDTA block, or reset the result
6300     * set cursor back one row to "unread" this row.
6301     * - when splitting a row across QRYDTA blocks, we tend to copy
6302     * data around multiple times. Careful coding could remove some
6303     * of these copies.
6304     * However, it is important not to over-complicate this code: it is
6305     * better to be correct than to be efficient, and there have been
6306     * several bugs in the split logic already.
6307     *
6308     * Instance Variables
6309     * Byte string
6310     *
6311     * @param stmt DRDA statement we are processing
6312     * @throws DRDAProtocolException
6313     * @throws SQLException
6314     */

6315    private void writeQRYDTA (DRDAStatement stmt)
6316        throws DRDAProtocolException, SQLException JavaDoc
6317    {
6318        boolean getMoreData = true;
6319        boolean sentExtData = false;
6320        int startLength = 0;
6321        writer.createDssObject();
6322
6323        if (SanityManager.DEBUG)
6324            trace("Write QRYDTA");
6325        writer.startDdm(CodePoint.QRYDTA);
6326        // Check to see if there was leftover data from splitting
6327
// the previous QRYDTA for this result set. If there was, and
6328
// if we have now sent all of it, send any EXTDTA for that row
6329
// and increment the rowCount which we failed to increment in
6330
// writeFDODTA when we realized the row needed to be split.
6331
if (processLeftoverQRYDTA(stmt))
6332        {
6333            if (stmt.getSplitQRYDTA() == null)
6334            {
6335                stmt.rowCount += 1;
6336                if (stmt.getExtDtaObjects() != null)
6337                    writeEXTDTA(stmt);
6338            }
6339            return;
6340        }
6341        
6342        while(getMoreData)
6343        {
6344            sentExtData = false;
6345            getMoreData = writeFDODTA(stmt);
6346
6347            if (stmt.getExtDtaObjects() != null &&
6348                    stmt.getSplitQRYDTA() == null)
6349            {
6350                writer.endDdmAndDss();
6351                writeEXTDTA(stmt);
6352                getMoreData=false;
6353                sentExtData = true;
6354            }
6355
6356            // if we don't have enough room for a row of the
6357
// last row's size, don't try to cram it in.
6358
// It would get split up but it is not very efficient.
6359
if (getMoreData == true)
6360            {
6361                int endLength = writer.getDSSLength();
6362                int rowsize = endLength - startLength;
6363                if ((stmt.getBlksize() - endLength ) < rowsize)
6364                    getMoreData = false;
6365
6366                startLength = endLength;
6367            }
6368
6369        }
6370        // If we sent extDta we will rely on
6371
// writeScalarStream to end the dss with the proper chaining.
6372
// otherwise end it here.
6373
if (! sentExtData)
6374            writer.endDdmAndDss();
6375
6376        if (!stmt.hasdata()) {
6377            final boolean qryclsOnLmtblkprc =
6378                appRequester.supportsQryclsimpForLmtblkprc();
6379            if (stmt.isRSCloseImplicit(qryclsOnLmtblkprc)) {
6380                stmt.rsClose();
6381            }
6382        }
6383    }
6384
6385    /**
6386     * This routine places some data into the current QRYDTA block using
6387     * FDODTA (Formatted Data Object DaTA rules).
6388     *
6389     * There are 3 basic types of processing flow for this routine:
6390     * - In normal non-rowset, non-scrollable cursor flow, this routine
6391     * places a single row into the QRYDTA block and returns TRUE,
6392     * indicating that the caller can call us back to place another
6393     * row into the result set if he wishes. (The caller may need to
6394     * send Externalized Data, which would be a reason for him NOT to
6395     * place any more rows into the QRYDTA).
6396     * - In ROWSET processing, this routine places an entire ROWSET of
6397     * rows into the QRYDTA block and returns FALSE, indicating that
6398     * the QRYDTA block is full and should now be sent.
6399     * - In callable statement processing, this routine places the
6400     * results from the output parameters of the called procedure into
6401     * the QRYDTA block. This code path is really dramatically
6402     * different from the other two paths and shares only a very small
6403     * amount of common code in this routine.
6404     *
6405     * In all cases, it is possible that the data we wish to return may
6406     * not fit into the QRYDTA block, in which case we call splitQRYDTA
6407     * to split the data and remember the remainder data in the result set.
6408     * Splitting the data is relatively rare in the normal cursor case,
6409     * because our caller (writeQRYDTA) uses a coarse estimation
6410     * technique to avoid calling us if he thinks a split is likely.
6411     *
6412     * The overall structure of this routine is implemented as two
6413     * loops:
6414     * - the outer "do ... while ... " loop processes a ROWSET, one row
6415     * at a time. For non-ROWSET cursors, and for callable statements,
6416     * this loop executes only once.
6417     * - the inner "for ... i < numCols ..." loop processes each column
6418     * in the current row, or each output parmeter in the procedure.
6419     *
6420     * Most column data is written directly inline in the QRYDTA block.
6421     * Some data, however, is written as Externalized Data. This is
6422     * commonly used for Large Objects. In that case, an Externalized
6423     * Data Pointer is written into the QRYDTA block, and the actual
6424     * data flows in separate EXTDTA blocks which are returned
6425     * after this QRYDTA block.
6426     */

6427    private boolean writeFDODTA (DRDAStatement stmt)
6428        throws DRDAProtocolException, SQLException JavaDoc
6429    {
6430        boolean hasdata = false;
6431        int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize() : CodePoint.QRYBLKSZ_MAX;
6432        long rowCount = 0;
6433        ResultSet JavaDoc rs =null;
6434        boolean moreData = (stmt.getQryprctyp()
6435                            == CodePoint.LMTBLKPRC);
6436        int numCols;
6437
6438        if (!stmt.needsToSendParamData)
6439        {
6440            rs = stmt.getResultSet();
6441        }
6442
6443        if (rs != null)
6444        {
6445            numCols = stmt.getNumRsCols();
6446            if (stmt.isScrollable())
6447                hasdata = positionCursor(stmt, rs);
6448            else
6449                hasdata = rs.next();
6450        }
6451        else // it's for a CallableStatement
6452
{
6453            hasdata = stmt.hasOutputParams();
6454            numCols = stmt.getNumParams();
6455        }
6456
6457
6458        do {
6459            if (!hasdata)
6460            {
6461                doneData(stmt, rs);
6462                moreData = false;
6463                return moreData;
6464            }
6465            
6466            // Send ResultSet warnings if there are any
6467
SQLWarning JavaDoc sqlw = (rs != null)? rs.getWarnings(): null;
6468            if (rs != null) {
6469                rs.clearWarnings();
6470            }
6471
6472            // for updatable, insensitive result sets we signal the
6473
// row updated condition to the client via a warning to be
6474
// popped by client onto its rowUpdated state, i.e. this
6475
// warning should not reach API level.
6476
if (rs != null && rs.rowUpdated()) {
6477                SQLWarning JavaDoc w = new SQLWarning JavaDoc("", SQLState.ROW_UPDATED,
6478                        ExceptionSeverity.WARNING_SEVERITY);
6479                if (sqlw != null) {
6480                    sqlw.setNextWarning(w);
6481                } else {
6482                    sqlw = w;
6483                }
6484            }
6485            // Delete holes are manifest as a row consisting of a non-null
6486
// SQLCARD and a null data group. The SQLCARD has a warning
6487
// SQLSTATE of 02502
6488
if (rs != null && rs.rowDeleted()) {
6489                SQLWarning JavaDoc w = new SQLWarning JavaDoc("", SQLState.ROW_DELETED,
6490                        ExceptionSeverity.WARNING_SEVERITY);
6491                if (sqlw != null) {
6492                    sqlw.setNextWarning(w);
6493                } else {
6494                    sqlw = w;
6495                }
6496            }
6497
6498            if (sqlw == null)
6499                writeSQLCAGRP(nullSQLState, 0, -1, -1);
6500            else
6501                writeSQLCAGRP(sqlw, sqlw.getErrorCode(), 1, -1);
6502
6503            // if we were asked not to return data, mark QRYDTA null; do not
6504
// return yet, need to make rowCount right
6505
// if the row has been deleted return QRYDTA null (delete hole)
6506
boolean noRetrieveRS = (rs != null &&
6507                    (!stmt.getQryrtndta() || rs.rowDeleted()));
6508            if (noRetrieveRS)
6509                writer.writeByte(0xFF); //QRYDTA null indicator: IS NULL
6510
else
6511                writer.writeByte(0); //QRYDTA null indicator: not null
6512

6513            for (int i = 1; i <= numCols; i++)
6514            {
6515                if (noRetrieveRS)
6516                    break;
6517
6518                int drdaType;
6519                int ndrdaType;
6520                int precision;
6521                int scale;
6522
6523                Object JavaDoc val = null;
6524                boolean valNull;
6525                if (rs != null)
6526                {
6527                    drdaType = stmt.getRsDRDAType(i) & 0xff;
6528                    precision = stmt.getRsPrecision(i);
6529                    scale = stmt.getRsScale(i);
6530                    ndrdaType = drdaType | 1;
6531
6532                    if (SanityManager.DEBUG)
6533                        trace("!!drdaType = " + java.lang.Integer.toHexString(drdaType) +
6534                                 "precision = " + precision +" scale = " + scale);
6535                    switch (ndrdaType)
6536                    {
6537                        case DRDAConstants.DRDA_TYPE_NLOBBYTES:
6538                        case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
6539                            EXTDTAInputStream extdtaStream=
6540                                EXTDTAInputStream.getEXTDTAStream(rs, i, drdaType);
6541                            writeFdocaVal(i,extdtaStream, drdaType,
6542                                          precision,scale,rs.wasNull(),stmt);
6543                            break;
6544                        case DRDAConstants.DRDA_TYPE_NINTEGER:
6545                            int ival = rs.getInt(i);
6546                            valNull = rs.wasNull();
6547                            if (SanityManager.DEBUG)
6548                                trace("====== writing int: "+ ival + " is null: " + valNull);
6549                            writeNullability(drdaType,valNull);
6550                            if (! valNull)
6551                                writer.writeInt(ival);
6552                            break;
6553                        case DRDAConstants.DRDA_TYPE_NSMALL:
6554                            short sval = rs.getShort(i);
6555                            valNull = rs.wasNull();
6556                            if (SanityManager.DEBUG)
6557                                trace("====== writing small: "+ sval + " is null: " + valNull);
6558                            writeNullability(drdaType,valNull);
6559                            if (! valNull)
6560                                writer.writeShort(sval);
6561                            break;
6562                        case DRDAConstants.DRDA_TYPE_NINTEGER8:
6563                            long lval = rs.getLong(i);
6564                            valNull = rs.wasNull();
6565                            if (SanityManager.DEBUG)
6566                                trace("====== writing long: "+ lval + " is null: " + valNull);
6567                            writeNullability(drdaType,valNull);
6568                            if (! valNull)
6569                                writer.writeLong(lval);
6570                            break;
6571                        case DRDAConstants.DRDA_TYPE_NFLOAT4:
6572                            float fval = rs.getFloat(i);
6573                            valNull = rs.wasNull();
6574                            if (SanityManager.DEBUG)
6575                                trace("====== writing float: "+ fval + " is null: " + valNull);
6576                            writeNullability(drdaType,valNull);
6577                            if (! valNull)
6578                                writer.writeFloat(fval);
6579                            break;
6580                        case DRDAConstants.DRDA_TYPE_NFLOAT8:
6581                            double dval = rs.getDouble(i);
6582                            valNull = rs.wasNull();
6583                            if (SanityManager.DEBUG)
6584                                trace("====== writing double: "+ dval + " is null: " + valNull);
6585                            writeNullability(drdaType,valNull);
6586                            if (! valNull)
6587                                writer.writeDouble(dval);
6588                            break;
6589                        case DRDAConstants.DRDA_TYPE_NCHAR:
6590                        case DRDAConstants.DRDA_TYPE_NVARCHAR:
6591                        case DRDAConstants.DRDA_TYPE_NVARMIX:
6592                        case DRDAConstants.DRDA_TYPE_NLONG:
6593                        case DRDAConstants.DRDA_TYPE_NLONGMIX:
6594                            String JavaDoc valStr = rs.getString(i);
6595                            if (SanityManager.DEBUG)
6596                                trace("====== writing char/varchar/mix :"+ valStr + ":");
6597                            writeFdocaVal(i, valStr, drdaType,
6598                                          precision,scale,rs.wasNull(),stmt);
6599                            break;
6600                        default:
6601                            writeFdocaVal(i, rs.getObject(i),drdaType,
6602                                          precision,scale,rs.wasNull(),stmt);
6603                    }
6604                }
6605                else
6606                {
6607                    drdaType = stmt.getParamDRDAType(i) & 0xff;
6608                    precision = stmt.getParamPrecision(i);
6609                    scale = stmt.getParamScale(i);
6610                    ndrdaType = drdaType | 1;
6611                    
6612                    if (stmt.isOutputParam(i)) {
6613                        if (SanityManager.DEBUG)
6614                            trace("***getting Object "+i);
6615                        val = ((CallableStatement JavaDoc) stmt.ps).getObject(i);
6616                        valNull = (val == null);
6617                        writeFdocaVal(i,val,drdaType,precision, scale, valNull,stmt);
6618                    }
6619                    else
6620                        writeFdocaVal(i,null,drdaType,precision,scale,true,stmt);
6621
6622                }
6623            }
6624            // does all this fit in one QRYDTA
6625
if (writer.getDSSLength() > blksize)
6626            {
6627                splitQRYDTA(stmt, blksize);
6628                return false;
6629            }
6630
6631            if (rs == null)
6632                return moreData;
6633
6634            //get the next row
6635
rowCount++;
6636            if (rowCount < stmt.getQryrowset())
6637            {
6638                hasdata = rs.next();
6639            }
6640            /*(1) scrollable we return at most a row set; OR (2) no retrieve data
6641             */

6642            else if (stmt.isScrollable() || noRetrieveRS)
6643                moreData=false;
6644
6645        } while (hasdata && rowCount < stmt.getQryrowset());
6646
6647        // add rowCount to statement row count
6648
// for non scrollable cursors
6649
if (!stmt.isScrollable())
6650            stmt.rowCount += rowCount;
6651
6652        if (!hasdata)
6653        {
6654            doneData(stmt, rs);
6655            moreData=false;
6656        }
6657
6658        if (!stmt.isScrollable())
6659            stmt.setHasdata(hasdata);
6660        return moreData;
6661    }
6662    /**
6663     * Split QRYDTA into blksize chunks
6664     *
6665     * This routine is called if the QRYDTA data will not fit. It writes
6666     * as much data as it can, then stores the remainder in the result
6667     * set. At some later point, when the client returns with a CNTQRY,
6668     * we will call processLeftoverQRYDTA to handle that data.
6669     *
6670     * The interaction between DRDAConnThread and DDMWriter is rather
6671     * complicated here. This routine gets called because DRDAConnThread
6672     * realizes that it has constructed a QRYDTA message which is too
6673     * large. At that point, we need to reclaim the "extra" data and
6674     * hold on to it. To aid us in that processing, DDMWriter provides
6675     * the routines getDSSLength, copyDSSDataToEnd, and truncateDSS.
6676     * For some additional detail on this complex sub-protocol, the
6677     * interested reader should study bug DERBY-491 and 492 at:
6678     * http://issues.apache.org/jira/browse/DERBY-491 and
6679     * http://issues.apache.org/jira/browse/DERBY-492
6680     *
6681     * @param stmt DRDA statment
6682     * @param blksize size of query block
6683     *
6684     * @throws SQLException
6685     * @throws DRDAProtocolException
6686     */

6687    private void splitQRYDTA(DRDAStatement stmt, int blksize) throws SQLException JavaDoc,
6688            DRDAProtocolException
6689    {
6690        // make copy of extra data
6691
byte [] temp = writer.copyDSSDataToEnd(blksize);
6692        // truncate to end of blocksize
6693
writer.truncateDSS(blksize);
6694        if (temp.length == 0)
6695            agentError("LMTBLKPRC violation: splitQRYDTA was " +
6696                "called to split a QRYDTA block, but the " +
6697                "entire row fit successfully into the " +
6698                "current block. Server rowsize computation " +
6699                "was probably incorrect (perhaps an off-by-" +
6700                "one bug?). QRYDTA blocksize: " + blksize);
6701        stmt.setSplitQRYDTA(temp);
6702    }
6703    /*
6704     * Process remainder data resulting from a split.
6705     *
6706     * This routine is called at the start of building each QRYDTA block.
6707     * Normally, it observes that there is no remainder data from the
6708     * previous QRYDTA block, and returns FALSE, indicating that there
6709     * was nothing to do.
6710     *
6711     * However, if it discovers that the previous QRYDTA block was split,
6712     * then it retrieves the remainder data from the result set, writes
6713     * as much of it as will fit into the QRYDTA block (hopefully all of
6714     * it will fit, but the row may be very long), and returns TRUE,
6715     * indicating that this QRYDTA block has been filled with remainder
6716     * data and should now be sent immediately.
6717     */

6718    private boolean processLeftoverQRYDTA(DRDAStatement stmt)
6719        throws SQLException JavaDoc,DRDAProtocolException
6720    {
6721        byte []leftovers = stmt.getSplitQRYDTA();
6722        if (leftovers == null)
6723            return false;
6724        int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize() : CodePoint.QRYBLKSZ_MAX;
6725        blksize = blksize - 10; //DSS header + QRYDTA and length
6726
if (leftovers.length < blksize)
6727        {
6728            writer.writeBytes(leftovers, 0, leftovers.length);
6729            stmt.setSplitQRYDTA(null);
6730        }
6731        else
6732        {
6733            writer.writeBytes(leftovers, 0, blksize);
6734            byte []newLeftovers = new byte[leftovers.length-blksize];
6735            for (int i = 0; i < newLeftovers.length; i++)
6736                newLeftovers[i] = leftovers[blksize+i];
6737            stmt.setSplitQRYDTA(newLeftovers);
6738        }
6739        // finish off query block and send
6740
writer.endDdmAndDss();
6741        return true;
6742    }
6743
6744
6745    /**
6746     * Done data
6747     * Send SQLCARD for the end of the data
6748     *
6749     * @param stmt DRDA statement
6750     * @param rs Result set
6751     * @throws DRDAProtocolException
6752     * @throws SQLException
6753     */

6754    private void doneData(DRDAStatement stmt, ResultSet JavaDoc rs)
6755            throws DRDAProtocolException, SQLException JavaDoc
6756    {
6757        if (SanityManager.DEBUG)
6758            trace("*****NO MORE DATA!!");
6759        int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize() : CodePoint.QRYBLKSZ_MAX;
6760        if (rs != null)
6761        {
6762            if (stmt.isScrollable())
6763            {
6764                                //keep isAfterLast and isBeforeFirst to be able
6765
//to reposition after counting rows
6766
boolean isAfterLast = rs.isAfterLast();
6767                                boolean isBeforeFirst = rs.isBeforeFirst();
6768                                
6769                // for scrollable cursors - calculate the row count
6770
// since we may not have gone through each row
6771
rs.last();
6772                stmt.rowCount = rs.getRow();
6773
6774                                // reposition after last or before first
6775
if (isAfterLast) {
6776                                    rs.afterLast();
6777                                }
6778                                if (isBeforeFirst) {
6779                                    rs.beforeFirst();
6780                                }
6781            }
6782            else // non-scrollable cursor
6783
{
6784                final boolean qryclsOnLmtblkprc =
6785                    appRequester.supportsQryclsimpForLmtblkprc();
6786                if (stmt.isRSCloseImplicit(qryclsOnLmtblkprc)) {
6787                    stmt.rsClose();
6788                    stmt.rsSuspend();
6789                }
6790             
6791            }
6792        }
6793
6794        // For scrollable cursor's QRYSCRAFT, when we reach here, DRDA spec says sqlstate
6795
// is 00000, sqlcode is not mentioned. But DB2 CLI code expects sqlcode to be 0.
6796
// We return sqlcode 0 in this case, as the DB2 server does.
6797
boolean isQRYSCRAFT = (stmt.getQryscrorn() == CodePoint.QRYSCRAFT);
6798
6799        // Using sqlstate 00000 or 02000 for end of data.
6800
writeSQLCAGRP((isQRYSCRAFT ? eod00000 : eod02000),
6801                              (isQRYSCRAFT ? 0 : 100), 0, stmt.rowCount);
6802                
6803        writer.writeByte(CodePoint.NULLDATA);
6804        // does all this fit in one QRYDTA
6805
if (writer.getDSSLength() > blksize)
6806        {
6807            splitQRYDTA(stmt, blksize);
6808        }
6809    }
6810    /**
6811     * Position cursor for insensitive scrollable cursors
6812     *
6813     * @param stmt DRDA statement
6814     * @param rs Result set
6815     */

6816    private boolean positionCursor(DRDAStatement stmt, ResultSet JavaDoc rs)
6817        throws SQLException JavaDoc, DRDAProtocolException
6818    {
6819        boolean retval = false;
6820        switch (stmt.getQryscrorn())
6821        {
6822            case CodePoint.QRYSCRREL:
6823                                int rows = (int)stmt.getQryrownbr();
6824                                if ((rs.isAfterLast() && rows > 0) || (rs.isBeforeFirst() && rows < 0)) {
6825                                    retval = false;
6826                                } else {
6827                                    retval = rs.relative(rows);
6828                                }
6829                                break;
6830            case CodePoint.QRYSCRABS:
6831                // JCC uses an absolute value of 0 which is not allowed in JDBC
6832
// We translate it into beforeFirst which seems to work.
6833
if (stmt.getQryrownbr() == 0)
6834                {
6835                    rs.beforeFirst();
6836                    retval = false;
6837                }
6838                else
6839                {
6840                    retval = rs.absolute((int)stmt.getQryrownbr());
6841                }
6842                break;
6843            case CodePoint.QRYSCRAFT:
6844                rs.afterLast();
6845                retval = false;
6846                break;
6847            case CodePoint.QRYSCRBEF:
6848                rs.beforeFirst();
6849                retval = false;
6850                break;
6851            default:
6852                agentError("Invalid value for cursor orientation "+ stmt.getQryscrorn());
6853        }
6854        return retval;
6855    }
6856    /**
6857     * Write SQLDAGRP
6858     * SQLDAGRP : EARLY FDOCA GROUP
6859     * SQL Data Area Group Description
6860     *
6861     * FORMAT FOR SQLAM <= 6
6862     * SQLPRECISION; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6863     * SQLSCALE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6864     * SQLLENGTH; DRDA TYPE I4; ENVLID 0x02; Length Override 4
6865     * SQLTYPE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6866     * SQLCCSID; DRDA TYPE FB; ENVLID 0x26; Length Override 2
6867     * SQLNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6868     * SQLNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6869     * SQLLABEL_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6870     * SQLLABEL_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6871     * SQLCOMMENTS_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 254
6872     * SQLCOMMENTS_m; DRDA TYPE VCS; ENVLID 0x32; Length Override 254
6873     *
6874     * FORMAT FOR SQLAM == 6
6875     * SQLPRECISION; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6876     * SQLSCALE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6877     * SQLLENGTH; DRDA TYPE I8; ENVLID 0x16; Length Override 8
6878     * SQLTYPE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6879     * SQLCCSID; DRDA TYPE FB; ENVLID 0x26; Length Override 2
6880     * SQLNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6881     * SQLNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6882     * SQLLABEL_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 30
6883     * SQLLABEL_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 30
6884     * SQLCOMMENTS_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 254
6885     * SQLCOMMENTS_m; DRDA TYPE VCS; ENVLID 0x32; Length Override 254
6886     * SQLUDTGRP; DRDA TYPE N-GDA; ENVLID 0x51; Length Override 0
6887     *
6888     * FORMAT FOR SQLAM >= 7
6889     * SQLPRECISION; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6890     * SQLSCALE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6891     * SQLLENGTH; DRDA TYPE I8; ENVLID 0x16; Length Override 8
6892     * SQLTYPE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
6893     * SQLCCSID; DRDA TYPE FB; ENVLID 0x26; Length Override 2
6894     * SQLDOPTGRP; DRDA TYPE N-GDA; ENVLID 0xD2; Length Override 0
6895     *
6896     * @param rsmeta resultset meta data
6897     * @param pmeta parameter meta data
6898     * @param elemNum column number we are returning (in case of result set), or,
6899     * parameter number (in case of parameter)
6900     * @param rtnOutput whether this is for a result set
6901     *
6902     * @throws DRDAProtocolException
6903     * @throws SQLException
6904     */

6905    private void writeSQLDAGRP(ResultSetMetaData JavaDoc rsmeta, EngineParameterMetaData pmeta, int elemNum, boolean rtnOutput)
6906        throws DRDAProtocolException, SQLException JavaDoc
6907    {
6908        //jdbc uses offset of 1
6909

6910        int jdbcElemNum = elemNum +1;
6911        // length to be retreived as output parameter
6912
int[] outlen = {-1};
6913
6914        int elemType = rtnOutput ? rsmeta.getColumnType(jdbcElemNum) : pmeta.getParameterType(jdbcElemNum);
6915
6916        int precision = rtnOutput ? rsmeta.getPrecision(jdbcElemNum) : pmeta.getPrecision(jdbcElemNum);
6917        if (precision > FdocaConstants.NUMERIC_MAX_PRECISION)
6918            precision = FdocaConstants.NUMERIC_MAX_PRECISION;
6919
6920        // 2-byte precision
6921
writer.writeShort(precision);
6922        // 2-byte scale
6923
int scale = (rtnOutput ? rsmeta.getScale(jdbcElemNum) : pmeta.getScale(jdbcElemNum));
6924        writer.writeShort(scale);
6925
6926        boolean nullable = rtnOutput ? (rsmeta.isNullable(jdbcElemNum) ==
6927                                        ResultSetMetaData.columnNullable) :
6928            (pmeta.isNullable(jdbcElemNum) == JDBC30Translation.PARAMETER_NULLABLE);
6929        
6930        int sqlType = SQLTypes.mapJdbcTypeToDB2SqlType(elemType,
6931                                                       nullable,
6932                                                       outlen);
6933        
6934        if (outlen[0] == -1) //some types not set
6935
{
6936            switch (elemType)
6937            {
6938                case Types.DECIMAL:
6939                case Types.NUMERIC:
6940                    scale = rtnOutput ? rsmeta.getScale(jdbcElemNum) : pmeta.getScale(jdbcElemNum);
6941                    outlen[0] = ((precision <<8) | (scale <<0));
6942                    if (SanityManager.DEBUG)
6943                        trace("\n\nprecision =" +precision +
6944                          " scale =" + scale);
6945                    break;
6946                default:
6947                    outlen[0] = Math.min(FdocaConstants.LONGVARCHAR_MAX_LEN,
6948                                        (rtnOutput ? rsmeta.getColumnDisplaySize(jdbcElemNum) :
6949                                                pmeta.getPrecision(jdbcElemNum)));
6950            }
6951        }
6952
6953        switch (elemType)
6954        {
6955            case Types.BINARY:
6956            case Types.VARBINARY:
6957            case Types.LONGVARBINARY:
6958            case Types.BLOB: //for CLI describe to be correct
6959
case Types.CLOB:
6960                outlen[0] = (rtnOutput ? rsmeta.getPrecision(jdbcElemNum) :
6961                                            pmeta.getPrecision(jdbcElemNum));
6962        }
6963
6964        if (SanityManager.DEBUG)
6965            trace("SQLDAGRP len =" + java.lang.Integer.toHexString(outlen[0]) + "for type:" + elemType);
6966
6967       // 8 or 4 byte sqllength
6968
if (sqlamLevel >= MGRLVL_6)
6969            writer.writeLong(outlen[0]);
6970        else
6971            writer.writeInt(outlen[0]);
6972
6973
6974        String JavaDoc typeName = rtnOutput ? rsmeta.getColumnTypeName(jdbcElemNum) :
6975                                        pmeta.getParameterTypeName(jdbcElemNum);
6976        if (SanityManager.DEBUG)
6977            trace("jdbcType =" + typeName + " sqlType =" + sqlType + "len =" +outlen[0]);
6978
6979        writer.writeShort(sqlType);
6980
6981        // CCSID
6982
// CCSID should be 0 for Binary Types.
6983

6984        if (elemType == java.sql.Types.CHAR ||
6985            elemType == java.sql.Types.VARCHAR
6986            || elemType == java.sql.Types.LONGVARCHAR
6987            || elemType == java.sql.Types.CLOB)
6988            writer.writeScalar2Bytes(1208);
6989        else
6990            writer.writeScalar2Bytes(0);
6991
6992        if (sqlamLevel < MGRLVL_7)
6993        {
6994
6995            //SQLName
6996
writeVCMorVCS(rtnOutput ? rsmeta.getColumnName(jdbcElemNum) : null);
6997            //SQLLabel
6998
writeVCMorVCS(null);
6999            //SQLComments
7000
writeVCMorVCS(null);
7001
7002            if (sqlamLevel == MGRLVL_6)
7003                writeSQLUDTGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
7004        }
7005        else
7006        {
7007            writeSQLDOPTGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
7008        }
7009
7010    }
7011
7012    /**
7013     * Write variable character mixed byte or single byte
7014     * The preference is to write mixed byte if it is defined for the server,
7015     * since that is our default and we don't allow it to be changed, we always
7016     * write mixed byte.
7017     *
7018     * @param s string to write
7019     * @exception DRDAProtocolException
7020     */

7021    private void writeVCMorVCS(String JavaDoc s)
7022        throws DRDAProtocolException
7023    {
7024        //Write only VCM and 0 length for VCS
7025

7026        if (s == null)
7027        {
7028            writer.writeShort(0);
7029            writer.writeShort(0);
7030            return;
7031        }
7032
7033        // VCM
7034
writer.writeLDString(s);
7035        // VCS
7036
writer.writeShort(0);
7037    }
7038
7039  
7040    private void writeSQLUDTGRP(ResultSetMetaData JavaDoc rsmeta, EngineParameterMetaData pmeta, int jdbcElemNum, boolean rtnOutput)
7041        throws DRDAProtocolException,SQLException JavaDoc
7042    {
7043        writer.writeByte(CodePoint.NULLDATA);
7044
7045    }
7046
7047    private void writeSQLDOPTGRP(ResultSetMetaData JavaDoc rsmeta, EngineParameterMetaData pmeta, int jdbcElemNum, boolean rtnOutput)
7048        throws DRDAProtocolException,SQLException JavaDoc
7049    {
7050
7051        writer.writeByte(0);
7052        //SQLUNAMED
7053
writer.writeShort(0);
7054        //SQLName
7055
writeVCMorVCS(rtnOutput ? rsmeta.getColumnName(jdbcElemNum) : null);
7056        //SQLLabel
7057
writeVCMorVCS(null);
7058        //SQLComments
7059
writeVCMorVCS(null);
7060        //SQLDUDTGRP
7061
writeSQLUDTGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
7062        //SQLDXGRP
7063
writeSQLDXGRP(rsmeta, pmeta, jdbcElemNum, rtnOutput);
7064    }
7065
7066
7067    private void writeSQLDXGRP(ResultSetMetaData JavaDoc rsmeta, EngineParameterMetaData pmeta, int jdbcElemNum, boolean rtnOutput)
7068        throws DRDAProtocolException,SQLException JavaDoc
7069    {
7070        // Null indicator indicates we have data
7071
writer.writeByte(0);
7072        // SQLXKEYMEM; DRDA TYPE I2; ENVLID 0x04; Length Override 2
7073
// Hard to get primary key info. Send 0 for now
7074
writer.writeShort(0);
7075        // SQLXUPDATEABLE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
7076
writer.writeShort(rtnOutput ? rsmeta.isWritable(jdbcElemNum) : false);
7077
7078        // SQLXGENERATED; DRDA TYPE I2; ENVLID 0x04; Length Override 2
7079
if (rtnOutput && rsmeta.isAutoIncrement(jdbcElemNum))
7080            writer.writeShort(2);
7081        else
7082            writer.writeShort(0);
7083
7084        // SQLXPARMMODE; DRDA TYPE I2; ENVLID 0x04; Length Override 2
7085
if (pmeta != null && !rtnOutput)
7086        {
7087            int mode = pmeta.getParameterMode(jdbcElemNum);
7088            if (mode == JDBC30Translation.PARAMETER_MODE_UNKNOWN)
7089            {
7090                // For old style callable statements. We assume in/out if it
7091
// is an output parameter.
7092
int type = DRDAStatement.getOutputParameterTypeFromClassName(
7093                                                                              pmeta.getParameterClassName(jdbcElemNum));
7094                if (type != DRDAStatement.NOT_OUTPUT_PARAM)
7095                    mode = JDBC30Translation.PARAMETER_MODE_IN_OUT;
7096            }
7097            writer.writeShort(mode);
7098        }
7099        else
7100        {
7101            writer.writeShort(0);
7102        }
7103    
7104        // SQLXRDBNAM; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
7105
// JCC uses this as the catalog name so we will send null.
7106
writer.writeShort(0);
7107
7108        // SQLXCORNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
7109
// SQLXCORNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
7110
writeVCMorVCS(null);
7111
7112        // SQLXBASENAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
7113
// SQLXBASENAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
7114
writeVCMorVCS(rtnOutput ? rsmeta.getTableName(jdbcElemNum) : null);
7115
7116        // SQLXSCHEMA_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
7117
// SQLXSCHEMA_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
7118
writeVCMorVCS(rtnOutput ? rsmeta.getSchemaName(jdbcElemNum): null);
7119
7120
7121        // SQLXNAME_m; DRDA TYPE VCM; ENVLID 0x3E; Length Override 255
7122
// SQLXNAME_s; DRDA TYPE VCS; ENVLID 0x32; Length Override 255
7123
writeVCMorVCS(rtnOutput ? rsmeta.getColumnName(jdbcElemNum): null);
7124        
7125    }
7126
7127  /**
7128   * Write Fdoca Value to client
7129   * @param index Index of column being returned
7130   * @param val Value to write to client
7131   * @param drdaType FD:OCA DRDA Type from FdocaConstants
7132   * @param precision Precision
7133   * @param stmt Statement being processed
7134   *
7135   * @exception DRDAProtocolException
7136   * @exception SQLException
7137   *
7138   * @see FdocaConstants
7139   */

7140
7141    protected void writeFdocaVal(int index, Object JavaDoc val, int drdaType,
7142                                 int precision, int scale, boolean valNull,
7143                                 
7144                                 DRDAStatement stmt) throws DRDAProtocolException, SQLException JavaDoc
7145    {
7146        writeNullability(drdaType,valNull);
7147
7148        if (! valNull)
7149        {
7150            int ndrdaType = drdaType | 1;
7151            long valLength = 0;
7152            switch (ndrdaType)
7153            {
7154                case DRDAConstants.DRDA_TYPE_NSMALL:
7155                    // DB2 does not have a BOOLEAN java.sql.bit type,
7156
// so we need to send it as a small
7157
if (val instanceof Boolean JavaDoc)
7158                    {
7159                        writer.writeShort(((Boolean JavaDoc) val).booleanValue());
7160                    }
7161                    else if (val instanceof Short JavaDoc)
7162                        writer.writeShort(((Short JavaDoc) val).shortValue());
7163                    else if (val instanceof Byte JavaDoc)
7164                        writer.writeShort(((Byte JavaDoc) val).byteValue());
7165                    else
7166                        writer.writeShort(((Integer JavaDoc) val).shortValue());
7167                    break;
7168                case DRDAConstants.DRDA_TYPE_NINTEGER:
7169                    writer.writeInt(((Integer JavaDoc) val).intValue());
7170                    break;
7171                case DRDAConstants.DRDA_TYPE_NINTEGER8:
7172                    writer.writeLong(((Long JavaDoc) val).longValue());
7173                    break;
7174                case DRDAConstants.DRDA_TYPE_NFLOAT4:
7175                    writer.writeFloat(((Float JavaDoc) val).floatValue());
7176                    break;
7177                case DRDAConstants.DRDA_TYPE_NFLOAT8:
7178                    writer.writeDouble(((Double JavaDoc) val).doubleValue());
7179                    break;
7180                case DRDAConstants.DRDA_TYPE_NDECIMAL:
7181                    if (precision == 0)
7182                        precision = FdocaConstants.NUMERIC_DEFAULT_PRECISION;
7183                    BigDecimal JavaDoc bd = (java.math.BigDecimal JavaDoc) val;
7184                    writer.writeBigDecimal(bd,precision,scale);
7185                    break;
7186                case DRDAConstants.DRDA_TYPE_NDATE:
7187                    writer.writeString(((java.sql.Date JavaDoc) val).toString());
7188                    break;
7189                case DRDAConstants.DRDA_TYPE_NTIME:
7190                    writer.writeString(((java.sql.Time JavaDoc) val).toString());
7191                    break;
7192                case DRDAConstants.DRDA_TYPE_NTIMESTAMP:
7193                    // we need to send it in a slightly different format, and pad it
7194
// up to or truncate it into 26 chars
7195
String JavaDoc ts1 = ((java.sql.Timestamp JavaDoc) val).toString();
7196                    String JavaDoc ts2 = ts1.replace(' ','-').replace(':','.');
7197                    int tsLen = ts2.length();
7198                    if (tsLen < 26)
7199                    {
7200                        for (int i = 0; i < 26-tsLen; i++)
7201                            ts2 += "0";
7202                    }
7203                    else if (tsLen > 26)
7204                        ts2 = ts2.substring(0,26);
7205                    writer.writeString(ts2);
7206                    break;
7207                case DRDAConstants.DRDA_TYPE_NCHAR:
7208                    writer.writeString(((String JavaDoc) val).toString());
7209                    break;
7210                case DRDAConstants.DRDA_TYPE_NVARCHAR:
7211                case DRDAConstants.DRDA_TYPE_NVARMIX:
7212                case DRDAConstants.DRDA_TYPE_NLONG:
7213                case DRDAConstants.DRDA_TYPE_NLONGMIX:
7214                    //WriteLDString and generate warning if truncated
7215
// which will be picked up by checkWarning()
7216
writer.writeLDString(val.toString(), index);
7217                    break;
7218                case DRDAConstants.DRDA_TYPE_NLOBBYTES:
7219                case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
7220                    
7221                    // do not send EXTDTA for lob of length 0, beetle 5967
7222
if( ! ((EXTDTAInputStream) val).isEmptyStream() ){
7223                        stmt.addExtDtaObject(val, index);
7224                    
7225                    //indicate externalized and size is unknown.
7226
writer.writeExtendedLength(0x8000);
7227                    
7228                    }else{
7229                    writer.writeExtendedLength(0);
7230                    
7231                    }
7232                    
7233                    break;
7234                    
7235                case DRDAConstants.DRDA_TYPE_NFIXBYTE:
7236                    writer.writeBytes((byte[]) val);
7237                    break;
7238                case DRDAConstants.DRDA_TYPE_NVARBYTE:
7239                case DRDAConstants.DRDA_TYPE_NLONGVARBYTE:
7240                        writer.writeLDBytes((byte[]) val, index);
7241                    break;
7242                default:
7243                    if (SanityManager.DEBUG)
7244                        trace("ndrdaType is: "+ndrdaType);
7245                    writer.writeLDString(val.toString(), index);
7246            }
7247        }
7248    }
7249
7250    /**
7251     * write nullability if this is a nullable drdatype and FDOCA null
7252     * value if appropriate
7253     * @param drdaType FDOCA type
7254     * @param valNull true if this is a null value. False otherwise
7255     *
7256     **/

7257    private void writeNullability(int drdaType, boolean valNull)
7258    {
7259        if(FdocaConstants.isNullable(drdaType))
7260        {
7261            if (valNull)
7262                writer.writeByte(FdocaConstants.NULL_DATA);
7263            else
7264            {
7265                writer.writeByte(FdocaConstants.INDICATOR_NULLABLE);
7266            }
7267        }
7268        
7269    }
7270
7271    /**
7272     * Methods to keep track of required codepoints
7273     */

7274    /**
7275     * Copy a list of required code points to template for checking
7276     *
7277     * @param req list of required codepoints
7278     */

7279    private void copyToRequired(int [] req)
7280    {
7281        currentRequiredLength = req.length;
7282        if (currentRequiredLength > required.length)
7283            required = new int[currentRequiredLength];
7284        for (int i = 0; i < req.length; i++)
7285            required[i] = req[i];
7286    }
7287    /**
7288     * Remove codepoint from required list
7289     *
7290     * @param codePoint - code point to be removed
7291     */

7292    private void removeFromRequired(int codePoint)
7293    {
7294        for (int i = 0; i < currentRequiredLength; i++)
7295            if (required[i] == codePoint)
7296                required[i] = 0;
7297
7298    }
7299    /**
7300     * Check whether we have seen all the required code points
7301     *
7302     * @param codePoint code point for which list of code points is required
7303     */

7304    private void checkRequired(int codePoint) throws DRDAProtocolException
7305    {
7306        int firstMissing = 0;
7307        for (int i = 0; i < currentRequiredLength; i++)
7308        {
7309            if (required[i] != 0)
7310            {
7311                firstMissing = required[i];
7312                break;
7313            }
7314        }
7315        if (firstMissing != 0)
7316            missingCodePoint(firstMissing);
7317    }
7318    /**
7319     * Error routines
7320     */

7321    /**
7322     * Seen too many of this code point
7323     *
7324     * @param codePoint code point which has been duplicated
7325     *
7326     * @exception DRDAProtocolException
7327     */

7328    private void tooMany(int codePoint) throws DRDAProtocolException
7329    {
7330        throwSyntaxrm(CodePoint.SYNERRCD_TOO_MANY, codePoint);
7331    }
7332    /**
7333     * Object too big
7334     *
7335     * @param codePoint code point with too big object
7336     * @exception DRDAProtocolException
7337     */

7338    private void tooBig(int codePoint) throws DRDAProtocolException
7339    {
7340        throwSyntaxrm(CodePoint.SYNERRCD_TOO_BIG, codePoint);
7341    }
7342    /**
7343     * Object length not allowed
7344     *
7345     * @param codePoint code point with bad object length
7346     * @exception DRDAProtocolException
7347     */

7348    private void badObjectLength(int codePoint) throws DRDAProtocolException
7349    {
7350        throwSyntaxrm(CodePoint.SYNERRCD_OBJ_LEN_NOT_ALLOWED, codePoint);
7351    }
7352    /**
7353     * RDB not found
7354     *
7355     * @param rdbnam name of database
7356     * @exception DRDAProtocolException
7357     */

7358    private void rdbNotFound(String JavaDoc rdbnam) throws DRDAProtocolException
7359    {
7360        Object JavaDoc[] oa = {rdbnam};
7361        throw new
7362            DRDAProtocolException(DRDAProtocolException.DRDA_Proto_RDBNFNRM,
7363                                  this,0,
7364                                  DRDAProtocolException.NO_ASSOC_ERRCD, oa);
7365    }
7366    /**
7367     * Invalid value for this code point
7368     *
7369     * @param codePoint code point value
7370     * @exception DRDAProtocolException
7371     */

7372    private void invalidValue(int codePoint) throws DRDAProtocolException
7373    {
7374        throwSyntaxrm(CodePoint.SYNERRCD_REQ_VAL_NOT_FOUND, codePoint);
7375    }
7376    /**
7377     * Invalid codepoint for this command
7378     *
7379     * @param codePoint code point value
7380     *
7381     * @exception DRDAProtocolException
7382     */

7383    protected void invalidCodePoint(int codePoint) throws DRDAProtocolException
7384    {
7385        throwSyntaxrm(CodePoint.SYNERRCD_INVALID_CP_FOR_CMD, codePoint);
7386    }
7387    /**
7388     * Don't support this code point
7389     *
7390     * @param codePoint code point value
7391     * @exception DRDAProtocolException
7392     */

7393    protected void codePointNotSupported(int codePoint) throws DRDAProtocolException
7394    {
7395        throw new
7396            DRDAProtocolException(DRDAProtocolException.DRDA_Proto_CMDNSPRM,
7397                                  this,codePoint,
7398                                  DRDAProtocolException.NO_ASSOC_ERRCD);
7399    }
7400    /**
7401     * Don't support this value
7402     *
7403     * @param codePoint code point value
7404     * @exception DRDAProtocolException
7405     */

7406    private void valueNotSupported(int codePoint) throws DRDAProtocolException
7407    {
7408        throw new
7409            DRDAProtocolException(DRDAProtocolException.DRDA_Proto_VALNSPRM,
7410                                  this,codePoint,
7411                                  DRDAProtocolException.NO_ASSOC_ERRCD);
7412    }
7413    /**
7414     * Verify that the code point is the required code point
7415     *
7416     * @param codePoint code point we have
7417     * @param reqCodePoint code point required at this time
7418     *
7419     * @exception DRDAProtocolException
7420     */

7421    private void verifyRequiredObject(int codePoint, int reqCodePoint)
7422        throws DRDAProtocolException
7423    {
7424        if (codePoint != reqCodePoint )
7425        {
7426            throwSyntaxrm(CodePoint.SYNERRCD_REQ_OBJ_NOT_FOUND,codePoint);
7427        }
7428    }
7429    /**
7430     * Verify that the code point is in the right order
7431     *
7432     * @param codePoint code point we have
7433     * @param reqCodePoint code point required at this time
7434     *
7435     * @exception DRDAProtocolException
7436     */

7437    private void verifyInOrderACCSEC_SECCHK(int codePoint, int reqCodePoint)
7438        throws DRDAProtocolException
7439    {
7440        if (codePoint != reqCodePoint )
7441        {
7442            throw
7443                new DRDAProtocolException(DRDAProtocolException.DRDA_Proto_PRCCNVRM,
7444                                          this, codePoint,
7445                                          CodePoint.PRCCNVCD_ACCSEC_SECCHK_WRONG_STATE);
7446        }
7447    }
7448
7449    /**
7450     * Database name given under code point doesn't match previous database names
7451     *
7452     * @param codePoint codepoint where the mismatch occurred
7453     *
7454     * @exception DRDAProtocolException
7455     */

7456    private void rdbnamMismatch(int codePoint)
7457        throws DRDAProtocolException
7458    {
7459        throw new DRDAProtocolException(DRDAProtocolException.DRDA_Proto_PRCCNVRM,
7460                                          this, codePoint,
7461                                          CodePoint.PRCCNVCD_RDBNAM_MISMATCH);
7462    }
7463    /**
7464     * Close the current session
7465     */

7466    private void closeSession()
7467    {
7468        if (session == null)
7469            return;
7470        server.removeFromSessionTable(session.connNum);
7471        try {
7472            session.close();
7473        } catch (SQLException JavaDoc se)
7474        {
7475            // If something went wrong closing down the session.
7476
// Print an error to the console and close this
7477
//thread. (6013)
7478
sendUnexpectedException(se);
7479            close();
7480        }
7481        finally {
7482            session = null;
7483            database = null;
7484            appRequester=null;
7485            sockis = null;
7486            sockos=null;
7487            databaseAccessException=null;
7488        }
7489    }
7490
7491    /**
7492     * Handle Exceptions - write error protocol if appropriate and close session
7493     * or thread as appropriate
7494     */

7495    private void handleException(Exception JavaDoc e)
7496    {
7497        try {
7498            if (e instanceof DRDAProtocolException) {
7499                // protocol error - write error message
7500
sendProtocolException((DRDAProtocolException) e);
7501            } else {
7502                // something unexpected happened
7503
sendUnexpectedException(e);
7504                server.consoleExceptionPrintTrace(e);
7505            }
7506        } finally {
7507            // always close the session and stop the thread after handling
7508
// these exceptions
7509
closeSession();
7510            close();
7511        }
7512    }
7513    
7514    /**
7515     * Notice the client about a protocol error.
7516     *
7517     * @param de <code>DRDAProtocolException</code> to be sent
7518     */

7519    private void sendProtocolException(DRDAProtocolException de) {
7520        String JavaDoc dbname = null;
7521        if (database != null) {
7522            dbname = database.dbName;
7523        }
7524
7525        try {
7526            println2Log(dbname, session.drdaID, de.getMessage());
7527            server.consoleExceptionPrintTrace(de);
7528            reader.clearBuffer();
7529            de.write(writer);
7530            finalizeChain();
7531        } catch (DRDAProtocolException ioe) {
7532            // There may be an IO exception in the write.
7533
println2Log(dbname, session.drdaID, de.getMessage());
7534            server.consoleExceptionPrintTrace(ioe);
7535        }
7536    }
7537
7538    /**
7539     * Send unpexpected error to the client
7540     * @param e Exception to be sent
7541     */

7542    private void sendUnexpectedException(Exception JavaDoc e)
7543    {
7544
7545        DRDAProtocolException unExpDe;
7546        String JavaDoc dbname = null;
7547        try {
7548            if (database != null)
7549                dbname = database.dbName;
7550            println2Log(dbname,session.drdaID, e.getMessage());
7551            server.consoleExceptionPrintTrace(e);
7552            unExpDe = DRDAProtocolException.newAgentError(this,
7553                                                          CodePoint.SVRCOD_PRMDMG,
7554                                                          dbname, e.getMessage());
7555        
7556            reader.clearBuffer();
7557            unExpDe.write(writer);
7558            finalizeChain();
7559        }
7560        catch (DRDAProtocolException nde)
7561        {
7562            // we can't tell the client, but we tried.
7563
}
7564        
7565    }
7566
7567
7568    /**
7569     * Test if DRDA connection thread is closed
7570     *
7571     * @return true if close; false otherwise
7572     */

7573    private boolean closed()
7574    {
7575        synchronized (closeSync)
7576        {
7577            return close;
7578        }
7579    }
7580    /**
7581     * Get whether connections are logged
7582     *
7583     * @return true if connections are being logged; false otherwise
7584     */

7585    private boolean getLogConnections()
7586    {
7587        synchronized(logConnectionsSync) {
7588            return logConnections;
7589        }
7590    }
7591    /**
7592     * Get time slice value for length of time to work on a session
7593     *
7594     * @return time slice
7595     */

7596    private long getTimeSlice()
7597    {
7598        synchronized(timeSliceSync) {
7599            return timeSlice;
7600        }
7601    }
7602    /**
7603     * Send string to console
7604     *
7605     * @param value - value to print on console
7606     */

7607    protected void trace(String JavaDoc value)
7608    {
7609        if (SanityManager.DEBUG && server.debugOutput == true)
7610            server.consoleMessage(value);
7611    }
7612
7613    /***
7614     * Show runtime memory
7615     *
7616     ***/

7617    public static void showmem() {
7618        Runtime JavaDoc rt = null;
7619        Date JavaDoc d = null;
7620        rt = Runtime.getRuntime();
7621        rt.gc();
7622        d = new Date JavaDoc();
7623        System.out.println("total memory: "
7624                           + rt.totalMemory()
7625                           + " free: "
7626                           + rt.freeMemory()
7627                           + " " + d.toString());
7628
7629    }
7630
7631    /**
7632     * convert byte array to a Hex string
7633     *
7634     * @param buf buffer to convert
7635     * @return hex string representation of byte array
7636     */

7637    private String JavaDoc convertToHexString(byte [] buf)
7638    {
7639        StringBuffer JavaDoc str = new StringBuffer JavaDoc();
7640        str.append("0x");
7641        String JavaDoc val;
7642        int byteVal;
7643        for (int i = 0; i < buf.length; i++)
7644        {
7645            byteVal = buf[i] & 0xff;
7646            val = Integer.toHexString(byteVal);
7647            if (val.length() < 2)
7648                str.append("0");
7649            str.append(val);
7650        }
7651        return str.toString();
7652    }
7653    /**
7654     * check that the given typdefnam is acceptable
7655     *
7656     * @param typdefnam
7657     *
7658     * @exception DRDAProtocolException
7659     */

7660    private void checkValidTypDefNam(String JavaDoc typdefnam)
7661        throws DRDAProtocolException
7662    {
7663        if (typdefnam.equals("QTDSQL370"))
7664            return;
7665        if (typdefnam.equals("QTDSQL400"))
7666            return;
7667        if (typdefnam.equals("QTDSQLX86"))
7668            return;
7669        if (typdefnam.equals("QTDSQLASC"))
7670            return;
7671        if (typdefnam.equals("QTDSQLVAX"))
7672            return;
7673        if (typdefnam.equals("QTDSQLJVM"))
7674            return;
7675        invalidValue(CodePoint.TYPDEFNAM);
7676    }
7677    /**
7678     * Check that the length is equal to the required length for this codepoint
7679     *
7680     * @param codepoint codepoint we are checking
7681     * @param reqlen required length
7682     *
7683     * @exception DRDAProtocolException
7684     */

7685    private void checkLength(int codepoint, int reqlen)
7686        throws DRDAProtocolException
7687    {
7688        long len = reader.getDdmLength();
7689        if (len < reqlen)
7690            badObjectLength(codepoint);
7691        else if (len > reqlen)
7692            tooBig(codepoint);
7693    }
7694    /**
7695     * Read and check a boolean value
7696     *
7697     * @param codepoint codePoint to be used in error reporting
7698     * @return true or false depending on boolean value read
7699     *
7700     * @exception DRDAProtocolException
7701     */

7702    private boolean readBoolean(int codepoint) throws DRDAProtocolException
7703    {
7704        checkLength(codepoint, 1);
7705        byte val = reader.readByte();
7706        if (val == CodePoint.TRUE)
7707            return true;
7708        else if (val == CodePoint.FALSE)
7709            return false;
7710        else
7711            invalidValue(codepoint);
7712        return false; //to shut the compiler up
7713
}
7714    /**
7715     * Add a database to the current session
7716     *
7717     */

7718    private void addDatabase(String JavaDoc dbname)
7719    {
7720        Database db;
7721        if (appRequester.isXARequester())
7722        {
7723            db = new XADatabase(dbname);
7724        }
7725        else
7726            db = new Database(dbname);
7727        session.addDatabase(db);
7728        session.database = db;
7729        database = db;
7730    }
7731    /**
7732     * Set the current database
7733     *
7734     * @param codePoint codepoint we are processing
7735     *
7736     * @exception DRDAProtocolException
7737     */

7738    private void setDatabase(int codePoint) throws DRDAProtocolException
7739    {
7740        String JavaDoc rdbnam = parseRDBNAM();
7741        // using same database so we are done
7742
if (database != null && database.dbName.equals(rdbnam))
7743            return;
7744        Database d = session.getDatabase(rdbnam);
7745        if (d == null)
7746            rdbnamMismatch(codePoint);
7747        else
7748            database = d;
7749        session.database = d;
7750    }
7751    /**
7752     * Write ENDUOWRM
7753     * Instance Variables
7754     * SVCOD - severity code - WARNING - required
7755     * UOWDSP - Unit of Work Disposition - required
7756     * RDBNAM - Relational Database name - optional
7757     * SRVDGN - Server Diagnostics information - optional
7758     *
7759     * @param opType - operation type 1 - commit, 2 -rollback
7760     */

7761    private void writeENDUOWRM(int opType)
7762    {
7763        writer.createDssReply();
7764        writer.startDdm(CodePoint.ENDUOWRM);
7765        writer.writeScalar2Bytes(CodePoint.SVRCOD, CodePoint.SVRCOD_WARNING);
7766        writer.writeScalar1Byte(CodePoint.UOWDSP, opType);
7767        writer.endDdmAndDss();
7768    }
7769
7770  void writeEXTDTA (DRDAStatement stmt) throws SQLException JavaDoc, DRDAProtocolException
7771  {
7772
7773      ArrayList JavaDoc extdtaValues = stmt.getExtDtaObjects();
7774    // build the EXTDTA data, if necessary
7775
if (extdtaValues == null)
7776        return;
7777    boolean chainFlag, chainedWithSameCorrelator;
7778    boolean writeNullByte = false;
7779
7780    for (int i = 0; i < extdtaValues.size(); i++) {
7781        // is this the last EXTDTA to be built?
7782
if (i != extdtaValues.size() - 1) { // no
7783
chainFlag = true;
7784            chainedWithSameCorrelator = true;
7785        }
7786        else { // yes
7787
chainFlag = false; //last blob DSS stream itself is NOT chained with the NEXT DSS
7788
chainedWithSameCorrelator = false;
7789        }
7790
7791        
7792        if (sqlamLevel >= MGRLVL_7)
7793            if (stmt.isExtDtaValueNullable(i))
7794                writeNullByte = true;
7795        
7796        Object JavaDoc o = extdtaValues.get(i);
7797        if (o instanceof EXTDTAInputStream) {
7798            EXTDTAInputStream stream = (EXTDTAInputStream) o;
7799            try{
7800            writer.writeScalarStream (chainedWithSameCorrelator,
7801                                      CodePoint.EXTDTA,
7802                                      stream,
7803                                      writeNullByte);
7804            
7805            }finally{
7806                // close the stream when done
7807
closeStream(stream);
7808        }
7809            
7810        }
7811    }
7812    // reset extdtaValues after sending
7813
stmt.clearExtDtaObjects();
7814
7815  }
7816
7817
7818    /**
7819     * Check SQLWarning and write SQLCARD as needed.
7820     *
7821     * @param conn connection to check
7822     * @param stmt statement to check
7823     * @param rs result set to check
7824     * @param updateCount update count to include in SQLCARD
7825     * @param alwaysSend whether always send SQLCARD regardless of
7826     * the existance of warnings
7827     * @param sendWarn whether to send any warnings or not.
7828     *
7829     * @exception DRDAProtocolException
7830     */

7831    private void checkWarning(Connection JavaDoc conn, Statement JavaDoc stmt, ResultSet JavaDoc rs,
7832                          int updateCount, boolean alwaysSend, boolean sendWarn)
7833        throws DRDAProtocolException, SQLException JavaDoc
7834    {
7835        // instead of writing a chain of sql warning, we send the first one, this is
7836
// jcc/db2 limitation, see beetle 4629
7837
SQLWarning JavaDoc warning = null;
7838        SQLWarning JavaDoc reportWarning = null;
7839        try
7840        {
7841            if (stmt != null)
7842            {
7843                warning = stmt.getWarnings();
7844                if (warning != null)
7845                {
7846                    stmt.clearWarnings();
7847                    reportWarning = warning;
7848                }
7849            }
7850            if (rs != null)
7851            {
7852                warning = rs.getWarnings();
7853                if (warning != null)
7854                {
7855                    rs.clearWarnings();
7856                    if (reportWarning == null)
7857                        reportWarning = warning;
7858                }
7859            }
7860            if (conn != null)
7861            {
7862                warning = conn.getWarnings();
7863                if (warning != null)
7864                {
7865                    conn.clearWarnings();
7866                    if (reportWarning == null)
7867                        reportWarning = warning;
7868                }
7869            }
7870            
7871        }
7872        catch (SQLException JavaDoc se)
7873        {
7874            if (SanityManager.DEBUG)
7875                trace("got SQLException while trying to get warnings.");
7876        }
7877
7878
7879        if ((alwaysSend || reportWarning != null) && sendWarn)
7880            writeSQLCARDs(reportWarning, updateCount);
7881    }
7882
7883
7884    protected String JavaDoc buildRuntimeInfo(String JavaDoc indent, LocalizedResource localLangUtil )
7885    {
7886        String JavaDoc s ="";
7887        if (session == null)
7888            return s;
7889        else
7890            s += session.buildRuntimeInfo("", localLangUtil);
7891        s += "\n";
7892        return s;
7893    }
7894
7895
7896    /**
7897     * Finalize the current DSS chain and send it if
7898     * needed.
7899     */

7900    private void finalizeChain() throws DRDAProtocolException {
7901
7902        writer.finalizeChain(reader.getCurrChainState(), getOutputStream());
7903        return;
7904
7905    }
7906
7907    /**
7908     * Validate SECMEC_USRSSBPWD (Strong Password Substitute) can be used as
7909     * DRDA security mechanism.
7910     *
7911     * Here we check that the target server can support SECMEC_USRSSBPWD
7912     * security mechanism based on the environment, application
7913     * requester's identity (PRDID) and connection URL.
7914     *
7915     * IMPORTANT NOTE:
7916     * --------------
7917     * SECMEC_USRSSBPWD is ONLY supported by the target server if:
7918     * - current authentication provider is Derby BUILTIN or
7919     * NONE. (database / system level) (Phase I)
7920     * - Application requester is 'DNC' (Derby Network Client)
7921     * (Phase I)
7922     *
7923     * @return security check code - 0 if everything O.K.
7924     */

7925    private int validateSecMecUSRSSBPWD() throws DRDAProtocolException
7926    {
7927        String JavaDoc dbName = null;
7928        AuthenticationService authenticationService = null;
7929        org.apache.derby.iapi.db.Database databaseObj = null;
7930        String JavaDoc srvrlslv = appRequester.srvrlslv;
7931
7932        // Check if application requester is the Derby Network Client (DNC)
7933
//
7934
// We use a trick here - as the product ID is not yet available
7935
// since ACCRDB message is only coming later, we check the server
7936
// release level field sent as part of the initial EXCSAT message;
7937
// indeed, the product ID (PRDID) is prefixed to in the field.
7938
// Derby always sets it as part of the EXCSAT message so if it is
7939
// not available, we stop here and inform the requester that
7940
// SECMEC_USRSSBPWD cannot be supported for this connection.
7941
if ((srvrlslv == null) || (srvrlslv.length() == 0) ||
7942            (srvrlslv.length() < CodePoint.PRDID_MAX) ||
7943            (srvrlslv.indexOf(DRDAConstants.DERBY_DRDA_CLIENT_ID)
7944                    == -1))
7945            return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
7946

7947
7948        // Client product version is extracted from the srvrlslv field.
7949
// srvrlslv has the format <PRDID>/<ALTERNATE VERSION FORMAT>
7950
// typically, a known Derby client has a four part version number
7951
// with a pattern such as DNC10020/10.2.0.3 alpha. If the alternate
7952
// version format is not specified, clientProductVersion_ will just
7953
// be set to the srvrlslvl. Final fallback will be the product id.
7954
//
7955
// SECMEC_USRSSBPWD is only supported by the Derby engine and network
7956
// server code starting at version major '10' and minor '02'. Hence,
7957
// as this is the same for the derby client driver, we need to ensure
7958
// our DNC client is at version and release level of 10.2 at least.
7959
// We set the client version in the application requester and check
7960
// if it is at the level we require at a minimum.
7961
appRequester.setClientVersion(
7962                srvrlslv.substring(0, (int) CodePoint.PRDID_MAX));
7963
7964        if (appRequester.supportsSecMecUSRSSBPWD() == false)
7965            return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
7966

7967        dbName = database.shortDbName;
7968        // Check if the database is available (booted)
7969
//
7970
// First we need to have the database name available and it should
7971
// have been set as part of the ACCSEC request (in the case of a Derby
7972
// 'DNC' client)
7973
if ((dbName == null) || (dbName.length() == 0))
7974        {
7975            // No database specified in the connection URL attributes
7976
//
7977
// In this case, we get the authentication service handle from the
7978
// local driver, as the requester may simply be trying to shutdown
7979
// the engine.
7980
authenticationService = ((InternalDriver)
7981              NetworkServerControlImpl.getDriver()).getAuthenticationService();
7982        }
7983        else
7984        {
7985            // We get the authentication service from the database as this
7986
// last one might have specified its own auth provider (at the
7987
// database level).
7988
//
7989
// if monitor is never setup by any ModuleControl, getMonitor
7990
// returns null and no cloudscape database has been booted.
7991
if (Monitor.getMonitor() != null)
7992                databaseObj = (org.apache.derby.iapi.db.Database)
7993                    Monitor.findService(Property.DATABASE_MODULE, dbName);
7994
7995            if (databaseObj == null)
7996            {
7997                // If database is not found, try connecting to it.
7998
database.makeDummyConnection();
7999
8000                // now try to find it again
8001
databaseObj = (org.apache.derby.iapi.db.Database)
8002                    Monitor.findService(Property.DATABASE_MODULE, dbName);
8003            }
8004
8005            // If database still could not be found, it means the database
8006
// does not exist - we just return security mechanism not
8007
// supported down below as we could not verify we can handle
8008
// it.
8009
if (databaseObj != null)
8010                authenticationService =
8011                        databaseObj.getAuthenticationService();
8012        }
8013
8014        // Now we check if the authentication provider is NONE or BUILTIN
8015
if (authenticationService != null)
8016        {
8017            String JavaDoc authClassName = authenticationService.getClass().getName();
8018                
8019            if (!authClassName.equals(AUTHENTICATION_PROVIDER_BUILTIN_CLASS) &&
8020                !authClassName.equals(AUTHENTICATION_PROVIDER_NONE_CLASS))
8021                return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
8022
}
8023
8024        // SECMEC_USRSSBPWD target initialization
8025
try {
8026            myTargetSeed = decryptionManager.generateSeed();
8027            database.secTokenOut = myTargetSeed;
8028        } catch (SQLException JavaDoc se) {
8029            println2Log(null, session.drdaID, se.getMessage());
8030            // Local security service non-retryable error.
8031
return CodePoint.SECCHKCD_0A;
8032        }
8033                                
8034        return 0; // SECMEC_USRSSBPWD is supported
8035
}
8036    
8037    private static int peekStream(EXTDTAInputStream is) throws IOException JavaDoc{
8038    
8039    is.mark(1);
8040
8041    try{
8042        return is.read();
8043        
8044    }finally{
8045        is.reset();
8046    }
8047    
8048    }
8049    
8050    
8051    private static void closeStream(InputStream JavaDoc stream){
8052    
8053    try{
8054        if (stream != null)
8055        stream.close();
8056        
8057    } catch (IOException JavaDoc e) {
8058        Util.javaException(e);
8059        
8060    }
8061    
8062    }
8063}
8064
Popular Tags