1 /* Copyright (c) 2001-2016, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
operator ""_kind(char p)9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 package org.hsqldb.jdbc;
33 
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.InputStreamReader;
37 import java.io.Reader;
38 import java.io.Serializable;
39 import java.io.StringWriter;
40 import java.math.BigDecimal;
fractional_digits_impl(const char * p)41 import java.sql.Array;
42 import java.sql.BatchUpdateException;
43 import java.sql.Blob;
operator ""_fractional_digits(const char * p)44 import java.sql.Clob;
45 import java.sql.Connection;
46 import java.sql.Date;
streq(const char * p,const char * q)47 import java.sql.ParameterMetaData;
48 import java.sql.PreparedStatement;
49 import java.sql.Ref;
50 import java.sql.ResultSet;
51 import java.sql.ResultSetMetaData;
52 import java.sql.SQLException;
53 import java.sql.SQLWarning;
54 import java.sql.Time;
55 import java.sql.Timestamp;
56 import java.util.ArrayList;
57 import java.util.Calendar;
58 import java.util.UUID;
59 
60 //#ifdef JAVA6
61 import java.sql.NClob;
62 import java.sql.RowId;
63 import java.sql.SQLXML;
64 
65 //#endif JAVA6
66 import org.hsqldb.HsqlDateTime;
67 import org.hsqldb.HsqlException;
68 import org.hsqldb.SchemaObject;
69 import org.hsqldb.SessionInterface;
70 import org.hsqldb.StatementTypes;
71 import org.hsqldb.error.Error;
72 import org.hsqldb.error.ErrorCode;
73 import org.hsqldb.lib.ArrayUtil;
74 import org.hsqldb.lib.CharArrayWriter;
75 import org.hsqldb.lib.CountdownInputStream;
76 import org.hsqldb.lib.HsqlByteArrayOutputStream;
77 import org.hsqldb.lib.StringConverter;
78 import org.hsqldb.map.ValuePool;
79 import org.hsqldb.navigator.RowSetNavigator;
80 import org.hsqldb.result.Result;
81 import org.hsqldb.result.ResultConstants;
82 import org.hsqldb.result.ResultLob;
83 import org.hsqldb.result.ResultMetaData;
84 import org.hsqldb.result.ResultProperties;
85 import org.hsqldb.types.BinaryData;
86 import org.hsqldb.types.BinaryUUIDType;
87 import org.hsqldb.types.BlobDataID;
88 import org.hsqldb.types.BlobInputStream;
89 import org.hsqldb.types.ClobDataID;
90 import org.hsqldb.types.ClobInputStream;
91 import org.hsqldb.types.DateTimeType;
92 import org.hsqldb.types.JavaObjectData;
93 import org.hsqldb.types.JavaObjectDataInternal;
94 import org.hsqldb.types.TimeData;
95 import org.hsqldb.types.TimestampData;
96 import org.hsqldb.types.Type;
97 import org.hsqldb.types.Types;
98 
99 /* $Id: JDBCPreparedStatement.java 5623 2016-05-05 21:03:57Z fredt $ */
100 
101 // changes by fredt
102 // SimpleDateFormat objects moved out of methods to improve performance
103 // this is safe because only one thread at a time should access a
104 // PreparedStatement object until it has finished executing the statement
105 //
106 // fredt@users    20020215 - patch 517028 by peterhudson@users - method defined
107 // minor changes by fredt
108 // fredt@users    20020320 - patch 1.7.0 - JDBC 2 support and error trapping;
109 //                           JDBC 2 methods can now be called from jdk 1.1.x
110 //                           - see javadoc comments
111 // fredt@users    20020414 - patch 517028 by peterhudson@users - setDate method defined
112 //                                                             - setTime method defined
113 //                                                             - setTimestamp method defined
114 //                           changes by fredt                  - moved conversion to HsqlDateTime
115 // fredt@users    20020429 - patch 1.7.0 - setCharacterStream method defined
mash(unsigned a)116 //
117 // boucherb &     20020409 - extensive review and update of docs and behaviour
118 // fredt@users  - 20020505   to comply with previous and latest java.sql specification
119 //
120 // boucherb@users 20020509 - added "throws SQLException" to all methods where it
121 //                           was missing here but specified in the java.sql.PreparedStatement and
122 //                           java.sqlCallableStatement interfaces, updated generic documentation to
123 //                           JDK 1.4, and added JDBC3 methods and docs
124 // fredt@users    20020627 - patch 574234 for setCharacterStream by ohioedge@users
125 // fredt@users    20030620 - patch 1.7.2 - rewritten to support real prepared statements
126 // boucherb@users 20030801 - patch 1.7.2 - support for batch execution
127 // boucherb@users 20030801 - patch 1.7.2 - support for getMetaData and getParameterMetadata
128 // boucherb@users 20030801 - patch 1.7.2 - updated some setXXX methods, incl. setCharacterStream
129 // boucherb@users 20030801 - patch 1.7.2 - setBlob method implemented
130 // boucherb@users 200403/4 - doc 1.7.2   - javadoc updates toward 1.7.2 final
131 // boucherb@users 200403/4 - patch 1.7.2 - eliminate eager buffer allocation from setXXXStream/Blob/Clob
132 // boucherb@users 20051207 - patch 1.8.0.x initial JDBC 4.0 support work
133 // fredt@users    20060215 - patch 1.8.0 - check for unset parameters
134 // fredt@users    20061008 - patch 1.9.0 - partial rewrite with enhancements - separated from jdbcStatement
135 // boucherb@users 20060424 - patch 1.8.x - Mustang Build 81 JDBC 4.0 support
136 // boucherb@users 20060424 - doc   1.9.0 - Full synch up to Mustang Build 84
137 // Revision 1.19  2006/07/12 12:24:17  boucherb
138 // patch 1.9.0
139 // - full synch up to Mustang b90
140 
141 /**
142  * <!-- start generic documentation -->
143  *
144  * An object that represents a precompiled SQL statement.
145  * <P>A SQL statement is precompiled and stored in a
146  * <code>PreparedStatement</code> object. This object can then be used to
147  * efficiently execute this statement multiple times.
148  *
149  * <P><B>Note:</B> The setter methods (<code>setShort</code>, <code>setString</code>,
150  * and so on) for setting IN parameter values
151  * must specify types that are compatible with the defined SQL type of
152  * the input parameter. For instance, if the IN parameter has SQL type
153  * <code>INTEGER</code>, then the method <code>setInt</code> should be used.
154  *
155  * <p>If arbitrary parameter type conversions are required, the method
156  * <code>setObject</code> should be used with a target SQL type.
157  * <P>
158  * In the following example of setting a parameter, <code>con</code> represents
159  * an active connection:
160  * <PRE>
161  *   PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
162  *                                     SET SALARY = ? WHERE ID = ?");
163  *   pstmt.setBigDecimal(1, 153833.00)
164  *   pstmt.setInt(2, 110592)
165  * </PRE>
166  *
167  * <!-- end generic documentation -->
168  *
169  * <!-- start Release-specific documentation -->
170  * <div class="ReleaseSpecificDocumentation">
171  * <h3>HSQLDB-Specific Information:</h3> <p>
172  *
173  * From version 2.0, the implementation meets the JDBC specification
174  * requirement that any existing ResultSet is closed when execute() or
175  * executeQuery() methods are called. The connection property close_result=true
176  * is required for this behaviour.
177  * <p>
178  * JDBCPreparedStatement objects are backed by
179  * a true compiled parameteric representation. Hence, there are now significant
180  * performance gains to be had by using a JDBCPreparedStatement object in
181  * preference to a JDBCStatement object when a short-running SQL statement is
182  * to be executed more than once. <p>
183  *
184  * When it can be otherwise avoided, it should be considered poor practice to
185  * fully prepare (construct), parameterize, execute, fetch and close a
186  * JDBCParameterMetaData object for each execution cycle. Indeed,
187  * because the prepare and execute phases
188  * both represent a round-trip to the engine, this practice is likely to be
189  * noticeably <em>less</em> performant for short-running statements (and
190  * possibly even orders of magnitude less performant over network connections
191  * for short-running statements) than the equivalent process using JDBCStatement
192  * objects, albeit far more convenient, less error prone and certainly much
193  * less resource-intensive, especially when large binary and character values
194  * are involved, due to the optimized parameterization facility. <p>
195  *
196  * Instead, when developing an application that is not totally oriented toward
197  * the execution of ad hoc SQL, it is recommended to expend some effort toward
198  * identifying the SQL statements that are good candidates for regular reuse and
199  * adapting the structure of the application accordingly. Often, this is done
200  * by recording the text of candidate SQL statements in an application resource
201  * object (which has the nice side-benefit of isolating and hiding differences
202  * in SQL dialects across different drivers) and caching for possible reuse the
203  * PreparedStatement objects derived from the recorded text. <p>
204  *
205  * Starting with 2.0, when built under a JDBC 4 environment, statement caching
206  * can be transparently enabled or disabled on a statement-by-statement basis by
207  * invoking setPoolable(true | false), respectively, upon Statement objects of
208  * interest. <p>
209  *
210  * <b>Multi thread use:</b> <p>
211  *
212  * A PreparedStatement object is stateful and should not normally be shared
213  * by multiple threads. If it has to be shared, the calls to set the
214  * parameters, calls to add batch statements, the execute call and any
215  * post-execute calls should be made within a block synchronized on the
216  * PreparedStatement Object.<p>
217  *
218  * <b>JRE 1.1.x Notes:</b> <p>
219  *
220  * In general, JDBC 2 support requires Java 1.2 and above, and JDBC3 requires
221  * Java 1.4 and above. In HSQLDB, support for methods introduced in different
222  * versions of JDBC depends on the JDK version used for compiling and building
223  * HSQLDB.<p>
224  *
225  * Since 1.7.0, all JDBC 2 methods can be called while executing under the
226  * version 1.1.x
227  * <em>Java Runtime Environment</em><sup><font size="-2">TM</font></sup>.
228  * However, in addition to this technique requiring explicit casts to the
229  * org.hsqldb.jdbc.* classes, some of these method calls require
230  * <code>int</code> values that are defined only in the JDBC 2 or greater
231  * version of the {@link java.sql.ResultSet ResultSet} interface.  For this
232  * reason these values are defined in {@link JDBCResultSet JDBCResultSet}.<p>
233  *
234  * In a JRE 1.1.x environment, calling JDBC 2 methods that take or return the
235  * JDBC2-only <code>ResultSet</code> values can be achieved by referring
236  * to them in parameter specifications and return value comparisons,
237  * respectively, as follows: <p>
238  *
239  * <pre class="JavaCodeExample">
240  * JDBCResultSet.FETCH_FORWARD
241  * JDBCResultSet.TYPE_FORWARD_ONLY
242  * JDBCResultSet.TYPE_SCROLL_INSENSITIVE
243  * JDBCResultSet.CONCUR_READ_ONLY
244  * //etc.
245  * </pre> <p>
246  *
247  * However, please note that code written to use HSQLDB JDBC 2 features under
248  * JDK 1.1.x will not be compatible for use with other JDBC 2 drivers. Please
249  * also note that this feature is offered solely as a convenience to developers
250  * who must work under JDK 1.1.x due to operating constraints, yet wish to
251  * use some of the more advanced features available under the JDBC 2
252  * specification. <p>
253  *
254  * (fredt@users)<br>
255  * (boucherb@users)<p>
256  *
257  * </div>
258  * <!-- end release-specific documentation -->
259  *
260  * @author Campbell Burnet (boucherb@users dot sourceforge.net)
261  * @author Fred Toussi (fredt@users dot sourceforge.net)
262  * @version 2.3.4
263  * @since 1.7.2
264  * @see JDBCConnection#prepareStatement
265  * @see JDBCResultSet
266  */
267 public class JDBCPreparedStatement extends JDBCStatementBase implements PreparedStatement {
268 
269     /**
270      * <!-- start generic documentation -->
271      * Executes the SQL query in this <code>PreparedStatement</code> object
272      * and returns the <code>ResultSet</code> object generated by the query.
273      * <!-- end generic documentation -->
274      *
275      * @return a <code>ResultSet</code> object that contains the data produced by the
276      *         query; never <code>null</code>
277      * @exception SQLException if a database access error occurs,
278      * this method is called on a closed  <code>PreparedStatement</code> or the SQL
279      *            statement does not return a <code>ResultSet</code> object
280      */
281     public synchronized ResultSet executeQuery() throws SQLException {
282 
283         if (statementRetType != StatementTypes.RETURN_RESULT) {
284             checkStatementType(StatementTypes.RETURN_RESULT);
285         }
286         fetchResult();
287 
288         return getResultSet();
289     }
290 
291     /**
292      * <!-- start generic documentation -->
293      * Executes the SQL statement in this <code>PreparedStatement</code> object,
294      * (JDBC4 clarification:)
295      * which must be an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
296      * <code>DELETE</code>; or an SQL statement that returns nothing,
297      * such as a DDL statement.
298      * <!-- end generic documentation -->
299      *
300      * @return (JDBC4 clarification:) either (1) the row count for SQL Data Manipulation Language (DML) statements
301      *         or (2) 0 for SQL statements that return nothing
302      * @exception SQLException if a database access error occurs,
303      * this method is called on a closed  <code>PreparedStatement</code>
304      * or the SQL
305      *            statement returns a <code>ResultSet</code> object
306      */
307     public synchronized int executeUpdate() throws SQLException {
308 
309         if (statementRetType != StatementTypes.RETURN_COUNT) {
310             checkStatementType(StatementTypes.RETURN_COUNT);
311         }
312         fetchResult();
313 
314         return resultIn.getUpdateCount();
315     }
316 
317     /**
318      * <!-- start generic documentation -->
319      * Sets the designated parameter to SQL <code>NULL</code>.
320      *
321      * <P><B>Note:</B> You must specify the parameter's SQL type.
322      * <!-- end generic documentation -->
323      *
324      * <!-- start release-specific documentation -->
325      * <div class="ReleaseSpecificDocumentation">
326      * <h3>HSQLDB-Specific Information:</h3> <p>
327      *
328      * HSQLDB currently ignores the sqlType argument.
329      * </div>
330      * <!-- end release-specific documentation -->
331      *
332      * @param parameterIndex the first parameter is 1, the second is 2, ...
333      * @param sqlType the SQL type code defined in <code>java.sql.Types</code>
334      * @exception SQLException if a database access error occurs or
335      * this method is called on a closed <code>PreparedStatement</code>
336      * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
337      * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
338      * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
339      * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
340      *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
341      * or  <code>STRUCT</code> data type and the JDBC driver does not support
342      * this data type
343      */
344     public synchronized void setNull(int parameterIndex,
345                                      int sqlType) throws SQLException {
346         setParameter(parameterIndex, null);
347     }
348 
349     /**
350      * <!-- start generic documentation -->
351      * Sets the designated parameter to the given Java <code>boolean</code> value.
352      * The driver converts this
353      * (JDBC4 Modified:)
354      * to an SQL <code>BIT</code> or <code>BOOLEAN</code> value when it sends it to the database.
355      * <!-- end generic documentation -->
356      *
357      * <!-- start release-specific documentation -->
358      * <div class="ReleaseSpecificDocumentation">
359      * <h3>HSQLDB-Specific Information:</h3> <p>
360      *
361      * HSQLDB supports BOOLEAN type for boolean values. This method can also
362      * be used to set the value of a parameter of the SQL type BIT(1), which is
363      * a bit string consisting of a 0 or 1.
364      * </div>
365      * <!-- end release-specific documentation -->
366      *
367      * @param parameterIndex the first parameter is 1, the second is 2, ...
368      * @param x the parameter value
369      * @exception SQLException if a database access error occurs or
370      * this method is called on a closed <code>PreparedStatement</code>
371      */
372     public synchronized void setBoolean(int parameterIndex,
373                                         boolean x) throws SQLException {
374 
375         Boolean b = x ? Boolean.TRUE
376                       : Boolean.FALSE;
377 
378         setParameter(parameterIndex, b);
379     }
380 
381     /**
382      * <!-- start generic documentation -->
383      * Sets the designated parameter to the given Java <code>byte</code> value.
384      * The driver converts this
385      * to an SQL <code>TINYINT</code> value when it sends it to the database.
386      * <!-- end generic documentation -->
387      *
388      * @param parameterIndex the first parameter is 1, the second is 2, ...
389      * @param x the parameter value
390      * @exception SQLException if a database access error occurs or
391      * this method is called on a closed <code>PreparedStatement</code>
392      */
393     public synchronized void setByte(int parameterIndex,
394                                      byte x) throws SQLException {
395         setIntParameter(parameterIndex, x);
396     }
397 
398     /**
399      * <!-- start generic documentation -->
400      * Sets the designated parameter to the given Java <code>short</code> value.
401      * The driver converts this
402      * to an SQL <code>SMALLINT</code> value when it sends it to the database.
403      * <!-- end generic documentation -->
404      *
405      * @param parameterIndex the first parameter is 1, the second is 2, ...
406      * @param x the parameter value
407      * @exception SQLException if a database access error occurs or
408      * this method is called on a closed <code>PreparedStatement</code>
409      */
410     public synchronized void setShort(int parameterIndex,
411                                       short x) throws SQLException {
412 
413         if (isClosed || connection.isClosed) {
414             checkClosed();
415         }
416         checkSetParameterIndex(parameterIndex);
417 
418         if (parameterTypes[parameterIndex - 1].typeCode
419                 == Types.SQL_SMALLINT) {
420             parameterValues[--parameterIndex] = Integer.valueOf(x);
421             parameterSet[parameterIndex]      = Boolean.TRUE;
422 
423             return;
424         }
425         setIntParameter(parameterIndex, x);
426     }
427 
428     /**
429      * <!-- start generic documentation -->
430      * Sets the designated parameter to the given Java <code>int</code> value.
431      * The driver converts this
432      * to an SQL <code>INTEGER</code> value when it sends it to the database.
433      * <!-- end generic documentation -->
434      *
435      * @param parameterIndex the first parameter is 1, the second is 2, ...
436      * @param x the parameter value
437      * @exception SQLException if a database access error occurs or
438      * this method is called on a closed <code>PreparedStatement</code>
439      */
440     public synchronized void setInt(int parameterIndex,
441                                     int x) throws SQLException {
442 
443         if (isClosed || connection.isClosed) {
444             checkClosed();
445         }
446         checkSetParameterIndex(parameterIndex);
447 
448         if (parameterTypes[parameterIndex - 1].typeCode == Types.SQL_INTEGER) {
449             parameterValues[--parameterIndex] = Integer.valueOf(x);
450             parameterSet[parameterIndex]      = Boolean.TRUE;
451 
452             return;
453         }
454         setIntParameter(parameterIndex, x);
455     }
456 
457     /**
458      * <!-- start generic documentation -->
459      * Sets the designated parameter to the given Java <code>long</code> value.
460      * The driver converts this
461      * to an SQL <code>BIGINT</code> value when it sends it to the database.
462      * <!-- end generic documentation -->
463      *
464      * @param parameterIndex the first parameter is 1, the second is 2, ...
465      * @param x the parameter value
466      * @exception SQLException if a database access error occurs or
467      * this method is called on a closed <code>PreparedStatement</code>
468      */
469     public synchronized void setLong(int parameterIndex,
470                                      long x) throws SQLException {
471 
472         if (isClosed || connection.isClosed) {
473             checkClosed();
474         }
475         checkSetParameterIndex(parameterIndex);
476 
477         if (parameterTypes[parameterIndex - 1].typeCode == Types.SQL_BIGINT) {
478             parameterValues[--parameterIndex] = Long.valueOf(x);
479             parameterSet[parameterIndex]      = Boolean.TRUE;
480 
481             return;
482         }
483         setLongParameter(parameterIndex, x);
484     }
485 
486     /**
487      * <!-- start generic documentation -->
488      * Sets the designated parameter to the given Java <code>float</code> value.
489      * The driver converts this
490      * (JDBC4 correction:)
491      * to an SQL <code>REAL</code> value when it sends it to the database.
492      * <!-- end generic documentation -->
493      *
494      * <!-- start release-specific documentation -->
495      * <div class="ReleaseSpecificDocumentation">
496      * <h3>HSQLDB-Specific Information:</h3> <p>
497      *
498      * Since 1.7.1, HSQLDB handles Java positive/negative Infinity
499      * and NaN <code>float</code> values consistent with the Java Language
500      * Specification; these <em>special</em> values are now correctly stored
501      * to and retrieved from the database.
502      * </div>
503      * <!-- start release-specific documentation -->
504      *
505      * @param parameterIndex the first parameter is 1, the second is 2, ...
506      * @param x the parameter value
507      * @exception SQLException if a database access error occurs or
508      * this method is called on a closed <code>PreparedStatement</code>
509      */
510     public synchronized void setFloat(int parameterIndex,
511                                       float x) throws SQLException {
512         setDouble(parameterIndex, (double) x);
513     }
514 
515     /**
516      * <!-- start generic documentation -->
517      * Sets the designated parameter to the given Java <code>double</code> value.
518      * The driver converts this
519      * to an SQL <code>DOUBLE</code> value when it sends it to the database.
520      * <!-- end generic documentation -->
521      *
522      * <!-- start release-specific documentation -->
523      * <div class="ReleaseSpecificDocumentation">
524      * <h3>HSQLDB-Specific Information:</h3> <p>
525      *
526      * Since 1.7.1, HSQLDB handles Java positive/negative Infinity
527      * and NaN <code>double</code> values consistent with the Java Language
528      * Specification; these <em>special</em> values are now correctly stored
529      * to and retrieved from the database.
530      * </div>
531      * <!-- start release-specific documentation -->
532      *
533      * @param parameterIndex the first parameter is 1, the second is 2, ...
534      * @param x the parameter value
535      * @exception SQLException if a database access error occurs or
536      * this method is called on a closed <code>PreparedStatement</code>
537      */
538     public synchronized void setDouble(int parameterIndex,
539                                        double x) throws SQLException {
540 
541         Double d = new Double(x);
542 
543         setParameter(parameterIndex, d);
544     }
545 
546     /**
547      * <!-- start generic documentation -->
548      * Sets the designated parameter to the given <code>java.math.BigDecimal</code> value.
549      * The driver converts this to an SQL <code>NUMERIC</code> value when
550      * it sends it to the database.
551      * <!-- end generic documentation -->
552      *
553      * @param parameterIndex the first parameter is 1, the second is 2, ...
554      * @param x the parameter value
555      * @exception SQLException if a database access error occurs or
556      * this method is called on a closed <code>PreparedStatement</code>
557      */
558     public synchronized void setBigDecimal(int parameterIndex,
559             BigDecimal x) throws SQLException {
560         setParameter(parameterIndex, x);
561     }
562 
563     /**
564      * <!-- start generic documentation -->
565      * Sets the designated parameter to the given Java <code>String</code> value.
566      * The driver converts this
567      * to an SQL <code>VARCHAR</code> or <code>LONGVARCHAR</code> value
568      * (depending on the argument's
569      * size relative to the driver's limits on <code>VARCHAR</code> values)
570      * when it sends it to the database.
571      * <!-- end generic documentation -->
572      *
573      * <!-- start release-specific documentation -->
574      * <div class="ReleaseSpecificDocumentation">
575      * <h3>HSQLDB-Specific Information:</h3> <p>
576      *
577      * Including 2.0, HSQLDB represents all XXXCHAR values internally as
578      * java.lang.String objects; there is no appreciable difference between
579      * CHAR, VARCHAR and LONGVARCHAR.
580      * </div>
581      * <!-- start release-specific documentation -->
582      *
583      * @param parameterIndex the first parameter is 1, the second is 2, ...
584      * @param x the parameter value
585      * @exception SQLException if a database access error occurs or
586      * this method is called on a closed <code>PreparedStatement</code>
587      */
588     public synchronized void setString(int parameterIndex,
589                                        String x) throws SQLException {
590         setParameter(parameterIndex, x);
591     }
592 
593     /**
594      * <!-- start generic documentation -->
595      * Sets the designated parameter to the given Java array of bytes.  The driver converts
596      * this to an SQL <code>VARBINARY</code> or <code>LONGVARBINARY</code>
597      * (depending on the argument's size relative to the driver's limits on
598      * <code>VARBINARY</code> values) when it sends it to the database.
599      * <!-- end generic documentation -->
600      *
601      * <!-- start release-specific documentation -->
602      * <div class="ReleaseSpecificDocumentation">
603      * <h3>HSQLDB-Specific Information:</h3> <p>
604      *
605      * Including 2.0, HSQLDB represents all XXXBINARY values the same way
606      * internally; there is no appreciable difference between BINARY,
607      * VARBINARY and LONGVARBINARY as far as JDBC is concerned.
608      * </div>
609      * <!-- start release-specific documentation -->
610      *
611      * @param parameterIndex the first parameter is 1, the second is 2, ...
612      * @param x the parameter value
613      * @exception SQLException if a database access error occurs or
614      * this method is called on a closed <code>PreparedStatement</code>
615      */
616     public synchronized void setBytes(int parameterIndex,
617                                       byte[] x) throws SQLException {
618         setParameter(parameterIndex, x);
619     }
620 
621     /**
622      * <!-- start generic documentation -->
623      * (JDBC4 clarification:)
624      * Sets the designated parameter to the given <code>java.sql.Date</code> value
625      * using the default time zone of the virtual machine that is running
626      * the application.
627      * The driver converts this
628      * to an SQL <code>DATE</code> value when it sends it to the database.
629      * <!-- end generic documentation -->
630      * <div class="ReleaseSpecificDocumentation">
631      * <h3>HSQLDB-Specific Information:</h3> <p>
632      *
633      * When a setXXX method is used to set a parameter of type
634      * TIMESTAMP WITH TIME ZONE or TIME WITH TIME ZONE the time zone of the
635      * client application is used as time zone
636      * </div>
637      * <!-- end release-specific documentation -->
638      *
639      * @param parameterIndex the first parameter is 1, the second is 2, ...
640      * @param x the parameter value
641      * @exception SQLException if a database access error occurs or
642      * this method is called on a closed <code>PreparedStatement</code>
643      */
644     public synchronized void setDate(int parameterIndex,
645                                      Date x) throws SQLException {
646         setParameter(parameterIndex, x);
647     }
648 
649     /**
650      * <!-- start generic documentation -->
651      * Sets the designated parameter to the given <code>java.sql.Time</code> value.
652      * The driver converts this
653      * to an SQL <code>TIME</code> value when it sends it to the database.
654      * <!-- end generic documentation -->
655      * <div class="ReleaseSpecificDocumentation">
656      * <h3>HSQLDB-Specific Information:</h3> <p>
657      *
658      * When a setXXX method is used to set a parameter of type
659      * TIMESTAMP WITH TIME ZONE or TIME WITH TIME ZONE the time zone of the
660      * client application is used as time zone
661      * </div>
662      * <!-- end release-specific documentation -->
663      *
664      * @param parameterIndex the first parameter is 1, the second is 2, ...
665      * @param x the parameter value
666      * @exception SQLException if a database access error occurs or
667      * this method is called on a closed <code>PreparedStatement</code>
668      */
669     public synchronized void setTime(int parameterIndex,
670                                      Time x) throws SQLException {
671         setParameter(parameterIndex, x);
672     }
673 
674     /**
675      * <!-- start generic documentation -->
676      * Sets the designated parameter to the given <code>java.sql.Timestamp</code> value.
677      * The driver
678      * converts this to an SQL <code>TIMESTAMP</code> value when it sends it to the
679      * database.
680      * <!-- end generic documentation -->
681      * <div class="ReleaseSpecificDocumentation">
682      * <h3>HSQLDB-Specific Information:</h3> <p>
683      *
684      * When a setXXX method is used to set a parameter of type
685      * TIMESTAMP WITH TIME ZONE or TIME WITH TIME ZONE the time zone of the
686      * client application is used as time zone.<p>
687      *
688      * When this method is used to set a parameter of type TIME or
689      * TIME WITH TIME ZONE, then the nanosecond value of the Timestamp object
690      * will be used if the TIME parameter accepts fractional seconds.
691      * </div>
692      * <!-- end release-specific documentation -->
693      *
694      * @param parameterIndex the first parameter is 1, the second is 2, ...
695      * @param x the parameter value
696      * @exception SQLException if a database access error occurs or
697      * this method is called on a closed <code>PreparedStatement</code>
698      */
699     public synchronized void setTimestamp(int parameterIndex,
700             Timestamp x) throws SQLException {
701         setParameter(parameterIndex, x);
702     }
703 
704     /** @todo 1.9.0 - implement streaming */
705 
706     /**
707      * <!-- start generic documentation -->
708      * Sets the designated parameter to the given input stream, which will have
709      * the specified number of bytes.
710      * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
711      * parameter, it may be more practical to send it via a
712      * <code>java.io.InputStream</code>. Data will be read from the stream
713      * as needed until end-of-file is reached.  The JDBC driver will
714      * do any necessary conversion from ASCII to the database char format.
715      *
716      * <P><B>Note:</B> This stream object can either be a standard
717      * Java stream object or your own subclass that implements the
718      * standard interface.
719      * <!-- end generic documentation -->
720      * <!-- start release-specific documentation -->
721      * <div class="ReleaseSpecificDocumentation">
722      * <h3>HSQLDB-Specific Information:</h3> <p>
723      *
724      * From HSQLDB 2.0 this method uses the US-ASCII character encoding to convert bytes
725      * from the stream into the characters of a String.<p>
726      * This method does not use streaming to send the data,
727      * whether the target is a CLOB or other binary object.<p>
728      *
729      * For long streams (larger than a few megabytes) with CLOB targets,
730      * it is more efficient to use a version of setCharacterStream which takes
731      * the a length parameter.
732      * </div>
733      * <!-- end release-specific documentation -->
734      *
735      * @param parameterIndex the first parameter is 1, the second is 2, ...
736      * @param x the Java input stream that contains the ASCII parameter value
737      * @param length the number of bytes in the stream
738      * @exception SQLException if a database access error occurs or
739      * this method is called on a closed <code>PreparedStatement</code>
740      */
741     public synchronized void setAsciiStream(int parameterIndex,
742             java.io.InputStream x, int length) throws SQLException {
743         setAsciiStream(parameterIndex, x, (long) length);
744     }
745 
746     /**
747      * <!-- start generic documentation -->
748      * Sets the designated parameter to the given input stream, which
749      * will have the specified number of bytes.
750      * (JDBC4 deleted:)
751      * [A Unicode character has two bytes, with the first byte being the high
752      * byte, and the second being the low byte.] <p>
753      *
754      * When a very large Unicode value is input to a <code>LONGVARCHAR</code>
755      * parameter, it may be more practical to send it via a
756      * <code>java.io.InputStream</code> object. The data will be read from the
757      * stream as needed until end-of-file is reached.  The JDBC driver will
758      * do any necessary conversion from Unicode to the database char format.
759      *
760      * (JDBC4 added:)
761      * The byte format of the Unicode stream must be a Java UTF-8, as defined in the
762      * Java Virtual Machine Specification.
763      *
764      * <P><B>Note:</B> This stream object can either be a standard
765      * Java stream object or your own subclass that implements the
766      * standard interface.
767      * <!-- end generic documentation -->
768      *
769      * <!-- start release-specific documentation -->
770      * <div class="ReleaseSpecificDocumentation">
771      * <h3>HSQLDB-Specific Information:</h3> <p>
772      *
773      * From 1.7.0 to 1.8.0.x, this method complies with behavior as defined by
774      * the JDBC3 specification (the stream is treated as though it has UTF16
775      * encoding). <p>
776      *
777      * Starting with 2.0, this method behaves according to the JDBC4
778      * specification (the stream is treated as though it has UTF-8
779      * encoding, as defined in the Java Virtual Machine Specification) when
780      * built under JDK 1.6+; otherwise, it behaves as defined by the JDBC3
781      * specification.  Regardless, this method is deprecated: please use
782      * setCharacterStream(...) instead.
783      * </div>
784      * <!-- end release-specific documentation -->
785      *
786      * @param parameterIndex the first parameter is 1, the second is 2, ...
787      * @param x a <code>java.io.InputStream</code> object that contains the
788      *        Unicode parameter value
789      * (JDBC4 deleted:)
790      *       [as two-byte Unicode characters]
791      * @param length the number of bytes in the stream
792      * @exception SQLException if a database access error occurs or
793      * this method is called on a closed <code>PreparedStatement</code>
794      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
795      * this method
796      * @deprecated
797      *      Sun does not include a reason, but presumably
798      *      this is because setCharacterStream is now preferred
799      */
800 
801 //#ifdef DEPRECATEDJDBC
802     public synchronized void setUnicodeStream(int parameterIndex,
803             java.io.InputStream x, int length) throws SQLException {
804 
805         checkSetParameterIndex(parameterIndex);
806 
807         String    msg = null;
808         final int ver = JDBCDatabaseMetaData.JDBC_MAJOR;
809 
810         if (x == null) {
811             throw JDBCUtil.nullArgument("x");
812         }
813 
814         // CHECKME:  Is JDBC4 clarification of UNICODE stream format retroactive?
815         if ((ver < 4) && (length % 2 != 0)) {
816             msg = "Odd length argument for UTF16 encoded stream: " + length;
817 
818             throw JDBCUtil.invalidArgument(msg);
819         }
820 
821         String       encoding = (ver < 4) ? "UTF16"
822                 : "UTF8";
823         StringWriter writer   = new StringWriter();
824 
825         try {
826             CountdownInputStream cis    = new CountdownInputStream(x);
827             InputStreamReader    reader = new InputStreamReader(cis, encoding);
828             char[]               buff   = new char[1024];
829             int                  charsRead;
830 
831             cis.setCount(length);
832 
833             while (-1 != (charsRead = reader.read(buff))) {
834                 writer.write(buff, 0, charsRead);
835             }
836         } catch (IOException ex) {
837             throw JDBCUtil.sqlException(ErrorCode.SERVER_TRANSFER_CORRUPTED,
838                                     ex.toString(), ex);
839         }
840         setParameter(parameterIndex, writer.toString());
841     }
842 
843 //#endif
844 
845     /** @todo 1.9.0 - implement streaming */
846 
847     /**
848      * <!-- start generic documentation -->
849      * Sets the designated parameter to the given input stream, which will have
850      * the specified number of bytes.
851      * When a very large binary value is input to a <code>LONGVARBINARY</code>
852      * parameter, it may be more practical to send it via a
853      * <code>java.io.InputStream</code> object. The data will be read from the
854      * stream as needed until end-of-file is reached.
855      *
856      * <P><B>Note:</B> This stream object can either be a standard
857      * Java stream object or your own subclass that implements the
858      * standard interface.
859      * <!-- end generic documentation -->
860      *
861      * <!-- start release-specific documentation -->
862      * <div class="ReleaseSpecificDocumentation">
863      * <h3>HSQLDB-Specific Information:</h3> <p>
864      *
865      * Since 1.7.2, this method works according to the standard.
866      * </div>
867      * <!-- end release-specific documentation -->
868      *
869      * @param parameterIndex the first parameter is 1, the second is 2, ...
870      * @param x the java input stream which contains the binary parameter value
871      * @param length the number of bytes in the stream
872      * @exception SQLException if a database access error occurs or
873      * this method is called on a closed <code>PreparedStatement</code>
874      */
875     public synchronized void setBinaryStream(int parameterIndex,
876             java.io.InputStream x, int length) throws SQLException {
877         setBinaryStream(parameterIndex, x, (long) length);
878     }
879 
880     /**
881      * <!-- start generic documentation -->
882      * Clears the current parameter values immediately.
883      * <P>In general, parameter values remain in force for repeated use of a
884      * statement. Setting a parameter value automatically clears its
885      * previous value.  However, in some cases it is useful to immediately
886      * release the resources used by the current parameter values; this can
887      * be done by calling the method <code>clearParameters</code>.
888      * <!-- end generic documentation -->
889      *
890      * @exception SQLException if a database access error occurs or
891      * this method is called on a closed <code>PreparedStatement</code>
892      */
893     public synchronized void clearParameters() throws SQLException {
894 
895         if (isClosed || connection.isClosed) {
896             checkClosed();
897         }
898         ArrayUtil.fillArray(parameterValues, null);
899         ArrayUtil.fillArray(parameterSet, null);
900         ArrayUtil.clearArray(ArrayUtil.CLASS_CODE_LONG, streamLengths, 0,
901                              streamLengths.length);
902     }
903 
904     //----------------------------------------------------------------------
905     // Advanced features:
906 
907     /**
908      * <p>Sets the value of the designated parameter with the given object. The second
909      * argument must be an object type; for integral values, the
910      * <code>java.lang</code> equivalent objects should be used.
911      *
912      * If the second argument is an <code>InputStream</code> then the stream must contain
913      * the number of bytes specified by scaleOrLength.  If the second argument is a
914      * <code>Reader</code> then the reader must contain the number of characters specified
915      * by scaleOrLength. If these conditions are not true the driver will generate a
916      * <code>SQLException</code> when the prepared statement is executed.
917      *
918      * <p>The given Java object will be converted to the given targetSqlType
919      * before being sent to the database.
920      *
921      * If the object has a custom mapping (is of a class implementing the
922      * interface <code>SQLData</code>),
923      * the JDBC driver should call the method <code>SQLData.writeSQL</code> to
924      * write it to the SQL data stream.
925      * If, on the other hand, the object is of a class implementing
926      * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>,  <code>NClob</code>,
927      *  <code>Struct</code>, <code>java.net.URL</code>,
928      * or <code>Array</code>, the driver should pass it to the database as a
929      * value of the corresponding SQL type.
930      *
931      * <p>Note that this method may be used to pass database-specific
932      * abstract data types.
933      *
934      * @param parameterIndex the first parameter is 1, the second is 2, ...
935      * @param x the object containing the input parameter value
936      * @param targetSqlType the SQL type (as defined in java.sql.Types) to be
937      * sent to the database. The scale argument may further qualify this type.
938      * @param scaleOrLength for <code>java.sql.Types.DECIMAL</code>
939      *          or <code>java.sql.Types.NUMERIC types</code>,
940      *          this is the number of digits after the decimal point. For
941      *          Java Object types <code>InputStream</code> and <code>Reader</code>,
942      *          this is the length
943      *          of the data in the stream or reader.  For all other types,
944      *          this value will be ignored.
945      * @exception SQLException if a database access error occurs,
946      * this method is called on a closed <code>PreparedStatement</code> or
947      *            if the Java Object specified by x is an InputStream
948      *            or Reader object and the value of the scale parameter is less
949      *            than zero
950      * @exception SQLFeatureNotSupportedException if <code>targetSqlType</code> is
951      * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
952      * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
953      * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
954      *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
955      * or  <code>STRUCT</code> data type and the JDBC driver does not support
956      * this data type
957      * @see java.sql.Types
958      */
959     public synchronized void setObject(int parameterIndex, Object x,
960                                        int targetSqlType,
961                                        int scaleOrLength) throws SQLException {
962 
963         if (x instanceof InputStream) {
964             setBinaryStream(parameterIndex, (InputStream) x, scaleOrLength);
965         } else if (x instanceof Reader) {
966             setCharacterStream(parameterIndex, (Reader) x, scaleOrLength);
967         } else {
968             setObject(parameterIndex, x);
969         }
970     }
971 
972     /**
973      * <!-- start generic documentation -->
974      * Sets the value of the designated parameter with the given object.
975      * This method is like the method <code>setObject</code>
976      * above, except that it assumes a scale of zero.
977      * <!-- end generic documentation -->
978      *
979      * <!-- start release-specific documentation -->
980      * <div class="ReleaseSpecificDocumentation">
981      * <h3>HSQLDB-Specific Information:</h3> <p>
982      *
983      * Since 1.7.2, this method supports conversions listed in the
984      * conversion table B-5 of the JDBC 3 specification.
985      * </div>
986      * <!-- end release-specific documentation -->
987      *
988      * @param parameterIndex the first parameter is 1, the second is 2, ...
989      * @param x the object containing the input parameter value
990      * @param targetSqlType the SQL type (as defined in java.sql.Types) to be
991      *                      sent to the database
992      * @exception SQLException if a database access error occurs or
993      * this method is called on a closed <code>PreparedStatement</code>
994      * @exception SQLFeatureNotSupportedException if <code>targetSqlType</code> is
995      * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
996      * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
997      * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
998      *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
999      * or  <code>STRUCT</code> data type and the JDBC driver does not support
1000      * this data type
1001      * @see #setObject(int,Object)
1002      */
1003     public synchronized void setObject(int parameterIndex, Object x,
1004                                        int targetSqlType) throws SQLException {
1005         setObject(parameterIndex, x);
1006     }
1007 
1008     /**
1009      * <!-- start generic documentation -->
1010      * <p>Sets the value of the designated parameter using the given object.
1011      * The second parameter must be of type <code>Object</code>; therefore, the
1012      * <code>java.lang</code> equivalent objects should be used for built-in types.
1013      *
1014      * <p>The JDBC specification specifies a standard mapping from
1015      * Java <code>Object</code> types to SQL types.  The given argument
1016      * will be converted to the corresponding SQL type before being
1017      * sent to the database.
1018      *
1019      * <p>Note that this method may be used to pass database-
1020      * specific abstract data types, by using a driver-specific Java
1021      * type.
1022      *
1023      * If the object is of a class implementing the interface <code>SQLData</code>,
1024      * the JDBC driver should call the method <code>SQLData.writeSQL</code>
1025      * to write it to the SQL data stream.
1026      * If, on the other hand, the object is of a class implementing
1027      * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>, (JDBC4 new:) [ <code>NClob</code> ],
1028      *  <code>Struct</code>, <code>java.net.URL</code>, (JDBC4 new:) [ <code>RowId</code>, <code>SQLXML</code> ]
1029      * or <code>Array</code>, the driver should pass it to the database as a
1030      * value of the corresponding SQL type.
1031      * <P>
1032      * <b>Note:</b> Not all databases allow for a non-typed Null to be sent to
1033      * the backend. For maximum portability, the <code>setNull</code> or the
1034      * <code>setObject(int parameterIndex, Object x, int sqlType)</code>
1035      * method should be used
1036      * instead of <code>setObject(int parameterIndex, Object x)</code>.
1037      * <p>
1038      * <b>Note:</b> This method throws an exception if there is an ambiguity, for example, if the
1039      * object is of a class implementing more than one of the interfaces named above.
1040      * <!-- end generic documentation -->
1041      *
1042      * <!-- start release-specific documentation -->
1043      * <div class="ReleaseSpecificDocumentation">
1044      * <h3>HSQLDB-Specific Information:</h3><p>
1045      *
1046      * Since 1.7.2, this method supports conversions listed in the conversion
1047      * table B-5 of the JDBC 3 specification.
1048      * </div>
1049      *
1050      * @param parameterIndex the first parameter is 1, the second is 2, ...
1051      * @param x the object containing the input parameter value
1052      * @exception SQLException if a database access error occurs,
1053      *  this method is called on a closed <code>PreparedStatement</code>
1054      * or the type of the given object is ambiguous
1055      */
1056     public synchronized void setObject(int parameterIndex,
1057                                        Object x) throws SQLException {
1058         setParameter(parameterIndex, x);
1059     }
1060 
1061     /**
1062      * <!-- start generic documentation -->
1063      * Executes the SQL statement in this <code>PreparedStatement</code> object,
1064      * which may be any kind of SQL statement.
1065      * Some prepared statements return multiple results; the <code>execute</code>
1066      * method handles these complex statements as well as the simpler
1067      * form of statements handled by the methods <code>executeQuery</code>
1068      * and <code>executeUpdate</code>.
1069      * <P>
1070      * The <code>execute</code> method returns a <code>boolean</code> to
1071      * indicate the form of the first result.  You must call either the method
1072      * <code>getResultSet</code> or <code>getUpdateCount</code>
1073      * to retrieve the result; you must call <code>getMoreResults</code> to
1074      * move to any subsequent result(s).
1075      * <!-- end generic documentation -->
1076      *
1077      * <!-- start release-specific documentation -->
1078      * <div class="ReleaseSpecificDocumentation">
1079      * <h3>HSQLDB-Specific Information:</h3> <p>
1080      *
1081      * If the statement is a call to a PROCEDURE, it may return multiple
1082      * multiple fetchable results. <p>
1083      *
1084      * </div>
1085      *
1086      * @return <code>true</code> if the first result is a <code>ResultSet</code>
1087      *         object; <code>false</code> if the first result is an update
1088      *         count or there is no result
1089      * @exception SQLException if a database access error occurs,
1090      * this method is called on a closed <code>PreparedStatement</code>
1091      * or an argument is supplied to this method
1092      * @see JDBCStatement#execute
1093      * @see JDBCStatement#getResultSet
1094      * @see JDBCStatement#getUpdateCount
1095      * @see JDBCStatement#getMoreResults
1096      *
1097      */
1098     public synchronized boolean execute() throws SQLException {
1099 
1100         fetchResult();
1101 
1102         return statementRetType == StatementTypes.RETURN_RESULT;
1103     }
1104 
1105     //--------------------------JDBC 2.0-----------------------------
1106 
1107     /**
1108      * <!-- start generic documentation -->
1109      * Adds a set of parameters to this <code>PreparedStatement</code>
1110      * object's batch of commands.
1111      * <!-- end generic documentation -->
1112      *
1113      * <!-- start release-specific documentation -->
1114      * <div class="ReleaseSpecificDocumentation">
1115      * <h3>HSQLDB-Specific Information:</h3> <p>
1116      *
1117      * Since 1.7.2, this feature is supported.
1118      * </div>
1119      * <!-- end release-specific documentation -->
1120      *
1121      * @exception SQLException if a database access error occurs or
1122      * this method is called on a closed <code>PreparedStatement</code>
1123      * @see JDBCStatement#addBatch
1124      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1125      * JDBCParameterMetaData)
1126      */
1127     public synchronized void addBatch() throws SQLException {
1128 
1129         if (isClosed || connection.isClosed) {
1130             checkClosed();
1131         }
1132         checkParametersSet();
1133 
1134         if (!isBatch) {
1135             resultOut.setBatchedPreparedExecuteRequest();
1136 
1137             isBatch = true;
1138         }
1139 
1140         try {
1141             performPreExecute();
1142         } catch (HsqlException e) {
1143             throw JDBCUtil.sqlException(e);
1144         }
1145 
1146         int      len              = parameterValues.length;
1147         Object[] batchParamValues = new Object[len];
1148 
1149         System.arraycopy(parameterValues, 0, batchParamValues, 0, len);
1150         resultOut.addBatchedPreparedExecuteRequest(batchParamValues);
1151     }
1152 
1153     /** @todo 1.9.0 - implement streaming */
1154 
1155     /**
1156      * <!-- start generic documentation -->
1157      * Sets the designated parameter to the given <code>Reader</code>
1158      * object, which is the given number of characters long.
1159      * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
1160      * parameter, it may be more practical to send it via a
1161      * <code>java.io.Reader</code> object. The data will be read from the stream
1162      * as needed until end-of-file is reached.  The JDBC driver will
1163      * do any necessary conversion from UNICODE to the database char format.
1164      *
1165      * <P><B>Note:</B> This stream object can either be a standard
1166      * Java stream object or your own subclass that implements the
1167      * standard interface.
1168      * <!-- end generic documentation -->
1169      *
1170      * <!-- start release-specific documentation -->
1171      * <div class="ReleaseSpecificDocumentation">
1172      * <h3>HSQLDB-Specific Information:</h3> <p>
1173      *
1174      * From HSQLDB 2.0 this method uses streaming to send data
1175      * when the target is a CLOB.<p>
1176      * HSQLDB represents CHARACTER and related SQL types as UTF16 Unicode
1177      * internally, so this method does not perform any conversion.
1178      * </div>
1179      * <!-- end release-specific documentation -->
1180      *
1181      * @param parameterIndex the first parameter is 1, the second is 2, ...
1182      * @param reader the <code>java.io.Reader</code> object that contains the
1183      *        Unicode data
1184      * @param length the number of characters in the stream
1185      * @exception SQLException if a database access error occurs or
1186      * this method is called on a closed <code>PreparedStatement</code>
1187      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1188      * JDBCParameterMetaData)
1189      */
1190     public synchronized void setCharacterStream(int parameterIndex,
1191             java.io.Reader reader, int length) throws SQLException {
1192         setCharacterStream(parameterIndex, reader, (long) length);
1193     }
1194 
1195     /**
1196      * <!-- start generic documentation -->
1197      * Sets the designated parameter to the given
1198      *  <code>REF(&lt;structured-type&gt;)</code> value.
1199      * The driver converts this to an SQL <code>REF</code> value when it
1200      * sends it to the database.
1201      * <!-- end generic documentation -->
1202      *
1203      * <!-- start release-specific documentation -->
1204      * <div class="ReleaseSpecificDocumentation">
1205      * <h3>HSQLDB-Specific Information:</h3> <p>
1206      *
1207      * Including 2.0 HSQLDB does not support the SQL REF type. Calling this method
1208      * throws an exception.
1209      *
1210      * </div>
1211      * <!-- end release-specific documentation -->
1212      * @param parameterIndex the first parameter is 1, the second is 2, ...
1213      * @param x an SQL <code>REF</code> value
1214      * @exception SQLException if a database access error occurs or
1215      * this method is called on a closed <code>PreparedStatement</code>
1216      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
1217      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1218      * JDBCParameterMetaData)
1219      */
1220     public void setRef(int parameterIndex, Ref x) throws SQLException {
1221         throw JDBCUtil.notSupported();
1222     }
1223 
1224     /**
1225      * <!-- start generic documentation -->
1226      * Sets the designated parameter to the given <code>java.sql.Blob</code> object.
1227      * The driver converts this to an SQL <code>BLOB</code> value when it
1228      * sends it to the database.
1229      * <!-- end generic documentation -->
1230      *
1231      * <!-- start release-specific documentation -->
1232      * <div class="ReleaseSpecificDocumentation">
1233      * <h3>HSQLDB-Specific Information:</h3> <p>
1234      *
1235      * For parameters of type Blob, setBlob works normally.<p>
1236      *
1237      * In addition since 1.7.2, setBlob is supported for BINARY and VARBINARY
1238      * parameters. In this context, the Blob object is
1239      * hard-limited to those of length less than or equal to Integer.MAX_VALUE.
1240      * In practice, soft limits such as available heap and maximum disk usage
1241      * per file (such as the transaction log) dictate a much smaller maximum
1242      * length. <p>
1243      *
1244      * For BINARY and VARBINARY parameter types setBlob(i,x) is roughly
1245      * equivalent (null and length handling not shown) to:<p>
1246      *
1247      * <pre class="JavaCodeExample">
1248      * <b>setBinaryStream</b>(i, x.<b>getBinaryStream</b>(), (<span class="JavaKeyWord">int</span>) x.<b>length</b>());
1249      * </pre></div>
1250      * <!-- end release-specific documentation -->
1251      *
1252      * @param parameterIndex the first parameter is 1, the second is 2, ...
1253      * @param x a <code>Blob</code> object that maps an SQL <code>BLOB</code> value
1254      * @exception SQLException if a database access error occurs or
1255      * this method is called on a closed <code>PreparedStatement</code>
1256      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
1257      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1258      * JDBCParameterMetaData)
1259      */
1260     public synchronized void setBlob(int parameterIndex,
1261                                      Blob x) throws SQLException {
1262 
1263         checkSetParameterIndex(parameterIndex);
1264 
1265         Type outType = parameterTypes[parameterIndex - 1];
1266 
1267         switch (outType.typeCode) {
1268 
1269             case Types.SQL_BINARY :
1270             case Types.SQL_VARBINARY :
1271                 setBlobForBinaryParameter(parameterIndex, x);
1272 
1273                 return;
1274             case Types.SQL_BLOB :
1275                 setBlobParameter(parameterIndex, x);
1276 
1277                 break;
1278             default :
1279                 throw JDBCUtil.invalidArgument();
1280         }
1281     }
1282 
1283     /**
1284      * Converts a blob to binary data for non-blob binary parameters.
1285      */
1286     private void setBlobForBinaryParameter(int parameterIndex,
1287             Blob x) throws SQLException {
1288 
1289         if (x instanceof JDBCBlob) {
1290             setParameter(parameterIndex, ((JDBCBlob) x).data());
1291 
1292             return;
1293         } else if (x == null) {
1294             setParameter(parameterIndex, null);
1295 
1296             return;
1297         }
1298 
1299         final long length = x.length();
1300 
1301         if (length > Integer.MAX_VALUE) {
1302             String msg = "Maximum Blob input octet length exceeded: " + length;    // NOI18N
1303 
1304             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR, msg);
1305         }
1306 
1307         try {
1308             java.io.InputStream in = x.getBinaryStream();
1309             HsqlByteArrayOutputStream out = new HsqlByteArrayOutputStream(in,
1310                 (int) length);
1311 
1312             setParameter(parameterIndex, out.toByteArray());
1313             out.close();
1314         } catch (Throwable e) {
1315             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR,
1316                                     e.toString(), e);
1317         }
1318     }
1319 
1320     /**
1321      * <!-- start generic documentation -->
1322      * Sets the designated parameter to the given <code>java.sql.Clob</code> object.
1323      * The driver converts this to an SQL <code>CLOB</code> value when it
1324      * sends it to the database.
1325      * <!-- end generic documentation -->
1326      *
1327      * <!-- start release-specific documentation -->
1328      * <div class="ReleaseSpecificDocumentation">
1329      * <h3>HSQLDB-Specific Information:</h3> <p>
1330      *
1331      * For parameters of type Clob, setClob works normally.<p>
1332      *
1333      * In addition since 1.7.2, setClob is supported for CHARACTER and VARCHAR
1334      * parameters. In this context, the Clob object is
1335      * hard-limited to those of length less than or equal to Integer.MAX_VALUE.
1336      * In practice, soft limits such as available heap and maximum disk usage
1337      * per file (such as the transaction log) dictate a much smaller maximum
1338      * length. <p>
1339      *
1340      * For CHARACTER and VARCHAR parameter types setClob(i,x) is roughly
1341      * equivalent (null and length handling not shown) to:<p>
1342      *
1343      * <pre class="JavaCodeExample">
1344      * <b>setCharacterStream</b>(i, x.<b>getCharacterStream</b>(), (<span class="JavaKeyWord">int</span>) x.<b>length</b>());
1345      * </pre></div>
1346      * <!-- end release-specific documentation -->
1347      * @param parameterIndex the first parameter is 1, the second is 2, ...
1348      * @param x a <code>Clob</code> object that maps an SQL <code>CLOB</code> value
1349      * @exception SQLException if a database access error occurs or
1350      * this method is called on a closed <code>PreparedStatement</code>
1351      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
1352      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1353      *  JDBCParameterMetaData)
1354      */
1355     public synchronized void setClob(int parameterIndex,
1356                                      Clob x) throws SQLException {
1357 
1358         checkSetParameterIndex(parameterIndex);
1359 
1360         Type outType = parameterTypes[parameterIndex - 1];
1361 
1362         switch (outType.typeCode) {
1363 
1364             case Types.SQL_CHAR :
1365             case Types.SQL_VARCHAR :
1366                 setClobForStringParameter(parameterIndex, x);
1367 
1368                 return;
1369             case Types.SQL_CLOB :
1370                 setClobParameter(parameterIndex, x);
1371 
1372                 return;
1373             default :
1374                 throw JDBCUtil.invalidArgument();
1375         }
1376     }
1377 
1378     private void setClobForStringParameter(int parameterIndex,
1379             Clob x) throws SQLException {
1380 
1381         if (x instanceof JDBCClob) {
1382             setParameter(parameterIndex, ((JDBCClob) x).data());
1383 
1384             return;
1385         } else if (x == null) {
1386             setParameter(parameterIndex, null);
1387 
1388             return;
1389         }
1390 
1391         final long length = x.length();
1392 
1393         if (length > Integer.MAX_VALUE) {
1394             String msg = "Max Clob input character length exceeded: " + length;    // NOI18N
1395 
1396             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR, msg);
1397         }
1398 
1399         try {
1400             java.io.Reader  reader = x.getCharacterStream();
1401             CharArrayWriter writer = new CharArrayWriter(reader, (int) length);
1402 
1403             setParameter(parameterIndex, writer.toString());
1404         } catch (Throwable e) {
1405             throw JDBCUtil.sqlException(ErrorCode.SERVER_TRANSFER_CORRUPTED,
1406                                     e.toString(), e);
1407         }
1408     }
1409 
1410     /**
1411      * <!-- start generic documentation -->
1412      * Sets the designated parameter to the given <code>java.sql.Array</code> object.
1413      * The driver converts this to an SQL <code>ARRAY</code> value when it
1414      * sends it to the database.
1415      * <!-- end generic documentation -->
1416      *
1417      * <!-- start release-specific documentation -->
1418      * <div class="ReleaseSpecificDocumentation">
1419      * <h3>HSQLDB-Specific Information:</h3> <p>
1420      *
1421      * From version 2.0, HSQLDB supports the SQL ARRAY type.
1422      *
1423      * </div>
1424      * <!-- end release-specific documentation -->
1425      *
1426      * @param parameterIndex the first parameter is 1, the second is 2, ...
1427      * @param x an <code>Array</code> object that maps an SQL <code>ARRAY</code> value
1428      * @exception SQLException if a database access error occurs or
1429      * this method is called on a closed <code>PreparedStatement</code>
1430      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
1431      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1432      *   JDBCParameterMetaData)
1433      */
1434     public synchronized void setArray(int parameterIndex,
1435                                       Array x) throws SQLException {
1436 
1437         checkParameterIndex(parameterIndex);
1438 
1439         Type type = this.parameterMetaData.columnTypes[parameterIndex - 1];
1440 
1441         if (!type.isArrayType()) {
1442             throw JDBCUtil.sqlException(ErrorCode.X_42561);
1443         }
1444 
1445         if (x == null) {
1446             setParameter(parameterIndex, null);
1447 
1448             return;
1449         }
1450 
1451         Object[] data = null;
1452 
1453         if (x instanceof JDBCArray) {
1454             data = ((JDBCArray) x).getArrayInternal();
1455         } else {
1456             Object object = x.getArray();
1457 
1458             if (object instanceof Object[]) {
1459                 Type     baseType = type.collectionBaseType();
1460                 Object[] array    = (Object[]) object;
1461 
1462                 data = new Object[array.length];
1463 
1464                 for (int i = 0; i < data.length; i++) {
1465                     data[i] = baseType.convertJavaToSQL(session, array[i]);
1466                 }
1467             } else {
1468 
1469                 // if foreign data is not Object[]
1470                 throw JDBCUtil.notSupported();
1471             }
1472         }
1473         parameterValues[parameterIndex - 1] = data;
1474         parameterSet[parameterIndex - 1]    = Boolean.TRUE;
1475     }
1476 
1477     /**
1478      * <!-- start generic documentation -->
1479      * Retrieves a <code>ResultSetMetaData</code> object that contains
1480      * information about the columns of the <code>ResultSet</code> object
1481      * that will be returned when this <code>PreparedStatement</code> object
1482      * is executed.
1483      * <P>
1484      * Because a <code>PreparedStatement</code> object is pre-compiled, it is
1485      * possible to know about the <code>ResultSet</code> object that it will
1486      * return without having to execute it.  Consequently, it is possible
1487      * to invoke the method <code>getMetaData</code> on a
1488      * <code>PreparedStatement</code> object rather than waiting to execute
1489      * it and then invoking the <code>ResultSet.getMetaData</code> method
1490      * on the <code>ResultSet</code> object that is returned.
1491      * <P>
1492      * <B>NOTE:</B> Using this method may be expensive for some drivers due
1493      * to the lack of underlying DBMS support.
1494      * <!-- end generic documentation -->
1495      *
1496      * <!-- start release-specific documentation -->
1497      * <div class="ReleaseSpecificDocumentation">
1498      * <h3>HSQLDB-Specific Information:</h3> <p>
1499      *
1500      * Since 1.7.2, this feature is supported and is <em>inexpensive</em> as
1501      * it is backed by underlying DBMS support.  If the statement
1502      * generates an update count, then null is returned.
1503      * </div>
1504      * <!-- end release-specific documentation -->
1505      * @return the description of a <code>ResultSet</code> object's columns or
1506      *         <code>null</code> if the driver cannot return a
1507      *         <code>ResultSetMetaData</code> object
1508      * @exception SQLException if a database access error occurs or
1509      * this method is called on a closed <code>PreparedStatement</code>
1510      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
1511      * this method
1512      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1513      *   JDBCParameterMetaData)
1514      */
1515     public synchronized ResultSetMetaData getMetaData() throws SQLException {
1516 
1517         if (isClosed || connection.isClosed) {
1518             checkClosed();
1519         }
1520 
1521         if (statementRetType != StatementTypes.RETURN_RESULT) {
1522             return null;
1523         }
1524 
1525         if (resultSetMetaData == null) {
1526             boolean isUpdatable  = ResultProperties.isUpdatable(rsProperties);
1527             boolean isInsertable = isUpdatable;
1528 
1529             if (isInsertable) {
1530                 for (int i = 0; i < resultMetaData.colIndexes.length; i++) {
1531                     if (resultMetaData.colIndexes[i] < 0) {
1532                         isInsertable = false;
1533 
1534                         break;
1535                     }
1536                 }
1537             }
1538             resultSetMetaData = new JDBCResultSetMetaData(resultMetaData,
1539                     isUpdatable, isInsertable, connection);
1540         }
1541 
1542         return resultSetMetaData;
1543     }
1544 
1545     /**
1546      * <!-- start generic documentation -->
1547      * Sets the designated parameter to the given <code>java.sql.Date</code> value,
1548      * using the given <code>Calendar</code> object.  The driver uses
1549      * the <code>Calendar</code> object to construct an SQL <code>DATE</code> value,
1550      * which the driver then sends to the database.  With
1551      * a <code>Calendar</code> object, the driver can calculate the date
1552      * taking into account a custom timezone.  If no
1553      * <code>Calendar</code> object is specified, the driver uses the default
1554      * timezone, which is that of the virtual machine running the application.
1555      * <!-- end generic documentation -->
1556      *
1557      * @param parameterIndex the first parameter is 1, the second is 2, ...
1558      * @param x the parameter value
1559      * @param cal the <code>Calendar</code> object the driver will use
1560      *            to construct the date
1561      * @exception SQLException if a database access error occurs or
1562      * this method is called on a closed <code>PreparedStatement</code>
1563      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1564      *   JDBCParameterMetaData)
1565      */
1566     public synchronized void setDate(int parameterIndex, Date x,
1567                                      Calendar cal) throws SQLException {
1568 
1569         checkSetParameterIndex(parameterIndex);
1570 
1571         int i = parameterIndex - 1;
1572 
1573         if (x == null) {
1574             parameterValues[i] = null;
1575             parameterSet[i]    = Boolean.TRUE;
1576 
1577             return;
1578         }
1579 
1580         Type outType = parameterTypes[i];
1581         Calendar calendar = cal == null ? session.getCalendar()
1582                 : cal;
1583 
1584         long millis = HsqlDateTime.convertMillisFromCalendar(
1585                 session.getCalendarGMT(), calendar, x.getTime());
1586 
1587         millis = HsqlDateTime.getNormalisedDate(session.getCalendarGMT(),
1588                 millis);
1589 
1590         switch (outType.typeCode) {
1591 
1592             case Types.SQL_DATE :
1593             case Types.SQL_TIMESTAMP :
1594                 parameterValues[i] = new TimestampData(millis / 1000);
1595 
1596                 break;
1597             case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
1598                 int zoneOffset = HsqlDateTime.getZoneMillis(calendar, millis);
1599 
1600                 parameterValues[i] = new TimestampData(millis / 1000, 0,
1601                         zoneOffset / 1000);
1602 
1603                 break;
1604             default :
1605                 throw JDBCUtil.sqlException(ErrorCode.X_42561);
1606         }
1607         parameterSet[i] = Boolean.TRUE;
1608     }
1609 
1610     /**
1611      * <!-- start generic documentation -->
1612      * Sets the designated parameter to the given <code>java.sql.Time</code> value,
1613      * using the given <code>Calendar</code> object.  The driver uses
1614      * the <code>Calendar</code> object to construct an SQL <code>TIME</code> value,
1615      * which the driver then sends to the database.  With
1616      * a <code>Calendar</code> object, the driver can calculate the time
1617      * taking into account a custom timezone.  If no
1618      * <code>Calendar</code> object is specified, the driver uses the default
1619      * timezone, which is that of the virtual machine running the application.
1620      * <!-- end generic documentation -->
1621      * <div class="ReleaseSpecificDocumentation">
1622      * <h3>HSQLDB-Specific Information:</h3> <p>
1623      *
1624      * When a setXXX method is used to set a parameter of type
1625      * TIMESTAMP WITH TIME ZONE or TIME WITH TIME ZONE the time zone (including
1626      * Daylight Saving Time) of the Calendar is used as time zone for the
1627      * value.<p>
1628      *
1629      * </div>
1630      * <!-- end release-specific documentation -->
1631      *
1632      * @param parameterIndex the first parameter is 1, the second is 2, ...
1633      * @param x the parameter value
1634      * @param cal the <code>Calendar</code> object the driver will use
1635      *            to construct the time
1636      * @exception SQLException if a database access error occurs or
1637      * this method is called on a closed <code>PreparedStatement</code>
1638      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1639      *   JDBCParameterMetaData)
1640      */
1641     public synchronized void setTime(int parameterIndex, Time x,
1642                                      Calendar cal) throws SQLException {
1643 
1644         checkSetParameterIndex(parameterIndex);
1645 
1646         int i = parameterIndex - 1;
1647 
1648         if (x == null) {
1649             parameterValues[i] = null;
1650             parameterSet[i]    = Boolean.TRUE;
1651 
1652             return;
1653         }
1654 
1655         Type     outType    = parameterTypes[i];
1656         long     millis     = x.getTime();
1657         int      zoneOffset = 0;
1658         Calendar calendar   = cal == null ? session.getCalendar()
1659                 : cal;
1660 
1661         millis = HsqlDateTime.convertMillisFromCalendar(
1662                 session.getCalendarGMT(), calendar, millis);
1663         millis = HsqlDateTime.convertToNormalisedTime(millis,
1664                 session.getCalendarGMT());
1665 
1666         switch (outType.typeCode) {
1667 
1668             case Types.SQL_TIME :
1669                 break;
1670             case Types.SQL_TIME_WITH_TIME_ZONE :
1671                 zoneOffset = HsqlDateTime.getZoneMillis(calendar, millis);
1672 
1673                 break;
1674             default :
1675                 throw JDBCUtil.sqlException(ErrorCode.X_42561);
1676         }
1677         parameterValues[i] = new TimeData((int) (millis / 1000), 0,
1678                 zoneOffset / 1000);
1679         parameterSet[i] = Boolean.TRUE;
1680     }
1681 
1682     /**
1683      * <!-- start generic documentation -->
1684      * Sets the designated parameter to the given <code>java.sql.Timestamp</code> value,
1685      * using the given <code>Calendar</code> object.  The driver uses
1686      * the <code>Calendar</code> object to construct an SQL <code>TIMESTAMP</code> value,
1687      * which the driver then sends to the database.  With a
1688      *  <code>Calendar</code> object, the driver can calculate the timestamp
1689      * taking into account a custom timezone.  If no
1690      * <code>Calendar</code> object is specified, the driver uses the default
1691      * timezone, which is that of the virtual machine running the application.
1692      * <!-- end generic documentation -->
1693      * <div class="ReleaseSpecificDocumentation">
1694      * <h3>HSQLDB-Specific Information:</h3> <p>
1695      *
1696      * When a setXXX method is used to set a parameter of type
1697      * TIMESTAMP WITH TIME ZONE or TIME WITH TIME ZONE the time zone (including
1698      * Daylight Saving Time) of the Calendar is used as time zone.<p>
1699      * In this case, if the Calendar argument is null, then the default Calendar
1700      * for the clients JVM is used as the Calendar<p>
1701      *
1702      * When this method is used to set a parameter of type TIME or
1703      * TIME WITH TIME ZONE, then the nanosecond value of the Timestamp object
1704      * is used if the TIME parameter accepts fractional seconds.<p>
1705      *
1706      * </div>
1707      * <!-- end release-specific documentation -->
1708      *
1709      * @param parameterIndex the first parameter is 1, the second is 2, ...
1710      * @param x the parameter value
1711      * @param cal the <code>Calendar</code> object the driver will use
1712      *            to construct the timestamp
1713      * @exception SQLException if a database access error occurs or
1714      * this method is called on a closed <code>PreparedStatement</code>
1715      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1716      *   JDBCParameterMetaData)
1717      */
1718     public synchronized void setTimestamp(int parameterIndex, Timestamp x,
1719             Calendar cal) throws SQLException {
1720 
1721         checkSetParameterIndex(parameterIndex);
1722 
1723         int i = parameterIndex - 1;
1724 
1725         if (x == null) {
1726             parameterValues[i] = null;
1727             parameterSet[i]    = Boolean.TRUE;
1728 
1729             return;
1730         }
1731 
1732         Type     outType    = parameterTypes[i];
1733         long     millis     = x.getTime();
1734         long     seconds;
1735         int      zoneOffset = 0;
1736         Calendar calendar   = cal == null ? session.getCalendar()
1737                 : cal;
1738 
1739         millis = HsqlDateTime.convertMillisFromCalendar(
1740                 session.getCalendarGMT(),calendar, millis);
1741         switch (outType.typeCode) {
1742 
1743             case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
1744                 zoneOffset = HsqlDateTime.getZoneMillis(calendar, millis);
1745 
1746             // fall through
1747             case Types.SQL_TIMESTAMP :
1748                 seconds    = millis / 1000;
1749                 if (seconds < DateTimeType.epochSeconds
1750                     || seconds > DateTimeType.limitSeconds) {
1751                     throw Error.error(ErrorCode.X_22008);
1752                 }
1753                 parameterValues[i] = new TimestampData(seconds,
1754                         x.getNanos(), zoneOffset / 1000);
1755 
1756                 break;
1757             case Types.SQL_TIME :
1758                 millis = HsqlDateTime.getNormalisedTime(
1759                         session.getCalendarGMT(), millis);
1760                 parameterValues[i] = new TimeData((int) (millis / 1000),
1761                         x.getNanos(), 0);
1762 
1763                 break;
1764             case Types.SQL_TIME_WITH_TIME_ZONE :
1765                 millis = HsqlDateTime.getNormalisedTime(
1766                         session.getCalendarGMT(), millis);
1767                 zoneOffset = HsqlDateTime.getZoneMillis(calendar, millis);
1768                 parameterValues[i] = new TimeData((int) (millis / 1000),
1769                         x.getNanos(), zoneOffset / 1000);
1770 
1771                 break;
1772             case Types.SQL_DATE :
1773                 millis  = HsqlDateTime.getNormalisedDate(
1774                         session.getCalendarGMT(), millis);
1775                 seconds = millis / 1000;
1776 
1777                 if (seconds < DateTimeType.epochSeconds
1778                     || seconds > DateTimeType.limitSeconds) {
1779                     throw Error.error(ErrorCode.X_22008);
1780                 }
1781 
1782                 parameterValues[i] = new TimestampData(seconds);
1783 
1784                 break;
1785             default :
1786                 throw JDBCUtil.sqlException(ErrorCode.X_42561);
1787         }
1788         parameterSet[i] = Boolean.TRUE;
1789     }
1790 
1791     /**
1792      * <!-- start generic documentation -->
1793      * Sets the designated parameter to SQL <code>NULL</code>.
1794      * This version of the method <code>setNull</code> should
1795      * be used for user-defined types and REF type parameters.  Examples
1796      * of user-defined types include: STRUCT, DISTINCT, JAVA_OBJECT, and
1797      * named array types.
1798      *
1799      * <P><B>Note:</B> To be portable, applications must give the
1800      * SQL type code and the fully-qualified SQL type name when specifying
1801      * a NULL user-defined or REF parameter.  In the case of a user-defined type
1802      * the name is the type name of the parameter itself.  For a REF
1803      * parameter, the name is the type name of the referenced type.  If
1804      * a JDBC driver does not need the type code or type name information,
1805      * it may ignore it.
1806      *
1807      * Although it is intended for user-defined and Ref parameters,
1808      * this method may be used to set a null parameter of any JDBC type.
1809      * If the parameter does not have a user-defined or REF type, the given
1810      * typeName is ignored.
1811      *
1812      * <!-- end generic documentation -->
1813      *
1814      * <!-- start release-specific documentation -->
1815      * <div class="ReleaseSpecificDocumentation">
1816      * <h3>HSQLDB-Specific Information:</h3> <p>
1817      *
1818      * HSQLDB simply ignores the sqlType and typeName arguments.
1819      * </div>
1820      * <!-- end release-specific documentation -->
1821      *
1822      * @param parameterIndex the first parameter is 1, the second is 2, ...
1823      * @param sqlType a value from <code>java.sql.Types</code>
1824      * @param typeName the fully-qualified name of an SQL user-defined type;
1825      *  ignored if the parameter is not a user-defined type or REF
1826      * @exception SQLException if a database access error occurs or
1827      * this method is called on a closed <code>PreparedStatement</code>
1828      * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
1829      * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
1830      * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
1831      * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
1832      *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
1833      * or  <code>STRUCT</code> data type and the JDBC driver does not support
1834      * this data type or if the JDBC driver does not support this method
1835      * @since JDK 1.2 (JDK 1.1.x developers: read the overview for
1836      *   JDBCParameterMetaData)
1837      */
1838     public synchronized void setNull(int parameterIndex, int sqlType,
1839                                      String typeName) throws SQLException {
1840         setParameter(parameterIndex, null);
1841     }
1842 
1843     //------------------------- JDBC 2.0 - overriden methods -------------------
1844 
1845     /**
1846      * <!-- start generic documentation -->
1847      * Submits a batch of commands to the database for execution and
1848      * if all commands execute successfully, returns an array of update counts.
1849      * The <code>int</code> elements of the array that is returned are ordered
1850      * to correspond to the commands in the batch, which are ordered
1851      * according to the order in which they were added to the batch.
1852      * The elements in the array returned by the method <code>executeBatch</code>
1853      * may be one of the following:
1854      * <OL>
1855      * <LI>A number greater than or equal to zero -- indicates that the
1856      * command was processed successfully and is an update count giving the
1857      * number of rows in the database that were affected by the command's
1858      * execution
1859      * <LI>A value of <code>SUCCESS_NO_INFO</code> -- indicates that the command was
1860      * processed successfully but that the number of rows affected is
1861      * unknown
1862      * <P>
1863      * If one of the commands in a batch update fails to execute properly,
1864      * this method throws a <code>BatchUpdateException</code>, and a JDBC
1865      * driver may or may not continue to process the remaining commands in
1866      * the batch.  However, the driver's behavior must be consistent with a
1867      * particular DBMS, either always continuing to process commands or never
1868      * continuing to process commands.  If the driver continues processing
1869      * after a failure, the array returned by the method
1870      * <code>BatchUpdateException.getUpdateCounts</code>
1871      * will contain as many elements as there are commands in the batch, and
1872      * at least one of the elements will be the following:
1873      * <P>
1874      * <LI>A value of <code>EXECUTE_FAILED</code> -- indicates that the command failed
1875      * to execute successfully and occurs only if a driver continues to
1876      * process commands after a command fails
1877      * </OL>
1878      * <P>
1879      * A driver is not required to implement this method.
1880      * The possible implementations and return values have been modified in
1881      * the Java 2 SDK, Standard Edition, version 1.3 to
1882      * accommodate the option of continuing to proccess commands in a batch
1883      * update after a <code>BatchUpdateException</code> object has been thrown. <p>
1884      * <!-- end generic documentation -->
1885      *
1886      * <!-- start release-specific documentation -->
1887      * <div class="ReleaseSpecificDocumentation">
1888      * <h3>HSQLDB-Specific Information:</h3> <p>
1889      *
1890      * Starting with HSQLDB 1.7.2, this feature is supported. <p>
1891      *
1892      * HSQLDB stops execution of commands in a batch when one of the commands
1893      * results in an exception. The size of the returned array equals the
1894      * number of commands that were executed successfully.<p>
1895      *
1896      * </div>
1897      * <!-- end release-specific documentation -->
1898      *
1899      * @return an array of update counts containing one element for each
1900      * command in the batch.  The elements of the array are ordered according
1901      * to the order in which commands were added to the batch.
1902      * @exception SQLException if a database access error occurs,
1903      * this method is called on a closed <code>Statement</code> or the
1904      * driver does not support batch statements. Throws {@link BatchUpdateException}
1905      * (a subclass of <code>SQLException</code>) if one of the commands sent to the
1906      * database fails to execute properly or attempts to return a result set.
1907      *
1908      *
1909      * @see #addBatch
1910      * @see java.sql.DatabaseMetaData#supportsBatchUpdates()
1911      * @since JDK 1.3 (JDK 1.1.x developers: read the overview for
1912      * JDBCStatement)
1913      */
1914     public synchronized int[] executeBatch() throws SQLException {
1915 
1916         if (isClosed || connection.isClosed) {
1917             checkClosed();
1918         }
1919         checkStatementType(StatementTypes.RETURN_COUNT);
1920 
1921         if (!isBatch) {
1922             if (connection.isEmptyBatchAllowed) {
1923                 return ValuePool.emptyIntArray;
1924             }
1925 
1926             throw JDBCUtil.sqlExceptionSQL(ErrorCode.X_07506);
1927         }
1928         generatedResult = null;
1929 
1930         int batchCount = resultOut.getNavigator().getSize();
1931 
1932         resultIn = null;
1933 
1934         try {
1935             resultIn = session.execute(resultOut);
1936         } catch (HsqlException e) {
1937             throw JDBCUtil.sqlException(e);
1938         } finally {
1939             performPostExecute();
1940             resultOut.getNavigator().clear();
1941 
1942             isBatch = false;
1943         }
1944 
1945         if (resultIn.mode == ResultConstants.ERROR) {
1946             throw JDBCUtil.sqlException(resultIn);
1947         }
1948 
1949         RowSetNavigator navigator    = resultIn.getNavigator();
1950         int[]           updateCounts = new int[navigator.getSize()];
1951 
1952         for (int i = 0; i < updateCounts.length; i++) {
1953             Object[] data = navigator.getNext();
1954 
1955             updateCounts[i] = ((Integer) data[0]).intValue();
1956         }
1957 
1958         if (updateCounts.length != batchCount) {
1959             if (errorResult == null) {
1960                 throw new BatchUpdateException(updateCounts);
1961             } else {
1962                 throw new BatchUpdateException(errorResult.getMainString(),
1963                         errorResult.getSubString(),
1964                         errorResult.getErrorCode(), updateCounts);
1965             }
1966         }
1967 
1968         return updateCounts;
1969     }
1970 
1971     /**
1972      * <!-- start generic documentation -->
1973      * Sets escape processing on or off. <p>
1974      * <!-- end generic documentation -->
1975      *
1976      * <!-- start release-specific documentation -->
1977      * <div class="ReleaseSpecificDocumentation">
1978      * <h3>HSQLDB-Specific Information:</h3> <p>
1979      *
1980      * As per JDBC spec, calling this method has no effect.
1981      * </div>
1982      * <!-- end release-specific documentation -->
1983      *
1984      * @param enable <code>true</code> to enable escape processing;
1985      *     <code>false</code> to disable it
1986      * @exception SQLException if a database access error occurs
1987      */
1988     public void setEscapeProcessing(boolean enable) throws SQLException {
1989         checkClosed();
1990     }
1991 
1992     /**
1993      * This method should always throw if called for a PreparedStatement or
1994      * CallableStatement.
1995      *
1996      * @param sql ignored
1997      * @throws SQLException always
1998      */
1999     public void addBatch(String sql) throws SQLException {
2000         throw JDBCUtil.notSupported();
2001     }
2002 
2003     /**
2004      * This method should always throw if called for a PreparedStatement or
2005      * CallableStatement.
2006      *
2007      * @param sql ignored
2008      * @throws SQLException always
2009      * @return nothing
2010      */
2011     public synchronized ResultSet executeQuery(
2012             String sql) throws SQLException {
2013         throw JDBCUtil.notSupported();
2014     }
2015 
2016     /**
2017      * This method should always throw if called for a PreparedStatement or
2018      * CallableStatement.
2019      *
2020      * @param sql ignored
2021      * @throws SQLException always
2022      * @return nothing
2023      */
2024     public boolean execute(String sql) throws SQLException {
2025         throw JDBCUtil.notSupported();
2026     }
2027 
2028     /**
2029      * This method should always throw if called for a PreparedStatement or
2030      * CallableStatement.
2031      *
2032      * @param sql ignored
2033      * @throws SQLException always
2034      * @return nothing
2035      */
2036     public int executeUpdate(String sql) throws SQLException {
2037         throw JDBCUtil.notSupported();
2038     }
2039 
2040     /**
2041      * Does the specialized work required to free this object's resources and
2042      * that of it's parent class. <p>
2043      *
2044      * @throws SQLException if a database access error occurs
2045      */
2046     public synchronized void close() throws SQLException {
2047 
2048         if (isClosed()) {
2049             return;
2050         }
2051         closeResultData();
2052 
2053         HsqlException he = null;
2054 
2055         try {
2056 
2057             // fredt - if this is called by Connection.close() then there's no
2058             // need to free the prepared statements on the server - it is done
2059             // by Connection.close()
2060             if (!connection.isClosed) {
2061                 session.execute(Result.newFreeStmtRequest(statementID));
2062             }
2063         } catch (HsqlException e) {
2064             he = e;
2065         }
2066         parameterValues   = null;
2067         parameterSet      = null;
2068         parameterTypes    = null;
2069         parameterModes    = null;
2070         resultMetaData    = null;
2071         parameterMetaData = null;
2072         resultSetMetaData = null;
2073         pmd               = null;
2074         connection        = null;
2075         session           = null;
2076         resultIn          = null;
2077         resultOut         = null;
2078         isClosed          = true;
2079 
2080         if (he != null) {
2081             throw JDBCUtil.sqlException(he);
2082         }
2083     }
2084 
2085     /**
2086      * Retrieves a String representation of this object.  <p>
2087      *
2088      * The representation is of the form: <p>
2089      *
2090      * class-name@hash[sql=[char-sequence], parameters=[p1, ...pi, ...pn]] <p>
2091      *
2092      * p1, ...pi, ...pn are the String representations of the currently set
2093      * parameter values that will be used with the non-batch execution
2094      * methods. <p>
2095      *
2096      * @return a String representation of this object
2097      */
2098     public String toString() {
2099 
2100         StringBuffer sb = new StringBuffer();
2101         String       sql;
2102         Object[]     pv;
2103 
2104         sb.append(super.toString());
2105 
2106         sql = this.sql;
2107         pv  = parameterValues;
2108 
2109         if (sql == null || pv == null) {
2110             sb.append("[closed]");
2111 
2112             return sb.toString();
2113         }
2114         sb.append("[sql=[").append(sql).append("]");
2115 
2116         if (pv.length > 0) {
2117             sb.append(", parameters=[");
2118 
2119             for (int i = 0; i < pv.length; i++) {
2120                 sb.append('[');
2121                 sb.append(pv[i]);
2122                 sb.append("], ");
2123             }
2124             sb.setLength(sb.length() - 2);
2125             sb.append(']');
2126         }
2127         sb.append(']');
2128 
2129         return sb.toString();
2130     }
2131 
2132     //------------------------- JDBC 3.0 -----------------------------------
2133 
2134     /**
2135      * <!-- start generic documentation -->
2136      * Sets the designated parameter to the given <code>java.net.URL</code> value.
2137      * The driver converts this to an SQL <code>DATALINK</code> value
2138      * when it sends it to the database.
2139      * <!-- end generic documentation -->
2140      *
2141      * <!-- start release-specific documentation -->
2142      * <div class="ReleaseSpecificDocumentation">
2143      * <h3>HSQLDB-Specific Information:</h3> <p>
2144      *
2145      * Including 2.0, HSQLDB does not support the DATALINK SQL type for which this
2146      * method is intended. Calling this method throws an exception.
2147      *
2148      * </div>
2149      * <!-- end release-specific documentation -->
2150      * @param parameterIndex the first parameter is 1, the second is 2, ...
2151      * @param x the <code>java.net.URL</code> object to be set
2152      * @exception SQLException if a database access error occurs or
2153      * this method is called on a closed <code>PreparedStatement</code>
2154      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2155      * @since JDK 1.4, HSQL 1.7.0
2156      */
2157     public void setURL(int parameterIndex,
2158                        java.net.URL x) throws SQLException {
2159         throw JDBCUtil.notSupported();
2160     }
2161 
2162     /**
2163      * <!-- start generic documentation -->
2164      * Retrieves the number, types and properties of this
2165      * <code>PreparedStatement</code> object's parameters.
2166      * <!-- end generic documentation -->
2167      *
2168      * <!-- start release-specific documentation -->
2169      * <div class="ReleaseSpecificDocumentation">
2170      * <h3>HSQLDB-Specific Information:</h3> <p>
2171      *
2172      * Since 1.7.2, this feature is supported.
2173      * </div>
2174      * <!-- end release-specific documentation -->
2175      *
2176      * @return a <code>ParameterMetaData</code> object that contains information
2177      *         about the number, types and properties for each
2178      *  parameter marker of this <code>PreparedStatement</code> object
2179      * @exception SQLException if a database access error occurs or
2180      * this method is called on a closed <code>PreparedStatement</code>
2181      * @see java.sql.ParameterMetaData
2182      * @since JDK 1.4, HSQL 1.7.0
2183      */
2184     public synchronized ParameterMetaData getParameterMetaData() throws SQLException {
2185 
2186         checkClosed();
2187 
2188         if (pmd == null) {
2189             pmd = new JDBCParameterMetaData(connection, parameterMetaData);
2190         }
2191 
2192         // NOTE:  pmd is declared as Object to avoid yet another #ifdef.
2193         return (ParameterMetaData) pmd;
2194     }
2195 
2196     /**
2197      * Statement methods that must be overridden in this class and throw
2198      * an exception.
2199      */
2200     public int executeUpdate(String sql,
2201                              int autoGeneratedKeys) throws SQLException {
2202         throw JDBCUtil.notSupported();
2203     }
2204 
2205     public boolean execute(String sql,
2206                            int autoGeneratedKeys) throws SQLException {
2207         throw JDBCUtil.notSupported();
2208     }
2209 
2210     public int executeUpdate(String sql,
2211                              int[] columnIndexes) throws SQLException {
2212         throw JDBCUtil.notSupported();
2213     }
2214 
2215     public boolean execute(String sql,
2216                            int[] columnIndexes) throws SQLException {
2217         throw JDBCUtil.notSupported();
2218     }
2219 
2220     public int executeUpdate(String sql,
2221                              String[] columnNames) throws SQLException {
2222         throw JDBCUtil.notSupported();
2223     }
2224 
2225     public boolean execute(String sql,
2226                            String[] columnNames) throws SQLException {
2227         throw JDBCUtil.notSupported();
2228     }
2229 
2230     /**
2231      * <!-- start generic documentation -->
2232      * Moves to this <code>Statement</code> object's next result, deals with
2233      * any current <code>ResultSet</code> object(s) according  to the instructions
2234      * specified by the given flag, and returns
2235      * <code>true</code> if the next result is a <code>ResultSet</code> object.
2236      *
2237      * <P>There are no more results when the following is true:
2238      * <PRE>
2239      *     // stmt is a Statement object
2240      *     ((stmt.getMoreResults(current) == false) && (stmt.getUpdateCount() == -1))
2241      * </PRE>
2242      * <!-- end generic documentation -->
2243      *
2244      * <!-- start release-specific documentation -->
2245      * <div class="ReleaseSpecificDocumentation">
2246      * <h3>HSQLDB-Specific Information:</h3> <p>
2247      *
2248      * HSQLDB supports this feature. <p>
2249      *
2250      * This is used with CallableStatement objects that return multiple
2251      * ResultSet objects.
2252      * </div>
2253      * <!-- end release-specific documentation -->
2254      *
2255      * @param current one of the following <code>Statement</code>
2256      *        constants indicating what should happen to current
2257      *        <code>ResultSet</code> objects obtained using the method
2258      *        <code>getResultSet</code>:
2259      *        <code>Statement.CLOSE_CURRENT_RESULT</code>,
2260      *        <code>Statement.KEEP_CURRENT_RESULT</code>, or
2261      *        <code>Statement.CLOSE_ALL_RESULTS</code>
2262      * @return <code>true</code> if the next result is a <code>ResultSet</code>
2263      *         object; <code>false</code> if it is an update count or there are no
2264      *         more results
2265      * @exception SQLException if a database access error occurs,
2266      * this method is called on a closed <code>Statement</code> or the argument
2267      *             supplied is not one of the following:
2268      *        <code>Statement.CLOSE_CURRENT_RESULT</code>,
2269      *        <code>Statement.KEEP_CURRENT_RESULT</code>, or
2270      *        <code>Statement.CLOSE_ALL_RESULTS</code>
2271      * @since JDK 1.4, HSQLDB 1.7
2272      * @see #execute
2273      */
2274     public synchronized boolean getMoreResults(
2275             int current) throws SQLException {
2276         return super.getMoreResults(current);
2277     }
2278 
2279     /**
2280      * <!-- start generic documentation -->
2281      * Retrieves any auto-generated keys created as a result of executing this
2282      * <code>Statement</code> object. If this <code>Statement</code> object did
2283      * not generate any keys, an empty <code>ResultSet</code>
2284      * object is returned.
2285      * <p>(JDBC4 clarification:)
2286      * <p><B>Note:</B>If the columns which represent the auto-generated keys were not specified,
2287      * the JDBC driver implementation will determine the columns which best represent the auto-generated keys.
2288      * <!-- end generic documentation -->
2289      *
2290      * <!-- start release-specific documentation -->
2291      * <div class="ReleaseSpecificDocumentation">
2292      * <h3>HSQLDB-Specific Information:</h3> <p>
2293      *
2294      * Starting with version 2.0, HSQLDB supports this feature with single-row and
2295      * multi-row insert, update and merge statements. <p>
2296      *
2297      * This method returns a result set only if
2298      * the executeUpdate methods that was used is one of the three methods that
2299      * have the extra parameter indicating return of generated keys<p>
2300      *
2301      * If the executeUpdate method did not specify the columns which represent
2302      * the auto-generated keys the IDENTITY column or GENERATED column(s) of the
2303      * table are returned.<p>
2304      *
2305      * The executeUpdate methods with column indexes or column names return the
2306      * post-insert or post-update values of the specified columns, whether the
2307      * columns are generated or not. This allows values that have been modified
2308      * by execution of triggers to be returned.<p>
2309      *
2310      * If column names or indexes provided by the user in the executeUpdate()
2311      * method calls do not correspond to table columns (incorrect names or
2312      * indexes larger than the column count), an empty result is returned.
2313      *
2314      * </div>
2315      * <!-- end release-specific documentation -->
2316      *
2317      * @return a <code>ResultSet</code> object containing the auto-generated key(s)
2318      *         generated by the execution of this <code>Statement</code> object
2319      * @exception SQLException if a database access error occurs or
2320      * this method is called on a closed <code>Statement</code>
2321      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2322      * @since JDK 1.4, HSQLDB 1.7
2323      */
2324     public synchronized ResultSet getGeneratedKeys() throws SQLException {
2325         return getGeneratedResultSet();
2326     }
2327 
2328     /**
2329      * <!-- start generic documentation -->
2330      * Retrieves the result set holdability for <code>ResultSet</code> objects
2331      * generated by this <code>Statement</code> object.
2332      * <!-- end generic documentation -->
2333      *
2334      * @return either <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
2335      *         <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
2336      * @exception SQLException if a database access error occurs or
2337      * this method is called on a closed <code>Statement</code>
2338      * @since JDK 1.4, HSQLDB 1.7
2339      */
2340     public synchronized int getResultSetHoldability() throws SQLException {
2341 
2342         if (isClosed || connection.isClosed) {
2343             checkClosed();
2344         }
2345 
2346         return ResultProperties.getJDBCHoldability(rsProperties);
2347     }
2348 
2349     //------------------------- JDBC 4.0 -----------------------------------
2350 
2351     /**
2352      * Retrieves whether this <code>Statement</code> object has been closed. A <code>Statement</code> is closed if the
2353      * method close has been called on it, or if it is automatically closed.
2354      * @return true if this <code>Statement</code> object is closed; false if it is still open
2355      * @throws SQLException if a database access error occurs
2356      * @since JDK 1.6, HSQLDB 2.0
2357      */
2358     public synchronized boolean isClosed() {
2359         return isClosed;
2360     }
2361 
2362     /**
2363      * Sets the designated parameter to the given <code>java.sql.RowId</code> object. The
2364      * driver converts this to a SQL <code>ROWID</code> value when it sends it
2365      * to the database
2366      *
2367      * @param parameterIndex the first parameter is 1, the second is 2, ...
2368      * @param x the parameter value
2369      * @throws SQLException if a database access error occurs or
2370      * this method is called on a closed <code>PreparedStatement</code>
2371      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2372      *
2373      * @since JDK 1.6, HSQLDB 2.0
2374      */
2375 
2376 //#ifdef JAVA6
2377     public void setRowId(int parameterIndex, RowId x) throws SQLException {
2378         throw JDBCUtil.notSupported();
2379     }
2380 
2381 //#endif JAVA6
2382 
2383     /**
2384      * Sets the designated parameter to the given <code>String</code> object.
2385      * The driver converts this to a SQL <code>NCHAR</code> or
2386      * <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
2387      * (depending on the argument's
2388      * size relative to the driver's limits on <code>NVARCHAR</code> values)
2389      * when it sends it to the database.
2390      *
2391      * @param parameterIndex of the first parameter is 1, the second is 2, ...
2392      * @param value the parameter value
2393      * @throws SQLException if the driver does not support national
2394      *         character sets;  if the driver can detect that a data conversion
2395      *  error could occur ; if a database access error occurs; or
2396      * this method is called on a closed <code>PreparedStatement</code>
2397      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2398      * @since JDK 1.6, HSQLDB 2.0
2399      */
2400     public synchronized void setNString(int parameterIndex,
2401                                         String value) throws SQLException {
2402         setString(parameterIndex, value);
2403     }
2404 
2405     /**
2406      * Sets the designated parameter to a <code>Reader</code> object. The
2407      * <code>Reader</code> reads the data till end-of-file is reached. The
2408      * driver does the necessary conversion from Java character format to
2409      * the national character set in the database.
2410      * @param parameterIndex of the first parameter is 1, the second is 2, ...
2411      * @param value the parameter value
2412      * @param length the number of characters in the parameter data.
2413      * @throws SQLException if the driver does not support national
2414      *         character sets;  if the driver can detect that a data conversion
2415      *  error could occur ; if a database access error occurs; or
2416      * this method is called on a closed <code>PreparedStatement</code>
2417      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2418      * @since JDK 1.6, HSQLDB 2.0
2419      */
2420     public synchronized void setNCharacterStream(int parameterIndex,
2421             Reader value, long length) throws SQLException {
2422         setCharacterStream(parameterIndex, value, length);
2423     }
2424 
2425     /**
2426      * Sets the designated parameter to a <code>java.sql.NClob</code> object. The driver converts this to a
2427      * SQL <code>NCLOB</code> value when it sends it to the database.
2428      * @param parameterIndex of the first parameter is 1, the second is 2, ...
2429      * @param value the parameter value
2430      * @throws SQLException if the driver does not support national
2431      *         character sets;  if the driver can detect that a data conversion
2432      *  error could occur ; if a database access error occurs; or
2433      * this method is called on a closed <code>PreparedStatement</code>
2434      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2435      * @since JDK 1.6, HSQLDB 2.0
2436      */
2437 
2438 //#ifdef JAVA6
2439     public synchronized void setNClob(int parameterIndex,
2440                                       NClob value) throws SQLException {
2441         setClob(parameterIndex, value);
2442     }
2443 
2444 //#endif JAVA6
2445 
2446     /** @todo 1.9.0 - implement streaming and remove length limits */
2447 
2448     /**
2449      * Sets the designated parameter to a <code>Reader</code> object.  The reader must contain  the number
2450      * of characters specified by length otherwise a <code>SQLException</code> will be
2451      * generated when the <code>PreparedStatement</code> is executed.
2452      * This method differs from the <code>setCharacterStream (int, Reader, int)</code> method
2453      * because it informs the driver that the parameter value should be sent to
2454      * the server as a <code>CLOB</code>.  When the <code>setCharacterStream</code> method is used, the
2455      * driver may have to do extra work to determine whether the parameter
2456      * data should be send to the server as a <code>LONGVARCHAR</code> or a <code>CLOB</code>
2457      * @param parameterIndex index of the first parameter is 1, the second is 2, ...
2458      * @param reader An object that contains the data to set the parameter value to.
2459      * @param length the number of characters in the parameter data.
2460      * @throws SQLException if a database access error occurs, this method is called on
2461      * a closed <code>PreparedStatement</code>, if parameterIndex does not correspond to a parameter
2462      * marker in the SQL statement, or if the length specified is less than zero.
2463      *
2464      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2465      * @since JDK 1.6, HSQLDB 2.0
2466      */
2467     public synchronized void setClob(int parameterIndex, Reader reader,
2468                                      long length) throws SQLException {
2469         setCharacterStream(parameterIndex, reader, length);
2470     }
2471 
2472     /** @todo 1.9.0 - implement streaming and remove length limits */
2473 
2474     /**
2475      * Sets the designated parameter to a <code>InputStream</code> object.  The input stream must contain  the number
2476      * of characters specified by length otherwise a <code>SQLException</code> will be
2477      * generated when the <code>PreparedStatement</code> is executed.
2478      * This method differs from the <code>setBinaryStream (int, InputStream, int)</code>
2479      * method because it informs the driver that the parameter value should be
2480      * sent to the server as a <code>BLOB</code>.  When the <code>setBinaryStream</code> method is used,
2481      * the driver may have to do extra work to determine whether the parameter
2482      * data should be send to the server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
2483      * <!-- start release-specific documentation -->
2484      * <div class="ReleaseSpecificDocumentation">
2485      * <h3>HSQLDB-Specific Information:</h3> <p>
2486      *
2487      * In HSQLDB 2.0, this method uses streaming to send the data when the
2488      * stream is assigned to a BLOB target. For other binary targets the
2489      * stream is read on the client side and a byte array is sent.
2490      * </div>
2491      * <!-- end release-specific documentation -->
2492      *
2493      * @param parameterIndex index of the first parameter is 1,
2494      * the second is 2, ...
2495      * @param inputStream An object that contains the data to set the parameter
2496      * value to.
2497      * @param length the number of bytes in the parameter data.
2498      * @throws SQLException if a database access error occurs,
2499      * this method is called on a closed <code>PreparedStatement</code>,
2500      * if parameterIndex does not correspond
2501      * to a parameter marker in the SQL statement,  if the length specified
2502      * is less than zero or if the number of bytes in the input stream does not match
2503      * the specified length.
2504      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2505      *
2506      * @since JDK 1.6, HSQLDB 2.0
2507      */
2508     public synchronized void setBlob(int parameterIndex,
2509                                      InputStream inputStream,
2510                                      long length) throws SQLException {
2511         setBinaryStream(parameterIndex, inputStream, length);
2512     }
2513 
2514     /**
2515      * Sets the designated parameter to a <code>Reader</code> object.  The reader must contain  the number
2516      * of characters specified by length otherwise a <code>SQLException</code> will be
2517      * generated when the <code>PreparedStatement</code> is executed.
2518      * This method differs from the <code>setCharacterStream (int, Reader, int)</code> method
2519      * because it informs the driver that the parameter value should be sent to
2520      * the server as a <code>NCLOB</code>.  When the <code>setCharacterStream</code> method is used, the
2521      * driver may have to do extra work to determine whether the parameter
2522      * data should be send to the server as a <code>LONGNVARCHAR</code> or a <code>NCLOB</code>
2523      * @param parameterIndex index of the first parameter is 1, the second is 2, ...
2524      * @param reader An object that contains the data to set the parameter value to.
2525      * @param length the number of characters in the parameter data.
2526      * @throws SQLException if parameterIndex does not correspond to a parameter
2527      * marker in the SQL statement; if the length specified is less than zero;
2528      * if the driver does not support national character sets;
2529      * if the driver can detect that a data conversion
2530      *  error could occur;  if a database access error occurs or
2531      * this method is called on a closed <code>PreparedStatement</code>
2532      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2533      *
2534      * @since JDK 1.6, HSQLDB 2.0
2535      */
2536     public synchronized void setNClob(int parameterIndex, Reader reader,
2537                                       long length) throws SQLException {
2538         setClob(parameterIndex, reader, length);
2539     }
2540 
2541     /**
2542      * Sets the designated parameter to the given <code>java.sql.SQLXML</code> object.
2543      * The driver converts this to an
2544      * SQL <code>XML</code> value when it sends it to the database.
2545      * <p>
2546      *
2547      * @param parameterIndex index of the first parameter is 1, the second is 2, ...
2548      * @param xmlObject a <code>SQLXML</code> object that maps an SQL <code>XML</code> value
2549      * @throws SQLException if a database access error occurs,
2550      *  this method is called on a closed <code>PreparedStatement</code>
2551      * or the <code>java.xml.transform.Result</code>,
2552      *  <code>Writer</code> or <code>OutputStream</code> has not been closed for
2553      * the <code>SQLXML</code> object
2554      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2555      *
2556      * @since JDK 1.6, HSQLDB 2.0
2557      */
2558 
2559 //#ifdef JAVA6
2560     public void setSQLXML(int parameterIndex,
2561                           SQLXML xmlObject) throws SQLException {
2562         throw JDBCUtil.notSupported();
2563     }
2564 
2565 //#endif JAVA6
2566 // --------------------------- Added: Mustang Build 86 -------------------------
2567 
2568     /** @todo 1.9.0 - implement streaming and remove length limits */
2569 
2570     /**
2571      * Sets the designated parameter to the given input stream, which will have
2572      * the specified number of bytes.
2573      * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
2574      * parameter, it may be more practical to send it via a
2575      * <code>java.io.InputStream</code>. Data will be read from the stream
2576      * as needed until end-of-file is reached.  The JDBC driver will
2577      * do any necessary conversion from ASCII to the database char format.
2578      *
2579      * <P><B>Note:</B> This stream object can either be a standard
2580      * Java stream object or your own subclass that implements the
2581      * standard interface.
2582      *
2583      * <!-- start release-specific documentation -->
2584      * <div class="ReleaseSpecificDocumentation">
2585      * <h3>HSQLDB-Specific Information:</h3> <p>
2586      *
2587      * From HSQLDB 2.0 this method uses the US-ASCII character encoding to convert bytes
2588      * from the stream into the characters of a String.<p>
2589      * This method does not use streaming to send the data,
2590      * whether the target is a CLOB or other binary object.<p>
2591      *
2592      * For long streams (larger than a few megabytes) with CLOB targets,
2593      * it is more efficient to use a version of setCharacterStream which takes
2594      * the a length parameter.
2595      * </div>
2596      * <!-- end release-specific documentation -->
2597      * @param parameterIndex the first parameter is 1, the second is 2, ...
2598      * @param x the Java input stream that contains the ASCII parameter value
2599      * @param length the number of bytes in the stream
2600      * @exception SQLException if a database access error occurs or
2601      * this method is called on a closed <code>PreparedStatement</code>
2602      * @since JDK 1.6 b86, HSQLDB 2.0
2603      */
2604     public synchronized void setAsciiStream(int parameterIndex,
2605             java.io.InputStream x, long length) throws SQLException {
2606 
2607         if (length < 0) {
2608             throw JDBCUtil.sqlException(ErrorCode.JDBC_INVALID_ARGUMENT,
2609                                     "length: " + length);
2610         }
2611         setAscStream(parameterIndex, x, (long) length);
2612     }
2613 
2614     void setAscStream(int parameterIndex, java.io.InputStream x,
2615                       long length) throws SQLException {
2616 
2617         if (length > Integer.MAX_VALUE) {
2618             throw JDBCUtil.sqlException(ErrorCode.X_22001);
2619         }
2620 
2621         if (x == null) {
2622             throw JDBCUtil.nullArgument("x");
2623         }
2624 
2625         try {
2626             String s = StringConverter.inputStreamToString(x, "US-ASCII");
2627 
2628             if (length >= 0 && s.length() > length) {
2629                 s = s.substring(0, (int) length);
2630             }
2631             setParameter(parameterIndex, s);
2632         } catch (IOException e) {
2633             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR, null, e);
2634         }
2635     }
2636 
2637     /**
2638      * Sets the designated parameter to the given input stream, which will have
2639      * the specified number of bytes.
2640      * When a very large binary value is input to a <code>LONGVARBINARY</code>
2641      * parameter, it may be more practical to send it via a
2642      * <code>java.io.InputStream</code> object. The data will be read from the
2643      * stream as needed until end-of-file is reached.
2644      *
2645      * <P><B>Note:</B> This stream object can either be a standard
2646      * Java stream object or your own subclass that implements the
2647      * standard interface.
2648      *
2649      * <!-- start release-specific documentation -->
2650      * <div class="ReleaseSpecificDocumentation">
2651      * <h3>HSQLDB-Specific Information:</h3> <p>
2652      *
2653      * This method uses streaming to send the data when the
2654      * stream is assigned to a BLOB target. For other binary targets the
2655      * stream is read on the client side and a byte array is sent.
2656      * </div>
2657      * <!-- end release-specific documentation -->
2658      *
2659      * @param parameterIndex the first parameter is 1, the second is 2, ...
2660      * @param x the java input stream which contains the binary parameter value
2661      * @param length the number of bytes in the stream
2662      * @exception SQLException if a database access error occurs or
2663      * this method is called on a closed <code>PreparedStatement</code>
2664      * @since JDK 1.6 b86, HSQLDB 2.0
2665      */
2666     public synchronized void setBinaryStream(int parameterIndex,
2667             java.io.InputStream x, long length) throws SQLException {
2668 
2669         if (length < 0) {
2670             throw JDBCUtil.sqlException(ErrorCode.JDBC_INVALID_ARGUMENT,
2671                                     "length: " + length);
2672         }
2673         setBinStream(parameterIndex, x, length);
2674     }
2675 
2676     private void setBinStream(int parameterIndex, java.io.InputStream x,
2677                               long length) throws SQLException {
2678 
2679         if (isClosed || connection.isClosed) {
2680             checkClosed();
2681         }
2682 
2683         if (parameterTypes[parameterIndex - 1].typeCode == Types.SQL_BLOB) {
2684             setBlobParameter(parameterIndex, x, length);
2685 
2686             return;
2687         }
2688 
2689         if (length > Integer.MAX_VALUE) {
2690             String msg = "Maximum Blob input length exceeded: " + length;
2691 
2692             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR, msg);
2693         }
2694 
2695         try {
2696             HsqlByteArrayOutputStream output;
2697 
2698             if (length < 0) {
2699                 output = new HsqlByteArrayOutputStream(x);
2700             } else {
2701                 output = new HsqlByteArrayOutputStream(x, (int) length);
2702             }
2703             setParameter(parameterIndex, output.toByteArray());
2704         } catch (Throwable e) {
2705             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR,
2706                                     e.toString(), e);
2707         }
2708     }
2709 
2710     /**
2711      * Sets the designated parameter to the given <code>Reader</code>
2712      * object, which is the given number of characters long.
2713      * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
2714      * parameter, it may be more practical to send it via a
2715      * <code>java.io.Reader</code> object. The data will be read from the stream
2716      * as needed until end-of-file is reached.  The JDBC driver will
2717      * do any necessary conversion from UNICODE to the database char format.
2718      *
2719      * <P><B>Note:</B> This stream object can either be a standard
2720      * Java stream object or your own subclass that implements the
2721      * standard interface.
2722      *
2723      * <!-- start release-specific documentation -->
2724      * <div class="ReleaseSpecificDocumentation">
2725      * <h3>HSQLDB-Specific Information:</h3> <p>
2726      *
2727      * This method uses streaming to send data
2728      * when the target is a CLOB.<p>
2729      * </div>
2730      * <!-- end release-specific documentation -->
2731      * @param parameterIndex the first parameter is 1, the second is 2, ...
2732      * @param reader the <code>java.io.Reader</code> object that contains the
2733      *        Unicode data
2734      * @param length the number of characters in the stream
2735      * @exception SQLException if a database access error occurs or
2736      * this method is called on a closed <code>PreparedStatement</code>
2737      * @since JDK 1.6 b86, HSQLDB 2.0
2738      */
2739     public synchronized void setCharacterStream(int parameterIndex,
2740             java.io.Reader reader, long length) throws SQLException {
2741 
2742         if (length < 0) {
2743             throw JDBCUtil.sqlException(ErrorCode.JDBC_INVALID_ARGUMENT,
2744                                     "length: " + length);
2745         }
2746         setCharStream(parameterIndex, reader, length);
2747     }
2748 
2749     private void setCharStream(int parameterIndex, java.io.Reader reader,
2750                                long length) throws SQLException {
2751 
2752         checkSetParameterIndex(parameterIndex);
2753 
2754         if (parameterTypes[parameterIndex - 1].typeCode == Types.SQL_CLOB) {
2755             setClobParameter(parameterIndex, reader, length);
2756 
2757             return;
2758         }
2759 
2760         if (length > Integer.MAX_VALUE) {
2761             String msg = "Maximum Clob input length exceeded: " + length;
2762 
2763             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR, msg);
2764         }
2765 
2766         try {
2767             CharArrayWriter writer;
2768 
2769             if (length < 0) {
2770                 writer = new CharArrayWriter(reader);
2771             } else {
2772                 writer = new CharArrayWriter(reader, (int) length);
2773             }
2774             setParameter(parameterIndex, writer.toString());
2775         } catch (Throwable e) {
2776             throw JDBCUtil.sqlException(ErrorCode.JDBC_INPUTSTREAM_ERROR,
2777                                     e.toString(), e);
2778         }
2779     }
2780 
2781     /**
2782      * Sets the designated parameter to the given input stream.
2783      * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
2784      * parameter, it may be more practical to send it via a
2785      * <code>java.io.InputStream</code>. Data will be read from the stream
2786      * as needed until end-of-file is reached.  The JDBC driver will
2787      * do any necessary conversion from ASCII to the database char format.
2788      *
2789      * <P><B>Note:</B> This stream object can either be a standard
2790      * Java stream object or your own subclass that implements the
2791      * standard interface.
2792      * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
2793      * it might be more efficient to use a version of
2794      * <code>setAsciiStream</code> which takes a length parameter.
2795      *
2796      * <!-- start release-specific documentation -->
2797      * <div class="ReleaseSpecificDocumentation">
2798      * <h3>HSQLDB-Specific Information:</h3> <p>
2799      *
2800      * In HSQLDB 2.0, this method does not use streaming to send the data,
2801      * whether the target is a CLOB or other binary object.
2802      *
2803      * For long streams (larger than a few megabytes), it is more efficient to
2804      * use a version of setCharacterStream which takes the a length parameter.
2805      * </div>
2806      * <!-- end release-specific documentation -->
2807      *
2808      * @param parameterIndex the first parameter is 1, the second is 2, ...
2809      * @param x the Java input stream that contains the ASCII parameter value
2810      * @exception SQLException if parameterIndex does not correspond to a parameter
2811      * marker in the SQL statement; if a database access error occurs or
2812      * this method is called on a closed <code>PreparedStatement</code>
2813      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2814      *   @since 1.6
2815      */
2816     public void setAsciiStream(int parameterIndex,
2817                                java.io.InputStream x) throws SQLException {
2818         setAscStream(parameterIndex, x, -1);
2819     }
2820 
2821     /** @todo 1.9.0 - implement streaming and remove length limits */
2822 
2823     /**
2824      * Sets the designated parameter to the given input stream.
2825      * When a very large binary value is input to a <code>LONGVARBINARY</code>
2826      * parameter, it may be more practical to send it via a
2827      * <code>java.io.InputStream</code> object. The data will be read from the
2828      * stream as needed until end-of-file is reached.
2829      *
2830      * <P><B>Note:</B> This stream object can either be a standard
2831      * Java stream object or your own subclass that implements the
2832      * standard interface.
2833      * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
2834      * it might be more efficient to use a version of
2835      * <code>setBinaryStream</code> which takes a length parameter.
2836      *
2837      * <!-- start release-specific documentation -->
2838      * <div class="ReleaseSpecificDocumentation">
2839      * <!-- start release-specific documentation -->
2840      * <div class="ReleaseSpecificDocumentation">
2841      * <h3>HSQLDB-Specific Information:</h3> <p>
2842      *
2843      * This method does not use streaming to send the data,
2844      * whether the target is a CLOB or other binary object.<p>
2845      *
2846      * For long streams (larger than a few megabytes) with CLOB targets,
2847      * it is more efficient to use a version of setCharacterStream which takes
2848      * the a length parameter.
2849      * </div>
2850      * <!-- end release-specific documentation -->
2851      *
2852      * @param parameterIndex the first parameter is 1, the second is 2, ...
2853      * @param x the java input stream which contains the binary parameter value
2854      * @exception SQLException if parameterIndex does not correspond to a parameter
2855      * marker in the SQL statement; if a database access error occurs or
2856      * this method is called on a closed <code>PreparedStatement</code>
2857      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2858      * @since 1.6
2859      */
2860     public synchronized void setBinaryStream(int parameterIndex,
2861             java.io.InputStream x) throws SQLException {
2862         setBinStream(parameterIndex, x, -1);
2863     }
2864 
2865     /** @todo 1.9.0 - implement streaming and remove length limits */
2866 
2867     /**
2868      * Sets the designated parameter to the given <code>Reader</code>
2869      * object.
2870      * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
2871      * parameter, it may be more practical to send it via a
2872      * <code>java.io.Reader</code> object. The data will be read from the stream
2873      * as needed until end-of-file is reached.  The JDBC driver will
2874      * do any necessary conversion from UNICODE to the database char format.
2875      *
2876      * <P><B>Note:</B> This stream object can either be a standard
2877      * Java stream object or your own subclass that implements the
2878      * standard interface.
2879      * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
2880      * it might be more efficient to use a version of
2881      * <code>setCharacterStream</code> which takes a length parameter.
2882      *
2883      * <!-- start release-specific documentation -->
2884      * <div class="ReleaseSpecificDocumentation">
2885      * <h3>HSQLDB-Specific Information:</h3> <p>
2886      *
2887      * In HSQLDB 2.0, this method does not use streaming to send the data,
2888      * whether the target is a CLOB or other binary object.
2889      *
2890      * For long streams (larger than a few megabytes), it is more efficient to
2891      * use a version of setCharacterStream which takes the a length parameter.
2892      * </div>
2893      * <!-- end release-specific documentation -->
2894      *
2895      * @param parameterIndex the first parameter is 1, the second is 2, ...
2896      * @param reader the <code>java.io.Reader</code> object that contains the
2897      *        Unicode data
2898      * @exception SQLException if parameterIndex does not correspond to a parameter
2899      * marker in the SQL statement; if a database access error occurs or
2900      * this method is called on a closed <code>PreparedStatement</code>
2901      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2902      * @since 1.6
2903      */
2904     public void setCharacterStream(int parameterIndex,
2905                                    java.io.Reader reader) throws SQLException {
2906         setCharStream(parameterIndex, reader, -1);
2907     }
2908 
2909     /** @todo 1.9.0 - implement streaming and remove length limits */
2910 
2911     /**
2912      *   Sets the designated parameter to a <code>Reader</code> object. The
2913      *   <code>Reader</code> reads the data till end-of-file is reached. The
2914      *   driver does the necessary conversion from Java character format to
2915      *   the national character set in the database.
2916      *
2917      *   <P><B>Note:</B> This stream object can either be a standard
2918      *   Java stream object or your own subclass that implements the
2919      *   standard interface.
2920      *   <P><B>Note:</B> Consult your JDBC driver documentation to determine if
2921      *   it might be more efficient to use a version of
2922      *   <code>setNCharacterStream</code> which takes a length parameter.
2923      *
2924      *   @param parameterIndex of the first parameter is 1, the second is 2, ...
2925      *   @param value the parameter value
2926      *   @throws SQLException if parameterIndex does not correspond to a parameter
2927      *   marker in the SQL statement; if the driver does not support national
2928      *           character sets;  if the driver can detect that a data conversion
2929      *    error could occur; if a database access error occurs; or
2930      *   this method is called on a closed <code>PreparedStatement</code>
2931      *   @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2932      *   @since 1.6
2933      */
2934     public void setNCharacterStream(int parameterIndex,
2935                                     Reader value) throws SQLException {
2936         setCharStream(parameterIndex, value, -1);
2937     }
2938 
2939     /** @todo 1.9.0 - implement streaming and remove length limits */
2940 
2941     /**
2942      * Sets the designated parameter to a <code>Reader</code> object.
2943      * This method differs from the <code>setCharacterStream (int, Reader)</code> method
2944      * because it informs the driver that the parameter value should be sent to
2945      * the server as a <code>CLOB</code>.  When the <code>setCharacterStream</code> method is used, the
2946      * driver may have to do extra work to determine whether the parameter
2947      * data should be sent to the server as a <code>LONGVARCHAR</code> or a <code>CLOB</code>
2948      *
2949      * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
2950      * it might be more efficient to use a version of
2951      * <code>setClob</code> which takes a length parameter.
2952      *
2953      * @param parameterIndex index of the first parameter is 1, the second is 2, ...
2954      * @param reader An object that contains the data to set the parameter value to.
2955      * @throws SQLException if parameterIndex does not correspond to a parameter
2956      * marker in the SQL statement; if a database access error occurs; this method is called on
2957      * a closed <code>PreparedStatement</code>or if parameterIndex does not correspond to a parameter
2958      * marker in the SQL statement
2959      *
2960      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2961      * @since 1.6
2962      */
2963     public void setClob(int parameterIndex,
2964                         Reader reader) throws SQLException {
2965         setCharStream(parameterIndex, reader, -1);
2966     }
2967 
2968     /** @todo 1.9.0 - implement streaming and remove length limits */
2969 
2970     /**
2971      * Sets the designated parameter to a <code>InputStream</code> object.
2972      * This method differs from the <code>setBinaryStream (int, InputStream)</code>
2973      * method because it informs the driver that the parameter value should be
2974      * sent to the server as a <code>BLOB</code>.  When the <code>setBinaryStream</code> method is used,
2975      * the driver may have to do extra work to determine whether the parameter
2976      * data should be sent to the server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
2977      *
2978      * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
2979      * it might be more efficient to use a version of
2980      * <code>setBlob</code> which takes a length parameter.
2981      *
2982      * @param parameterIndex index of the first parameter is 1,
2983      * the second is 2, ...
2984      * @param inputStream An object that contains the data to set the parameter
2985      * value to.
2986      * @throws SQLException if parameterIndex does not correspond to a parameter
2987      * marker in the SQL statement; if a database access error occurs;
2988      * this method is called on a closed <code>PreparedStatement</code> or
2989      * if parameterIndex does not correspond
2990      * to a parameter marker in the SQL statement,
2991      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
2992      *
2993      * @since 1.6
2994      */
2995     public void setBlob(int parameterIndex,
2996                         InputStream inputStream) throws SQLException {
2997         setBinStream(parameterIndex, inputStream, -1);
2998     }
2999 
3000     /** @todo 1.9.0 - implement streaming and remove length limits */
3001 
3002     /**
3003      * Sets the designated parameter to a <code>Reader</code> object.
3004      * This method differs from the <code>setCharacterStream (int, Reader)</code> method
3005      * because it informs the driver that the parameter value should be sent to
3006      * the server as a <code>NCLOB</code>.  When the <code>setCharacterStream</code> method is used, the
3007      * driver may have to do extra work to determine whether the parameter
3008      * data should be sent to the server as a <code>LONGNVARCHAR</code> or a <code>NCLOB</code>
3009      * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
3010      * it might be more efficient to use a version of
3011      * <code>setNClob</code> which takes a length parameter.
3012      *
3013      * @param parameterIndex index of the first parameter is 1, the second is 2, ...
3014      * @param reader An object that contains the data to set the parameter value to.
3015      * @throws SQLException if parameterIndex does not correspond to a parameter
3016      * marker in the SQL statement;
3017      * if the driver does not support national character sets;
3018      * if the driver can detect that a data conversion
3019      *  error could occur;  if a database access error occurs or
3020      * this method is called on a closed <code>PreparedStatement</code>
3021      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
3022      *
3023      * @since 1.6
3024      */
3025     public void setNClob(int parameterIndex,
3026                          Reader reader) throws SQLException {
3027         setCharStream(parameterIndex, reader, -1);
3028     }
3029 
3030     /**
3031      * <!-- start generic documentation -->
3032      * Retrieves the maximum number of bytes that can be
3033      * returned for character and binary column values in a <code>ResultSet</code>
3034      * object produced by this <code>Statement</code> object.
3035      * This limit applies only to  <code>BINARY</code>, <code>VARBINARY</code>,
3036      * <code>LONGVARBINARY</code>, <code>CHAR</code>, <code>VARCHAR</code>,
3037      * (JDBC4 new:) <code>NCHAR</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>
3038      * and <code>LONGVARCHAR</code> columns.  If the limit is exceeded, the
3039      * excess data is silently discarded.
3040      * <!-- end generic documentation -->
3041      *
3042      * <!-- start release-specific documentation -->
3043      * <div class="ReleaseSpecificDocumentation">
3044      * <h3>HSQLDB-Specific Information:</h3> <p>
3045      *
3046      * HSQLDB always returns zero, meaning there is no limit.
3047      * </div>
3048      * <!-- end release-specific documentation -->
3049      *
3050      * @return the current column size limit for columns storing character and
3051      *         binary values; zero means there is no limit
3052      * @exception SQLException if a database access error occurs or
3053      * this method is called on a closed <code>Statement</code>
3054      * @see #setMaxFieldSize
3055      */
3056     public synchronized int getMaxFieldSize() throws SQLException {
3057 
3058         if (isClosed || connection.isClosed) {
3059             checkClosed();
3060         }
3061 
3062         return 0;
3063     }
3064 
3065     /**
3066      * <!-- start generic documentation -->
3067      * (JDBC4 clarification:) Sets the limit for the maximum number of bytes in a <code>ResultSet</code>
3068      * Sets the limit for the maximum number of bytes that can be returned for
3069      * character and binary column values in a <code>ResultSet</code>
3070      * object produced by this <code>Statement</code> object.
3071      *
3072      * This limit applies
3073      * only to <code>BINARY</code>, <code>VARBINARY</code>,
3074      * <code>LONGVARBINARY</code>, <code>CHAR</code>, <code>VARCHAR</code>,
3075      * (JDBC4 new:) <code>NCHAR</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code> and
3076      * <code>LONGVARCHAR</code> fields.  If the limit is exceeded, the excess data
3077      * is silently discarded. For maximum portability, use values
3078      * greater than 256.
3079      * <!-- emd generic documentation -->
3080      *
3081      * <!-- start release-specific documentation -->
3082      * <div class="ReleaseSpecificDocumentation">
3083      * <h3>HSQLDB-Specific Information:</h3> <p>
3084      *
3085      * To present, calls to this method are simply ignored; HSQLDB always
3086      * stores the full number of bytes when dealing with any of the field types
3087      * mentioned above. These types all have an absolute maximum element upper
3088      * bound determined by the Java array index limit
3089      * java.lang.Integer.MAX_VALUE.  For XXXBINARY types, this translates to
3090      * Integer.MAX_VALUE bytes.  For XXXCHAR types, this translates to
3091      * 2 * Integer.MAX_VALUE bytes (2 bytes / character). <p>
3092      *
3093      * In practice, field sizes are limited to values much smaller than the
3094      * absolute maximum element upper bound, in particular due to limits imposed
3095      * on the maximum available Java heap memory.
3096      * </div>
3097      * <!-- end release-specific documentation -->
3098      *
3099      * @param max the new column size limit in bytes; zero means there is no limit
3100      * @exception SQLException if a database access error occurs,
3101      * this method is called on a closed <code>Statement</code>
3102      *            or the condition max >= 0 is not satisfied
3103      * @see #getMaxFieldSize
3104      */
3105     public synchronized void setMaxFieldSize(int max) throws SQLException {
3106 
3107         if (isClosed || connection.isClosed) {
3108             checkClosed();
3109         }
3110 
3111         if (max < 0) {
3112             throw JDBCUtil.outOfRangeArgument();
3113         }
3114     }
3115 
3116     /**
3117      * <!-- start generic documentation -->
3118      * Retrieves the maximum number of rows that a
3119      * <code>ResultSet</code> object produced by this
3120      * <code>Statement</code> object can contain.  If this limit is exceeded,
3121      * the excess rows are silently dropped.
3122      * <!-- start generic documentation -->
3123      *
3124      * @return the current maximum number of rows for a <code>ResultSet</code>
3125      *         object produced by this <code>Statement</code> object;
3126      *         zero means there is no limit
3127      * @exception SQLException if a database access error occurs or
3128      * this method is called on a closed <code>Statement</code>
3129      * @see #setMaxRows
3130      */
3131     public synchronized int getMaxRows() throws SQLException {
3132 
3133         if (isClosed || connection.isClosed) {
3134             checkClosed();
3135         }
3136 
3137         return maxRows;
3138     }
3139 
3140     /**
3141      * <!-- start generic documentation -->
3142      * (JDBC4 clarification:)
3143      * Sets the limit for the maximum number of rows that any
3144      * <code>ResultSet</code> object  generated by this <code>Statement</code>
3145      * object can contain to the given number.
3146      * If the limit is exceeded, the excess
3147      * rows are silently dropped.
3148      * <!-- end generic documentation -->
3149      *
3150      * @param max the new max rows limit; zero means there is no limit
3151      * @exception SQLException if a database access error occurs,
3152      * this method is called on a closed <code>Statement</code>
3153      *            or the condition max >= 0 is not satisfied
3154      * @see #getMaxRows
3155      */
3156     public synchronized void setMaxRows(int max) throws SQLException {
3157 
3158         if (isClosed || connection.isClosed) {
3159             checkClosed();
3160         }
3161 
3162         if (max < 0) {
3163             throw JDBCUtil.outOfRangeArgument();
3164         }
3165         maxRows = max;
3166     }
3167 
3168     /**
3169      * <!-- start generic documentation -->
3170      * Retrieves the number of seconds the driver will
3171      * wait for a <code>Statement</code> object to execute.
3172      * If the limit is exceeded, a
3173      * <code>SQLException</code> is thrown.
3174      * <!-- end generic documentation -->
3175      *
3176      * <!-- start release-specific documentation -->
3177      * <div class="ReleaseSpecificDocumentation">
3178      * <h3>HSQLDB-Specific Information:</h3> <p>
3179      *
3180      * To present, HSQLDB always returns zero, meaning there
3181      * is no limit.
3182      * </div>
3183      * <!-- end release-specific documentation -->
3184      *
3185      * @return the current query timeout limit in seconds; zero means there is
3186      *         no limit
3187      * @exception SQLException if a database access error occurs or
3188      * this method is called on a closed <code>Statement</code>
3189      * @see #setQueryTimeout
3190      */
3191     public synchronized int getQueryTimeout() throws SQLException {
3192 
3193         if (isClosed || connection.isClosed) {
3194             checkClosed();
3195         }
3196 
3197         return queryTimeout;
3198     }
3199 
3200     /**
3201      * <!-- start generic documentation -->
3202      * Sets the number of seconds the driver will wait for a
3203      * <code>Statement</code> object to execute to the given number of seconds.
3204      * If the limit is exceeded, an <code>SQLException</code> is thrown. A JDBC
3205      * (JDBC4 clarification:)
3206      * driver must apply this limit to the <code>execute</code>,
3207      * <code>executeQuery</code> and <code>executeUpdate</code> methods. JDBC driver
3208      * implementations may also apply this limit to <code>ResultSet</code> methods
3209      * (consult your driver vendor documentation for details).
3210      * <!-- end generic documentation -->
3211      *
3212      * <!-- start release-specific documentation -->
3213      * <div class="ReleaseSpecificDocumentation">
3214      * <h3>HSQLDB-Specific Information:</h3> <p>
3215      *
3216      * The maximum number of seconds to wait is 32767.
3217      * </div>
3218      * <!-- end release-specific documentation -->
3219      *
3220      * @param seconds the new query timeout limit in seconds; zero means
3221      *        there is no limit
3222      * @exception SQLException if a database access error occurs,
3223      * this method is called on a closed <code>Statement</code>
3224      *            or the condition seconds >= 0 is not satisfied
3225      * @see #getQueryTimeout
3226      */
3227     public synchronized void setQueryTimeout(int seconds) throws SQLException {
3228 
3229         if (isClosed || connection.isClosed) {
3230             checkClosed();
3231         }
3232 
3233         if (seconds < 0) {
3234             throw JDBCUtil.outOfRangeArgument();
3235         }
3236 
3237         if (seconds > Short.MAX_VALUE) {
3238             seconds = Short.MAX_VALUE;
3239         }
3240         queryTimeout = seconds;
3241     }
3242 
3243     /**
3244      * <!-- start generic documentation -->
3245      * Cancels this <code>Statement</code> object if both the DBMS and
3246      * driver support aborting an SQL statement.
3247      * This method can be used by one thread to cancel a statement that
3248      * is being executed by another thread.
3249      * <!-- end generic documentation -->
3250      *
3251      * <!-- start release-specific documentation -->
3252      * <div class="ReleaseSpecificDocumentation">
3253      * <h3>HSQLDB-Specific Information:</h3> <p>
3254      *
3255      * HSQLDB version 2.3.4 and later supports aborting an SQL query
3256      * or data update statement.
3257      * </div>
3258      * <!-- end release-specific documentation -->
3259      *
3260      * @exception SQLException if a database access error occurs or
3261      * this method is called on a closed <code>Statement</code>
3262      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
3263      * this method
3264      */
3265     public void cancel() throws SQLException {
3266         checkClosed();
3267         String sql = resultOut.getMainString();
3268         Result request = Result.newCancelRequest(statementID, sql);
3269 
3270         try {
3271             Result response = connection.sessionProxy.cancel(request);
3272         } catch (HsqlException e) {
3273             throw JDBCUtil.sqlException(e);
3274         }
3275 
3276     }
3277 
3278     /**
3279      * <!-- start generic documentation -->
3280      * Retrieves the first warning reported by calls on this <code>Statement</code> object.
3281      * Subsequent <code>Statement</code> object warnings will be chained to this
3282      * <code>SQLWarning</code> object.
3283      *
3284      * <p>The warning chain is automatically cleared each time
3285      * a statement is (re)executed. This method may not be called on a closed
3286      * <code>Statement</code> object; doing so will cause an <code>SQLException</code>
3287      * to be thrown.
3288      *
3289      * <P><B>Note:</B> If you are processing a <code>ResultSet</code> object, any
3290      * warnings associated with reads on that <code>ResultSet</code> object
3291      * will be chained on it rather than on the <code>Statement</code>
3292      * object that produced it.
3293      * <!-- end generic documentation -->
3294      *
3295      * <!-- start release-specific documentation -->
3296      * <div class="ReleaseSpecificDocumentation">
3297      * <h3>HSQLDB-Specific Information:</h3> <p>
3298      *
3299      * From 1.9 HSQLDB, produces Statement warnings.
3300      * </div>
3301      * <!-- end release-specific documentation -->
3302      *
3303      * @return the first <code>SQLWarning</code> object or <code>null</code>
3304      *         if there are no warnings
3305      * @exception SQLException if a database access error occurs or
3306      * this method is called on a closed <code>Statement</code>
3307      */
3308     public synchronized SQLWarning getWarnings() throws SQLException {
3309 
3310         if (isClosed || connection.isClosed) {
3311             checkClosed();
3312         }
3313 
3314         return rootWarning;
3315     }
3316 
3317     /**
3318      * <!-- start generic documentation -->
3319      * Clears all the warnings reported on this <code>Statement</code>
3320      * object. After a call to this method,
3321      * the method <code>getWarnings</code> will return
3322      * <code>null</code> until a new warning is reported for this
3323      * <code>Statement</code> object.
3324      * <!-- end generic documentation -->
3325      *
3326      * <!-- start release-specific documentation -->
3327      * <div class="ReleaseSpecificDocumentation">
3328      * <h3>HSQLDB-Specific Information:</h3> <p>
3329      *
3330      * Supported in HSQLDB 1.9.
3331      * </div>
3332      * <!-- end release-specific documentation -->
3333      *
3334      * @exception SQLException if a database access error occurs or
3335      * this method is called on a closed <code>Statement</code>
3336      */
3337     public synchronized void clearWarnings() throws SQLException {
3338 
3339         if (isClosed || connection.isClosed) {
3340             checkClosed();
3341         }
3342         rootWarning = null;
3343     }
3344 
3345     /** @todo 1.9.0 - implement */
3346 
3347     /**
3348      * <!-- start generic documentation -->
3349      * Sets the SQL cursor name to the given <code>String</code>, which
3350      * will be used by subsequent <code>Statement</code> object
3351      * <code>execute</code> methods. This name can then be
3352      * used in SQL positioned update or delete statements to identify the
3353      * current row in the <code>ResultSet</code> object generated by this
3354      * statement.  If the database does not support positioned update/delete,
3355      * this method is a noop.  To insure that a cursor has the proper isolation
3356      * level to support updates, the cursor's <code>SELECT</code> statement
3357      * should have the form <code>SELECT FOR UPDATE</code>.  If
3358      * <code>FOR UPDATE</code> is not present, positioned updates may fail.
3359      *
3360      * <P><B>Note:</B> By definition, the execution of positioned updates and
3361      * deletes must be done by a different <code>Statement</code> object than
3362      * the one that generated the <code>ResultSet</code> object being used for
3363      * positioning. Also, cursor names must be unique within a connection.
3364      * <!-- end generic documentation -->
3365      *
3366      * <!-- start release-specific documentation -->
3367      * <div class="ReleaseSpecificDocumentation">
3368      * <h3>HSQLDB-Specific Information:</h3> <p>
3369      *
3370      * Including 2.0, HSQLDB does not support named cursors;
3371      * calls to this method are ignored.
3372      * </div>
3373      * <!-- end release-specific documentation -->
3374      *
3375      * @param name the new cursor name, which must be unique within
3376      *             a connection
3377      * @exception SQLException if a database access error occurs or
3378      * this method is called on a closed <code>Statement</code>
3379      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
3380      */
3381     public void setCursorName(String name) throws SQLException {
3382         checkClosed();
3383     }
3384 
3385     //----------------------- Multiple Results --------------------------
3386 
3387     /**
3388      * <!-- start generic documentation -->
3389      *  Retrieves the current result as a <code>ResultSet</code> object.
3390      *  This method should be called only once per result.
3391      * <!-- end generic documentation -->
3392      *
3393      * <!-- start release-specific documentation -->
3394      * <div class="ReleaseSpecificDocumentation">
3395      * <h3>HSQLDB-Specific Information:</h3> <p>
3396      *
3397      * Without an interceding call to executeXXX, each invocation of this
3398      * method will produce a new, initialized ResultSet instance referring to
3399      * the current result, if any.
3400      * </div>
3401      * <!-- end release-specific documentation -->
3402      *
3403      * @return the current result as a <code>ResultSet</code> object or
3404      * <code>null</code> if the result is an update count or there are no more results
3405      * @exception SQLException if a database access error occurs or
3406      * this method is called on a closed <code>Statement</code>
3407      * @see #execute
3408      */
3409     public synchronized ResultSet getResultSet() throws SQLException {
3410         return super.getResultSet();
3411     }
3412 
3413     /**
3414      * <!-- start generic documentation -->
3415      *  Retrieves the current result as an update count;
3416      *  if the result is a <code>ResultSet</code> object or there are no more results, -1
3417      *  is returned. This method should be called only once per result.
3418      * <!-- end generic documentation -->
3419      *
3420      * @return the current result as an update count; -1 if the current result is a
3421      * <code>ResultSet</code> object or there are no more results
3422      * @exception SQLException if a database access error occurs or
3423      * this method is called on a closed <code>Statement</code>
3424      * @see #execute
3425      */
3426     public synchronized int getUpdateCount() throws SQLException {
3427         return super.getUpdateCount();
3428     }
3429 
3430     /**
3431      * <!-- start generic documentation -->
3432      * Moves to this <code>Statement</code> object's next result, returns
3433      * <code>true</code> if it is a <code>ResultSet</code> object, and
3434      * implicitly closes any current <code>ResultSet</code>
3435      * object(s) obtained with the method <code>getResultSet</code>.
3436      *
3437      * <P>There are no more results when the following is true:
3438      * <PRE>
3439      *     // stmt is a Statement object
3440      *     ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
3441      * </PRE>
3442      * <!-- end generic documentation -->
3443      *
3444      * @return <code>true</code> if the next result is a <code>ResultSet</code>
3445      *         object; <code>false</code> if it is an update count or there are
3446      *         no more results
3447      * @exception SQLException if a database access error occurs or
3448      * this method is called on a closed <code>Statement</code>
3449      * @see #execute
3450      */
3451     public synchronized boolean getMoreResults() throws SQLException {
3452         return getMoreResults(JDBCStatementBase.CLOSE_CURRENT_RESULT);
3453     }
3454 
3455     //--------------------------JDBC 2.0-----------------------------
3456 
3457     /**
3458      * <!-- start generic documentation -->
3459      * Gives the driver a hint as to the direction in which
3460      * rows will be processed in <code>ResultSet</code>
3461      * objects created using this <code>Statement</code> object.  The
3462      * default value is <code>ResultSet.FETCH_FORWARD</code>.
3463      * <P>
3464      * Note that this method sets the default fetch direction for
3465      * result sets generated by this <code>Statement</code> object.
3466      * Each result set has its own methods for getting and setting
3467      * its own fetch direction.
3468      * <!-- end generic documentation -->
3469      *
3470      * <!-- start release-specific documentation -->
3471      * <div class="ReleaseSpecificDocumentation">
3472      * <h3>HSQLDB-Specific Information:</h3> <p>
3473      *
3474      * Up to 1.8.0.x, HSQLDB supports only <code>FETCH_FORWARD</code>;
3475      * Setting any other value would throw an <code>SQLException</code>
3476      * stating that the operation is not supported. <p>
3477      *
3478      * Starting with 2.0, HSQLDB accepts any valid value.
3479      * </div>
3480      * <!-- end release-specific documentation -->
3481      *
3482      * @param direction the initial direction for processing rows
3483      * @exception SQLException if a database access error occurs,
3484      * this method is called on a closed <code>Statement</code>
3485      * or the given direction
3486      * is not one of <code>ResultSet.FETCH_FORWARD</code>,
3487      * <code>ResultSet.FETCH_REVERSE</code>, or <code>ResultSet.FETCH_UNKNOWN</code>
3488      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3489      *    for JDBCStatement)
3490      * @see #getFetchDirection
3491      */
3492     public synchronized void setFetchDirection(
3493             int direction) throws SQLException {
3494 
3495         if (isClosed || connection.isClosed) {
3496             checkClosed();
3497         }
3498 
3499         if (direction != JDBCResultSet.FETCH_FORWARD
3500                 && direction != JDBCResultSet.FETCH_REVERSE
3501                 && direction != JDBCResultSet.FETCH_UNKNOWN) {
3502             throw JDBCUtil.notSupported();
3503         }
3504         fetchDirection = direction;
3505     }
3506 
3507     /**
3508      * <!-- start generic documentation -->
3509      * Retrieves the direction for fetching rows from
3510      * database tables that is the default for result sets
3511      * generated from this <code>Statement</code> object.
3512      * If this <code>Statement</code> object has not set
3513      * a fetch direction by calling the method <code>setFetchDirection</code>,
3514      * the return value is implementation-specific.
3515      * <!-- end generic documentation -->
3516      *
3517      * <!-- start release-specific documentation -->
3518      * <div class="ReleaseSpecificDocumentation">
3519      * <h3>HSQLDB-Specific Information:</h3> <p>
3520      *
3521      * Up to 1.8.0.x, HSQLDB always returned FETCH_FORWARD.
3522      *
3523      * Starting with 2.0, HSQLDB returns FETCH_FORWARD by default, or
3524      * whatever value has been explicitly assigned by invoking
3525      * <code>setFetchDirection</code>.
3526      * .
3527      * </div>
3528      * <!-- end release-specific documentation -->
3529      *
3530      * @return the default fetch direction for result sets generated
3531      *          from this <code>Statement</code> object
3532      * @exception SQLException if a database access error occurs or
3533      * this method is called on a closed <code>Statement</code>
3534      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3535      *    for JDBCStatement)
3536      * @see #setFetchDirection
3537      */
3538     public synchronized int getFetchDirection() throws SQLException {
3539 
3540         if (isClosed || connection.isClosed) {
3541             checkClosed();
3542         }
3543 
3544         return fetchDirection;
3545     }
3546 
3547     /**
3548      * <!-- start generic documentation -->
3549      * (JDBC4 clarification:)
3550      * Gives the JDBC driver a hint as to the number of rows that should
3551      * be fetched from the database when more rows are needed for
3552      * <code>ResultSet</code> objects generated by this <code>Statement</code>.
3553      * If the value specified is zero, then the hint is ignored.
3554      * The default value is zero.
3555      * <!-- start generic documentation -->
3556      *
3557      * <!-- start release-specific documentation -->
3558      * <div class="ReleaseSpecificDocumentation">
3559      * <h3>HSQLDB-Specific Information:</h3> <p>
3560      *
3561      * HSQLDB uses the specified value as a hint, but may process more or fewer
3562      * rows than specified.
3563      * </div>
3564      * <!-- end release-specific documentation -->
3565      *
3566      * @param rows the number of rows to fetch
3567      * @exception SQLException if a database access error occurs,
3568      * this method is called on a closed <code>Statement</code> or the
3569      *        (JDBC4 modified:)
3570      *        condition  <code>rows >= 0</code> is not satisfied.
3571      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3572      *   for JDBCStatement)
3573      * @see #getFetchSize
3574      */
3575     public synchronized void setFetchSize(int rows) throws SQLException {
3576 
3577         if (isClosed || connection.isClosed) {
3578             checkClosed();
3579         }
3580 
3581         if (rows < 0) {
3582             throw JDBCUtil.outOfRangeArgument();
3583         }
3584         fetchSize = rows;
3585     }
3586 
3587     /**
3588      * <!-- start generic documentation -->
3589      * Retrieves the number of result set rows that is the default
3590      * fetch size for <code>ResultSet</code> objects
3591      * generated from this <code>Statement</code> object.
3592      * If this <code>Statement</code> object has not set
3593      * a fetch size by calling the method <code>setFetchSize</code>,
3594      * the return value is implementation-specific.
3595      * <!-- end generic documentation -->
3596      *
3597      * <!-- start release-specific documentation -->
3598      * <div class="ReleaseSpecificDocumentation">
3599      * <b>HSQLDB-Specific Information</b> <p>
3600      *
3601      * HSQLDB returns 0 by default, or the fetch size specified by setFetchSize
3602      * </div>
3603      * <!-- end release-specific documentation -->
3604      *
3605      * @return the default fetch size for result sets generated
3606      *          from this <code>Statement</code> object
3607      * @exception SQLException if a database access error occurs or
3608      * this method is called on a closed <code>Statement</code>
3609      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3610      *  for JDBCStatement)
3611      * @see #setFetchSize
3612      */
3613     public synchronized int getFetchSize() throws SQLException {
3614 
3615         if (isClosed || connection.isClosed) {
3616             checkClosed();
3617         }
3618 
3619         return fetchSize;
3620     }
3621 
3622     /**
3623      * <!-- start generic documentation -->
3624      * Retrieves the result set concurrency for <code>ResultSet</code> objects
3625      * generated by this <code>Statement</code> object.
3626      * <!-- end generic documentation -->
3627      *
3628      * <!-- start release-specific documentation -->
3629      * <div class="ReleaseSpecificDocumentation">
3630      * <h3>HSQLDB-Specific Information:</h3> <p>
3631      *
3632      * HSQLDB supports <code>CONCUR_READ_ONLY</code> and
3633      * <code>CONCUR_READ_UPDATEBLE</code> concurrency.
3634      * </div>
3635      * <!-- end release-specific documentation -->
3636      *
3637      * @return either <code>ResultSet.CONCUR_READ_ONLY</code> or
3638      * <code>ResultSet.CONCUR_UPDATABLE</code>
3639      * @exception SQLException if a database access error occurs or
3640      * this method is called on a closed <code>Statement</code>
3641      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3642      *  for JDBCStatement)
3643      */
3644     public synchronized int getResultSetConcurrency() throws SQLException {
3645 
3646         if (isClosed || connection.isClosed) {
3647             checkClosed();
3648         }
3649 
3650         return ResultProperties.getJDBCConcurrency(rsProperties);
3651     }
3652 
3653     /**
3654      * <!-- start generic documentation -->
3655      * Retrieves the result set type for <code>ResultSet</code> objects
3656      * generated by this <code>Statement</code> object.
3657      * <!-- end generic documentation -->
3658      *
3659      * <!-- start release-specific documentation -->
3660      * <div class="ReleaseSpecificDocumentation">
3661      * <h3>HSQLDB-Specific Information:</h3> <p>
3662      *
3663      * HSQLDB 1.7.0 and later versions support <code>TYPE_FORWARD_ONLY</code>
3664      * and <code>TYPE_SCROLL_INSENSITIVE</code>.
3665      * </div>
3666      * <!-- end release-specific documentation -->
3667      *
3668      * @return one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
3669      * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
3670      * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
3671      * @exception SQLException if a database access error occurs or
3672      * this method is called on a closed <code>Statement</code>
3673      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3674      *   for JDBCStatement)
3675      */
3676     public synchronized int getResultSetType() throws SQLException {
3677 
3678         // fredt - omit checkClosed() in order to be able to handle the result of a
3679         // SHUTDOWN query
3680         if (isClosed || connection.isClosed) {
3681             checkClosed();
3682         }
3683 
3684         return ResultProperties.getJDBCScrollability(rsProperties);
3685     }
3686 
3687     /**
3688      * <!-- start generic documentation -->
3689      * Empties this <code>Statement</code> object's current list of
3690      * SQL commands.
3691      * <P>
3692      * (JDBC4 clarification:) <p>
3693      * <B>NOTE:</B>  Support of an ability to batch updates is optional.
3694      * <!-- start generic documentation -->
3695      *
3696      * <!-- start release-specific documentation -->
3697      * <div class="ReleaseSpecificDocumentation">
3698      * <h3>HSQLDB-Specific Information:</h3> <p>
3699      *
3700      * Starting with HSQLDB 1.7.2, this feature is supported.
3701      * </div>
3702      * <!-- end release-specific documentation -->
3703      *
3704      * @exception SQLException if a database access error occurs,
3705      *  this method is called on a closed <code>Statement</code> or the
3706      * driver does not support batch updates
3707      * @see #addBatch
3708      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3709      *   for JDBCStatement)
3710      */
3711     public synchronized void clearBatch() throws SQLException {
3712 
3713         if (isClosed || connection.isClosed) {
3714             checkClosed();
3715         }
3716 
3717         if (isBatch) {
3718             resultOut.getNavigator().clear();
3719         }
3720     }
3721 
3722     /**
3723      * <!-- start generic documentation -->
3724      * Retrieves the <code>Connection</code> object
3725      * that produced this <code>Statement</code> object.
3726      * <!-- end generic documentation -->
3727      *
3728      * @return the connection that produced this statement
3729      * @exception SQLException if a database access error occurs or
3730      * this method is called on a closed <code>Statement</code>
3731      * @since JDK 1.2 (JDK 1.1.x developers: read the overview
3732      *    for JDBCStatement)
3733      */
3734     public synchronized Connection getConnection() throws SQLException {
3735 
3736         if (isClosed || connection.isClosed) {
3737             checkClosed();
3738         }
3739 
3740         return connection;
3741     }
3742 
3743     //----------------------------- JDBC 4.0 -----------------------------------
3744 // --------------------------- Added: Mustang Build 81 -------------------------
3745     boolean poolable = true;
3746 
3747     /**
3748      * Requests that a <code>Statement</code> be pooled or not pooled.  The value
3749      * specified is a hint to the statement pool implementation indicating
3750      * whether the application wants the statement to be pooled.  It is up to
3751      * the statement pool manager as to whether the hint is used.
3752      * <p>
3753      * The poolable value of a statement is applicable to both internal
3754      * statement caches implemented by the driver and external statement caches
3755      * implemented by application servers and other applications.
3756      * <p>
3757      * By default, a <code>Statement</code> is not poolable when created, and
3758      * a <code>PreparedStatement</code> and <code>CallableStatement</code>
3759      * are poolable when created.
3760      * <p>
3761      * @param poolable          requests that the statement be pooled if true and
3762      *                                          that the statement not be pooled if false
3763      * <p>
3764      * @throws SQLException if this method is called on a closed
3765      * <code>Statement</code>
3766      * <p>
3767      * @since JDK 1.6 Build 81, HSQLDB 2.0
3768      */
3769     public synchronized void setPoolable(
3770             boolean poolable) throws SQLException {
3771 
3772         if (isClosed || connection.isClosed) {
3773             checkClosed();
3774         }
3775         this.poolable = poolable;
3776     }
3777 
3778     /**
3779      * Returns a  value indicating whether the <code>Statement</code>
3780      * is poolable or not.
3781      * <p>
3782      * @return          <code>true</code> if the <code>Statement</code>
3783      * is poolable; <code>false</code> otherwise
3784      * @throws SQLException if this method is called on a closed
3785      * <code>Statement</code>
3786      * <p>
3787      * @since JDK 1.6 Build 81, HSQLDB 2.0
3788      * <p>
3789      * @see #setPoolable(boolean) setPoolable(boolean)
3790      */
3791     public synchronized boolean isPoolable() throws SQLException {
3792 
3793         if (isClosed || connection.isClosed) {
3794             checkClosed();
3795         }
3796 
3797         return this.poolable;
3798     }
3799 
3800     // ------------------- java.sql.Wrapper implementation ---------------------
3801 
3802     /**
3803      * Returns an object that implements the given interface to allow access to
3804      * non-standard methods, or standard methods not exposed by the proxy.
3805      *
3806      * If the receiver implements the interface then the result is the receiver
3807      * or a proxy for the receiver. If the receiver is a wrapper
3808      * and the wrapped object implements the interface then the result is the
3809      * wrapped object or a proxy for the wrapped object. Otherwise return the
3810      * the result of calling <code>unwrap</code> recursively on the wrapped object
3811      * or a proxy for that result. If the receiver is not a
3812      * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
3813      *
3814      * @param iface A Class defining an interface that the result must implement.
3815      * @return an object that implements the interface. May be a proxy for the actual implementing object.
3816      * @throws java.sql.SQLException If no object found that implements the interface
3817      * @since JDK 1.6, HSQLDB 2.0
3818      */
3819 //#ifdef JAVA6
3820     @SuppressWarnings("unchecked")
3821     public <T>T unwrap(Class<T> iface) throws java.sql.SQLException {
3822 
3823         if (isWrapperFor(iface)) {
3824             return (T) this;
3825         }
3826 
3827         throw JDBCUtil.invalidArgument("iface: " + iface);
3828     }
3829 
3830 //#endif JAVA6
3831 
3832     /**
3833      * Returns true if this either implements the interface argument or is directly or indirectly a wrapper
3834      * for an object that does. Returns false otherwise. If this implements the interface then return true,
3835      * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
3836      * object. If this does not implement the interface and is not a wrapper, return false.
3837      * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
3838      * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
3839      * returns true then calling <code>unwrap</code> with the same argument should succeed.
3840      *
3841      * @param iface a Class defining an interface.
3842      * @return true if this implements the interface or directly or indirectly wraps an object that does.
3843      * @throws java.sql.SQLException  if an error occurs while determining whether this is a wrapper
3844      * for an object with the given interface.
3845      * @since JDK 1.6, HSQLDB 2.0
3846      */
3847 //#ifdef JAVA6
3848     public boolean isWrapperFor(
3849             java.lang.Class<?> iface) throws java.sql.SQLException {
3850         return (iface != null && iface.isAssignableFrom(this.getClass()));
3851     }
3852 
3853 //#endif JAVA6
3854     //-------------------- Internal Implementation -----------------------------
3855 
3856     /**
3857      * Constructs a statement that produces results of the requested
3858      * <code>type</code>. <p>
3859      *
3860      * A prepared statement must be a single SQL statement. <p>
3861      *
3862      * @param c the Connection used execute this statement
3863      * @param sql the SQL statement this object represents
3864      * @param resultSetType the type of result this statement will produce (scrollability)
3865      * @param resultSetConcurrency (updatability)
3866      * @param resultSetHoldability (validity beyond commit)
3867      * @param generatedKeys internal mode of handling generated key reporting
3868      * @param generatedIndexes column indexes for generated keys
3869      * @param generatedNames column names for generated keys are given
3870      * @throws HsqlException if the statement is not accepted by the database
3871      * @throws SQLException if preprocessing by driver fails
3872      */
3873     JDBCPreparedStatement(JDBCConnection c, String sql, int resultSetType,
3874                           int resultSetConcurrency, int resultSetHoldability,
3875                           int generatedKeys, int[] generatedIndexes,
3876                           String[] generatedNames) throws HsqlException,
3877                               SQLException {
3878 
3879         isResult              = false;
3880         connection            = c;
3881         connectionIncarnation = connection.incarnation;
3882         session               = c.sessionProxy;
3883         sql                   = c.nativeSQL(sql);
3884 
3885         resultOut = Result.newPrepareStatementRequest();
3886 
3887         int props = ResultProperties.getValueForJDBC(resultSetType,
3888             resultSetConcurrency, resultSetHoldability);
3889 
3890         resultOut.setPrepareOrExecuteProperties(sql, 0, 0, 0, queryTimeout,
3891                 props, generatedKeys, generatedIndexes, generatedNames);
3892 
3893         Result in = session.execute(resultOut);
3894 
3895         if (in.mode == ResultConstants.ERROR) {
3896             throw JDBCUtil.sqlException(in);
3897         }
3898         rootWarning = null;
3899 
3900         Result current = in;
3901 
3902         while (current.getChainedResult() != null) {
3903             current = current.getUnlinkChainedResult();
3904 
3905             if (current.isWarning()) {
3906                 SQLWarning w = JDBCUtil.sqlWarning(current);
3907 
3908                 if (rootWarning == null) {
3909                     rootWarning = w;
3910                 } else {
3911                     rootWarning.setNextWarning(w);
3912                 }
3913             }
3914         }
3915         connection.setWarnings(rootWarning);
3916 
3917         statementID       = in.getStatementID();
3918         statementRetType  = in.getStatementType();
3919         resultMetaData    = in.metaData;
3920         parameterMetaData = in.parameterMetaData;
3921         parameterTypes    = parameterMetaData.getParameterTypes();
3922         parameterModes    = parameterMetaData.paramModes;
3923         rsProperties      = in.rsProperties;
3924 
3925         //
3926         int paramCount = parameterMetaData.getColumnCount();
3927 
3928         parameterValues = new Object[paramCount];
3929         parameterSet    = new Boolean[paramCount];
3930         streamLengths   = new long[paramCount];
3931 
3932         //
3933         //
3934         for (int i = 0; i < paramCount; i++) {
3935             if (parameterTypes[i].isLobType()) {
3936                 hasLOBs = true;
3937 
3938                 break;
3939             }
3940         }
3941 
3942         //
3943         resultOut = Result.newPreparedExecuteRequest(parameterTypes,
3944                 statementID);
3945 
3946         resultOut.setStatement(in.getStatement());
3947 
3948         // for toString()
3949         this.sql = sql;
3950     }
3951 
3952     /**
3953      * Constructor for updatable ResultSet
3954      */
3955     JDBCPreparedStatement(JDBCConnection c, Result result) {
3956 
3957         isResult              = true;
3958         connection            = c;
3959         connectionIncarnation = connection.incarnation;
3960         session               = c.sessionProxy;
3961 
3962         int paramCount = result.metaData.getExtendedColumnCount();
3963 
3964         parameterMetaData = result.metaData;
3965         parameterTypes    = result.metaData.columnTypes;
3966         parameterModes    = new byte[paramCount];
3967         parameterValues   = new Object[paramCount];
3968         parameterSet      = new Boolean[paramCount];
3969         streamLengths     = new long[paramCount];
3970 
3971         //
3972         for (int i = 0; i < paramCount; i++) {
3973             parameterModes[i] = SchemaObject.ParameterModes.PARAM_IN;
3974 
3975             if (parameterTypes[i].isLobType()) {
3976                 hasLOBs = true;
3977             }
3978         }
3979 
3980         //
3981         resultOut = Result.newUpdateResultRequest(parameterTypes,
3982                 result.getResultId());
3983     }
3984 
3985     /**
3986      * Checks if execution does or does not generate a single row
3987      * update count, throwing if the argument, yes, does not match. <p>
3988      *
3989      * @param type type of statement regarding what it returns
3990      *      something other than a single row update count.
3991      * @throws SQLException if the argument, yes, does not match
3992      */
3993     protected void checkStatementType(int type) throws SQLException {
3994 
3995         if (type != statementRetType) {
3996             if (statementRetType == StatementTypes.RETURN_COUNT) {
3997                 throw JDBCUtil.sqlException(ErrorCode.X_07504);
3998             } else {
3999                 throw JDBCUtil.sqlException(ErrorCode.X_07503);
4000             }
4001         }
4002     }
4003 
4004     protected void checkParameterIndex(int i) throws SQLException {
4005 
4006         if (isClosed || connection.isClosed) {
4007             checkClosed();
4008         }
4009 
4010         if (i < 1 || i > parameterValues.length) {
4011             String msg = "parameter index out of range: " + i;
4012 
4013             throw JDBCUtil.outOfRangeArgument(msg);
4014         }
4015     }
4016 
4017     /**
4018      * Checks if the specified parameter index value is valid in terms of
4019      * setting an IN or IN OUT parameter value. <p>
4020      *
4021      * @param i The parameter index to check
4022      * @throws SQLException if the specified parameter index is invalid
4023      */
4024     protected void checkSetParameterIndex(int i) throws SQLException {
4025 
4026         if (isClosed || connection.isClosed) {
4027             checkClosed();
4028         }
4029 
4030         if (i < 1 || i > parameterValues.length) {
4031             String msg = "parameter index out of range: " + i;
4032 
4033             throw JDBCUtil.outOfRangeArgument(msg);
4034         }
4035 
4036         if (parameterModes[i - 1] == SchemaObject.ParameterModes.PARAM_OUT) {
4037             String msg = "Not IN or INOUT mode for parameter: " + i;
4038 
4039             throw JDBCUtil.invalidArgument(msg);
4040         }
4041     }
4042 
4043     /**
4044      * Checks if the specified parameter index value is valid in terms of
4045      * getting an OUT or INOUT parameter value. <p>
4046      *
4047      * @param i The parameter index to check
4048      * @throws SQLException if the specified parameter index is invalid
4049      */
4050     protected void checkGetParameterIndex(int i) throws SQLException {
4051 
4052         String msg;
4053 
4054         if (isClosed || connection.isClosed) {
4055             checkClosed();
4056         }
4057 
4058         if (i < 1 || i > parameterValues.length) {
4059             msg = "parameter index out of range: " + i;
4060 
4061             throw JDBCUtil.outOfRangeArgument(msg);
4062         }
4063 
4064         int mode = parameterModes[i - 1];
4065 
4066         switch (mode) {
4067 
4068             case SchemaObject.ParameterModes.PARAM_UNKNOWN :
4069             case SchemaObject.ParameterModes.PARAM_OUT :
4070             case SchemaObject.ParameterModes.PARAM_INOUT :
4071                 break;
4072             case SchemaObject.ParameterModes.PARAM_IN :
4073             default :
4074                 msg = "Not OUT or INOUT mode: " + mode + " for parameter: "
4075                       + i;
4076 
4077                 throw JDBCUtil.invalidArgument(msg);
4078         }
4079     }
4080 
4081     /**
4082      * Called just before execution or adding to batch, this ensures all the
4083      * parameters have been set.<p>
4084      *
4085      * If a parameter has been set using a stream method, it should be set
4086      * again for the next reuse. When set using other methods, the parameter
4087      * setting is retained for the next use.
4088      * @throws SQLException
4089      */
4090     private void checkParametersSet() throws SQLException {
4091 
4092         if (isResult) {
4093             return;
4094         }
4095 
4096         for (int i = 0; i < parameterSet.length; i++) {
4097             if (parameterModes[i] != SchemaObject.ParameterModes.PARAM_OUT) {
4098                 if (parameterSet[i] == null) {
4099                     throw JDBCUtil.sqlException(ErrorCode.JDBC_PARAMETER_NOT_SET);
4100                 }
4101             }
4102         }
4103     }
4104 
4105     /**
4106      * The internal parameter value setter always converts the parameter to
4107      * the Java type required for data transmission.
4108      *
4109      * @param i parameter index
4110      * @param o object
4111      * @throws SQLException if either argument is not acceptable.
4112      */
4113     void setParameter(int i, Object o) throws SQLException {
4114 
4115         checkSetParameterIndex(i);
4116 
4117         i--;
4118 
4119         if (o == null) {
4120             parameterValues[i] = null;
4121             parameterSet[i]    = Boolean.TRUE;
4122 
4123             return;
4124         }
4125 
4126         Type outType = parameterTypes[i];
4127 
4128         switch (outType.typeCode) {
4129 
4130             case Types.OTHER :
4131                 try {
4132                     if (connection.isStoreLiveObject) {
4133                         o = new JavaObjectDataInternal(o);
4134 
4135                         break;
4136                     }
4137 
4138                     if (o instanceof Serializable) {
4139                         o = new JavaObjectData((Serializable) o);
4140 
4141                         break;
4142                     }
4143                 } catch (HsqlException e) {
4144                     JDBCUtil.throwError(e);
4145                 }
4146                 JDBCUtil.throwError(Error.error(ErrorCode.X_42563));
4147             case Types.SQL_BIT :
4148             case Types.SQL_BIT_VARYING :
4149                 try {
4150                     if (o instanceof Boolean) {
4151                         o = outType.convertToDefaultType(session, o);
4152 
4153                         break;
4154                     }
4155 
4156                     if (o instanceof Integer) {
4157                         o = outType.convertToDefaultType(session, o);
4158 
4159                         break;
4160                     }
4161 
4162                     if (o instanceof byte[]) {
4163                         o = outType.convertToDefaultType(session, o);
4164 
4165                         break;
4166                     }
4167 
4168                     if (o instanceof String) {
4169                         o = outType.convertToDefaultType(session, o);
4170 
4171                         break;
4172                     }
4173                 } catch (HsqlException e) {
4174                     JDBCUtil.throwError(e);
4175                 }
4176                 JDBCUtil.throwError(Error.error(ErrorCode.X_42563));
4177 
4178             // fall through
4179             case Types.SQL_BINARY :
4180             case Types.SQL_VARBINARY :
4181             case Types.SQL_GUID :
4182                 if (o instanceof byte[]) {
4183                     o = new BinaryData((byte[]) o, !connection.isNetConn);
4184 
4185                     break;
4186                 }
4187 
4188                 if (o instanceof UUID) {
4189                     o = BinaryUUIDType.getBinary((UUID) o);
4190                     break;
4191                 }
4192 
4193                 try {
4194                     if (o instanceof String) {
4195                         o = outType.convertToDefaultType(session, o);
4196 
4197                         break;
4198                     }
4199                 } catch (HsqlException e) {
4200                     JDBCUtil.throwError(e);
4201                 }
4202                 JDBCUtil.throwError(Error.error(ErrorCode.X_42563));
4203 
4204                 break;
4205             case Types.SQL_ARRAY :
4206                 if (o instanceof Array) {
4207                     setArray(i + 1, (Array) o);
4208 
4209                     return;
4210                 }
4211 
4212                 if (o instanceof ArrayList) {
4213                     o = ((ArrayList) o).toArray();
4214                 }
4215 
4216                 if (o instanceof Object[]) {
4217                     Type     baseType = outType.collectionBaseType();
4218                     Object[] array    = (Object[]) o;
4219                     Object[] data     = new Object[array.length];
4220 
4221                     for (int j = 0; j < data.length; j++) {
4222                         data[j] = baseType.convertJavaToSQL(session, array[j]);
4223                     }
4224                     o = data;
4225 
4226                     break;
4227                 }
4228                 JDBCUtil.throwError(Error.error(ErrorCode.X_42563));
4229             case Types.SQL_BLOB :
4230                 setBlobParameter(i + 1, o);
4231 
4232                 return;
4233             case Types.SQL_CLOB :
4234                 setClobParameter(i + 1, o);
4235 
4236                 return;
4237             case Types.SQL_DATE :
4238             case Types.SQL_TIME_WITH_TIME_ZONE :
4239             case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
4240             case Types.SQL_TIME :
4241             case Types.SQL_TIMESTAMP : {
4242                 try {
4243                     if (o instanceof String) {
4244                         o = outType.convertToType(session, o,
4245                                 Type.SQL_VARCHAR);
4246 
4247                         break;
4248                     }
4249                     o = outType.convertJavaToSQL(session, o);
4250 
4251                     break;
4252                 } catch (HsqlException e) {
4253                     JDBCUtil.throwError(e);
4254                 }
4255             }
4256             case Types.TINYINT :
4257             case Types.SQL_SMALLINT :
4258             case Types.SQL_INTEGER :
4259             case Types.SQL_BIGINT :
4260             case Types.SQL_REAL :
4261             case Types.SQL_FLOAT :
4262             case Types.SQL_DOUBLE :
4263             case Types.SQL_NUMERIC :
4264             case Types.SQL_DECIMAL :
4265                 try {
4266                     if (o instanceof String) {
4267                         o = outType.convertToType(session, o,
4268                                 Type.SQL_VARCHAR);
4269 
4270                         break;
4271                     } else if (o instanceof Boolean) {
4272                         boolean value = ((Boolean) o).booleanValue();
4273 
4274                         o = value ? Integer.valueOf(1)
4275                                   : Integer.valueOf(0);
4276                     }
4277                     o = outType.convertToDefaultType(session, o);
4278 
4279                     break;
4280                 } catch (HsqlException e) {
4281                     JDBCUtil.throwError(e);
4282                 }
4283             case Types.SQL_VARCHAR : {
4284                 if (o instanceof String) {
4285                     break;
4286                 } else {
4287                     try {
4288                         o = outType.convertToDefaultType(session, o);
4289 
4290                         break;
4291                     } catch (HsqlException e) {
4292                         JDBCUtil.throwError(e);
4293                     }
4294                 }
4295             }
4296             case Types.SQL_CHAR :
4297                 if (outType.precision == 1) {
4298                     if (o instanceof Character) {
4299                         o = new String(new char[] {
4300                             ((Character) o).charValue() });
4301 
4302                         break;
4303                     } else if (o instanceof Boolean) {
4304                         o = ((Boolean) o).booleanValue() ? "1"
4305                                 : "0";
4306 
4307                         break;
4308                     }
4309                 }
4310 
4311             // fall through
4312             default :
4313                 try {
4314                     o = outType.convertToDefaultType(session, o);
4315 
4316                     break;
4317                 } catch (HsqlException e) {
4318                     JDBCUtil.throwError(e);
4319                 }
4320         }
4321         parameterValues[i] = o;
4322         parameterSet[i]    = Boolean.TRUE;
4323     }
4324 
4325     /**
4326      * setParameterForClob
4327      *
4328      * @param i int
4329      * @param o Object
4330      * @throws SQLException
4331      */
4332     void setClobParameter(int i, Object o) throws SQLException {
4333         setClobParameter(i, o, 0);
4334     }
4335 
4336     void setClobParameter(int i, Object o,
4337                           long streamLength) throws SQLException {
4338 
4339         if (o instanceof JDBCClobClient) {
4340             JDBCClobClient clob = (JDBCClobClient) o;
4341 
4342             if (!clob.session.getDatabaseUniqueName().equals(
4343                     session.getDatabaseUniqueName())) {
4344                 streamLength = clob.length();
4345 
4346                 Reader is = clob.getCharacterStream();
4347 
4348                 parameterValues[i - 1] = is;
4349                 streamLengths[i - 1]   = streamLength;
4350                 parameterSet[i - 1]    = Boolean.FALSE;
4351 
4352                 return;
4353             }
4354             parameterValues[i - 1] = o;
4355             parameterSet[i - 1]    = Boolean.TRUE;
4356 
4357             return;
4358         } else if (o instanceof Clob) {
4359             parameterValues[i - 1] = o;
4360             parameterSet[i - 1]    = Boolean.TRUE;
4361 
4362             return;
4363         } else if (o instanceof ClobInputStream) {
4364             ClobInputStream is = (ClobInputStream) o;
4365 
4366             if (is.session.getDatabaseUniqueName().equals(
4367                     session.getDatabaseUniqueName())) {
4368                 throw JDBCUtil.sqlException(ErrorCode.JDBC_INVALID_ARGUMENT,
4369                                         "invalid Reader");
4370             }
4371             parameterValues[i - 1] = o;
4372             streamLengths[i - 1]   = streamLength;
4373             parameterSet[i - 1]    = Boolean.FALSE;
4374 
4375             return;
4376         } else if (o instanceof Reader) {
4377             parameterValues[i - 1] = o;
4378             streamLengths[i - 1]   = streamLength;
4379             parameterSet[i - 1]    = Boolean.FALSE;
4380 
4381             return;
4382         } else if (o instanceof String) {
4383             JDBCClob clob = new JDBCClob((String) o);
4384 
4385             parameterValues[i - 1] = clob;
4386             parameterSet[i - 1]    = Boolean.FALSE;
4387 
4388             return;
4389         }
4390 
4391         throw JDBCUtil.invalidArgument();
4392     }
4393 
4394     /**
4395      * setParameterForBlob
4396      *
4397      * @param i int
4398      * @param o Object
4399      */
4400     void setBlobParameter(int i, Object o) throws SQLException {
4401         setBlobParameter(i, o, 0);
4402     }
4403 
4404     void setBlobParameter(int i, Object o,
4405                           long streamLength) throws SQLException {
4406 
4407         if (o instanceof JDBCBlobClient) {
4408             JDBCBlobClient blob = (JDBCBlobClient) o;
4409 
4410             if (!blob.session.getDatabaseUniqueName().equals(
4411                     session.getDatabaseUniqueName())) {
4412                 streamLength = blob.length();
4413 
4414                 InputStream is = blob.getBinaryStream();
4415 
4416                 parameterValues[i - 1] = is;
4417                 streamLengths[i - 1]   = streamLength;
4418                 parameterSet[i - 1]    = Boolean.FALSE;
4419 
4420                 return;
4421             }
4422 
4423             // in the same database
4424             parameterValues[i - 1] = o;
4425             parameterSet[i - 1]    = Boolean.TRUE;
4426 
4427             return;
4428         } else if (o instanceof Blob) {
4429             parameterValues[i - 1] = o;
4430             parameterSet[i - 1]    = Boolean.FALSE;
4431 
4432             return;
4433         } else if (o instanceof BlobInputStream) {
4434             BlobInputStream is = (BlobInputStream) o;
4435 
4436             if (is.session.getDatabaseUniqueName().equals(
4437                     session.getDatabaseUniqueName())) {
4438                 throw JDBCUtil.sqlException(ErrorCode.JDBC_INVALID_ARGUMENT,
4439                                         "invalid Reader");
4440             }
4441 
4442             // in the same database ? see if it blocks in
4443             parameterValues[i - 1] = o;
4444             streamLengths[i - 1]   = streamLength;
4445             parameterSet[i - 1]    = Boolean.FALSE;
4446 
4447             return;
4448         } else if (o instanceof InputStream) {
4449             parameterValues[i - 1] = o;
4450             streamLengths[i - 1]   = streamLength;
4451             parameterSet[i - 1]    = Boolean.FALSE;
4452 
4453             return;
4454         } else if (o instanceof byte[]) {
4455             JDBCBlob blob = new JDBCBlob((byte[]) o);
4456 
4457             parameterValues[i - 1] = blob;
4458             parameterSet[i - 1]    = Boolean.TRUE;
4459 
4460             return;
4461         }
4462 
4463         throw JDBCUtil.invalidArgument();
4464     }
4465 
4466     /**
4467      * Used with int and narrower integral primitives
4468      * @param i parameter index
4469      * @param value object to set
4470      * @throws SQLException if either argument is not acceptable
4471      */
4472     void setIntParameter(int i, int value) throws SQLException {
4473 
4474         checkSetParameterIndex(i);
4475 
4476         int outType = parameterTypes[i - 1].typeCode;
4477 
4478         switch (outType) {
4479 
4480             case Types.TINYINT :
4481             case Types.SQL_SMALLINT :
4482             case Types.SQL_INTEGER : {
4483                 Object o = Integer.valueOf(value);
4484 
4485                 parameterValues[i - 1] = o;
4486                 parameterSet[i - 1]    = Boolean.TRUE;
4487 
4488                 break;
4489             }
4490             case Types.SQL_BIGINT : {
4491                 Object o = Long.valueOf(value);
4492 
4493                 parameterValues[i - 1] = o;
4494                 parameterSet[i - 1]    = Boolean.TRUE;
4495 
4496                 break;
4497             }
4498             case Types.SQL_BINARY :
4499             case Types.SQL_VARBINARY :
4500             case Types.OTHER :
4501                 throw JDBCUtil.sqlException(Error.error(ErrorCode.X_42563));
4502             default :
4503                 setParameter(i, Integer.valueOf(value));
4504         }
4505     }
4506 
4507     /**
4508      * Used with long and narrower integral primitives. Conversion to BINARY
4509      * or OTHER types will throw here and not passed to setParameter().
4510      *
4511      * @param i parameter index
4512      * @param value object to set
4513      * @throws SQLException if either argument is not acceptable
4514      */
4515     void setLongParameter(int i, long value) throws SQLException {
4516 
4517         checkSetParameterIndex(i);
4518 
4519         int outType = parameterTypes[i - 1].typeCode;
4520 
4521         switch (outType) {
4522 
4523             case Types.SQL_BIGINT :
4524                 Object o = Long.valueOf(value);
4525 
4526                 parameterValues[i - 1] = o;
4527                 parameterSet[i - 1]    = Boolean.TRUE;
4528 
4529                 break;
4530             case Types.SQL_BINARY :
4531             case Types.SQL_VARBINARY :
4532             case Types.OTHER :
4533                 throw JDBCUtil.sqlException(Error.error(ErrorCode.X_42563));
4534             default :
4535                 setParameter(i, Long.valueOf(value));
4536         }
4537     }
4538 
4539     private void performPreExecute() throws SQLException, HsqlException {
4540 
4541         if (!hasLOBs) {
4542             return;
4543         }
4544 
4545         for (int i = 0; i < parameterValues.length; i++) {
4546             Object value = parameterValues[i];
4547 
4548             if (value == null) {
4549                 continue;
4550             }
4551 
4552             if (parameterTypes[i].typeCode == Types.SQL_BLOB) {
4553                 long       id;
4554                 BlobDataID blob = null;
4555 
4556                 if (value instanceof JDBCBlobClient) {
4557 
4558                     // check or fix id mismatch
4559                     blob = ((JDBCBlobClient) value).blob;
4560                     id   = blob.getId();
4561                 } else if (value instanceof Blob) {
4562                     long length = ((Blob) value).length();
4563 
4564                     blob = session.createBlob(length);
4565                     id   = blob.getId();
4566 
4567                     InputStream stream = ((Blob) value).getBinaryStream();
4568                     ResultLob resultLob =
4569                         ResultLob.newLobCreateBlobRequest(session.getId(), id,
4570                             stream, length);
4571 
4572                     session.allocateResultLob(resultLob, null);
4573                     resultOut.addLobResult(resultLob);
4574                 } else if (value instanceof InputStream) {
4575                     long length = streamLengths[i];
4576 
4577                     long createLength = length > 0 ? length : 0;
4578 
4579                     blob = session.createBlob(createLength);
4580                     id   = blob.getId();
4581 
4582                     InputStream stream = (InputStream) value;
4583                     ResultLob resultLob =
4584                         ResultLob.newLobCreateBlobRequest(session.getId(), id,
4585                             stream, length);
4586 
4587                     session.allocateResultLob(resultLob, null);
4588                     resultOut.addLobResult(resultLob);
4589                 } else if (value instanceof BlobDataID) {
4590                     blob = (BlobDataID) value;
4591                 }
4592                 parameterValues[i] = blob;
4593             } else if (parameterTypes[i].typeCode == Types.SQL_CLOB) {
4594                 long       id;
4595                 ClobDataID clob = null;
4596 
4597                 if (value instanceof JDBCClobClient) {
4598 
4599                     // check or fix id mismatch
4600                     clob = ((JDBCClobClient) value).clob;
4601                     id   = clob.getId();
4602                 } else if (value instanceof Clob) {
4603                     long   length = ((Clob) value).length();
4604                     Reader reader = ((Clob) value).getCharacterStream();
4605 
4606                     clob = session.createClob(length);
4607                     id   = clob.getId();
4608 
4609                     ResultLob resultLob =
4610                         ResultLob.newLobCreateClobRequest(session.getId(), id,
4611                             reader, length);
4612 
4613                     session.allocateResultLob(resultLob, null);
4614                     resultOut.addLobResult(resultLob);
4615                 } else if (value instanceof Reader) {
4616                     long length = streamLengths[i];
4617 
4618                     long createLength = length > 0 ? length : 0;
4619 
4620                     clob = session.createClob(createLength);
4621                     id   = clob.getId();
4622 
4623                     Reader reader = (Reader) value;
4624                     ResultLob resultLob =
4625                         ResultLob.newLobCreateClobRequest(session.getId(), id,
4626                             reader, length);
4627 
4628                     session.allocateResultLob(resultLob, null);
4629                     resultOut.addLobResult(resultLob);
4630                 } else if (value instanceof ClobDataID) {
4631                     clob = (ClobDataID) value;
4632                 }
4633                 parameterValues[i] = clob;
4634             }
4635         }
4636     }
4637 
4638     /**
4639      * Internal result producer for JDBCStatement (sqlExecDirect mode).
4640      * <p>
4641      *
4642      * @throws SQLException when a database access error occurs
4643      */
4644     void fetchResult() throws SQLException {
4645 
4646         if (isClosed || connection.isClosed) {
4647             checkClosed();
4648         }
4649         closeResultData();
4650         checkParametersSet();
4651 
4652         if (isBatch) {
4653             throw JDBCUtil.sqlExceptionSQL(ErrorCode.X_07505);
4654         }
4655 
4656         //
4657         if (isResult) {
4658             resultOut.setPreparedResultUpdateProperties(parameterValues);
4659         } else {
4660             resultOut.setPreparedExecuteProperties(parameterValues, maxRows,
4661                     fetchSize, rsProperties, queryTimeout);
4662         }
4663 
4664         try {
4665             performPreExecute();
4666 
4667             resultIn = session.execute(resultOut);
4668         } catch (HsqlException e) {
4669             throw JDBCUtil.sqlException(e);
4670         } finally {
4671             performPostExecute();
4672         }
4673 
4674         if (resultIn.mode == ResultConstants.ERROR) {
4675             throw JDBCUtil.sqlException(resultIn);
4676         }
4677 
4678         if (resultIn.isData()) {
4679             currentResultSet = new JDBCResultSet(connection, this, resultIn,
4680                     resultIn.metaData);
4681         } else if (statementRetType == StatementTypes.RETURN_RESULT) {
4682             getMoreResults();
4683         }
4684     }
4685 
4686     boolean isAnyParameterSet() {
4687 
4688         for (int i = 0; i < parameterValues.length; i++) {
4689             if (parameterSet[i] != null) {
4690                 return true;
4691             }
4692         }
4693 
4694         return false;
4695     }
4696 
4697     /**
4698      * processes chained warnings and any generated columns result set
4699      */
4700     void performPostExecute() throws SQLException {
4701         super.performPostExecute();
4702     }
4703 
4704     /** The parameter values for the next non-batch execution. */
4705     protected Object[] parameterValues;
4706 
4707     /** Flags for bound variables. */
4708     protected Boolean[] parameterSet;
4709 
4710     /** The SQL types of the parameters. */
4711     protected Type[] parameterTypes;
4712 
4713     /** The (IN, IN OUT, or OUT) modes of parameters */
4714     protected byte[] parameterModes;
4715 
4716     /** Lengths for streams. */
4717     protected long[] streamLengths;
4718 
4719     /** Has one or more CLOB / BLOB type parameters. */
4720     protected boolean hasLOBs;
4721 
4722     /** Is in batch mode. */
4723     protected boolean isBatch;
4724 
4725     /** Description of result set metadata. */
4726     protected ResultMetaData resultMetaData;
4727 
4728     /** Description of parameter metadata. */
4729     protected ResultMetaData parameterMetaData;
4730 
4731     /** This object's one and one ResultSetMetaData object. */
4732     protected JDBCResultSetMetaData resultSetMetaData;
4733 
4734     // NOTE:  pmd is declared as Object to avoid yet another #ifdef.
4735 
4736     /** This object's one and only ParameterMetaData object. */
4737     protected Object pmd;
4738 
4739     /** The SQL character sequence that this object represents. */
4740     protected String sql;
4741 
4742     /** ID of the statement. */
4743     protected long statementID;
4744 
4745     /** Statement type - whether it generates a row update count or a result set. */
4746     protected int statementRetType;
4747 
4748     /** Is part of a Result. */
4749     protected final boolean isResult;
4750 
4751     /** The session attribute of the connection */
4752     protected SessionInterface session;
4753 }
4754