KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > driver > Statement


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Copyright (C) 2005-2006 Continuent, Inc.
7  * Contact: sequoia@continuent.org
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): Vadim Kassin, Jean-Bernard van Zuylen.
23  */

24
25 package org.continuent.sequoia.driver;
26
27 import java.sql.BatchUpdateException JavaDoc;
28 import java.sql.ResultSet JavaDoc;
29 import java.sql.ResultSetMetaData JavaDoc;
30 import java.sql.SQLException JavaDoc;
31 import java.sql.SQLWarning JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.LinkedList JavaDoc;
35 import java.util.Vector JavaDoc;
36 import java.util.regex.Matcher JavaDoc;
37
38 import org.continuent.sequoia.common.exceptions.NotImplementedException;
39 import org.continuent.sequoia.common.protocol.Field;
40 import org.continuent.sequoia.common.sql.Request;
41 import org.continuent.sequoia.common.sql.RequestWithResultSetParameters;
42
43 /**
44  * A <code>Statement</code> object is used for executing a static SQL
45  * statement and obtaining the results produced by it.
46  * <p>
47  * Only one <code>ResultSet</code> per <code>Statement</code> can be open at
48  * any point in time. Therefore, if the reading of one <code>ResultSet</code>
49  * is interleaved with the reading of another, each must have been generated by
50  * different <code>Statements</code>. All <code>Statements</code> execute
51  * methods implicitly close a statement's current <code>ResultSet</code> if an
52  * open one exists.
53  *
54  * @see java.sql.Statement
55  * @see DriverResultSet
56  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
57  * @author <a HREF="mailto:vadim@kase.kz">Vadim Kassin </a>
58  * @author <a HREF="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
59  * </a>
60  * @version 1.0
61  */

