KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > client > am > Statement


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

21 package org.apache.derby.client.am;
22
23 import java.sql.SQLException JavaDoc;
24
25 import org.apache.derby.shared.common.reference.JDBC30Translation;
26 import org.apache.derby.shared.common.reference.SQLState;
27
28 public class Statement implements java.sql.Statement JavaDoc, StatementCallbackInterface{
29
30     // JDBC 3 constant indicating that the current ResultSet object
31
// should be closed when calling getMoreResults.
32
// Constant value matches that defined by JDBC 3 java.sql.Statement.CLOSE_CURRENT_RESULT
33
public final static int CLOSE_CURRENT_RESULT = 1;
34
35     // JDBC 3 constant indicating that the current ResultSet object
36
// should not be closed when calling getMoreResults.
37
// Constant value matches that defined by JDBC 3 java.sql.Statement.KEEP_CURRENT_RESULT
38
public final static int KEEP_CURRENT_RESULT = 2;
39
40     // JDBC 3 constant indicating that all ResultSet objects that
41
// have previously been kept open should be closed when calling getMoreResults.
42
// Constant value matches that defined by JDBC 3 java.sql.Statement.CLOSE_ALL_RESULTS
43
public final static int CLOSE_ALL_RESULTS = 3;
44
45     //---------------------navigational members-----------------------------------
46

47     public MaterialStatement materialStatement_ = null;
48
49     public Connection connection_;
50     public Section section_;
51     public Agent agent_;
52
53     public ResultSet resultSet_ = null;
54
55     // Use -1, if there is no update count returned, ie. when result set is returned. 0 is a valid update count for DDL.
56
int updateCount_ = -1;
57     int returnValueFromProcedure_;
58
59     // Enumeration of the flavors of statement execute call used.
60
static final int executeQueryMethod__ = 1;
61     static final int executeUpdateMethod__ = 2;
62     static final int executeMethod__ = 3;
63
64     // sqlMode_ will be moved to PS as soon as we remove the hack reference in completeExecute()
65
// Enumerated in Statement: S.sqlIsQuery__, S.sqlIsCall__, S.sqlIsUpdate__
66
// Determines whether sql_ starts with SELECT/VALUES, CALL, or other (assumed to be an update).
67
protected int sqlMode_ = 0;
68     // Enum for sqlMode_:
69
static final int isQuery__ = 0x1; // sql starts with SELECT.... or VALUES...
70
static final int isCall__ = 0x2; // sql starts with CALL ...
71
static final int isUpdate__ = 0x4; // All other sql is categorized as a update DML or DDL.
72

73     // sqlUpdateMode_ is only set when the sqlMode_ == isUpdate__
74
public int sqlUpdateMode_ = 0;
75     // Enum for sqlUpdateMode_:
76
public final static int isCommitSql__ = 0x1;
77     public final static int isRollbackSql__ = 0x2;
78     final static int isPositionedUpdateDeleteSql__ = 0x10;
79     final static int isInsertSql__ = 0x20; // used to recognize "insert" for auto-generated keys
80
final static int isDeleteSql__ = 0x40; // used to recognize "delete" for parsing cursorname
81
final static int isUpdateSql__ = 0x80; // used to recognize "update" for parsing cursorname
82

83
84     public ColumnMetaData resultSetMetaData_; // type information for output sqlda
85

86     // these two are used during parsing of literals for call statement.
87
// please add a comment desribing what why you can't reuse inputs_ and parameterMetaData_
88
// members for the literal inputs
89

90     // Caching the Cursor object for reuse.
91
public Cursor cachedCursor_ = null;
92     public Cursor cachedSingletonRowData_ = null;
93     public boolean isPreparedStatement_ = false;
94     public boolean isCallableStatement_ = false; // we can get rid of this member once we define polymorphic reset() on S/PS/CS
95

96     //---------------------navigational cheat-links-------------------------------
97
// Cheat-links are for convenience only, and are not part of the conceptual model.
98
// Warning:
99
// Cheat-links should only be defined for invariant state data.
100
// That is, state data that is set by the constructor and never changes.
101

102     // Alias for connection_.databaseMetaData
103
public DatabaseMetaData databaseMetaData_;
104
105     //-----------------------------state------------------------------------------
106

107     // Jdbc 1 positioned updates are implemented via
108
// sql scan for "...where current of <users-cursor-name>",
109
// the addition of mappings from cursor names to query sections,
110
// and the subtitution of <users-cursor-name> with <canned-cursor-name> in the pass-thru sql string
111
// "...where current of <canned-cursor-name>" when user-defined cursor names are used.
112
// Both "canned" cursor names (from our jdbc package set) and user-defined cursor names are mapped.
113
// Statement.cursorName_ is initialized to null until the cursor name is requested or set.
114
// s.setCursorName()) adds a user-defined name, but it is not
115
// added to the cursor map until execution time (DERBY-1036);
116
// When requested (rs.getCursorName()), if the cursor name is still null,
117
// then is given the canned cursor name as defined by our jdbc package set.
118
// Still need to consider how positioned updates should interact with multiple result sets from a stored.
119
String JavaDoc cursorName_ = null;
120
121     // This means the client-side jdbc statement object is open.
122
// This value is set to true when the statement object is constructed, and will not change
123
// until statement.close() is called either directly or via connection.close(), finalizer, or other methods.
124
boolean openOnClient_ = true;
125     // This means a DERBY server-side section for this statement is in the prepared state.
126
// A client-side jdbc statement may remain open across commits (openOnClient=true),
127
// but the server-side DERBY section moves to an unprepared state (openOnServer=false) across commits,
128
// requiring an implicit re-prepare "under the covers" by the driver.
129
// Unprepared jdbc query statements still have prepared sections on the server.
130
// This openOnServer_ only has implications for preparedstatement
131
boolean openOnServer_ = false;
132
133
134     //private int indexOfCurrentResultSet_ = -1;
135
protected int indexOfCurrentResultSet_ = -1;
136     ResultSet[] resultSetList_ = null; // array of ResultSet objects
137

138     protected final static String JavaDoc TIMEOUT_STATEMENT = "SET STATEMENT_TIMEOUT ";
139     protected java.util.ArrayList JavaDoc timeoutArrayList = new java.util.ArrayList JavaDoc(1);
140     protected boolean doWriteTimeout = false;
141     int timeout_ = 0; // for query timeout in seconds
142
int maxRows_ = 0;
143     int maxFieldSize_ = 0; // zero means that there is no limit to the size of a column.
144
boolean escapedProcedureCallWithResult_ = false;
145
146     // When this is false we skip autocommit for this PreparedStatement.
147
// This is needed when the PreparedStatement object is used internally by
148
// the driver and a commit is not desired, e.g., Blob/Clob API calls
149
public boolean isAutoCommittableStatement_ = true;
150
151     // The user has no control over the statement that owns a catalog query, and has no ability to close that statement.
152
// We need a special member variable on our internal catalog query statements so that
153
// when the catalog query is closed, the result set will know to close it's owning statement.
154
boolean isCatalogQuery_ = false;
155
156
157     // This collection is used for two different purposes:
158
// For statement batching it contains the batched SQL strings.
159
// For prepared statement batching it contains the batched input rows.
160
java.util.ArrayList JavaDoc batch_ = new java.util.ArrayList JavaDoc();
161
162
163     // Scrollable cursor attributes
164
public int resultSetType_ = java.sql.ResultSet.TYPE_FORWARD_ONLY;
165     public int resultSetConcurrency_ = java.sql.ResultSet.CONCUR_READ_ONLY;
166     public int resultSetHoldability_;
167     // This is ignored by the driver if this is zero.
168
// For the net forward-only result set, if fetchSize is unset, we let the server return however many rows will fit in a query block.
169
// For the net scrollable result set, then we use a default of 64 rows.
170
public int fetchSize_ = 0;
171     public int fetchDirection_ = java.sql.ResultSet.FETCH_FORWARD;
172
173     // Conceptually this doesn't belong in Statement, but belongs in PreparedStatement,
174
// since Statement doesn't know about params, so we're just putting it here perhaps temporarily,
175
// Used for callable statement OUT paramters.
176
public Cursor singletonRowData_ = null;
177
178     // number of invisible result sets returned from a stored procedure.
179
public int numInvisibleRS_ = 0;
180
181     // This is a cache of the attributes to be sent on prepare.
182
// Think about caching the entire prepare DDM string for the re-prepares
183
public String JavaDoc cursorAttributesToSendOnPrepare_ = null;
184
185     // The following members are for the exclusive use of prepared statements that require auto-generated keys to be returned
186
public PreparedStatement preparedStatementForAutoGeneratedKeys_;
187     public ResultSet generatedKeysResultSet_;
188     public String JavaDoc[] generatedKeysColumnNames_;
189     public int autoGeneratedKeys_ = java.sql.Statement.NO_GENERATED_KEYS;
190
191     // This flag makes sure that only one copy of this statement
192
// will be in connection_.commitListeners_.
193

194     private SqlWarning warnings_ = null;
195
196     // A Statement is NOT poolable by default. The constructor for
197
// PreparedStatement overrides this.
198
protected boolean isPoolable = false;
199
200     //---------------------constructors/finalizer/accessors--------------------
201

202     private Statement() throws SqlException {
203         initStatement();
204     }
205
206     private void resetStatement() throws SqlException {
207         initStatement();
208     }
209
210     private void initStatement() throws SqlException {
211         materialStatement_ = null;
212         connection_ = null;
213         agent_ = null;
214         databaseMetaData_ = null;
215         resultSetType_ = java.sql.ResultSet.TYPE_FORWARD_ONLY;
216         resultSetConcurrency_ = java.sql.ResultSet.CONCUR_READ_ONLY;
217         resultSetHoldability_ = 0;
218         cursorAttributesToSendOnPrepare_ = null;
219         if (timeoutArrayList.size() == 0) {
220             timeoutArrayList.add(null); // Make sure the list's length is 1
221
}
222
223         initResetStatement();
224     }
225
226     private void initResetStatement() throws SqlException {
227         initResetPreparedStatement();
228
229         //section_ = null; // don't set section to null because write piggyback command require a section
230
if (section_ != null) {
231             section_.free();
232         }
233         sqlMode_ = 0;
234         sqlUpdateMode_ = 0;
235         resultSetMetaData_ = null;
236     }
237
238     protected void initResetPreparedStatement() {
239         warnings_ = null;
240         //section_ = null;
241
resultSet_ = null;
242         updateCount_ = -1;
243         returnValueFromProcedure_ = 0;
244         cursorName_ = null;
245         openOnClient_ = true;
246         openOnServer_ = false;
247         indexOfCurrentResultSet_ = -1;
248         resultSetList_ = null;
249         timeout_ = 0;
250         doWriteTimeout = false;
251         maxRows_ = 0;
252         maxFieldSize_ = 0;
253         escapedProcedureCallWithResult_ = false;
254         isCatalogQuery_ = false;
255         isAutoCommittableStatement_ = true;
256
257         if (batch_ == null) {
258             batch_ = new java.util.ArrayList JavaDoc();
259         } else {
260             batch_.clear();
261         }
262         fetchSize_ = 0;
263         fetchDirection_ = java.sql.ResultSet.FETCH_FORWARD;
264         singletonRowData_ = null;
265         numInvisibleRS_ = 0;
266         preparedStatementForAutoGeneratedKeys_ = null;
267         generatedKeysResultSet_ = null;
268         generatedKeysColumnNames_ = null;
269         autoGeneratedKeys_ = java.sql.Statement.NO_GENERATED_KEYS;
270
271         // these members were not initialized
272
isPreparedStatement_ = false;
273     }
274
275     // If a dataSource is passed into resetClientConnection(), then we will assume
276
// properties on the dataSource may have changed, and we will need to go through
277
// the open-statement list on the connection and do a full reset on all statements,
278
// including preparedStatement's and callableStatement's. This is because property
279
// change may influence the section we allocate for the preparedStatement, and
280
// also the cursor attributes, i.e. setCursorSensitivity().
281
// If no dataSource is passed into resetClientConnection(), then we will do the
282
// minimum reset required for preparedStatement's and callableStatement's.
283
public void reset(boolean fullReset) throws SqlException {
284         if (fullReset) {
285             connection_.resetStatement(this);
286         } else {
287             initResetStatement();
288             materialStatement_.reset_();
289         }
290     }
291
292     public Statement(Agent agent, Connection connection) throws SqlException {
293         this();
294         initStatement(agent, connection);
295     }
296
297     public void resetStatement(Agent agent, Connection connection) throws SqlException {
298         resetStatement();
299         initStatement(agent, connection);
300     }
301
302     private void initStatement(Agent agent, Connection connection) {
303         agent_ = agent;
304         connection_ = connection;
305         databaseMetaData_ = connection.databaseMetaData_;
306     }
307
308     // For jdbc 2 statements with scroll attributes
309
public Statement(Agent agent, Connection connection, int type, int concurrency, int holdability,
310                      int autoGeneratedKeys, String JavaDoc[] columnNames) throws SqlException {
311         this(agent, connection);
312         initStatement(type, concurrency, holdability, autoGeneratedKeys, columnNames);
313     }
314
315     public void resetStatement(Agent agent, Connection connection, int type, int concurrency, int holdability,
316                                int autoGeneratedKeys, String JavaDoc[] columnNames) throws SqlException {
317         resetStatement(agent, connection);
318         initStatement(type, concurrency, holdability, autoGeneratedKeys, columnNames);
319     }
320
321     private void initStatement(int type, int concurrency, int holdability,
322                                int autoGeneratedKeys, String JavaDoc[] columnNames) throws SqlException {
323         switch (type) {
324         case java.sql.ResultSet.TYPE_FORWARD_ONLY:
325         case java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE:
326         case java.sql.ResultSet.TYPE_SCROLL_SENSITIVE:
327             resultSetType_ = type;
328             break;
329         default:
330             throw new SqlException(agent_.logWriter_,
331                 new ClientMessageId(SQLState.INVALID_API_PARAMETER),
332                 new Integer JavaDoc(type), "type", "createStatement()");
333         }
334
335         switch (concurrency) {
336         case java.sql.ResultSet.CONCUR_READ_ONLY:
337         case java.sql.ResultSet.CONCUR_UPDATABLE:
338             resultSetConcurrency_ = concurrency;
339             break;
340         default:
341             throw new SqlException(agent_.logWriter_,
342                 new ClientMessageId(SQLState.INVALID_API_PARAMETER),
343                 new Integer JavaDoc(concurrency), "concurrency",
344                 "createStatement()");
345         }
346
347         switch (holdability) {
348         case JDBC30Translation.CLOSE_CURSORS_AT_COMMIT:
349         case JDBC30Translation.HOLD_CURSORS_OVER_COMMIT:
350             resultSetHoldability_ = holdability;
351             break;
352         default:
353             throw new SqlException(agent_.logWriter_,
354                 new ClientMessageId(SQLState.INVALID_API_PARAMETER),
355                 new Integer JavaDoc(holdability), "holdability",
356                 "createStatement()");
357         }
358
359         switch (autoGeneratedKeys) {
360         case java.sql.Statement.NO_GENERATED_KEYS:
361         case java.sql.Statement.RETURN_GENERATED_KEYS:
362             autoGeneratedKeys_ = autoGeneratedKeys;
363             break;
364         default:
365             throw new SqlException(agent_.logWriter_,
366                 new ClientMessageId(SQLState.INVALID_API_PARAMETER),
367                 new Integer JavaDoc(autoGeneratedKeys),
368                 "autoGeneratedKeys", "createStatement");
369         }
370
371         generatedKeysColumnNames_ = columnNames;
372     }
373
374     /* (non-Javadoc)
375      * @see java.lang.Object#finalize()
376      *
377      * This method cleans up client-side resources by calling markClosed().
378      * It is different from close() method, which also does clean up on server.
379      * Changes done as part of DERBY-210.
380      */

381     protected void finalize() throws java.lang.Throwable JavaDoc {
382         if (agent_.loggingEnabled()) {
383             agent_.logWriter_.traceEntry(this, "finalize");
384         }
385         if (openOnClient_) {
386             markClosed();
387         }
388         super.finalize();
389     }
390
391     /*
392      * Accessor to state variable warnings_
393      */

394     protected SqlWarning getSqlWarnings() {
395         return warnings_;
396     }
397
398     // ---------------------------jdbc 1------------------------------------------
399

400     public java.sql.ResultSet JavaDoc executeQuery(String JavaDoc sql) throws SQLException JavaDoc {
401         try
402         {
403             synchronized (connection_) {
404                 if (agent_.loggingEnabled()) {
405                     agent_.logWriter_.traceEntry(this, "executeQuery", sql);
406                 }
407                 ResultSet resultSet = executeQueryX(sql);
408                 if (agent_.loggingEnabled()) {
409                     agent_.logWriter_.traceExit(this, "executeQuery", resultSet);
410                 }
411                 return resultSet;
412             }
413         }
414         catch ( SqlException se )
415         {
416             throw se.getSQLException();
417         }
418         
419     }
420
421     private ResultSet executeQueryX(String JavaDoc sql) throws SqlException {
422         flowExecute(executeQueryMethod__, sql);
423         return resultSet_;
424     }
425
426     public int executeUpdate(String JavaDoc sql) throws SQLException JavaDoc {
427         try
428         {
429             synchronized (connection_) {
430                 if (agent_.loggingEnabled()) {
431                     agent_.logWriter_.traceEntry(this, "executeUpdate", sql);
432                 }
433                 int updateValue = executeUpdateX(sql);
434                 if (agent_.loggingEnabled()) {
435                     agent_.logWriter_.traceExit(this, "executeUpdate", updateValue);
436                 }
437                 return updateValue;
438             }
439         }
440         catch ( SqlException se )
441         {
442             throw se.getSQLException();
443         }
444     }
445
446     private int executeUpdateX(String JavaDoc sql) throws SqlException {
447         flowExecute(executeUpdateMethod__, sql);
448         return updateCount_;
449     }
450
451     /**
452      * Returns false unless <code>iface</code> is implemented
453      *
454      * @param iface a Class defining an interface.
455      * @return true if this implements the interface or
456      * directly or indirectly wraps an object
457      * that does.
458      * @throws java.sql.SQLException if an error occurs while determining
459      * whether this is a wrapper for an object
460      * with the given interface.
461      */

462     public boolean isWrapperFor(Class JavaDoc iface) throws SQLException JavaDoc {
463         try {
464             checkForClosedStatement();
465         } catch (SqlException se) {
466             throw se.getSQLException();
467         }
468         return iface.isInstance(this);
469     }
470
471     /**
472      * Tell whether the statement has been closed or not.
473      *
474      * @return <code>true</code> if closed, <code>false</code> otherwise.
475      * @exception SQLException if a database access error occurs (according to
476      * spec). Never thrown by this implementation.
477      */

478     public boolean isClosed()
479         throws SQLException JavaDoc {
480         if (agent_.loggingEnabled()) {
481             agent_.logWriter_.traceEntry(this, "isClosed", !openOnClient_);
482         }
483         if (agent_.loggingEnabled()) {
484             agent_.logWriter_.traceExit(this, "isClosed", !openOnClient_);
485         }
486         return !openOnClient_;
487     }
488     
489     // The server holds statement resources until transaction end.
490
public void close() throws SQLException JavaDoc {
491         try
492         {
493             synchronized (connection_) {
494                 if (agent_.loggingEnabled()) {
495                     agent_.logWriter_.traceEntry(this, "close");
496                 }
497                 closeX();
498             }
499         }
500         catch ( SqlException se )
501         {
502             throw se.getSQLException();
503         }
504     }
505
506     /**
507      * An untraced version of <code>close</code>. This method cleans up
508      * client-side resources and also sends commands to network server to
509      * perform clean up. This should not be called in the finalizer.
510      * Difference between <code>finalize</code> and <code>close</code> is
511      * that close method does these things additionally (Changes done as
512      * part of DERBY-210):
513      * 1) Sends commands to the server to close the result sets.
514      * 2) Sends commands to the server to close the result sets of the
515      * generated keys query.
516      * 3) Sends a commit if autocommit is on and it is appropriate.
517      * 4) Explicitly removes the statement from connection_.openStatements_
518      * and CommitAndRollbackListeners_ by passing true to markClosed.
519      *
520      * We may need to do 1) in finalizer too. This is being tracked in
521      * DERBY-1021
522      *
523      * @throws SqlException
524      */

525     public void closeX() throws SqlException {
526         if (!openOnClient_) {
527             return;
528         }
529         // Regardless of whether or not this statement is in the prepared state,
530
// we need to close any open cursors for this statement on the server.
531
int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : resultSetList_.length;
532         boolean willTickleServer = willTickleServer(numberOfResultSetsToClose, true);
533         try {
534             if (willTickleServer) {
535                 flowClose();
536             } else {
537                 flowCloseOutsideUOW();
538             }
539         } finally {
540             markClosed(true);
541         }
542     }
543
544     /**
545      * Returns the value of the poolable hint, indicating whether
546      * pooling is requested.
547      *
548      * @return The value of the poolable hint.
549      * @throws SQLException if the Statement has been closed.
550      */

551     public boolean isPoolable() throws SQLException JavaDoc {
552         try {
553             synchronized (connection_) {
554                 if (agent_.loggingEnabled()) {
555                     agent_.logWriter_.traceEntry(this, "isPoolable");
556                 }
557                 // Assert the statement has not been closed
558
checkForClosedStatement();
559                 
560                 return isPoolable;
561             }
562         }
563         catch (SqlException se) {
564             throw se.getSQLException();
565         }
566     }
567     
568     /**
569      * Requests that a Statement be pooled or not.
570      *
571      * @param poolable requests that the Statement be pooled if true
572      * and not be pooled if false.
573      * @throws SQLException if the Statement has been closed.
574      */

575     public void setPoolable(boolean poolable) throws SQLException JavaDoc {
576         try {
577             synchronized (connection_) {
578                 if (agent_.loggingEnabled()) {
579                     agent_.logWriter_.traceEntry(this, "setPoolable", poolable);
580                 }
581                 // Assert the statement has not been closed
582
checkForClosedStatement();
583                 
584                 isPoolable = poolable;
585             }
586         }
587         catch (SqlException se) {
588             throw se.getSQLException();
589         }
590     }
591     
592     public int getMaxFieldSize() throws SQLException JavaDoc {
593         try
594         {
595             if (agent_.loggingEnabled()) {
596                 agent_.logWriter_.traceEntry(this, "getMaxFieldSize");
597             }
598             checkForClosedStatement();
599             return maxFieldSize_;
600         }
601         catch ( SqlException se )
602         {
603             throw se.getSQLException();
604         }
605     }
606
607     public void setMaxFieldSize(int max) throws SQLException JavaDoc {
608         try
609         {
610             synchronized (connection_) {
611                 if (agent_.loggingEnabled()) {
612                     agent_.logWriter_.traceEntry(this, "setMaxFieldSize", max);
613                 }
614                 checkForClosedStatement();
615                 if (max < 0) {
616                     throw new SqlException(agent_.logWriter_,
617                         new ClientMessageId(SQLState.INVALID_MAXFIELD_SIZE),
618                         new Integer JavaDoc(max));
619                 }
620                 maxFieldSize_ = max;
621             }
622         }
623         catch ( SqlException se )
624         {
625             throw se.getSQLException();
626         }
627     }
628
629     public int getMaxRows() throws SQLException JavaDoc {
630         try
631         {
632             checkForClosedStatement();
633             if (agent_.loggingEnabled()) {
634                 agent_.logWriter_.traceExit(this, "getMaxRows", maxRows_);
635             }
636             return maxRows_;
637         }
638         catch ( SqlException se )
639         {
640             throw se.getSQLException();
641         }
642     }
643
644     public void setMaxRows(int maxRows) throws SQLException JavaDoc {
645         try
646         {
647             synchronized (connection_) {
648                 if (agent_.loggingEnabled()) {
649                     agent_.logWriter_.traceEntry(this, "setMaxRows", maxRows);
650                 }
651                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
652
if (maxRows < 0) {
653                     throw new SqlException(agent_.logWriter_,
654                         new ClientMessageId(SQLState.INVALID_MAX_ROWS_VALUE),
655                         new Integer JavaDoc(maxRows));
656                 }
657                 maxRows_ = maxRows;
658             }
659         }
660         catch ( SqlException se )
661         {
662             throw se.getSQLException();
663         }
664     }
665
666     public void setEscapeProcessing(boolean enable) throws SQLException JavaDoc {
667         try
668         {
669             synchronized (connection_) {
670                 if (agent_.loggingEnabled()) {
671                     agent_.logWriter_.traceEntry(this, "setEscapeProcessing", enable);
672                 }
673                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
674
}
675         }
676         catch ( SqlException se )
677         {
678             throw se.getSQLException();
679         }
680     }
681
682     public int getQueryTimeout() throws SQLException JavaDoc {
683         try
684         {
685             checkForClosedStatement();
686             if (agent_.loggingEnabled()) {
687                 agent_.logWriter_.traceExit(this, "getQueryTimeout", timeout_);
688             }
689             return timeout_;
690         }
691         catch ( SqlException se )
692         {
693             throw se.getSQLException();
694         }
695     }
696
697     public void setQueryTimeout(int seconds) throws SQLException JavaDoc {
698         try
699         {
700             synchronized (connection_) {
701                 if (agent_.loggingEnabled()) {
702                     agent_.logWriter_.traceEntry(this, "setQueryTimeout", seconds);
703                 }
704                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
705
if (seconds < 0) {
706                     throw new SqlException(agent_.logWriter_,
707                         new ClientMessageId(SQLState.INVALID_QUERYTIMEOUT_VALUE),
708                         new Integer JavaDoc(seconds));
709                 }
710                 if (seconds != timeout_) {
711                     timeout_ = seconds;
712                     doWriteTimeout = true;
713                 }
714             }
715         }
716         catch ( SqlException se )
717         {
718             throw se.getSQLException();
719         }
720     }
721
722     public void cancel() throws SQLException JavaDoc {
723         try
724         {
725             if (agent_.loggingEnabled()) {
726                 agent_.logWriter_.traceEntry(this, "cancel");
727             }
728             checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
729
throw new SqlException(agent_.logWriter_,
730                 new ClientMessageId(SQLState.CANCEL_NOT_SUPPORTED_BY_SERVER));
731         }
732         catch ( SqlException se )
733         {
734             throw se.getSQLException();
735         }
736     }
737
738     public java.sql.SQLWarning JavaDoc getWarnings() throws SQLException JavaDoc {
739         if (agent_.loggingEnabled()) {
740             agent_.logWriter_.traceExit(this, "getWarnings", warnings_);
741         }
742         try {
743             checkForClosedStatement();
744         } catch (SqlException se) {
745             throw se.getSQLException();
746         }
747         return warnings_ == null ? null : warnings_.getSQLWarning();
748     }
749
750     public void clearWarnings() throws SQLException JavaDoc {
751         synchronized (connection_) {
752             if (agent_.loggingEnabled()) {
753                 agent_.logWriter_.traceEntry(this, "clearWarnings");
754             }
755             try {
756                 checkForClosedStatement();
757             } catch (SqlException se) {
758                 throw se.getSQLException();
759             }
760             clearWarningsX();
761         }
762     }
763
764     // An untraced version of clearWarnings()
765
public void clearWarningsX() {
766         warnings_ = null;
767     }
768
769     // Dnc statements are already associated with a unique cursor name as defined
770
// by our canned dnc package set.
771
// ResultSet.getCursorName() should be used to
772
// obtain the for update cursor name to use when executing a positioned update statement.
773
// See Jdbc 3 spec section 14.2.4.4.
774
public void setCursorName(String JavaDoc name) throws SQLException JavaDoc {
775         try
776         {
777             synchronized (connection_) {
778                 if (agent_.loggingEnabled()) {
779                     agent_.logWriter_.traceEntry(this, "setCursorName", name);
780                 }
781                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
782
if (name == null || name.equals("")) {
783                     throw new SqlException(agent_.logWriter_,
784                         new ClientMessageId(SQLState.CURSOR_INVALID_NAME),
785                         name);
786                 }
787
788                 // Invalid to set the cursor name if there are ResultSet's open on the Statement.
789
if (resultSet_ != null && resultSet_.openOnClient_) {
790                     throw new SqlException(agent_.logWriter_,
791                         new ClientMessageId(SQLState.LANG_CANT_INVALIDATE_OPEN_RESULT_SET),
792                         "setCursorName()", "Statement");
793                 }
794
795                 // DERBY-1036: Duplicate cursor names not allowed, check
796
// deferred till execute time.
797

798                 cursorName_ = name;
799             }
800         }
801         catch ( SqlException se )
802         {
803             throw se.getSQLException();
804         }
805     }
806
807     //----------------------- Multiple Results --------------------------
808

809
810     public boolean execute(String JavaDoc sql) throws SQLException JavaDoc {
811         try
812         {
813             synchronized (connection_) {
814                 if (agent_.loggingEnabled()) {
815                     agent_.logWriter_.traceEntry(this, "execute", sql);
816                 }
817                 boolean b = executeX(sql);
818                 if (agent_.loggingEnabled()) {
819                     agent_.logWriter_.traceExit(this, "execute", b);
820                 }
821                 return b;
822             }
823         }
824         catch ( SqlException se )
825         {
826             throw se.getSQLException();
827         }
828     }
829
830     boolean executeX(String JavaDoc sql) throws SqlException {
831         flowExecute(executeMethod__, sql);
832         return resultSet_ != null;
833     }
834
835     public java.sql.ResultSet JavaDoc getResultSet() throws SQLException JavaDoc {
836         try
837         {
838             synchronized (connection_) {
839                 if (agent_.loggingEnabled()) {
840                     agent_.logWriter_.traceEntry(this, "getResultSet");
841                 }
842                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
843
if (agent_.loggingEnabled()) {
844                     agent_.logWriter_.traceExit(this, "getResultSet", resultSet_);
845                 }
846                 return resultSet_;
847             }
848         }
849         catch ( SqlException se )
850         {
851             throw se.getSQLException();
852         }
853     }
854
855     public int getUpdateCount() throws SQLException JavaDoc {
856         try
857         {
858             synchronized (connection_) {
859                 if (agent_.loggingEnabled()) {
860                     agent_.logWriter_.traceEntry(this, "getUpdateCount");
861                 }
862                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
863
if (agent_.loggingEnabled()) {
864                     agent_.logWriter_.traceExit(this, "getUpdateCount", updateCount_);
865                 }
866                 return updateCount_;
867             }
868         }
869         catch ( SqlException se )
870         {
871             throw se.getSQLException();
872         }
873     }
874
875     public boolean getMoreResults() throws SQLException JavaDoc {
876         try
877         {
878             synchronized (connection_) {
879                 if (agent_.loggingEnabled()) {
880                     agent_.logWriter_.traceEntry(this, "getMoreResults");
881                 }
882                 boolean resultIsResultSet = getMoreResultsX(CLOSE_ALL_RESULTS);
883                 if (agent_.loggingEnabled()) {
884                     agent_.logWriter_.traceExit(this, "getMoreResults", resultIsResultSet);
885                 }
886                 return resultIsResultSet;
887             }
888         }
889         catch ( SqlException se )
890         {
891             throw se.getSQLException();
892         }
893     }
894
895     //--------------------------JDBC 2.0-----------------------------
896

897     public void setFetchDirection(int direction) throws SQLException JavaDoc {
898         try
899         {
900             synchronized (connection_) {
901                 if (agent_.loggingEnabled()) {
902                     agent_.logWriter_.traceEntry(this, "setFetchDirection", direction);
903                 }
904                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
905
switch (direction) {
906                 case java.sql.ResultSet.FETCH_FORWARD:
907                 case java.sql.ResultSet.FETCH_REVERSE:
908                 case java.sql.ResultSet.FETCH_UNKNOWN:
909                     fetchDirection_ = direction;
910                     break;
911                 default:
912                     throw new SqlException(agent_.logWriter_,
913                         new ClientMessageId(SQLState.INVALID_FETCH_DIRECTION),
914                         new Integer JavaDoc(direction));
915                 }
916             }
917         }
918         catch ( SqlException se )
919         {
920             throw se.getSQLException();
921         }
922     }
923
924     public int getFetchDirection() throws SQLException JavaDoc {
925         try
926         {
927             checkForClosedStatement();
928             if (agent_.loggingEnabled()) {
929                 agent_.logWriter_.traceExit(this, "getFetchDirection", fetchDirection_);
930             }
931             return fetchDirection_;
932         }
933         catch ( SqlException se )
934         {
935             throw se.getSQLException();
936         }
937     }
938
939     public void setFetchSize(int rows) throws SQLException JavaDoc {
940         try
941         {
942             synchronized (connection_) {
943                 if (agent_.loggingEnabled()) {
944                     agent_.logWriter_.traceEntry(this, "setFetchSize", rows);
945                 }
946                 checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
947

948                 if (rows < 0 || (maxRows_ != 0 && rows > maxRows_)) {
949                     throw new SqlException(agent_.logWriter_,
950                         new ClientMessageId(SQLState.INVALID_ST_FETCH_SIZE),
951                         new Integer JavaDoc(rows)).getSQLException();
952                 }
953                 fetchSize_ = rows;
954             }
955         }
956         catch ( SqlException se )
957         {
958             throw se.getSQLException();
959         }
960     }
961
962     public int getFetchSize() throws SQLException JavaDoc {
963         try
964         {
965             checkForClosedStatement();
966             if (agent_.loggingEnabled()) {
967                 agent_.logWriter_.traceExit(this, "getFetchSize", fetchSize_);
968             }
969             return fetchSize_;
970         }
971         catch ( SqlException se )
972         {
973             throw se.getSQLException();
974         }
975     }
976
977     public int getResultSetConcurrency() throws SQLException JavaDoc {
978         try
979         {
980             checkForClosedStatement();
981             if (agent_.loggingEnabled()) {
982                 agent_.logWriter_.traceExit(this, "getResultSetConcurrency", resultSetConcurrency_);
983             }
984             return resultSetConcurrency_;
985         }
986         catch ( SqlException se )
987         {
988             throw se.getSQLException();
989         }
990     }
991
992     public int getResultSetType() throws SQLException JavaDoc {
993         try
994         {
995             checkForClosedStatement();
996             if (agent_.loggingEnabled()) {
997                 agent_.logWriter_.traceExit(this, "getResultSetType", resultSetType_);
998             }
999             return resultSetType_;
1000        }
1001        catch ( SqlException se )
1002        {
1003            throw se.getSQLException();
1004        }
1005    }
1006
1007    public void addBatch(String JavaDoc sql) throws SQLException JavaDoc {
1008        try
1009        {
1010            synchronized (connection_) {
1011                if (agent_.loggingEnabled()) {
1012                    agent_.logWriter_.traceEntry(this, "addBatch", sql);
1013                }
1014                checkForClosedStatement();
1015                sql = connection_.nativeSQLX(sql);
1016                batch_.add(sql);
1017            }
1018        }
1019        catch ( SqlException se )
1020        {
1021            throw se.getSQLException();
1022        }
1023    }
1024
1025    public void clearBatch() throws SQLException JavaDoc {
1026        try
1027        {
1028            synchronized (connection_) {
1029                if (agent_.loggingEnabled()) {
1030                    agent_.logWriter_.traceEntry(this, "clearBatch");
1031                }
1032                checkForClosedStatement();
1033                batch_.clear();
1034            }
1035        }
1036        catch ( SqlException se )
1037        {
1038            throw se.getSQLException();
1039        }
1040    }
1041
1042    public int[] executeBatch() throws SQLException JavaDoc, BatchUpdateException {
1043        try
1044        {
1045            synchronized (connection_) {
1046                if (agent_.loggingEnabled()) {
1047                    agent_.logWriter_.traceEntry(this, "executeBatch");
1048                }
1049                int[] updateCounts = executeBatchX();
1050                if (agent_.loggingEnabled()) {
1051                    agent_.logWriter_.traceExit(this, "executeBatch", updateCounts);
1052                }
1053                return updateCounts;
1054            }
1055        }
1056        catch ( SqlException se )
1057        {
1058            throw se.getSQLException();
1059        }
1060    }
1061
1062    private int[] executeBatchX() throws SqlException, BatchUpdateException {
1063        checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
1064
clearWarningsX(); // Per jdbc spec 0.7, and getWarnings() javadoc
1065
resultSetList_ = null;
1066        // Initialize all the updateCounts to indicate failure
1067
// This is done to account for "chain-breaking" errors where we cannot
1068
// read any more replies
1069
int[] updateCounts = new int[batch_.size()];
1070        for (int i = 0; i < batch_.size(); i++) {
1071            updateCounts[i] = -3;
1072        }
1073        flowExecuteBatch(updateCounts);
1074        return updateCounts;
1075    }
1076
1077    public java.sql.Connection JavaDoc getConnection() throws SQLException JavaDoc {
1078        try
1079        {
1080            checkForClosedStatement();
1081            if (agent_.loggingEnabled()) {
1082                agent_.logWriter_.traceExit(this, "getConnection", connection_);
1083            }
1084            return connection_;
1085        }
1086        catch ( SqlException se )
1087        {
1088            throw se.getSQLException();
1089        }
1090    }
1091
1092    //--------------------------JDBC 3.0-----------------------------
1093

1094    public boolean getMoreResults(int current) throws SQLException JavaDoc {
1095        try
1096        {
1097            synchronized (connection_) {
1098                if (agent_.loggingEnabled()) {
1099                    agent_.logWriter_.traceEntry(this, "getMoreResults", current);
1100                }
1101                boolean resultIsResultSet = getMoreResultsX(current);
1102                if (agent_.loggingEnabled()) {
1103                    agent_.logWriter_.traceExit(this, "getMoreResults", resultIsResultSet);
1104                }
1105                return resultIsResultSet;
1106            }
1107        }
1108        catch ( SqlException se )
1109        {
1110            throw se.getSQLException();
1111        }
1112    }
1113
1114    private boolean getMoreResultsX(int current) throws SqlException {
1115        checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
1116
boolean resultIsResultSet;
1117        updateCount_ = -1;
1118        if (resultSetList_ == null) {
1119            if (resultSet_ != null) {
1120                if (current != KEEP_CURRENT_RESULT) {
1121                    resultSet_.closeX();
1122                }
1123                resultSet_ = null;
1124            }
1125            resultIsResultSet = false;
1126        } else {
1127            if (numInvisibleRS_ == 0 &&
1128                    current == CLOSE_CURRENT_RESULT &&
1129                    resultSetList_[indexOfCurrentResultSet_] != null) {
1130                resultSetList_[indexOfCurrentResultSet_].closeX();
1131            }
1132            resultIsResultSet = indexOfCurrentResultSet_ + 1 < resultSetList_.length;
1133        }
1134        if ((current == CLOSE_ALL_RESULTS) && (numInvisibleRS_ == 0)) {
1135            int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : indexOfCurrentResultSet_ + 1;
1136            boolean willTickleServer = willTickleServer(numberOfResultSetsToClose, false);
1137            if (willTickleServer) {
1138                flowCloseRetrievedResultSets();
1139            } else {
1140                flowCloseRetrievedResultSetsOutsideUOW();
1141            }
1142        }
1143        if (resultIsResultSet) {
1144            resultSet_ = resultSetList_[++indexOfCurrentResultSet_];
1145        } else {
1146            resultSet_ = null;
1147        }
1148
1149        return resultIsResultSet;
1150    }
1151
1152    public java.sql.ResultSet JavaDoc getGeneratedKeys() throws SQLException JavaDoc {
1153        try
1154        {
1155            if (agent_.loggingEnabled()) {
1156                agent_.logWriter_.traceEntry(this, "getGeneratedKeys");
1157            }
1158            checkForClosedStatement();
1159            if (agent_.loggingEnabled()) {
1160                agent_.logWriter_.traceExit(this, "getGeneratedKeys", generatedKeysResultSet_);
1161            }
1162            return generatedKeysResultSet_;
1163        }
1164        catch ( SqlException se )
1165        {
1166            throw se.getSQLException();
1167        }
1168    }
1169
1170    public int executeUpdate(String JavaDoc sql, int autoGeneratedKeys) throws SQLException JavaDoc {
1171        try
1172        {
1173            synchronized (connection_) {
1174                if (agent_.loggingEnabled()) {
1175                    agent_.logWriter_.traceEntry(this, "executeUpdate", sql, autoGeneratedKeys);
1176                }
1177                autoGeneratedKeys_ = autoGeneratedKeys;
1178                int updateValue = executeUpdateX(sql);
1179                if (agent_.loggingEnabled()) {
1180                    agent_.logWriter_.traceExit(this, "executeUpdate", updateValue);
1181                }
1182                return updateValue;
1183            }
1184        }
1185        catch ( SqlException se )
1186        {
1187            throw se.getSQLException();
1188        }
1189    }
1190
1191    public int executeUpdate(String JavaDoc sql, int columnIndexes[]) throws SQLException JavaDoc {
1192        try
1193        {
1194            if (agent_.loggingEnabled()) {
1195                agent_.logWriter_.traceEntry(this, "executeUpdate", sql, columnIndexes);
1196            }
1197            checkForClosedStatement();
1198            throw new SqlException(agent_.logWriter_,
1199                new ClientMessageId(SQLState.NOT_IMPLEMENTED),
1200                "executeUpdate(String, int[])");
1201        }
1202        catch ( SqlException se )
1203        {
1204            throw se.getSQLException();
1205        }
1206    }
1207
1208    public int executeUpdate(String JavaDoc sql, String JavaDoc columnNames[]) throws SQLException JavaDoc {
1209        try
1210        {
1211            synchronized (connection_) {
1212                if (agent_.loggingEnabled()) {
1213                    agent_.logWriter_.traceEntry(this, "executeUpdate", sql, columnNames);
1214                }
1215                generatedKeysColumnNames_ = columnNames;
1216                int updateValue = executeUpdateX(sql);
1217                if (agent_.loggingEnabled()) {
1218                    agent_.logWriter_.traceExit(this, "executeUpdate", updateValue);
1219                }
1220                return updateValue;
1221            }
1222        }
1223        catch ( SqlException se )
1224        {
1225            throw se.getSQLException();
1226        }
1227    }
1228
1229    public boolean execute(String JavaDoc sql, int autoGeneratedKeys) throws SQLException JavaDoc {
1230        try
1231        {
1232            synchronized (connection_) {
1233                if (agent_.loggingEnabled()) {
1234                    agent_.logWriter_.traceEntry(this, "execute", sql, autoGeneratedKeys);
1235                }
1236                autoGeneratedKeys_ = autoGeneratedKeys;
1237                boolean b = executeX(sql);
1238                if (agent_.loggingEnabled()) {
1239                    agent_.logWriter_.traceExit(this, "execute", b);
1240                }
1241                return b;
1242            }
1243        }
1244        catch ( SqlException se )
1245        {
1246            throw se.getSQLException();
1247        }
1248    }
1249
1250    public boolean execute(String JavaDoc sql, int columnIndexes[]) throws SQLException JavaDoc {
1251        try
1252        {
1253            if (agent_.loggingEnabled()) {
1254                agent_.logWriter_.traceEntry(this, "execute", sql, columnIndexes);
1255            }
1256            checkForClosedStatement();
1257            throw new SqlException(agent_.logWriter_,
1258                new ClientMessageId(SQLState.NOT_IMPLEMENTED),
1259                "execute(String, int[])");
1260        }
1261        catch ( SqlException se )
1262        {
1263            throw se.getSQLException();
1264        }
1265    }
1266
1267    public boolean execute(String JavaDoc sql, String JavaDoc columnNames[]) throws SQLException JavaDoc {
1268        try
1269        {
1270            synchronized (connection_) {
1271                if (agent_.loggingEnabled()) {
1272                    agent_.logWriter_.traceEntry(this, "execute", sql, columnNames);
1273                }
1274                generatedKeysColumnNames_ = columnNames;
1275                boolean b = executeX(sql);
1276                if (agent_.loggingEnabled()) {
1277                    agent_.logWriter_.traceExit(this, "execute", b);
1278                }
1279                return b;
1280            }
1281        }
1282        catch ( SqlException se )
1283        {
1284            throw se.getSQLException();
1285        }
1286    }
1287
1288    public int getResultSetHoldability() throws SQLException JavaDoc {
1289        try
1290        {
1291            if (agent_.loggingEnabled()) {
1292                agent_.logWriter_.traceEntry(this, "getResultSetHoldability");
1293            }
1294            checkForClosedStatement();
1295            return resultSetHoldability_;
1296        }
1297        catch ( SqlException se )
1298        {
1299            throw se.getSQLException();
1300        }
1301    }
1302
1303    // ----------------------- box car and callback methods ---------------------
1304
// All callbacks must be client-side only operations.
1305
// Use of MaterialStatement interface is necessary to avoid multiple inheritance problem in Java.
1306
public void writeSetSpecialRegister(java.util.ArrayList JavaDoc sqlsttList) throws SqlException {
1307        materialStatement_.writeSetSpecialRegister_(sqlsttList);
1308    }
1309
1310    public void readSetSpecialRegister() throws SqlException {
1311        materialStatement_.readSetSpecialRegister_();
1312    }
1313
1314    public void writeExecuteImmediate(String JavaDoc sql,
1315                                      Section section) throws SqlException {
1316        materialStatement_.writeExecuteImmediate_(sql, section);
1317    }
1318
1319    public void readExecuteImmediate() throws SqlException {
1320        materialStatement_.readExecuteImmediate_();
1321    }
1322
1323    public void completeExecuteImmediate(Sqlca sqlca) {
1324        int sqlcode = completeSqlca(sqlca);
1325        if (sqlcode < 0) {
1326            return;
1327        }
1328        if (sqlca != null) {
1329            updateCount_ = sqlca.getUpdateCount();
1330        }
1331    }
1332
1333    public void readExecuteImmediateForBatch(String JavaDoc sql) throws SqlException {
1334        materialStatement_.readExecuteImmediateForBatch_(sql);
1335    }
1336
1337    public void writePrepareDescribeOutput(String JavaDoc sql,
1338                                           Section section) throws SqlException {
1339        materialStatement_.writePrepareDescribeOutput_(sql, section);
1340    }
1341
1342    public void readPrepareDescribeOutput() throws SqlException {
1343        materialStatement_.readPrepareDescribeOutput_();
1344    }
1345
1346    public void completePrepareDescribeOutput(ColumnMetaData resultSetMetaData,
1347                                              Sqlca sqlca) {
1348        completePrepare(sqlca);
1349        resultSetMetaData_ = resultSetMetaData;
1350        if (agent_.loggingEnabled()) {
1351            agent_.logWriter_.traceResultSetMetaData(this, resultSetMetaData_);
1352        }
1353    }
1354
1355    // Used for re-prepares across commit only
1356
public void writePrepare(String JavaDoc sql, Section section) throws SqlException {
1357        materialStatement_.writePrepare_(sql, section);
1358    }
1359
1360    public void readPrepare() throws SqlException {
1361        materialStatement_.readPrepare_();
1362    }
1363
1364    public void completePrepare(Sqlca sqlca) {
1365        int sqlcode = completeSqlca(sqlca);
1366        if (sqlcode < 0) {
1367            return;
1368        }
1369        markPrepared();
1370    }
1371
1372    public void writeOpenQuery(Section section,
1373                               int fetchSize,
1374                               int resultSetType) throws SqlException {
1375        materialStatement_.writeOpenQuery_(section,
1376                fetchSize,
1377                resultSetType);
1378    }
1379
1380    public void readOpenQuery() throws SqlException {
1381        materialStatement_.readOpenQuery_();
1382    }
1383
1384    public void completeOpenQuery(Sqlca sqlca, ResultSet resultSet) {
1385        completeSqlca(sqlca);
1386        resultSet_ = resultSet;
1387        // For NET, resultSet_ == null when open query fails and receives OPNQFLRM.
1388
// Then, in NetStatementReply.parseOpenQueryFailure(), completeOpenQuery() is
1389
// invoked with resultSet explicitly set to null.
1390
if (resultSet == null) {
1391            return;
1392        }
1393        resultSet.resultSetMetaData_ = resultSetMetaData_;
1394        resultSet.resultSetMetaData_.resultSetConcurrency_ = resultSet.resultSetConcurrency_;
1395
1396        // only cache the Cursor object for a PreparedStatement and if a Cursor object is
1397
// not already cached.
1398
if (cachedCursor_ == null && isPreparedStatement_) {
1399            cachedCursor_ = resultSet_.cursor_;
1400        }
1401
1402        // The following two assignments should have already happened via prepareEvent(),
1403
// but are included here for safety for the time being.
1404
if (sqlca != null && sqlca.getSqlCode() < 0) {
1405            return;
1406        }
1407        openOnServer_ = true;
1408        resultSet.cursor_.rowsRead_ = 0;
1409
1410        // Set fetchSize_ to the default(64) if not set by the user if the resultset is scrollable.
1411
// This fetchSize_ is used to check for a complete rowset when rowsets are parsed.
1412
// For scrollable cursors when the fetchSize_ is not set, (fetchSize_ == 0), a default
1413
// fetchSize of 64 is sent on behalf of the application, so we need to update the fetchSize_
1414
// here to 64.
1415
if (resultSet_.fetchSize_ == 0 &&
1416                (resultSet_.resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE ||
1417                resultSet_.resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_SENSITIVE)) {
1418            resultSet_.setFetchSize_(org.apache.derby.client.am.
1419                                     Configuration.defaultFetchSize);
1420        }
1421    }
1422
1423    public void completeExecuteCallOpenQuery(Sqlca sqlca, ResultSet resultSet, ColumnMetaData resultSetMetaData, Section generatedSection) {
1424        resultSet.completeSqlca(sqlca);
1425        // For CallableStatements we can't just clobber the resultSet_ here, must use setResultSetEvent() separately
1426
resultSet.resultSetMetaData_ = resultSetMetaData;
1427
1428        // The following two assignments should have already happened via prepareEvent(),
1429
// but are included here for safety for the time being.
1430
if (sqlca != null && sqlca.getSqlCode() < 0) {
1431            return;
1432        }
1433        openOnServer_ = true;
1434        resultSet.cursor_.rowsRead_ = 0;
1435
1436        resultSet.generatedSection_ = generatedSection;
1437
1438        // We are always sending the default fetchSize of 64 if not set for stored procedure calls.
1439
// This is different from the "normal" cursor case for forward_only cursors, where if
1440
// fetchSize_ is not set, we do not send any default value. Here since we always send
1441
// the fetchSize_, we need to set it to what we sent.
1442
if (resultSet.fetchSize_ == 0) {
1443            resultSet.fetchSize_ = org.apache.derby.client.am.Configuration.defaultFetchSize;
1444        }
1445    }
1446
1447    public void writeExecuteCall(boolean outputExpected,
1448                                 String JavaDoc procedureName,
1449                                 Section section,
1450                                 int fetchSize,
1451                                 boolean suppressResultSets, // for batch updates == true
1452
int resultSetType,
1453                                 ColumnMetaData parameterMetaData,
1454                                 Object JavaDoc[] inputs) throws SqlException {
1455        materialStatement_.writeExecuteCall_(outputExpected,
1456                procedureName,
1457                section,
1458                fetchSize,
1459                suppressResultSets,
1460                resultSetType,
1461                parameterMetaData,
1462                inputs);
1463    }
1464
1465    public void readExecuteCall() throws SqlException {
1466        materialStatement_.readExecuteCall_();
1467    }
1468
1469    public void completeExecuteCall(Sqlca sqlca, Cursor singletonParams, ResultSet[] resultSets) {
1470        completeExecuteCall(sqlca, singletonParams);
1471        resultSetList_ = resultSets;
1472        if (resultSets != null) {
1473            resultSet_ = resultSets[0];
1474        }
1475        indexOfCurrentResultSet_ = 0;
1476    }
1477
1478    public void completeExecuteCall(Sqlca sqlca, Cursor singletonParams) // no result sets returned
1479
{
1480        completeExecute(sqlca);
1481        //if ((sqlca != null) && ((sqlca.getSqlCode() < 0) || (sqlca.getSqlCode() == 100)))
1482
if (sqlca != null && sqlca.getSqlCode() < 0) {
1483            singletonRowData_ = null;
1484        } else {
1485            singletonRowData_ = singletonParams;
1486            if (cachedSingletonRowData_ == null && isPreparedStatement_) {
1487                cachedSingletonRowData_ = singletonRowData_;
1488            }
1489        }
1490    }
1491
1492    // Callback for CALLS, and PreparedStatement updates.
1493
public void completeExecute(Sqlca sqlca) {
1494        if (sqlca == null) {
1495            return;
1496        }
1497
1498        int sqlcode = sqlca.getSqlCode();
1499        if (sqlcode < 0) {
1500            agent_.accumulateReadException(new SqlException(agent_.logWriter_, sqlca));
1501            returnValueFromProcedure_ = sqlcode;
1502        } else {
1503            updateCount_ = sqlca.getUpdateCount();
1504            // sometime for call statement, protocol will return updateCount_, we will always set that to 0
1505
// sqlMode_ is not set for statements, only for prepared statements
1506
if (sqlMode_ == isCall__) {
1507                updateCount_ = -1;
1508                returnValueFromProcedure_ = sqlca.getSqlErrd()[0]; ////what is this for??
1509
}
1510            // Sqlcode 466 indicates a call statement has issued and result sets returned.
1511
// This is a good place to set some state variable to indicate result sets are open
1512
// for call, so that when autocommit is true, commit will not be issued until the
1513
// result sets are closed.
1514
// Currently, commit is not issued even there is no result set.
1515
// do not externalize sqlcode +100
1516
if (sqlcode > 0 && sqlcode != 466 && sqlcode != 100) {
1517                accumulateWarning(new SqlWarning(agent_.logWriter_, sqlca));
1518            }
1519        }
1520    }
1521
1522
1523    public void setUpdateCount(int updateCount) {
1524        updateCount_ = updateCount;
1525    }
1526
1527
1528    private boolean willTickleServer(int number, boolean allowAutoCommits) throws SqlException {
1529        boolean requiresAutocommit = false;
1530        if (resultSetList_ != null) {
1531            for (int i = 0; i < number; i++) {
1532                if (resultSetList_[i] != null) {
1533                    if (resultSetList_[i].openOnServer_) {
1534                        return true; // for the writeClose flow
1535
}
1536                    if (!resultSetList_[i].autoCommitted_ && allowAutoCommits) {
1537                        requiresAutocommit = true; // for the commit flow
1538
}
1539                }
1540            }
1541        } else if (generatedKeysResultSet_ != null && generatedKeysResultSet_.openOnServer_) {
1542            generatedKeysResultSet_.writeClose();
1543        } else if (resultSet_ != null) {
1544            if (resultSet_.openOnServer_) {
1545                return true; // for the writeClose flow
1546
}
1547            if (!resultSet_.autoCommitted_ && allowAutoCommits) {
1548                requiresAutocommit = true;
1549            }
1550        }
1551        if (connection_.autoCommit_ && requiresAutocommit) { // for the auto-commit;
1552
if (connection_.isXAConnection_) {
1553                return (connection_.getXAState() == Connection.XA_T0_NOT_ASSOCIATED) ;
1554            } else {
1555                return true;
1556            }
1557        }
1558        return false;
1559    }
1560
1561    private void flowClose() throws SqlException {
1562        agent_.beginWriteChain(this);
1563        writeClose(true); // true means permit auto-commits
1564
agent_.flow(this);
1565        readClose(true); // true means permit auto-commits
1566
agent_.endReadChain();
1567    }
1568
1569    private void flowCloseOutsideUOW() throws SqlException {
1570        agent_.beginWriteChainOutsideUOW();
1571        writeClose(true); // true means permit auto-commits
1572
agent_.flowOutsideUOW();
1573        readClose(true); // true means permit auto-commits
1574
agent_.endReadChain();
1575    }
1576
1577    final void writeClose(boolean allowAutoCommits) throws SqlException {
1578        writeCloseResultSets(allowAutoCommits);
1579    }
1580
1581    final void readClose(boolean allowAutoCommits) throws SqlException {
1582        readCloseResultSets(allowAutoCommits);
1583    }
1584
1585    boolean writeCloseResultSets(boolean allowAutoCommits) throws SqlException {
1586        int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : resultSetList_.length;
1587        return writeCloseResultSets(numberOfResultSetsToClose, allowAutoCommits);
1588    }
1589
1590    // The connection close processing passes allowAutoCommits=false because if we drove an
1591
// autocommits after each statement close, then when we issue close requests on non-held cursors
1592
// the server would complain that the non-held cursor was already closed from the previous statement's auto-commit.
1593
// So the solution is to never autocommit statements during connection close processing.
1594
//
1595
// Here's the operative explanation:
1596
// Given a sequence of open statements S1, S2, .... a logic problem is occuring after S1 close-query
1597
// drives an auto-commit, and S2 close-query is driven against a non-held cursor.
1598
// The first auto-commit driven by S1 triggers a callback that closes S2's non-held cursor,
1599
// and so the subsequent S2 close-query request generates an error from the server saying
1600
// that the cursor is already closed.
1601
//
1602
// This is fixed by passing a flag to our statement close processing that prevents
1603
// driving additional auto-commits after each statement close.
1604
// Connectino close drives its own final auto-commit.
1605
//
1606
boolean writeCloseResultSets(int number, boolean allowAutoCommits) throws SqlException {
1607        boolean requiresAutocommit = false;
1608        if (resultSetList_ != null) {
1609            for (int i = 0; i < number; i++) {
1610                if (resultSetList_[i] != null) {
1611                    if (resultSetList_[i].openOnServer_) {
1612                        resultSetList_[i].writeClose();
1613                    }
1614                    if (!resultSetList_[i].autoCommitted_ && allowAutoCommits) {
1615                        requiresAutocommit = true;
1616                    }
1617                }
1618            }
1619        } else if (generatedKeysResultSet_ != null && generatedKeysResultSet_.openOnServer_) {
1620            generatedKeysResultSet_.writeClose();
1621        } else if (resultSet_ != null) {
1622            if (resultSet_.openOnServer_) {
1623                resultSet_.writeClose();
1624            }
1625            if (!resultSet_.autoCommitted_ && allowAutoCommits) {
1626                requiresAutocommit = true;
1627            }
1628        }
1629        if (connection_.autoCommit_ && requiresAutocommit && isAutoCommittableStatement_) {
1630            connection_.writeAutoCommit();
1631            if (connection_.isXAConnection_) {
1632                return (connection_.getXAState() == Connection.XA_T0_NOT_ASSOCIATED) ;
1633            } else {
1634                return true;
1635            }
1636        }
1637        return false;
1638    }
1639
1640    // Helper method for S.flowCloseResultSets() and PS.flowExecute()
1641
void readCloseResultSets(boolean allowAutoCommits) throws SqlException {
1642        int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : resultSetList_.length;
1643        readCloseResultSets(numberOfResultSetsToClose, allowAutoCommits);
1644    }
1645
1646    void readCloseResultSets(int number, boolean allowAutoCommits) throws SqlException {
1647        boolean requiredAutocommit = false;
1648        if (resultSetList_ != null) {
1649            for (int i = 0; i < number; i++) {
1650                if (resultSetList_[i] != null) {
1651                    if (resultSetList_[i].openOnServer_) {
1652                        resultSetList_[i].readClose();
1653                    } else {
1654                        resultSetList_[i].markClosed();
1655                    }
1656                    if (!resultSetList_[i].autoCommitted_ && allowAutoCommits) {
1657                        requiredAutocommit = true;
1658                    }
1659                }
1660            }
1661        } else if (generatedKeysResultSet_ != null) {
1662            if (generatedKeysResultSet_.openOnServer_) {
1663                generatedKeysResultSet_.readClose();
1664            } else {
1665                generatedKeysResultSet_.markClosed();
1666            }
1667        } else if (resultSet_ != null) {
1668            if (resultSet_.openOnServer_) {
1669                resultSet_.readClose();
1670            } else {
1671                resultSet_.markClosed();
1672            }
1673            if (!resultSet_.autoCommitted_ && allowAutoCommits) {
1674                requiredAutocommit = true;
1675            }
1676        }
1677        // we only commit when auto commit is turned on and at least one result set needed closing on server.
1678
if (connection_.autoCommit_ && requiredAutocommit && isAutoCommittableStatement_) {
1679            connection_.readAutoCommit();
1680        }
1681    }
1682
1683    private void flowCloseRetrievedResultSets() throws SqlException {
1684        int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : indexOfCurrentResultSet_ + 1;
1685        agent_.beginWriteChain(this);
1686        // Need to refactor the ResultSet.readClose() path to check if we are the
1687
// last result set closed in a set of multiple result sets of the owning statement,
1688
// if so, we need to flow the auto-commit (but only then).
1689
// currently, the code to do this is only in the closeX() path, which isn't called here
1690
writeCloseResultSets(numberOfResultSetsToClose, false);
1691        agent_.flow(this);
1692        readCloseResultSets(numberOfResultSetsToClose, false); // true means permit auto-commits
1693
agent_.endReadChain();
1694    }
1695
1696    private void flowCloseRetrievedResultSetsOutsideUOW() throws SqlException {
1697        int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : indexOfCurrentResultSet_ + 1;
1698        agent_.beginWriteChainOutsideUOW();
1699        // Need to refactor the ResultSet.readClose() path to check if we are the
1700
// last result set closed in a set of multiple result sets of the owning statement,
1701
// if so, we need to flow the auto-commit (but only then).
1702
// currently, the code to do this is only in the closeX() path, which isn't called here
1703
writeCloseResultSets(numberOfResultSetsToClose, false);
1704        agent_.flowOutsideUOW();
1705        readCloseResultSets(numberOfResultSetsToClose, false); // true means permit auto-commits
1706
agent_.endReadChain();
1707    }
1708
1709    public int completeSqlca(Sqlca sqlca) {
1710        if (sqlca == null) {
1711            return 0;
1712        }
1713        int sqlcode = sqlca.getSqlCode();
1714        if (sqlcode < 0) {
1715            connection_.agent_.accumulateReadException(new SqlException(agent_.logWriter_, sqlca));
1716        } else if (sqlcode > 0) {
1717            accumulateWarning(new SqlWarning(agent_.logWriter_, sqlca));
1718        }
1719        return sqlcode;
1720    }
1721
1722    public void completeExecuteSetStatement(Sqlca sqlca) {
1723    }
1724
1725    void markClosedOnServer() {
1726        if (section_ != null) {
1727            section_.free();
1728            section_ = null;
1729        }
1730        openOnServer_ = false;
1731        // if an error occurs during the middle of the reset, before the statement
1732
// has a chance to reset its materialStatement_, and Agent.disconnectEvent() is called,
1733
// then the materialStatement_ here can be null.
1734
if (materialStatement_ != null) {
1735            materialStatement_.markClosedOnServer_();
1736        }
1737    }
1738
1739    /**
1740     * This method cleans up client-side resources held by this Statement.
1741     * The Statement will not be removed from the open statements list and
1742     * PreparedStatement will also not be removed from the commit and rollback
1743     * listeners list in <code>org.apache.derby.client.am.Connection</code>.
1744     *
1745     * This method is called from:
1746     * 1. finalize() - For the finaizer to be called, the Statement
1747     * should not have any references and so it should have been already
1748     * removed from the lists.
1749     *
1750     * 2. <code>org.apache.derby.client.am.Connection#markStatementsClosed</code>
1751     * This method explicitly removes the Statement from open statements list.
1752     *
1753     * 3. To close positioned update statements - These statements are not
1754     * added to the list of open statements.
1755     */

1756    void markClosed() {
1757        markClosed(false);
1758    }
1759    
1760    /**
1761     * This method cleans up client-side resources held by this Statement.
1762     * If removeListener is true, the Statement is removed from open statements
1763     * list and PreparedStatement is also removed from commit and rollback
1764     * listeners list. This is called from the close methods.
1765     *
1766     * @param removeListener if true the Statement will be removed
1767     * from the open statements list and PreparedStatement will also be removed
1768     * from commit and rollback listeners list in
1769     * <code>org.apache.derby.client.am.Connection</code>.
1770     */

1771    void markClosed(boolean removeListener) {
1772        openOnClient_ = false;
1773        markResultSetsClosed();
1774        // in case a cursorName was set on the Statement but the Statement was
1775
// never used to execute a query, the cursorName will not be removed
1776
// when the resultSets are mark closed, so we need to remove the
1777
// cursorName form the cache.
1778
removeClientCursorNameFromCache();
1779        markPreparedStatementForAutoGeneratedKeysClosed();
1780        markClosedOnServer();
1781
1782        // mark close ResultSetMetaData
1783
if (resultSetMetaData_ != null) {
1784            resultSetMetaData_.markClosed();
1785            resultSetMetaData_ = null;
1786        }
1787        
1788        if(removeListener)
1789            connection_.openStatements_.remove(this);
1790    }
1791
1792    void markPreparedStatementForAutoGeneratedKeysClosed() {
1793        if (preparedStatementForAutoGeneratedKeys_ != null) {
1794            preparedStatementForAutoGeneratedKeys_.markClosed();
1795        }
1796    }
1797
1798    /**
1799     * Mark all ResultSets associated with this statement as
1800     * closed. The ResultSets will not be removed from the commit and
1801     * rollback listeners list in
1802     * <code>org.apache.derby.client.am.Connection</code>.
1803     */

1804    void markResultSetsClosed() {
1805        markResultSetsClosed(false);
1806    }
1807
1808    /**
1809     * Mark all ResultSets associated with this statement as
1810     * closed.
1811     *
1812     * @param removeListener if true the ResultSets will be removed
1813     * from the commit and rollback listeners list in
1814     * <code>org.apache.derby.client.am.Connection</code>.
1815     */

1816    void markResultSetsClosed(boolean removeListener) {
1817        if (resultSetList_ != null) {
1818            for (int i = 0; i < resultSetList_.length; i++) {
1819                if (resultSetList_[i] != null) {
1820                    resultSetList_[i].markClosed(removeListener);
1821                }
1822                resultSetList_[i] = null;
1823            }
1824        }
1825        if (generatedKeysResultSet_ != null) {
1826            generatedKeysResultSet_.markClosed(removeListener);
1827        }
1828        if (resultSet_ != null) {
1829            resultSet_.markClosed(removeListener);
1830        }
1831        resultSet_ = null;
1832        resultSetList_ = null;
1833        generatedKeysResultSet_ = null;
1834    }
1835
1836    private void flowExecute(int executeType, String JavaDoc sql) throws SqlException {
1837        checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
1838
checkAutoGeneratedKeysParameters();
1839        clearWarningsX(); // Per jdbc spec 0.7, and getWarnings() javadoc
1840

1841        sql = escape(sql);
1842        parseSqlAndSetSqlModes(sql);
1843        if (sqlMode_ == isUpdate__) {
1844            updateCount_ = 0;
1845        } else {
1846            updateCount_ = -1;
1847        }
1848
1849        checkForAppropriateSqlMode(executeType, sqlMode_);
1850
1851        // DERBY-1036: Moved check till execute time to comply with embedded
1852
// behavior. Since we check here and not in setCursorName, several
1853
// statements can have the same cursor name as long as their result
1854
// sets are not simultaneously open.
1855

1856        if (sqlMode_ == isQuery__) {
1857            checkForDuplicateCursorName();
1858        }
1859
1860        boolean timeoutSent = false;
1861
1862            agent_.beginWriteChain(this);
1863            boolean piggybackedAutoCommit = writeCloseResultSets(true); // true means permit auto-commits
1864

1865            ResultSet scrollableRS = null;
1866            Section newSection = null;
1867            boolean repositionedCursor = false;
1868
1869            // DERBY-1692: Statement objects need to send the timeout value for
1870
// each execution since the server will create a new statement
1871
// object each time. Since the server forgets the timeout value,
1872
// doWriteTimeout should not be reset, and it is OK not to send the
1873
// timeout value when it is zero.
1874
if (doWriteTimeout && (timeout_ > 0)) {
1875                timeoutArrayList.set(0, TIMEOUT_STATEMENT + timeout_);
1876                writeSetSpecialRegister(timeoutArrayList);
1877                timeoutSent = true;
1878            }
1879            switch (sqlMode_) {
1880            case isQuery__:
1881                newSection = agent_.sectionManager_.getDynamicSection(resultSetHoldability_);
1882
1883                writePrepareDescribeOutput(sql, newSection);
1884                writeOpenQuery(newSection,
1885                        fetchSize_,
1886                        resultSetType_);
1887                break;
1888            case isUpdate__:
1889                String JavaDoc cursorName = null;
1890                if (sqlUpdateMode_ == isDeleteSql__ || sqlUpdateMode_ == isUpdateSql__) {
1891                    String JavaDoc[] sqlAndCursorName = extractCursorNameFromWhereCurrentOf(sql);
1892                    if (sqlAndCursorName != null) {
1893                        cursorName = sqlAndCursorName[0];
1894                        sql = sqlAndCursorName[1];
1895                    }
1896                }
1897                if (cursorName != null) {
1898                    newSection = agent_.sectionManager_.getPositionedUpdateSection(cursorName, true); // true means get an execute immediate section
1899
if (newSection == null) {
1900                        throw new SqlException(agent_.logWriter_,
1901                            new ClientMessageId(SQLState.CURSOR_INVALID_NAME),
1902                            cursorName);
1903                    }
1904                    scrollableRS = agent_.sectionManager_.getPositionedUpdateResultSet(cursorName);
1905                    // do not need to reposition for rowset cursors
1906
if (scrollableRS != null && !scrollableRS.isRowsetCursor_) {
1907                        repositionedCursor =
1908                                scrollableRS.repositionScrollableResultSetBeforeJDBC1PositionedUpdateDelete();
1909                        if (!repositionedCursor) {
1910                            scrollableRS = null;
1911                        }
1912                    }
1913
1914                    // if client's cursor name is set, and the cursor name in the positioned update
1915
// string is the same as the client's cursor name, replace client's cursor name
1916
// with the server's cursor name.
1917
if (newSection.getClientCursorName() != null &&
1918                            cursorName.compareTo(newSection.getClientCursorName()) == 0) {
1919                        // substitute cusor name in pass thru sql string
1920
sql = substituteClientCursorNameWithServerCursorName(sql, newSection);
1921                    }
1922                    writeExecuteImmediate(sql, newSection);
1923                }
1924                // if sql is an insert and columnNames is not null, and
1925
// then transform the insert statement into an
1926
// select from insert statement.
1927
// else chain an "select from identity_val_local()" to the insert statement
1928
else if (sqlUpdateMode_ == isInsertSql__ && generatedKeysColumnNames_ != null) {
1929                    newSection = agent_.sectionManager_.getDynamicSection(resultSetHoldability_);
1930                    writePrepareDescribeOutput(constructSelectFromInsertSQL(sql), newSection);
1931                    writeOpenQuery(newSection,
1932                            fetchSize_,
1933                            resultSetType_);
1934                } else {
1935                    newSection = agent_.sectionManager_.getDynamicSection(resultSetHoldability_);
1936
1937                    writeExecuteImmediate(sql, newSection);
1938                    if (sqlUpdateMode_ == isInsertSql__ && autoGeneratedKeys_ == RETURN_GENERATED_KEYS) {
1939                        prepareAutoGeneratedKeysStatement();
1940                        writeOpenQuery(preparedStatementForAutoGeneratedKeys_.section_,
1941                                preparedStatementForAutoGeneratedKeys_.fetchSize_,
1942                                preparedStatementForAutoGeneratedKeys_.resultSetType_);
1943                    }
1944                }
1945
1946                // maybe duplicate a commit here if the sql is a "commit"
1947
if (connection_.autoCommit_) {
1948                    connection_.writeAutoCommit();
1949                }
1950                break;
1951            case isCall__:
1952                newSection = writeExecuteCall(sql, false);
1953
1954                break;
1955            }
1956
1957            agent_.flow(this);
1958
1959            readCloseResultSets(true); // true means permit auto-commits
1960

1961            if (timeoutSent) {
1962                readSetSpecialRegister(); // Read response to the EXCSQLSET
1963
}
1964
1965            // turn inUnitOfWork_ flag back on and add statement
1966
// back on commitListeners_ list if they were off
1967
// by an autocommit chained to a close cursor.
1968
if (piggybackedAutoCommit) {
1969                connection_.completeTransactionStart();
1970            }
1971
1972            markResultSetsClosed(true); // true means remove from list of commit and rollback listeners
1973
markClosedOnServer();
1974            section_ = newSection;
1975
1976            switch (sqlMode_) {
1977            case isQuery__:
1978                // parse out the reply to a chained prepare and open request
1979
readPrepareDescribeOutput();
1980                // This establishes statement.resultSet
1981
readOpenQuery();
1982
1983                // resultSet_ is null if open query failed.
1984
// check for null resultSet_ before using it.
1985
// the first rowset comes back on OPEN for static non-rowset cursors.
1986
// no row is returned on open for rowset cursors.
1987
if (resultSet_ != null) {
1988                    resultSet_.parseScrollableRowset();
1989
1990                    // DERBY-1183: If we set it up it earlier, the entry in
1991
// clientCursorNameCache_ gets wiped out by the closing of
1992
// result sets happening during readCloseResultSets above
1993
// because ResultSet#markClosed calls
1994
// Statement#removeClientCursorNameFromCache.
1995
setupCursorNameCacheAndMappings();
1996                }
1997
1998                break;
1999
2000            case isUpdate__:
2001
2002                // do not need to reposition for rowset cursors.
2003
if (scrollableRS != null && !scrollableRS.isRowsetCursor_) {
2004                    scrollableRS.readPositioningFetch_();
2005                }
2006
2007                if (sqlUpdateMode_ == isInsertSql__ && generatedKeysColumnNames_ != null) {
2008                    readPrepareDescribeOutput();
2009                    readOpenQuery();
2010                    if (resultSet_ != null) {
2011                        generatedKeysResultSet_ = resultSet_;
2012                        resultSet_ = null;
2013                        updateCount_ = 1;
2014                    }
2015                } else {
2016                    readExecuteImmediate();
2017
2018                    if (sqlUpdateMode_ == isInsertSql__ && autoGeneratedKeys_ == RETURN_GENERATED_KEYS) {
2019                        readPrepareAutoGeneratedKeysStatement();
2020                        preparedStatementForAutoGeneratedKeys_.readOpenQuery();
2021                        generatedKeysResultSet_ = preparedStatementForAutoGeneratedKeys_.resultSet_;
2022                        preparedStatementForAutoGeneratedKeys_.resultSet_ = null;
2023                    }
2024                }
2025
2026                if (connection_.autoCommit_) {
2027                    connection_.readAutoCommit();
2028                }
2029                break;
2030
2031            case isCall__:
2032                readPrepare();
2033                readExecuteCall();
2034                break;
2035
2036            }
2037
2038            // in the case the stored procedure call is uncatalogued, we need to catch that
2039
// kind exception and changed the call from dynamic to static
2040
agent_.endReadChain();
2041
2042            // If we hear from Sun that we can just set a warning for this, then move this code to the ResultSet constructor.
2043
// Throw an exception if holdability returned by the server is different from requested.
2044
if (resultSet_ != null && resultSet_.resultSetHoldability_ != resultSetHoldability_ && sqlMode_ != isCall__) {
2045                throw new SqlException(agent_.logWriter_,
2046                    new ClientMessageId(SQLState.UNABLE_TO_OPEN_RS_WITH_REQUESTED_HOLDABILITY),
2047                    new Integer JavaDoc(resultSetHoldability_));
2048            }
2049
2050        // In the case of executing a call to a stored procedure.
2051
if (sqlMode_ == isCall__) {
2052            parseStorProcReturnedScrollableRowset();
2053            checkForStoredProcResultSetCount(executeType);
2054            // When there is no result sets back, we will commit immediately when autocommit is true.
2055
if (connection_.autoCommit_ && resultSet_ == null && resultSetList_ == null) {
2056                connection_.flowAutoCommit();
2057            }
2058        }
2059
2060        // The JDBC spec says that executeUpdate() should return 0
2061
// when no row count is returned.
2062
if (executeType == executeUpdateMethod__ && updateCount_ < 0) {
2063            updateCount_ = 0;
2064        }
2065    }
2066
2067    void flowExecuteBatch(int[] updateCounts) throws SqlException, BatchUpdateException {
2068        SqlException chainBreaker = null;
2069        boolean isCallCataloguedBestGuess = true;
2070        agent_.beginBatchedWriteChain(this);
2071        for (int i = 0; i < batch_.size(); i++) {
2072            boolean flowSQL = true;
2073            String JavaDoc sql = (String JavaDoc) batch_.get(i);
2074            parseSqlAndSetSqlModes(sql);
2075            try {
2076                checkForInvalidBatchedSql(sql);
2077            } catch (SqlException e) {
2078                flowSQL = false;
2079            }
2080
2081            // if you have a length mismatch for a lob flow, then we need to return a -3
2082
// need to trap the exceptions coming back from writeExecuteImmediate and continue on with a -3
2083
// net will need to be able to reset the send buffer
2084
if (flowSQL) {
2085                if (section_ != null) {
2086                    section_.free();
2087                }
2088                if (sqlMode_ != isCall__) {
2089                    section_ =
2090                            agent_.sectionManager_.getDynamicSection(resultSetHoldability_);
2091                    writeExecuteImmediate(sql, section_);
2092                } else {
2093                    section_ = writeExecuteCall(sql, true);
2094                }
2095            }
2096        }
2097
2098        if (connection_.autoCommit_) {
2099            connection_.writeAutoCommit();
2100        }
2101
2102        agent_.flowBatch(this, batch_.size());
2103
2104        try {
2105            for (int i = 0; i < batch_.size(); i++) {
2106                agent_.setBatchedExceptionLabelIndex(i);
2107                SqlException invalidSQLCaughtByClient = null;
2108                String JavaDoc sql = (String JavaDoc) batch_.get(i);
2109                parseSqlAndSetSqlModes(sql);
2110                try {
2111                    checkForInvalidBatchedSql(sql);
2112                } catch (SqlException e) {
2113                    invalidSQLCaughtByClient = e;
2114                }
2115                if (invalidSQLCaughtByClient == null) {
2116                    updateCount_ = -1;
2117                    if (sqlMode_ != isCall__) {
2118                        readExecuteImmediateForBatch(sql);
2119                    } else {
2120                        if (isCallCataloguedBestGuess) {
2121                            readPrepare();
2122                        }
2123                        readExecuteCall();
2124                    }
2125                } else {
2126                    agent_.accumulateReadException(invalidSQLCaughtByClient);
2127                    updateCount_ = java.sql.Statement.EXECUTE_FAILED;
2128                    invalidSQLCaughtByClient = null;
2129                }
2130
2131                updateCounts[i] = updateCount_;
2132
2133                // DERBY doesn't return an update count for DDL statements, so we need to
2134
// remap our initial value of -1 (represents invalid update count) to a
2135
// valid update count of zero.
2136
if (updateCounts[i] == -1) {
2137                    updateCounts[i] = 0;
2138                }
2139            }
2140            agent_.disableBatchedExceptionTracking(); // to prvent the following readCommit() from getting a batch label
2141
if (connection_.autoCommit_) {
2142                connection_.readAutoCommit(); // this could throw a chainbreaker too
2143
}
2144        }
2145                // for chain-breaking exception only, all read() methods do their own accumulation
2146
// this catches the entire accumulated chain, we need to be careful not to
2147
// reaccumulate it on the agent since the batch labels will be overwritten if
2148
// batch exception tracking is enabled.
2149
catch (SqlException e) {
2150            chainBreaker = e;
2151            chainBreaker.setNextException(new SqlException(agent_.logWriter_,
2152                new ClientMessageId(SQLState.BATCH_CHAIN_BREAKING_EXCEPTION)));
2153        }
2154        // We need to clear the batch before any exception is thrown from agent_.endBatchedReadChain().
2155
batch_.clear();
2156        agent_.endBatchedReadChain(updateCounts, chainBreaker);
2157    }
2158
2159    private Section writeExecuteCall(String JavaDoc sql,
2160                                     boolean isBatch) throws SqlException {
2161        Section newSection = null;
2162
2163        newSection = agent_.sectionManager_.getDynamicSection(resultSetHoldability_);
2164        // this code is beneficial only if there is literal in the sql call statement
2165
writePrepare(sql, newSection);
2166        writeExecuteCall(false, // no out parameters, outputExpected = false
2167
null, // sql is prepared, procedureName = null
2168
newSection,
2169                fetchSize_,
2170                isBatch, // do not suppress ResultSets for regular CALLs
2171
resultSetType_,
2172                null, // no parameters, parameterMetaData = null
2173
null); // no parameters, inputs = null
2174

2175        return newSection;
2176    }
2177
2178    //------------------material layer event callbacks follow---------------------
2179
// All callbacks are client-side only operations
2180

2181    public void listenToUnitOfWork() {
2182    } // do nothing for now.
2183

2184    public void completeLocalCommit(java.util.Iterator JavaDoc listenerIterator) {
2185    } // do nothing for now.
2186

2187    public void completeLocalRollback(java.util.Iterator JavaDoc listenerIterator) {
2188    } // do nothing for now.
2189

2190    // This method will not work if e is chained.
2191
// It is assumed that e is a single warning and is not chained.
2192
public void accumulateWarning(SqlWarning e) {
2193        if (warnings_ == null) {
2194            warnings_ = e;
2195        } else {
2196            warnings_.setNextWarning(e);
2197        }
2198    }
2199
2200    private void markPrepared() {
2201        //openOnClient_ = true;
2202
openOnServer_ = true;
2203        listenToUnitOfWork();
2204    }
2205
2206    //-------------------------------helper methods-------------------------------
2207

2208    /**
2209     * Returns the name of the java.sql interface implemented by this class.
2210     * @return name of java.sql interface
2211     */

2212    protected String JavaDoc getJdbcStatementInterfaceName() {
2213        return "java.sql.Statement";
2214    }
2215
2216    // Should investigate if it can be optimized.. if we can avoid this parsing..
2217
//
2218
void parseSqlAndSetSqlModes(String JavaDoc sql) throws SqlException {
2219        String JavaDoc delims = "\t\n\r\f=? (";
2220        java.util.StringTokenizer JavaDoc tokenizer = null;
2221        String JavaDoc firstToken = null;
2222
2223        // See if the statement starts with a comment; if so, move
2224
// past the comment and get the first token of the actual
2225
// statement to be executed. Note: must use "startsWith"
2226
// when looking for the comment delimiters instead of
2227
// "equals" because there may not be whitespace between the
2228
// the delimiter and the comment itself, ex "--my comment".
2229
if (sql.trim().startsWith("--")) {
2230
2231            // Read each line of the statement until we find a
2232
// line that is NOT a comment.
2233
int lastEndLine = -1;
2234            String JavaDoc endline = "\n\r\f";
2235            tokenizer = new java.util.StringTokenizer JavaDoc(sql, endline, true);
2236            while (tokenizer.hasMoreTokens()) {
2237                firstToken = tokenizer.nextToken();
2238                if (endline.indexOf(firstToken) != -1)
2239                // this is some sort of newline ("\n", "\r", or "\f").
2240
lastEndLine = sql.indexOf(firstToken, lastEndLine+1);
2241                else if (!firstToken.trim().startsWith("--"))
2242                    break;
2243            }
2244
2245            if (firstToken.startsWith("--")) {
2246            // entire statement was just one or more comments; pass it as
2247
// a query to the server and let the server deal with it.
2248
sqlMode_ = isQuery__;
2249                return;
2250            }
2251            else {
2252            // we have a non-comment line; get a tokenizer for the
2253
// statement beginning at the start of this line.
2254
tokenizer = new java.util.StringTokenizer JavaDoc(
2255                    sql.substring(lastEndLine+1), delims);
2256            }
2257
2258        }
2259        else {
2260        // there aren't any leading comments, so just get the first token
2261
// in the SQL statement.
2262
tokenizer = new java.util.StringTokenizer JavaDoc(sql, delims);
2263        }
2264
2265        if (!tokenizer.hasMoreTokens()) {
2266            throw new SqlException(agent_.logWriter_,
2267                new ClientMessageId(SQLState.NO_TOKENS_IN_SQL_TEXT), sql);
2268        }
2269
2270        sqlUpdateMode_ = 0;
2271        firstToken = tokenizer.nextToken();
2272
2273        if (firstToken.equalsIgnoreCase("select") || // captures <subselect> production
2274
firstToken.equalsIgnoreCase("values")) // captures <values-clause> production
2275
{
2276            sqlMode_ = isQuery__;
2277        } else if (firstToken.equalsIgnoreCase("call")) // captures CALL...and ?=CALL...
2278
{
2279            sqlMode_ = isCall__;
2280        } else {
2281            parseUpdateSql(firstToken);
2282        }
2283    }
2284
2285    private void parseUpdateSql(String JavaDoc firstToken) throws SqlException {
2286        sqlMode_ = isUpdate__;
2287        if (firstToken.equalsIgnoreCase("insert")) {
2288            sqlUpdateMode_ = isInsertSql__;
2289        }
2290        if (firstToken.equalsIgnoreCase("delete")) {
2291            sqlUpdateMode_ = isDeleteSql__;
2292        }
2293        if (firstToken.equalsIgnoreCase("update")) {
2294            sqlUpdateMode_ = isUpdateSql__;
2295        }
2296    }
2297
2298    // the sql is assumed to start with CALL... or ?=CALL...
2299
String JavaDoc getProcedureName(String JavaDoc sql) throws SqlException {
2300        java.util.StringTokenizer JavaDoc tokenizer = new java.util.StringTokenizer JavaDoc(sql, "\t\n\r\f= (?");
2301        if (!tokenizer.hasMoreTokens()) {
2302            throw new SqlException(agent_.logWriter_,
2303                new ClientMessageId(SQLState.NO_TOKENS_IN_SQL_TEXT), sql);
2304        }
2305        String JavaDoc firstToken = tokenizer.nextToken();
2306        if (!firstToken.equalsIgnoreCase("call")) {
2307            throw new SqlException(agent_.logWriter_,
2308                new ClientMessageId(SQLState.LANG_INVALID_CALL_STATEMENT));
2309        }
2310        if (!tokenizer.hasMoreTokens()) {
2311            throw new SqlException(agent_.logWriter_,
2312                new ClientMessageId(SQLState.LANG_INVALID_CALL_STATEMENT));
2313        }
2314        return tokenizer.nextToken();
2315    }
2316
2317    // Try to enforce the use of this method later.
2318
public static String JavaDoc upperCaseProcedureName(String JavaDoc procedureName) throws SqlException {
2319        // upper case the parts of a 3-part procedure name unless the part is in a double quotes
2320

2321        // Loop thru every character, if we're in double quotes just echo it,
2322
// if we're not in double quotes, upper case it.
2323
char[] charArray = null;
2324        if (procedureName.indexOf("\"") == -1) {
2325            return procedureName.toUpperCase();
2326        } else {
2327            charArray = procedureName.toCharArray();
2328            boolean inStringLiteral = false;
2329            for (int i = 0; i < charArray.length; i++) {
2330                if (charArray[i] == '"') {
2331                    inStringLiteral = !inStringLiteral;
2332                } else if (!inStringLiteral && charArray[i] != '.') {
2333                    charArray[i] = Character.toUpperCase(charArray[i]);
2334                }
2335            }
2336        }
2337        return new String JavaDoc(charArray);
2338    }
2339
2340    void checkForAppropriateSqlMode(int executeType, int sqlMode) throws SqlException {
2341        if (executeType == executeQueryMethod__ && sqlMode == isUpdate__) {
2342            throw new SqlException(agent_.logWriter_,
2343                new ClientMessageId(SQLState.CANT_USE_EXEC_QUERY_FOR_UPDATE));
2344        }
2345        if (executeType == executeUpdateMethod__ && sqlMode == isQuery__) {
2346            throw new SqlException(agent_.logWriter_,
2347                new ClientMessageId(SQLState.LANG_INVALID_CALL_TO_EXECUTE_UPDATE));
2348        }
2349    }
2350
2351    /**
2352     * Checks that the number of result sets returned by the statement
2353     * is consistent with the executed type. <code>executeQuery()</code>
2354     * should return exactly one result set and <code>executeUpdate()</code>
2355     * none. Raises an exception if the result set count does not match the
2356     * execute type.
2357     *
2358     * @param executeType one of <code>executeQueryMethod__</code>,
2359     * <code>executeUpdateMethod__</code> and <code>executeMethod__</code>
2360     * @exception SqlException if the number of result sets does not
2361     * match the execute type
2362     */

2363    private void checkResultSetCount(int executeType) throws SqlException {
2364        switch (executeType) {
2365        case executeQueryMethod__:
2366            // We'll just rely on finalizers to close the dangling result sets.
2367
if (resultSetList_ != null && resultSetList_.length > 1) {
2368                throw new
2369                    SqlException(agent_.logWriter_,
2370                                 new ClientMessageId(
2371                                    SQLState.MULTIPLE_RESULTS_ON_EXECUTE_QUERY),
2372                                 getJdbcStatementInterfaceName(),
2373                                 getJdbcStatementInterfaceName());
2374            }
2375            if (resultSet_ == null || resultSetList_.length == 0) {
2376                ClientMessageId messageId =
2377                    new ClientMessageId(
2378                                SQLState.USE_EXECUTE_UPDATE_WITH_NO_RESULTS);
2379                throw new SqlException(agent_.logWriter_, messageId,
2380                                       getJdbcStatementInterfaceName(),
2381                                       getJdbcStatementInterfaceName());
2382            }
2383            break;
2384        case executeUpdateMethod__:
2385            // We'll just rely on finalizers to close the dangling result sets.
2386
if (resultSet_ != null && resultSetList_.length > 0) {
2387                ClientMessageId messageId =
2388                    new ClientMessageId(
2389                        SQLState.LANG_INVALID_CALL_TO_EXECUTE_UPDATE);
2390                throw new SqlException(agent_.logWriter_, messageId);
2391            }
2392            break;
2393        }
2394    }
2395
2396    /**
2397     * Checks that a stored procedure returns the correct number of
2398     * result sets given its execute type. If the number is incorrect,
2399     * make sure the transaction is rolled back when auto commit is
2400     * enabled.
2401     *
2402     * @param executeType one of <code>executeQueryMethod__</code>,
2403     * <code>executeUpdateMethod__</code> and <code>executeMethod__</code>
2404     * @exception SqlException if the number of result sets does not
2405     * match the execute type
2406     * @see #checkResultSetCount(int)
2407     */

2408    protected final void checkForStoredProcResultSetCount(int executeType)
2409        throws SqlException
2410    {
2411        try {
2412            checkResultSetCount(executeType);
2413        } catch (SqlException se) {
2414            if (connection_.autoCommit_) {
2415                connection_.flowRollback();
2416            }
2417            throw se;
2418        }
2419    }
2420
2421    void checkForClosedStatement() throws SqlException {
2422        // For some odd reason, there was a JVM hotspot error with Sun's 1.4 JDK
2423
// when the code was written like this:
2424
// agent_checkForDeferredExceptions();
2425
// if (!openOnClient_)
2426
// throw new SqlException (agent_.logWriter_, "Invalid operation: statement closed");
2427
//
2428
if ( this.connection_ == null || this.connection_.isClosed() )
2429            throw new SqlException(agent_.logWriter_,
2430                new ClientMessageId(SQLState.NO_CURRENT_CONNECTION));
2431        
2432        if (!openOnClient_) {
2433            agent_.checkForDeferredExceptions();
2434            throw new SqlException(agent_.logWriter_,
2435                new ClientMessageId(SQLState.ALREADY_CLOSED), "Statement");
2436        } else {
2437            agent_.checkForDeferredExceptions();
2438        }
2439    }
2440
2441    // precondition: parseSqlAndSetSqlModes() must be called on the supplied sql string before invoking this method
2442
void checkForInvalidBatchedSql(String JavaDoc sql) throws SqlException {
2443        if (sql == null) {
2444            throw new SqlException(agent_.logWriter_,
2445                new ClientMessageId(SQLState.NULL_SQL_TEXT));
2446        }
2447
2448        if (sqlMode_ != isCall__
2449                && !(sqlMode_ == isUpdate__
2450                && (sqlUpdateMode_ == isInsertSql__
2451                || sqlUpdateMode_ == isDeleteSql__
2452                || sqlUpdateMode_ == isUpdateSql__
2453                || sqlUpdateMode_ == 0)))// For any undefined pass thru statement like drop create
2454
{
2455            throw new SqlException(agent_.logWriter_,
2456                new ClientMessageId(SQLState.LANG_INVALID_SQL_IN_BATCH), sql);
2457        }
2458    }
2459
2460
2461    // Two open result sets can not have the same cursor name.
2462
protected void checkForDuplicateCursorName() throws SqlException {
2463        if (cursorName_ != null && (connection_.clientCursorNameCache_.
2464                                    containsKey(cursorName_))) {
2465            throw new SqlException
2466                (agent_.logWriter_,
2467                 new ClientMessageId(SQLState.CURSOR_DUPLICATE_NAME),
2468                 cursorName_);
2469        }
2470    }
2471
2472
2473    // Set up information to be able to handle cursor names:
2474
// canned or user named (via setCursorName).
2475
protected void setupCursorNameCacheAndMappings() {
2476        if (cursorName_ != null) {
2477            // The user has set a cursor name for this statement.
2478
// This means we must subtitute the <users-cursor-name>
2479
// with the <canned-cursor-name> in the pass-thru sql
2480
// string "...where current of <canned-cursor-name>"
2481
// whenever the result set produced by this statement
2482
// is referenced in a positioned update/delete statement.
2483
agent_.sectionManager_.mapCursorNameToQuerySection
2484                (cursorName_, section_);
2485            section_.setClientCursorName(cursorName_);
2486            
2487            // Update cache to avoid duplicates of user set cursor name.
2488
connection_.clientCursorNameCache_.put(cursorName_,
2489                                                   cursorName_);
2490        } else {
2491        // canned cursor name
2492
agent_.sectionManager_.mapCursorNameToQuerySection
2493                (section_.getServerCursorName(), section_);
2494    }
2495
2496        // If client's cursor name is set, map the client's cursor name to the
2497
// result set, else map the server's cursor name to the result set.
2498
mapCursorNameToResultSet();
2499    }
2500
2501
2502    String JavaDoc[] extractCursorNameFromWhereCurrentOf(String JavaDoc sql) {
2503        String JavaDoc lowerSql = sql.toLowerCase();
2504        int currentIndex = lowerSql.lastIndexOf("current");
2505        if (currentIndex != -1) {
2506            int whereIndex = lowerSql.lastIndexOf("where");
2507            if (whereIndex != -1) {
2508                String JavaDoc[] whereCurrentOf = {"where", "current", "of"};
2509                java.util.StringTokenizer JavaDoc st = new java.util.StringTokenizer JavaDoc(sql.substring(whereIndex));
2510                while (st.hasMoreTokens()) {
2511                    if (st.nextToken().equalsIgnoreCase(whereCurrentOf[0]) &&
2512                            st.nextToken().equalsIgnoreCase(whereCurrentOf[1]) &&
2513                            st.nextToken().equalsIgnoreCase(whereCurrentOf[2])) {
2514                        String JavaDoc cursorName = st.nextToken();
2515                        String JavaDoc oldCursorName = cursorName;
2516                        int originalCursorNameLength = cursorName.length();
2517                        int index = sql.lastIndexOf(cursorName);
2518                        if (cursorName.charAt(0) == '\"' && cursorName.charAt(cursorName.length() - 1) == '\"') {
2519                            cursorName = cursorName.substring(1, cursorName.length() - 1);
2520                        } else {
2521                            cursorName = cursorName.toUpperCase();
2522                        }
2523                        // we cannot assume "where current of cursorName" is always the end of the sql string
2524
// with rowset cursors, it can be "where current of cursorName for row X of rowset"
2525
if (sql.length() > index + originalCursorNameLength) {
2526                            sql = sql.substring(0, index) + cursorName + sql.substring(index + oldCursorName.length(), sql.length());
2527                        } else {
2528                            sql = sql.substring(0, index) + cursorName;
2529                        }
2530                        return new String JavaDoc[]{cursorName, sql}; // delimited name, so just extract the name.
2531
}
2532                }
2533            }
2534        }
2535        return null;
2536    }
2537
2538    // Substitute the client cursor name in the SQL string with the server's cursor name.
2539
// Only called on positioned update statements.
2540
protected String JavaDoc substituteClientCursorNameWithServerCursorName(String JavaDoc sql,
2541                                                                    Section section) throws SqlException {
2542        String JavaDoc clientCursorName = section.getClientCursorName();
2543        int index = sql.lastIndexOf(clientCursorName);
2544        if (sql.length() > index + clientCursorName.length()) {
2545            return sql.substring(0, index) + section.getServerCursorNameForPositionedUpdate()
2546                    + sql.substring(index + clientCursorName.length(), sql.length());
2547        } else {
2548            return sql.substring(0, index) + section.getServerCursorNameForPositionedUpdate();
2549        }
2550    }
2551
2552    public ConnectionCallbackInterface getConnectionCallbackInterface() {
2553        return connection_;
2554    }
2555
2556    // This was being called only on positioned update statements. When working
2557
// on DERBY-210, it was found that result sets of all statements (not just
2558
// positioned update statements) get added to the table. So, this is called
2559
// for all statements. Otherwise, this will cause memory leaks when statements
2560
// are not explicitly closed in the application.
2561
void resetCursorNameAndRemoveFromWhereCurrentOfMappings() {
2562        // Remove client/server cursorName -> ResultSet mapping from the hashtable.
2563
// If Statement.close() is called before ResultSet.close(), then statement_.section is null.
2564
if (section_ != null) {
2565            agent_.sectionManager_.removeCursorNameToResultSetMapping(cursorName_,
2566                    section_.getServerCursorNameForPositionedUpdate());
2567
2568            // remove resultset mapping for other cursors (other than positioned
2569
// update statements) - DERBY-210
2570
agent_.sectionManager_.removeCursorNameToResultSetMapping(cursorName_,
2571                    section_.getServerCursorName());
2572
2573            // Remove client and server cursorName -> QuerySection mapping from the hashtable
2574
// if one exists
2575
agent_.sectionManager_.removeCursorNameToQuerySectionMapping(cursorName_,
2576                    section_.getServerCursorNameForPositionedUpdate());
2577        }
2578
2579        // client cursor name will be set to null when it is removed from the
2580
// clientCursorNameCache.
2581
//cursorName_ = null;
2582
}
2583
2584    void mapCursorNameToResultSet() {
2585        if (cursorName_ != null) {
2586            agent_.sectionManager_.mapCursorNameToResultSet(cursorName_, resultSet_);
2587        } else {
2588            agent_.sectionManager_.mapCursorNameToResultSet(section_.getServerCursorName(), resultSet_);
2589        }
2590    }
2591
2592    void parseStorProcReturnedScrollableRowset() throws SqlException {
2593        if (resultSetList_ != null) {
2594            for (int i = 0; i < resultSetList_.length; i++) {
2595                if (resultSetList_[i].scrollable_ && resultSetList_[i].cursor_.dataBufferHasUnprocessedData()) {
2596                    resultSetList_[i].parseScrollableRowset();
2597                    if (resultSetList_[i].rowCountIsUnknown()) {
2598                        resultSetList_[i].getRowCount();
2599                    }
2600                }
2601            }
2602        }
2603    }
2604
2605    String JavaDoc escape(String JavaDoc sql) throws SqlException {
2606        String JavaDoc nativeSQL = sql;
2607
2608        nativeSQL = connection_.nativeSQLX(sql);
2609        return nativeSQL;
2610    }
2611
2612    // Called by statement constructor only for jdbc 2 statements with scroll attributes.
2613
// This method is not in the StatementRequest class because it is not building into
2614
// the request buffer directly, it is building into a cache to be written into the request
2615
// buffer at prepare-time.
2616
String JavaDoc cacheCursorAttributesToSendOnPrepare() throws SqlException {
2617        StringBuffer JavaDoc cursorAttributes = new StringBuffer JavaDoc();
2618        if (resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_SENSITIVE) {
2619            // append "SENSITIVE STATIC SCROLL"
2620
cursorAttributes.append(Configuration.cursorAttribute_SensitiveStatic);
2621        } else if (resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE) {
2622            // if "insensitve, updatable" cursor is asked, then server sends back error
2623
// and we will pass that error back to the user.
2624
// we will not try to catch any errors/warnings here.
2625
// append "INSENSITIVE SCROLL"
2626
cursorAttributes.append(Configuration.cursorAttribute_Insensitive);
2627        }
2628
2629        // Default is read-only, forward-only. No attribute needs to be sent.
2630
if (resultSetConcurrency_ == java.sql.ResultSet.CONCUR_UPDATABLE) {
2631            cursorAttributes.append(Configuration.cursorAttribute_ForUpdate); // FOR UPDATE
2632
}
2633
2634        if ((resultSetHoldability_ == java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT)) {
2635            cursorAttributes.append(Configuration.cursorAttribute_WithHold); // WITH HOLD
2636
}
2637
2638        return
2639                (cursorAttributes == null || cursorAttributes.toString().equals(""))
2640                ? null
2641                : cursorAttributes.toString();
2642    }
2643
2644    protected String JavaDoc constructSelectFromInsertSQL(String JavaDoc sql) {
2645        String JavaDoc temp = "select ";
2646        int numOfColumns = generatedKeysColumnNames_.length;
2647
2648        for (int i = 0; i < numOfColumns; i++) {
2649            temp += generatedKeysColumnNames_[i];
2650            if ((i + 1) < numOfColumns) {
2651                temp += ",";
2652            }
2653        }
2654        temp += (" from final table (" + sql + ")");
2655        return temp;
2656    }
2657
2658    void getPreparedStatementForAutoGeneratedKeys() throws SqlException {
2659        if (preparedStatementForAutoGeneratedKeys_ == null) {
2660            String JavaDoc s = "select IDENTITY_VAL_LOCAL() from SYSIBM.SYSDUMMY1";
2661            preparedStatementForAutoGeneratedKeys_ =
2662                    connection_.newPreparedStatement_(s,
2663                            java.sql.ResultSet.TYPE_FORWARD_ONLY,
2664                            java.sql.ResultSet.CONCUR_READ_ONLY,
2665                            java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT,
2666                            java.sql.Statement.NO_GENERATED_KEYS,
2667                            null);
2668            // need a special case for Derby, since the attribute has to go through the wire.
2669
// This same special casing for Derby is already in place in method PS.cacheCursorAttributesToSendOnPrepare() as called by prepareStatementX().
2670
// We need to figure how some way to get code reuse here, ie. to consolidate to just one special casing rather than two?
2671
// Maybe just call prepareStatementX() or use some special purpose prepare method like the ones in Connection.
2672
// Something more abstract so that we don't have to special case the WITH HOLD thing twice.
2673
StringBuffer JavaDoc cursorAttributes = new StringBuffer JavaDoc();
2674            cursorAttributes.append(Configuration.cursorAttribute_WithHold);
2675            preparedStatementForAutoGeneratedKeys_.cursorAttributesToSendOnPrepare_ = cursorAttributes.toString();
2676        }
2677    }
2678
2679    void prepareAutoGeneratedKeysStatement() throws SqlException {
2680        getPreparedStatementForAutoGeneratedKeys();
2681        if (!preparedStatementForAutoGeneratedKeys_.openOnServer_) {
2682            preparedStatementForAutoGeneratedKeys_.materialPreparedStatement_.writePrepareDescribeOutput_(preparedStatementForAutoGeneratedKeys_.sql_,
2683                    preparedStatementForAutoGeneratedKeys_.section_);
2684        }
2685    }
2686
2687    void readPrepareAutoGeneratedKeysStatement() throws SqlException {
2688        if (!preparedStatementForAutoGeneratedKeys_.openOnServer_) {
2689            preparedStatementForAutoGeneratedKeys_.materialPreparedStatement_.readPrepareDescribeOutput_();
2690        }
2691    }
2692
2693    void checkAutoGeneratedKeysParameters() throws SqlException {
2694        if (autoGeneratedKeys_ != java.sql.Statement.NO_GENERATED_KEYS &&
2695                autoGeneratedKeys_ != java.sql.Statement.RETURN_GENERATED_KEYS) {
2696            throw new SqlException(agent_.logWriter_,
2697                new ClientMessageId(SQLState.INVALID_API_PARAMETER),
2698                new Integer JavaDoc(autoGeneratedKeys_), "autoGeneratedKeys",
2699                "Statement.execute()/executeQuery()");
2700        }
2701
2702        if (generatedKeysColumnNames_ != null) {
2703            throw new SqlException(agent_.logWriter_,
2704                new ClientMessageId(SQLState.NOT_IMPLEMENTED),
2705                "Connection.prepareStatement(String sql, String[] columnNames)");
2706        }
2707    }
2708
2709    public ColumnMetaData getGuessedResultSetMetaData() {
2710        return resultSetMetaData_;
2711    }
2712
2713    public boolean isQueryMode() {
2714        if (this.sqlMode_ == this.isQuery__) {
2715            return true;
2716        } else {
2717            return false;
2718        }
2719    }
2720
2721    protected void removeClientCursorNameFromCache() {
2722        if (cursorName_ != null &&
2723                connection_.clientCursorNameCache_.containsKey(cursorName_)) {
2724            connection_.clientCursorNameCache_.remove(cursorName_);
2725        }
2726    }
2727    
2728    /**
2729     * Convenience method for resultSetCommitting(ResultSet, boolean)
2730     *
2731     * @see Statement#resultSetCommitting(ResultSet, boolean)
2732     * @param closingRS The ResultSet to be closed
2733     * @throws SqlException
2734     */

2735    public void resultSetCommitting(ResultSet closingRS) throws SqlException {
2736        resultSetCommitting(closingRS, false);
2737    }
2738    
2739    /**
2740     * Method that checks to see if any other ResultSets are open. If not
2741     * proceeds with the autocommit.
2742     *
2743     * @param closingRS The ResultSet to be closed
2744     * @param writeChain A Boolean indicating whether this method
2745     * is part of a chain of write from client to Server
2746     * @throws SqlException
2747     */

2748    public boolean resultSetCommitting(ResultSet closingRS, boolean writeChain) throws SqlException {
2749
2750        // If the Connection is not in auto commit then this statement completion
2751
// cannot cause a commit.
2752
if (!connection_.autoCommit_ || closingRS.autoCommitted_)
2753            return false;
2754
2755        // If we have multiple results, see if there is another result set open.
2756
// If so, then no commit. The last result set to close will close the statement.
2757
if (resultSetList_ != null) {
2758            for (int i = 0; i < resultSetList_.length; i++) {
2759                ResultSet crs = resultSetList_[i];
2760                if (crs == null)
2761                    continue;
2762                if (!crs.openOnClient_)
2763                    continue;
2764                if (crs == closingRS)
2765                    continue;
2766
2767                // at least one still open so no commit now.
2768
return false;
2769            }
2770        }
2771        
2772        if (writeChain) {
2773            connection_.writeAutoCommit();
2774            return true;
2775        } else {
2776            if (connection_.flowAutoCommit()) {
2777                markAutoCommitted();
2778                return true;
2779            }
2780            return false;
2781        }
2782    }
2783    
2784    /**
2785     * Mark all ResultSets associated with this statement as auto-committed.
2786     */

2787    public void markAutoCommitted() {
2788        if (resultSetList_ != null) {
2789            for (int i = 0; i < resultSetList_.length; i++)
2790                if (resultSetList_[i] != null) {
2791                    resultSetList_[i].markAutoCommitted();
2792                }
2793        } else if (resultSet_ != null) {
2794            resultSet_.markAutoCommitted();
2795        }
2796    }
2797    
2798    protected SQLException JavaDoc jdbc3FeatureNotSupported(boolean checkStatement)
2799        throws SQLException JavaDoc
2800    {
2801        try
2802        {
2803            if ( checkStatement )
2804                checkForClosedStatement();
2805            
2806            throw new SqlException(agent_.logWriter_,
2807                new ClientMessageId(SQLState.JDBC_METHOD_NOT_IMPLEMENTED));
2808        }
2809        catch ( SqlException se )
2810        {
2811            throw se.getSQLException();
2812        }
2813    }
2814    
2815    protected SQLException JavaDoc jdbc3FeatureNotSupported() throws SQLException JavaDoc
2816    {
2817        return jdbc3FeatureNotSupported(true);
2818    }
2819}
2820
Popular Tags