62 public class Statement implements java.sql.Statement JavaDoc
63 {
64   /** The Driver used to create connections */
65   protected Driver driver;
66
67   /** The connection that created us */
68   protected Connection connection = null;
69
70   /** Vector for batch commands */
71   protected Vector JavaDoc batch = null;
72
73   /** The warnings chain - package private */
74   SQLWarning JavaDoc warnings = null;
75
76   /** The current result for a read request */
77   protected ResultSet JavaDoc result = null;
78
79   /** List of updateCount/ResultSet */
80   protected LinkedList JavaDoc resultList = null;
81   protected Iterator JavaDoc resultListIterator = null;
82
83   /** The update count for a write request */
84   protected int updateCount = -1;
85
86   /** Query timeout in seconds (0 means no timeout) */
87   protected int timeout = 0;
88
89   /** Default ResultSet fetch size */
90   private int fetchSize = 0;
91   /** Cursor name used jointly with fetch size */
92   private String JavaDoc cursorName;
93
94   /** Type of the ResultSet defaults to TYPE_FORWARD_ONLY */
95   private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
96
97   /** ResultSet Concurrency defaults to CONCUR_READ_ONLY */
98   private int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
99
100   /** Maximum field size (unused) */
101   private int maxFieldSize = 0;
102
103   /** Maximum number of rows */
104   private int maxRows = 0;
105
106   /**
107    * Direction for fetching rows from ResultSet (note that this hint is
108    * currently ignored
109    */

110   private int fetchDirection = ResultSet.FETCH_FORWARD;
111
112   /**
113    * Should the driver to escape processing before sending to the DB?
114    */

115   protected boolean escapeProcessing = true;
116
117   /** Auto generated keys */
118   protected ResultSet JavaDoc generatedKeys = null;
119   protected int generatedKeysFlag = java.sql.Statement.NO_GENERATED_KEYS;
120
121   /**
122    * Creates a new <code>Statement</code> instance.
123    *
124    * @param c the <code>Connection</code> that created us
125    * @param driver tje <code>Driver</code> used to create connections
126    */

127   Statement(Connection c, Driver driver)
128   {
129     connection = c;
130     this.driver = driver;
131   }
132
133   /**
134    * Adds sql to the current list of commands.
135    *
136    * @param sql an SQL statement that returns an update count (INSERT or UPDATE)
137    * @exception SQLException if an error occurs
138    */

139   public synchronized void addBatch(String JavaDoc sql) throws SQLException JavaDoc
140   {
141     if (batch == null)
142       batch = new Vector JavaDoc();
143     batch.addElement(sql.trim());
144   }
145
146   /**
147    * Could be use by one thread to cancel a statement that is being executed by
148    * another thread. We don't support that for instance.
149    *
150    * @exception SQLException if an error occurs
151    */

152   public void cancel() throws SQLException JavaDoc
153   {
154     throw new NotImplementedException("cancel()");
155   }
156
157   /**
158    * Empties the current list of commands.
159    *
160    * @exception SQLException if an error occurs
161    */

162   public void clearBatch() throws SQLException JavaDoc
163   {
164     if (batch != null)
165       batch.removeAllElements();
166   }
167
168   /**
169    * After this call, <code>getWarnings</code> returns <code>null</code>
170    * until a new warning is reported for this <code>Statement</code>.
171    *
172    * @exception SQLException if a database access error occurs (why?)
173    */

174   public void clearWarnings() throws SQLException JavaDoc
175   {
176     warnings = null;
177   }
178
179   /**
180    * Utility to add warnings to a given warning chain.
181    *
182    * @param addMe (in) warnings to be added
183    * @param toThis (in/out) reference chain on which to add addMe. If null, will
184    * be equal to addMe after the function returns
185    */

186   protected void addWarningTo(SQLWarning JavaDoc addMe, SQLWarning JavaDoc toThis)
187   {
188     if (toThis != null)
189       toThis.setNextWarning(warnings);
190     else
191       toThis = warnings;
192   }
193
194   /**
195    * Execute a batch of commands
196    *
197    * @return an array containing update count that corresponding to the commands
198    * that executed successfully
199    * @exception BatchUpdateException if an error occurs on one statement (the
200    * number of updated rows for the successfully executed
201    * statements can be found in
202    * BatchUpdateException.getUpdateCounts())
203    */

204   public int[] executeBatch() throws BatchUpdateException JavaDoc
205   {
206     if (batch == null || batch.isEmpty())
207       return new int[0];
208
209     ArrayList JavaDoc generatedKeysData = null;
210     Field generatedKeysField = null;
211     if (connection.isAlwaysGettingGeneratedKeys())
212       generatedKeysData = new ArrayList JavaDoc();
213
214     int size = batch.size();
215     int[] batchResult = new int[size];
216     int i = 0;
217     // must keep warning in a separate place otherwise they will be erased at
218
// each call to executeUpdate()
219
SQLWarning JavaDoc allWarnings = null;
220     try
221     {
222       for (i = 0; i < size; i++)
223       {
224         batchResult[i] = this.executeUpdate((String JavaDoc) batch.elementAt(i));
225         if (warnings != null)
226           addWarningTo(warnings, allWarnings);
227         if (connection.isAlwaysGettingGeneratedKeys())
228         {
229           if (generatedKeys != null)
230           {
231             while (generatedKeys.next())
232             {
233               generatedKeysData.add(generatedKeys.getObject(1));
234               if (generatedKeysField == null)
235               {
236                 ResultSetMetaData metaData = generatedKeys.getMetaData();
237                 generatedKeysField = new Field(metaData.getTableName(1),
238                     metaData.getColumnName(1),
239                     metaData.getColumnDisplaySize(1),
240                     metaData.getColumnType(1), metaData.getColumnTypeName(1),
241                     metaData.getColumnClassName(1));
242               }
243             }
244           }
245         }
246       }
247       // make one chain with all generated warnings
248
warnings = allWarnings;
249       generatedKeys = new DriverResultSet(connection, generatedKeysData,
250           generatedKeysField);
251       return batchResult;
252     }
253     catch (SQLException JavaDoc e)
254     {
255       String JavaDoc message = "Batch failed for request " + i + ": "
256           + batch.elementAt(i) + " (" + e + ")";
257
258       int[] updateCounts = new int[i];
259       System.arraycopy(batchResult, 0, updateCounts, 0, i);
260
261       throw new BatchUpdateException JavaDoc(message, updateCounts);
262     }
263     finally
264     {
265       batch.removeAllElements();
266     }
267   }
268
269   /**
270    * In many cases, it is desirable to immediately release a Statement's
271    * database and JDBC resources instead of waiting for this to happen when it
272    * is automatically closed. The close method provides this immediate release.
273    * <p>
274    * <B>Note: </B> A Statement is automatically closed when it is garbage
275    * collected. When a Statement is closed, its current ResultSet, if one
276    * exists, is also closed.
277    *
278    * @exception SQLException if a database access error occurs (why?)
279    */

280   public void close() throws SQLException JavaDoc
281   {
282     // Force the ResultSet to close
283
if (result != null)
284       try
285       {
286         result.close();
287       }
288       catch (SQLException JavaDoc ignore)
289       {
290       }
291
292     // Disasociate it from us (For Garbage Collection)
293
result = null;
294     connection = null;
295   }
296
297   /**
298    * Check if the statement is closed and cleanup the last results if any
299    * (update count is reset and last result is closed).
300    *
301    * @throws SQLException if the Statement is closed.
302    */

303   private void checkIfClosedAndCleanupLastResult() throws SQLException JavaDoc
304   {
305     if (isClosed())
306       throw new SQLException JavaDoc("Unable to execute query on a closed statement");
307
308     updateCount = -1; // invalidate the last write result
309
if (result != null)
310     { // Discard the previous result
311
try
312       {
313         result.close();
314       }
315       catch (Exception JavaDoc ignore)
316       {
317       }
318       result = null;
319     }
320     if (generatedKeys != null)
321     { // Discard the previous generated keys
322
try
323       {
324         generatedKeys.close();
325       }
326       catch (Exception JavaDoc ignore)
327       {
328       }
329       generatedKeys = null;
330     }
331     resultList = null;
332     resultListIterator = null;
333     clearWarnings();
334   }
335
336   /**
337    * Returns true if the given SQL query can be mapped to a JDBC call. This is
338    * the case for example of BEGIN, COMMIT or ROLLBACK that can be mapped to the
339    * corresponding JDBC calls.
340    *
341    * @param sqlQuery the SQL statement to try to map
342    * @return true if the SQL has been mapped to a JDBC call
343    */

344   private boolean sqlHasBeenMappedToJDBCCall(String JavaDoc sqlQuery)
345       throws SQLException JavaDoc
346   {
347     final JDBCRegExp jdbcRegExp = driver.getJDBCRegExp();
348     if (jdbcRegExp.getBeginPattern().matcher(sqlQuery).matches())
349     {
350       connection.setAutoCommit(false);
351       return true;
352     }
353     if (jdbcRegExp.getCommitPattern().matcher(sqlQuery).matches())
354     {
355       connection.commit();
356       return true;
357     }
358     Matcher JavaDoc m = jdbcRegExp.getRollbackToSavepointPattern().matcher(sqlQuery);
359     if (m.matches())
360     {
361       // Extract the savepoint name after the pattern
362
connection.rollback(new Savepoint(sqlQuery.substring(m.end(),
363           sqlQuery.length()).trim()));
364       return true;
365     }
366     m = jdbcRegExp.getReleaseSavepointPattern().matcher(sqlQuery);
367     if (m.matches())
368     {
369       // Extract the savepoint name after the pattern
370
connection.releaseSavepoint(new Savepoint(sqlQuery.substring(m.end(),
371           sqlQuery.length()).trim()));
372       return true;
373     }
374     if (jdbcRegExp.getRollbackPattern().matcher(sqlQuery).matches())
375     {
376       connection.rollback();
377       return true;
378     }
379     if (jdbcRegExp.getSetReadOnlyTransactionPattern().matcher(sqlQuery)
380         .matches())
381     {
382       connection.setReadOnly(true);
383       return true;
384     }
385     m = jdbcRegExp.getSetSavepointPattern().matcher(sqlQuery);
386     if (m.matches())
387     {
388       // Extract the savepoint name after the pattern
389
connection.setSavepoint(sqlQuery.substring(m.end(), sqlQuery.length())
390           .trim());
391       return true;
392     }
393     m = jdbcRegExp.getSetAutocommit1Pattern().matcher(sqlQuery);
394     if (m.matches())
395     {
396       connection.setAutoCommit(true);
397       return true;
398     }
399     m = jdbcRegExp.getSetIsolationLevelPattern().matcher(sqlQuery);
400     if (m.matches())
401     {
402       String JavaDoc isolationLevel = sqlQuery.substring(m.end(), sqlQuery.length())
403           .toLowerCase();
404       if (isolationLevel.startsWith("read commited"))
405       {
406         connection
407             .setTransactionIsolation(java.sql.Connection.TRANSACTION_READ_COMMITTED);
408         return true;
409       }
410       if (isolationLevel.startsWith("read uncommited"))
411       {
412         connection
413             .setTransactionIsolation(java.sql.Connection.TRANSACTION_READ_UNCOMMITTED);
414         return true;
415       }
416       if (isolationLevel.startsWith("repeatable read"))
417       {
418         connection
419             .setTransactionIsolation(java.sql.Connection.TRANSACTION_REPEATABLE_READ);
420         return true;
421       }
422       if (isolationLevel.startsWith("serializable"))
423       {
424         connection
425             .setTransactionIsolation(java.sql.Connection.TRANSACTION_SERIALIZABLE);
426
427         return true;
428       }
429     }
430     return false;
431   }
432
433   /**
434    * Execute a SQL statement that may return multiple results.
435    *
436    * @param sql any SQL statement
437    * @return true if the result is a ResultSet or false if it is an integer
438    * @exception SQLException if an error occurs
439    */

440   public boolean execute(String JavaDoc sql) throws SQLException JavaDoc
441   {
442     if (connection.isAlwaysGettingGeneratedKeys()
443         && sql.toLowerCase().trim().startsWith("insert"))
444       return execute(sql, RETURN_GENERATED_KEYS);
445     return execute(sql.trim(), (String JavaDoc) null);
446   }
447
448   /**
449    * Execute a SQL statement that returns a single ResultSet
450    *
451    * @param sqlSkeleton the SQL request squeleton or null
452    * @param parameters PreparedStaement parameters
453    * @return a ResulSet that contains the data produced by the query
454    * @throws SQLException if a database access error occurs or if this statement
455    * is closed
456    */

457   protected boolean execute(String JavaDoc sqlSkeleton, String JavaDoc parameters)
458       throws SQLException JavaDoc
459   {
460     checkIfClosedAndCleanupLastResult();
461
462     if (sqlHasBeenMappedToJDBCCall(sqlSkeleton))
463       return false;
464
465     RequestWithResultSetParameters request = new RequestWithResultSetParameters(
466         sqlSkeleton, parameters, escapeProcessing, timeout);
467     setReadRequestParameters(request);
468     ResultAndWarnings resultAndWarns = connection.statementExecute(request);
469     this.warnings = resultAndWarns.getStatementWarnings();
470     resultList = (LinkedList JavaDoc) resultAndWarns.getResultList();
471     resultListIterator = resultList.iterator();
472     generatedKeys = new DriverResultSet(this.connection, true);
473     return getMoreResults();
474   }
475
476   /**
477    * Execute a SQL statement that returns a single ResultSet
478    *
479    * @param sql typically a static SQL <code>SELECT</code> statement
480    * @return a ResulSet that contains the data produced by the query
481    * @exception SQLException if a database access error occurs
482    */

483   public java.sql.ResultSet JavaDoc executeQuery(String JavaDoc sql) throws SQLException JavaDoc
484   {
485     return executeQuery(sql.trim(), null);
486   }
487
488   /**
489    * Execute a SQL statement that returns a single ResultSet
490    *
491    * @param sqlSkeleton the SQL request squeleton or null
492    * @param parameters PreparedStaement parameters
493    * @return a ResulSet that contains the data produced by the query
494    * @exception SQLException if a database access error occurs or if this
495    * statement is closed
496    */

497   protected java.sql.ResultSet JavaDoc executeQuery(String JavaDoc sqlSkeleton,
498       String JavaDoc parameters) throws SQLException JavaDoc
499   {
500     checkIfClosedAndCleanupLastResult();
501
502     if (sqlHasBeenMappedToJDBCCall(sqlSkeleton))
503       // In theory executeQuery() is not allowed to return null,
504
// but after all we are here catering for some user's mistake in the
505
// first place (i.e., committing using executeQuery()).
506
// We can hardly imagine he will go as far as _using_ this resultset!
507
return null;
508
509     RequestWithResultSetParameters request = new RequestWithResultSetParameters(
510         sqlSkeleton, parameters, escapeProcessing, timeout);
511     setReadRequestParameters(request);
512     DriverResultSet drs = connection.statementExecuteQuery(request);
513     drs.setStatement(this);
514     this.warnings = drs.getStatementWarnings();
515     this.result = drs;
516
517     return result;
518   }
519
520   protected void setReadRequestParameters(RequestWithResultSetParameters request)
521   {
522     request.setMaxRows(maxRows);
523     request.setFetchSize(fetchSize);
524     request.setCursorName(cursorName);
525   }
526
527   /**
528    * Execute a SQL INSERT, UPDATE or DELETE statement. In addition SQL
529    * statements that return nothing such as SQL DDL statements can be executed
530    *
531    * @param sql a SQL statement
532    * @return either a row count, or 0 for SQL commands
533    * @exception SQLException if a database access error occurs
534    */

535   public int executeUpdate(String JavaDoc sql) throws SQLException JavaDoc
536   {
537     if (connection.isAlwaysGettingGeneratedKeys())
538       generatedKeysFlag = RETURN_GENERATED_KEYS;
539     return executeUpdateWithSkeleton(sql.trim(), null);
540   }
541
542   /**
543    * Execute a SQL INSERT, UPDATE or DELETE statement. In addition SQL
544    * statements that return nothing such as SQL DDL statements can be executed
545    *
546    * @param sqlSkeleton the SQL request squeleton or null
547    * @param parameters PreparedStaement parameters
548    * @return either a row count, or 0 for SQL commands
549    * @exception SQLException if a database access error occurs or if this
550    * statement is closed
551    */

552   protected int executeUpdateWithSkeleton(String JavaDoc sqlSkeleton, String JavaDoc parameters)
553       throws SQLException JavaDoc
554   {
555     checkIfClosedAndCleanupLastResult();
556
557     if (sqlHasBeenMappedToJDBCCall(sqlSkeleton))
558       return 0;
559
560     Request request = new Request(sqlSkeleton, parameters, escapeProcessing,
561         timeout);
562
563     if (generatedKeysFlag == java.sql.Statement.RETURN_GENERATED_KEYS)
564     { // Get the auto generated key back
565
DriverGeneratedKeysResult answer = connection
566           .statementExecuteUpdateWithKeys(request);
567       generatedKeys = answer.getDriverResultSet();
568       updateCount = answer.getUpdateCount();
569       warnings = answer.getWarnings();
570       return answer.getUpdateCount();
571     }
572     else
573     { // No generated keys
574
ResultAndWarnings resultAndWarns = connection
575           .statementExecuteUpdate(request);
576       this.warnings = resultAndWarns.getStatementWarnings();
577       updateCount = resultAndWarns.getUpdateCount();
578       generatedKeys = new DriverResultSet(this.connection, true);
579       return updateCount;
580     }
581   }
582
583   /**
584    * Retrieve the connection that created this Statement object
585    *
586    * @return a <code>java.sql.Connection</code> object
587    * @exception SQLException never
588    */

589   public java.sql.Connection JavaDoc getConnection() throws SQLException JavaDoc
590   {
591     return connection;
592   }
593
594   /**
595    * @see java.sql.Statement#getFetchDirection()
596    */

597   public int getFetchDirection() throws SQLException JavaDoc
598   {
599     return fetchDirection;
600   }
601
602   /**
603    * @see java.sql.Statement#getFetchSize()
604    */

605   public int getFetchSize() throws SQLException JavaDoc
606   {
607     return fetchSize;
608   }
609
610   /**
611    * The maxFieldSize limit (in bytes) is the maximum amount of data returned
612    * for any column value; it only applies to <code>BINARY</code>,
613    * <code>VARBINARY</code>,<code>LONGVARBINARY</code>,<code>CHAR</code>,
614    * <code>VARCHAR</code> and <code>LONGVARCHAR</code> columns. If the limit
615    * is exceeded, the excess data is silently discarded.
616    * <p>
617    * <b>Note: </b> We don't do anything with this value yet.
618    *
619    * @return the current max column size limit; zero means unlimited
620    * @exception SQLException if a database access error occurs
621    */

622   public int getMaxFieldSize() throws SQLException JavaDoc
623   {
624     return maxFieldSize;
625   }
626
627   /**
628    * The maxRows limit is set to limit the number of rows that any
629    * <code>ResultSet</code> can contain. If the limit is exceeded, the excess
630    * rows are silently dropped.
631    *
632    * @return the current maximum row limit; zero means unlimited
633    * @exception SQLException if a database access error occurs
634    */

635   public int getMaxRows() throws SQLException JavaDoc
636   {
637     return maxRows;
638   }
639
640   /**
641    * Return the true if next available result is a ResultSet or false it this is
642    * an update count. If the result is false and getUpdateCount() returns -1
643    * then there is no more result
644    * <p>
645    * Any open ResultSet is implicitly closed.
646    *
647    * @return true for a ResultSet, false otherwise
648    * @exception SQLException if an error occurs
649    */

650   public boolean getMoreResults() throws SQLException JavaDoc
651   {
652     return getMoreResults(CLOSE_CURRENT_RESULT);
653   }
654
655   /**
656    * The queryTimeout limit is the number of seconds the driver will wait for a
657    * Statement to execute. If the limit is exceeded, a <code>SQLException</code>
658    * is thrown.
659    *
660    * @return the current query timeout limit in seconds; 0 = unlimited
661    * @exception SQLException if a database access error occurs
662    */

663   public int getQueryTimeout() throws SQLException JavaDoc
664   {
665     return timeout;
666   }
667
668   /**
669    * Returns the current result as a <code>ResultSet</code>.
670    *
671    * @return the current result set; null if there are no more
672    * @exception SQLException never
673    */

674   public java.sql.ResultSet JavaDoc getResultSet() throws SQLException JavaDoc
675   {
676     return result;
677   }
678
679   /**
680    * Retrieve the concurrency mode for the <code>ResultSet</code>.
681    *
682    * @return <code>CONCUR_READ_ONLY</code> or <code>CONCUR_UPDATABLE</code>
683    * @exception SQLException never
684    */

685   public int getResultSetConcurrency() throws SQLException JavaDoc
686   {
687     return resultSetConcurrency;
688   }
689
690   /**
691    * Retrieve the type of the generated <code>ResultSet</code>.
692    *
693    * @return one of <code>TYPE_FORWARD_ONLY</code> or
694    * <code>TYPE_SCROLL_INSENSITIVE</code>
695    * @exception SQLException never
696    */

697   public int getResultSetType() throws SQLException JavaDoc
698   {
699     return resultSetType;
700   }
701
702   /**
703    * Returns the current result as an update count, if the result is a
704    * <code>ResultSet</code> or there are no more results, -1 is returned. It
705    * should only be called once per result.
706    *
707    * @return the current result as an update count.
708    * @exception SQLException if a database access error occurs
709    */

710   public int getUpdateCount() throws SQLException JavaDoc
711   {
712     return updateCount;
713   }
714
715   /**
716    * The first warning reported by calls on this Statement is returned. A
717    * Statement's execute methods clear its SQLWarning chain. Subsequent
718    * <code>Statement</code> warnings will be chained to this SQLWarning.
719    * <p>
720    * The Warning chain is automatically cleared each time a statement is
721    * (re)executed.
722    * <p>
723    * <B>Note: </B> if you are processing a <code>ResultSet</code> then any
724    * warnings associated with <code>ResultSet</code> reads will be chained on
725    * the <code>ResultSet</code> object.
726    *
727    * @return the first SQLWarning on null
728    * @exception SQLException if a database access error occurs or this method is
729    * called on a closed statement
730    */

731   public SQLWarning JavaDoc getWarnings() throws SQLException JavaDoc
732   {
733     if (isClosed())
734       throw new SQLException JavaDoc("Unable to get warnings on a closed statement");
735     return warnings;
736   }
737
738   /**
739    * Defines the SQL cursor name that will be used by subsequent execute
740    * methods. This name can then be used in SQL positioned update/delete
741    * statements to identify the current row in the ResultSet generated by this
742    * statement. If a database doesn't support positioned update/delete, this
743    * method is a no-op.
744    * <p>
745    *
746    * @param name the new cursor name
747    * @exception SQLException not supported
748    */

749   public void setCursorName(String JavaDoc name) throws SQLException JavaDoc
750   {
751     cursorName = name;
752   }
753
754   /**
755    * If escape scanning is on (the default), the driver will do escape
756    * substitution before sending the SQL to the database.
757    *
758    * @param enable true to enable; false to disable
759    * @exception SQLException if a database access error occurs
760    */

761   public void setEscapeProcessing(boolean enable) throws SQLException JavaDoc
762   {
763     escapeProcessing = enable;
764   }
765
766   /**
767    * @see java.sql.Statement#setFetchDirection(int)
768    */

769   public void setFetchDirection(int direction) throws SQLException JavaDoc
770   {
771     if ((direction == ResultSet.FETCH_FORWARD)
772         || (direction == ResultSet.FETCH_REVERSE)
773         || (direction == ResultSet.FETCH_UNKNOWN))
774       this.fetchDirection = direction;
775     else
776       throw new SQLException JavaDoc("Unsupported direction " + direction
777           + " in setFetchDirection");
778   }
779
780   /**
781    * Set the default fetch size for the produced ResultSet.
782    *
783    * @param rows number of rows that should be fetched from the database
784    * @exception SQLException if a database access error occurs or the condition
785    * 0 <= size <= this.getMaxRows is not satisfied
786    */

787   public void setFetchSize(int rows) throws SQLException JavaDoc
788   {
789     if (rows < 0
790     // The spec forgets the case maxRows = 0.
791
|| 0 < maxRows && maxRows < rows)
792     {
793       throw new SQLException JavaDoc("Invalid fetch size value: " + rows);
794     }
795     // It also forgets the case where maxRows is set < fetchSize AFTERwards,
796
// but we don't care about it.
797

798     fetchSize = rows;
799   }
800
801   /**
802    * Sets the <code>maxFieldSize</code>.
803    *
804    * @param max the new max column size limit; 0 means unlimited
805    * @exception SQLException if a database access error occurs or the condition
806    * max >= 0 is not satisfied
807    */

808   public void setMaxFieldSize(int max) throws SQLException JavaDoc
809   {
810     if (max < 0)
811     {
812       throw new SQLException JavaDoc("Invalid max field size value: " + max);
813     }
814     maxFieldSize = max;
815   }
816
817   /**
818    * Sets the maximum number of rows that any <code>ResultSet</code> can
819    * contain.
820    *
821    * @param max the new max rows limit; 0 means unlimited
822    * @exception SQLException if a database access error occurs or the condition
823    * max >= 0 is not satisfied
824    */

825   public void setMaxRows(int max) throws SQLException JavaDoc
826   {
827     if (max < 0)
828     {
829       throw new SQLException JavaDoc("Invalid max rows limit: " + max);
830     }
831     // this may break fetchSize <= maxRows
832
maxRows = max;
833   }
834
835   /**
836    * Sets the number of seconds the driver will wait for a
837    * <code>Statement</code> object to execute.
838    *
839    * @param seconds the new query timeout limit in seconds; 0 means no timeout
840    * @exception SQLException if a database access error occurs or the condition
841    * seconds >= 0 is not satisfied
842    */

843   public void setQueryTimeout(int seconds) throws SQLException JavaDoc
844   {
845     if (seconds < 0)
846     {
847       throw new SQLException JavaDoc("Invalid query timeout value: " + seconds);
848     }
849     timeout = seconds;
850   }
851
852   /**
853    * @param value an <code>int</code> value
854    * @exception SQLException if an error occurs
855    */

856   public void setResultSetConcurrency(int value) throws SQLException JavaDoc
857   {
858     switch (value)
859     {
860       case ResultSet.CONCUR_READ_ONLY :
861       case ResultSet.CONCUR_UPDATABLE :
862         resultSetConcurrency = value;
863         break;
864       default :
865         throw new SQLException JavaDoc("Invalid ResultSet " + "concurrency mode: "
866             + value);
867     }
868   }
869
870   /**
871    * @param value an <code>int</code> value
872    * @exception SQLException if an error occurs
873    */

874   public void setResultSetType(int value) throws SQLException JavaDoc
875   {
876     switch (value)
877     {
878       case ResultSet.TYPE_FORWARD_ONLY :
879       case ResultSet.TYPE_SCROLL_INSENSITIVE :
880         resultSetType = value;
881         break;
882       case ResultSet.TYPE_SCROLL_SENSITIVE :
883         throw new SQLException JavaDoc(
884             "TYPE_SCROLL_SENSITIVE is not a supported ResultSet type");
885       default :
886         throw new SQLException JavaDoc("Invalid ResultSet type");
887     }
888   }
889
890   // --------------------------JDBC 3.0-----------------------------
891

892   /**
893    * Moves to this <code>Statement</code> object's next result, deals with any
894    * current <code>ResultSet</code> object(s) according to the instructions
895    * specified by the given flag, and returns <code>true</code> if the next
896    * result is a <code>ResultSet</code> object.
897    * <p>
898    * There are no more results when the following is <code>true</code>:
899    *
900    * <pre>(!getMoreResults() &amp;&amp; (getUpdateCount() == -1)</pre>
901    *
902    * @param current one of the following <code>Statement</code> constants
903    * indicating what should happen to current <code>ResultSet</code>
904    * objects obtained using the method
905    * <code>getResultSet</code: <code>CLOSE_CURRENT_RESULT</code>,
906    * <code>KEEP_CURRENT_RESULT</code>, or <code>CLOSE_ALL_RESULTS</code>
907    * @return <code>true</code> if the next result is a <code>ResultSet</code>
908    * object; <code>false</code> if it is an update count or there are
909    * no more results
910    * @exception SQLException if a database access error occurs
911    * @since JDK 1.4
912    * @see #execute(String)
913    */

914   public boolean getMoreResults(int current) throws SQLException JavaDoc
915   {
916     // TODO: actually support CLOSE_ALL_RESULTS by calling result.close()
917
// on ALL previous resultsets.
918
if (current != KEEP_CURRENT_RESULT)
919     {
920       if (result != null)
921         try
922         {
923           result.close();
924         }
925         catch (SQLException JavaDoc ignore)
926         {
927         }
928     }
929
930     // Reset results so getResultSet() will return null if this is an
931
// update count, and getUpdateCount() will return -1 otherwise
932
updateCount = -1;
933     result = null;
934
935     if (!resultListIterator.hasNext())
936     {
937       // End of list, return false
938
return false;
939     }
940
941     Object JavaDoc nextResult = resultListIterator.next();
942     if (nextResult instanceof DriverResultSet)
943     {
944       // The previous ResultSet was NOT being streamed, this is currently
945
// incompatible with the generic LinkList this.execute() by design:
946
// VirtualDatabaseWorkerThread always returns FULL resultsets when using
947
// .execute()
948
result = (ResultSet JavaDoc) nextResult;
949
950       // FIXME: why did we miss this at construction time and left a half-built
951
// DriverResultSet?
952
((DriverResultSet) result).setStatement(this);
953       return true;
954     }
955     if (nextResult instanceof Integer JavaDoc)
956     {
957       updateCount = ((Integer JavaDoc) nextResult).intValue();
958       return false;
959     }
960     throw new SQLException JavaDoc("Unexpected result type in getMoreResults ("
961         + nextResult + ")");
962   }
963
964   /**
965    * Retrieves any auto-generated keys created as a result of executing this
966    * <code>Statement</code> object. If this <code>Statement</code> object
967    * did not generate any keys, an empty <code>ResultSet</code> object is
968    * returned.
969    *
970    * @return a <code>ResultSet</code> object containing the auto-generated
971    * key(s) generated by the execution of this <code>Statement</code>
972    * object
973    * @exception SQLException if a database access error occurs
974    * @since JDK 1.4
975    */

976   public java.sql.ResultSet JavaDoc getGeneratedKeys() throws SQLException JavaDoc
977   {
978     return generatedKeys;
979   }
980
981   /**
982    * Executes the given SQL statement and signals the driver with the given flag
983    * about whether the auto-generated keys produced by this
984    * <code>Statement</code> object should be made available for retrieval.
985    *
986    * @param sql must be an SQL <code>INSERT</code>,<code>UPDATE</code> or
987    * <code>DELETE</code> statement or an SQL statement that returns
988    * nothing
989    * @param autoGeneratedKeys a flag indicating whether auto-generated keys
990    * should be made available for retrieval; one of the following
991    * constants: <code>Statement.RETURN_GENERATED_KEYS</code>
992    * <code>Statement.NO_GENERATED_KEYS</code>
993    * @return either the row count for <code>INSERT</code>,
994    * <code>UPDATE</code> or <code>DELETE</code> statements, or
995    * <code>0</code> for SQL statements that return nothing
996    * @exception SQLException if a database access error occurs, the given SQL
997    * statement returns a <code>ResultSet</code> object, or the
998    * given constant is not one of those allowed
999    * @since JDK 1.4
1000   */

1001  public int executeUpdate(String JavaDoc sql, int autoGeneratedKeys)
1002      throws SQLException JavaDoc
1003  {
1004    if (!connection.isAlwaysGettingGeneratedKeys())
1005      generatedKeysFlag = autoGeneratedKeys;
1006    else
1007      generatedKeysFlag = RETURN_GENERATED_KEYS;
1008    int executeUpdateResult = executeUpdate(sql);
1009    if (!connection.isAlwaysGettingGeneratedKeys())
1010      generatedKeysFlag = NO_GENERATED_KEYS;
1011    return executeUpdateResult;
1012  }
1013
1014  /**
1015   * Executes the given SQL statement and signals the driver that the
1016   * auto-generated keys indicated in the given array should be made available
1017   * for retrieval. The driver will ignore the array if the SQL statement is not
1018   * an <code>INSERT</code> statement.
1019   *
1020   * @param sql an SQL <code>INSERT</code>,<code>UPDATE</code> or
1021   * <code>DELETE</code> statement or an SQL statement that returns
1022   * nothing, such as an SQL DDL statement
1023   * @param columnIndexes an array of column indexes indicating the columns that
1024   * should be returned from the inserted row
1025   * @return either the row count for <code>INSERT</code>,
1026   * <code>UPDATE</code>, or <code>DELETE</code> statements, or 0
1027   * for SQL statements that return nothing
1028   * @exception SQLException if a database access error occurs or the SQL
1029   * statement returns a <code>ResultSet</code> object
1030   * @since JDK 1.4
1031   */

1032  public int executeUpdate(String JavaDoc sql, int[] columnIndexes) throws SQLException JavaDoc
1033  {
1034    return executeUpdate(sql, RETURN_GENERATED_KEYS);
1035  }
1036
1037  /**
1038   * Executes the given SQL statement and signals the driver that the
1039   * auto-generated keys indicated in the given array should be made available
1040   * for retrieval. The driver will ignore the array if the SQL statement is not
1041   * an <code>INSERT</code> statement.
1042   *
1043   * @param sql an SQL <code>INSERT</code>,<code>UPDATE</code> or
1044   * <code>DELETE</code> statement or an SQL statement that returns
1045   * nothing
1046   * @param columnNames an array of the names of the columns that should be
1047   * returned from the inserted row
1048   * @return either the row count for <code>INSERT</code>,
1049   * <code>UPDATE</code>, or <code>DELETE</code> statements, or 0
1050   * for SQL statements that return nothing
1051   * @exception SQLException if a database access error occurs
1052   * @since JDK 1.4
1053   */

1054  public int executeUpdate(String JavaDoc sql, String JavaDoc[] columnNames)
1055      throws SQLException JavaDoc
1056  {
1057    return executeUpdate(sql, RETURN_GENERATED_KEYS);
1058  }
1059
1060  /**
1061   * Executes the given SQL statement, which may return multiple results, and
1062   * signals the driver that any auto-generated keys should be made available
1063   * for retrieval. The driver will ignore this signal if the SQL statement is
1064   * not an <code>INSERT</code> statement.
1065   * <p>
1066   * In some (uncommon) situations, a single SQL statement may return multiple
1067   * result sets and/or update counts. Normally you can ignore this unless you
1068   * are (1) executing a stored procedure that you know may return multiple
1069   * results or (2) you are dynamically executing an unknown SQL string.
1070   * <p>
1071   * The <code>execute</code> method executes an SQL statement and indicates
1072   * the form of the first result. You must then use the methods
1073   * <code>getResultSet</code> or <code>getUpdateCount</code> to retrieve
1074   * the result, and <code>getMoreResults</code> to move to any subsequent
1075   * result(s).
1076   *
1077   * @param sql any SQL statement
1078   * @param autoGeneratedKeys a constant indicating whether auto-generated keys
1079   * should be made available for retrieval using the method
1080   * <code>getGeneratedKeys</code>; one of the following constants:
1081   * <code>Statement.RETURN_GENERATED_KEYS</code> or
1082   * <code>Statement.NO_GENERATED_KEYS</code>
1083   * @return <code>true</code> if the first result is a <code>ResultSet</code>
1084   * object; <code>false</code> if it is an update count or there are
1085   * no results
1086   * @exception SQLException if a database access error occurs
1087   * @see #getResultSet
1088   * @see #getUpdateCount
1089   * @see #getMoreResults()
1090   * @see #getGeneratedKeys
1091   * @since JDK 1.4
1092   */

1093  public boolean execute(String JavaDoc sql, int autoGeneratedKeys) throws SQLException JavaDoc
1094  {
1095    if (connection.isAlwaysGettingGeneratedKeys()
1096        && sql.toLowerCase().trim().startsWith("insert"))
1097      generatedKeysFlag = RETURN_GENERATED_KEYS;
1098    else
1099      generatedKeysFlag = autoGeneratedKeys;
1100
1101    if (autoGeneratedKeys == RETURN_GENERATED_KEYS)
1102    {
1103      int executeUpdateResult = executeUpdate(sql);
1104      resultList = new LinkedList JavaDoc();
1105      resultList.add(new Integer JavaDoc(executeUpdateResult));
1106      resultListIterator = resultList.iterator();
1107      if (!connection.isAlwaysGettingGeneratedKeys())
1108        autoGeneratedKeys = NO_GENERATED_KEYS;
1109      return getMoreResults();
1110    }
1111    return execute(sql);
1112  }
1113
1114  /**
1115   * Executes the given SQL statement, which may return multiple results, and
1116   * signals the driver that the auto-generated keys indicated in the given
1117   * array should be made available for retrieval. This array contains the
1118   * indexes of the columns in the target table that contain the auto-generated
1119   * keys that should be made available. The driver will ignore the array if the
1120   * given SQL statement is not an <code>INSERT</code> statement.
1121   * <p>
1122   * Under some (uncommon) situations, a single SQL statement may return
1123   * multiple result sets and/or update counts. Normally you can ignore this
1124   * unless you are (1) executing a stored procedure that you know may return
1125   * multiple results or (2) you are dynamically executing an unknown SQL
1126   * string.
1127   * <p>
1128   * The <code>execute</code> method executes an SQL statement and indicates
1129   * the form of the first result. You must then use the methods
1130   * <code>getResultSet</code> or <code>getUpdateCount</code> to retrieve
1131   * the result, and <code>getMoreResults</code> to move to any subsequent
1132   * result(s).
1133   *
1134   * @param sql any SQL statement
1135   * @param columnIndexes an array of the indexes of the columns in the inserted
1136   * row that should be made available for retrieval by a call to the
1137   * method <code>getGeneratedKeys</code>
1138   * @return <code>true</code> if the first result is a <code>ResultSet</code>
1139   * object; <code>false</code> if it is an update count or there are
1140   * no results
1141   * @exception SQLException if a database access error occurs
1142   * @see #getResultSet
1143   * @see #getUpdateCount
1144   * @see #getMoreResults()
1145   * @since JDK 1.4
1146   */

1147  public boolean execute(String JavaDoc sql, int[] columnIndexes) throws SQLException JavaDoc
1148  {
1149    return execute(sql, RETURN_GENERATED_KEYS);
1150  }
1151
1152  /**
1153   * Executes the given SQL statement, which may return multiple results, and
1154   * signals the driver that the auto-generated keys indicated in the given
1155   * array should be made available for retrieval. This array contains the names
1156   * of the columns in the target table that contain the auto-generated keys
1157   * that should be made available. The driver will ignore the array if the
1158   * given SQL statement is not an <code>INSERT</code> statement.
1159   * <p>
1160   * In some (uncommon) situations, a single SQL statement may return multiple
1161   * result sets and/or update counts. Normally you can ignore this unless you
1162   * are (1) executing a stored procedure that you know may return multiple
1163   * results or (2) you are dynamically executing an unknown SQL string.
1164   * <p>
1165   * The <code>execute</code> method executes an SQL statement and indicates
1166   * the form of the first result. You must then use the methods
1167   * <code>getResultSet</code> or <code>getUpdateCount</code> to retrieve
1168   * the result, and <code>getMoreResults</code> to move to any subsequent
1169   * result(s).
1170   *
1171   * @param sql any SQL statement
1172   * @param columnNames an array of the names of the columns in the inserted row
1173   * that should be made available for retrieval by a call to the
1174   * method <code>getGeneratedKeys</code>
1175   * @return <code>true</code> if the next result is a <code>ResultSet</code>
1176   * object; <code>false</code> if it is an update count or there are
1177   * no more results
1178   * @exception SQLException if a database access error occurs
1179   * @see #getResultSet
1180   * @see #getUpdateCount
1181   * @see #getMoreResults()
1182   * @see #getGeneratedKeys
1183   * @since JDK 1.4
1184   */

1185  public boolean execute(String JavaDoc sql, String JavaDoc[] columnNames) throws SQLException JavaDoc
1186  {
1187    return execute(sql, RETURN_GENERATED_KEYS);
1188  }
1189
1190  /**
1191   * Retrieves the result set holdability for <code>ResultSet</code> objects
1192   * generated by this <code>Statement</code> object.
1193   *
1194   * @return either <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
1195   * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
1196   * @exception SQLException if a database access error occurs
1197   * @since JDK 1.4
1198   */

1199  public int getResultSetHoldability() throws SQLException JavaDoc
1200  {
1201    return connection.getHoldability();
1202  }
1203
1204  /**
1205   * Test if this statement is closed.
1206   *
1207   * @return <code>true</code> if this statement is closed
1208   */

1209  protected boolean isClosed()
1210  {
1211    return (connection == null);
1212  }
1213}
Popular Tags