View Javadoc

1   /***
2    * WrappedPreparedStatement.java
3    *
4    * This file is part of the creme library.
5    * The creme library intends to ease the development effort of large
6    * applications by providing easy to use support classes.
7    *
8    * Copyright (C) 2002 Denis Bregeon
9    *
10   *
11   * This library is free software; you can redistribute it and/or
12   * modify it under the terms of the GNU Lesser General Public
13   * License as published by the Free Software Foundation; either
14   * version 2.1 of the License, or (at your option) any later version.
15   *
16   * This library is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   * Lesser General Public License for more details.
20   *
21   * You should have received a copy of the GNU Lesser General Public
22   * License along with this library; if not, write to the Free Software
23   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24   *
25   * contact information: dbregeon@sourceforge.net
26   */
27  package org.jcreme.sql;
28  
29  import java.io.InputStream;
30  import java.io.Reader;
31  import java.math.BigDecimal;
32  import java.net.URL;
33  import java.sql.Array;
34  import java.sql.Blob;
35  import java.sql.Clob;
36  import java.sql.Date;
37  import java.sql.ParameterMetaData;
38  import java.sql.PreparedStatement;
39  import java.sql.Ref;
40  import java.sql.ResultSet;
41  import java.sql.ResultSetMetaData;
42  import java.sql.SQLException;
43  import java.sql.Statement;
44  import java.sql.Time;
45  import java.sql.Timestamp;
46  import java.util.Calendar;
47  
48  /***
49   * This class enables to wrap an actual statement to provide a few extra
50   * services: tracing of the queries, handling of some exceptions (rollback, loss
51   * of connection). The ResultSets provided by this class are wrapped around the
52   * actual ResultSet.
53   * 
54   * @author $Author: dbregeon $
55   * @version $Revision: 1.1 $
56   */
57  public class WrappedPreparedStatement extends WrappedStatement implements
58          PreparedStatement {
59      /***
60       * This array records the parameters that have currently been set in the
61       * PreparedStatement.
62       */
63      private Object[] currentParams = null;
64  
65      /***
66       * Enables to wrap a PreparedStatement.
67       * 
68       * @param preparedStatement
69       *            the statement to wrap.
70       * @param sql
71       *            the query associated to the PreparedStatement.
72       * @throws SQLException
73       *             if the preparedStatement is null.
74       */
75      public WrappedPreparedStatement(PreparedStatement preparedStatement,
76              String sql) throws SQLException {
77          super(preparedStatement);
78          if (preparedStatement == null) {
79              throw new SQLException("Null Prepared Statement.");
80          }
81          setBaseQuery(sql);
82      }
83  
84      /***
85       * This method enables to set the base query of the statement.
86       * 
87       * @param sql
88       *            the sql query underlying the statement.
89       * @throws SQLException
90       *             if the query is null.
91       */
92      protected void setBaseQuery(String sql) throws SQLException {
93          super.setBaseQuery(sql);
94          int j = 0;
95          for (int i = sql.indexOf('?', 0); i >= 0; i = sql.indexOf('?', i)) {
96              j++;
97              i++;
98          }
99          this.currentParams = new Object[j];
100     }
101 
102     /***
103      * This method enables to substitute the parameters set in the statement in
104      * the baseQuery. They replace the '?'.
105      * 
106      * @return the current query.
107      */
108     protected String buildActualQuery() {
109         String actualQuery = new String(super.baseQuery);
110         int i = actualQuery.indexOf('?');
111         String paramString;
112         for (int j = 0; j < this.currentParams.length; j++) {
113             if (this.currentParams[j] != null) {
114                 paramString = this.currentParams[j].toString();
115             } else {
116                 paramString = "null";
117             }
118             String beforeParam = actualQuery.substring(0, i);
119             String afterParam = actualQuery.substring(i + 1);
120             actualQuery = beforeParam + "'" + paramString + "'" + afterParam;
121             i = actualQuery.indexOf('?');
122         }
123         return actualQuery;
124     }
125 
126     /***
127      * This method enables to append a message to the original exception's
128      * message.
129      * 
130      * @param e
131      *            the original exception.
132      * @return an exception with the appended message.
133      */
134     protected SQLException generateException(SQLException e) {
135         return super.generateException(buildActualQuery(), e);
136     }
137 
138     /***
139      * Executes the SQL query in this <code>PreparedStatement</code> object
140      * and returns the <code>ResultSet</code> object generated by the query.
141      * 
142      * @return a <code>ResultSet</code> object that contains the data produced
143      *         by the query; never <code>null</code>
144      * @exception SQLException
145      *                if a database access error occurs or the SQL statement
146      *                does not return a <code>ResultSet</code> object
147      */
148     public ResultSet executeQuery() throws SQLException {
149         try {
150             return new WrappedResultSet(
151                     ((PreparedStatement) super.realStatement).executeQuery(),
152                     this, buildActualQuery());
153         } catch (SQLException e) {
154             CremeAction redo = null;
155             try {
156                 redo = new CremeAction(getClass().getMethod("executeQuery",
157                         new Class[0]));
158                 redo.setSubject(this);
159             } catch (NoSuchMethodException ex) {
160                 ex.printStackTrace();
161             } catch (IllegalArgumentException ex) {
162                 ex.printStackTrace();
163             }
164             manageException(e, redo);
165             if (redo != null && redo.isSuccessfull()) {
166                 return (ResultSet) redo.getResult();
167             }
168             throw generateException(e);
169         }
170     }
171 
172     /***
173      * Executes the SQL statement in this <code>PreparedStatement</code>
174      * object, which must be an SQL <code>INSERT</code>,<code>UPDATE</code>
175      * or <code>DELETE</code> statement; or an SQL statement that returns
176      * nothing, such as a DDL statement.
177      * 
178      * @return either (1) the row count for <code>INSERT</code>,
179      *         <code>UPDATE</code>, or <code>DELETE</code> statements or
180      *         (2) 0 for SQL statements that return nothing
181      * @exception SQLException
182      *                if a database access error occurs or the SQL statement
183      *                returns a <code>ResultSet</code> object
184      */
185     public int executeUpdate() throws SQLException {
186         try {
187             return ((PreparedStatement) super.realStatement).executeUpdate();
188         } catch (SQLException e) {
189             CremeAction redo = null;
190             try {
191                 redo = new CremeAction(getClass().getMethod("executeUpdate",
192                         new Class[0]));
193                 redo.setSubject(this);
194             } catch (NoSuchMethodException ex) {
195                 ex.printStackTrace();
196             } catch (IllegalArgumentException ex) {
197                 ex.printStackTrace();
198             }
199             manageException(e, redo);
200             if (redo != null && redo.isSuccessfull()) {
201                 return ((Integer) redo.getResult()).intValue();
202             }
203             throw generateException(e);
204         }
205     }
206 
207     /***
208      * Sets the designated parameter to SQL <code>NULL</code>.
209      * 
210      * <P>
211      * <B>Note: </B> You must specify the parameter's SQL type.
212      * 
213      * @param parameterIndex
214      *            the first parameter is 1, the second is 2, ...
215      * @param sqlType
216      *            the SQL type code defined in <code>java.sql.Types</code>
217      * @exception SQLException
218      *                if a database access error occurs
219      */
220     public void setNull(int parameterIndex, int sqlType) throws SQLException {
221         try {
222             ((PreparedStatement) this.realStatement).setNull(parameterIndex,
223                     sqlType);
224             if (parameterIndex <= this.currentParams.length) {
225                 this.currentParams[parameterIndex - 1] = null;
226             }
227         } catch (SQLException e) {
228             manageException(e);
229             throw generateException(e);
230         }
231     }
232 
233     /***
234      * Sets the designated parameter to the given Java <code>boolean</code>
235      * value. The driver converts this to an SQL <code>BIT</code> value when
236      * it sends it to the database.
237      * 
238      * @param parameterIndex
239      *            the first parameter is 1, the second is 2, ...
240      * @param x
241      *            the parameter value
242      * @exception SQLException
243      *                if a database access error occurs
244      */
245     public void setBoolean(int parameterIndex, boolean x) throws SQLException {
246         try {
247             ((PreparedStatement) this.realStatement).setBoolean(parameterIndex,
248                     x);
249             if (parameterIndex <= this.currentParams.length)
250                 this.currentParams[parameterIndex - 1] = new Boolean(x);
251         } catch (SQLException sqlexception) {
252             manageException(sqlexception);
253             throw generateException(sqlexception);
254         }
255     }
256 
257     /***
258      * Sets the designated parameter to the given Java <code>byte</code>
259      * value. The driver converts this to an SQL <code>TINYINT</code> value
260      * when it sends it to the database.
261      * 
262      * @param parameterIndex
263      *            the first parameter is 1, the second is 2, ...
264      * @param x
265      *            the parameter value
266      * @exception SQLException
267      *                if a database access error occurs
268      */
269     public void setByte(int parameterIndex, byte x) throws SQLException {
270         try {
271             ((PreparedStatement) this.realStatement).setByte(parameterIndex, x);
272             if (parameterIndex <= this.currentParams.length) {
273                 this.currentParams[parameterIndex - 1] = new Integer(x);
274             }
275         } catch (SQLException e) {
276             manageException(e);
277             throw generateException(e);
278         }
279     }
280 
281     /***
282      * Sets the designated parameter to the given Java <code>short</code>
283      * value. The driver converts this to an SQL <code>SMALLINT</code> value
284      * when it sends it to the database.
285      * 
286      * @param parameterIndex
287      *            the first parameter is 1, the second is 2, ...
288      * @param x
289      *            the parameter value
290      * @exception SQLException
291      *                if a database access error occurs
292      */
293     public void setShort(int parameterIndex, short x) throws SQLException {
294         try {
295             ((PreparedStatement) this.realStatement)
296                     .setShort(parameterIndex, x);
297             if (parameterIndex <= this.currentParams.length) {
298                 this.currentParams[parameterIndex - 1] = new Integer(x);
299             }
300         } catch (SQLException e) {
301             manageException(e);
302             throw generateException(e);
303         }
304     }
305 
306     /***
307      * Sets the designated parameter to the given Java <code>int</code> value.
308      * The driver converts this to an SQL <code>INTEGER</code> value when it
309      * sends it to the database.
310      * 
311      * @param parameterIndex
312      *            the first parameter is 1, the second is 2, ...
313      * @param x
314      *            the parameter value
315      * @exception SQLException
316      *                if a database access error occurs
317      */
318     public void setInt(int parameterIndex, int x) throws SQLException {
319         try {
320             ((PreparedStatement) this.realStatement).setInt(parameterIndex, x);
321             if (parameterIndex <= this.currentParams.length) {
322                 this.currentParams[parameterIndex - 1] = new Integer(x);
323             }
324         } catch (SQLException e) {
325             manageException(e);
326             throw generateException(e);
327         }
328     }
329 
330     /***
331      * Sets the designated parameter to the given Java <code>long</code>
332      * value. The driver converts this to an SQL <code>BIGINT</code> value
333      * when it sends it to the database.
334      * 
335      * @param parameterIndex
336      *            the first parameter is 1, the second is 2, ...
337      * @param x
338      *            the parameter value
339      * @exception SQLException
340      *                if a database access error occurs
341      */
342     public void setLong(int parameterIndex, long x) throws SQLException {
343         try {
344             ((PreparedStatement) this.realStatement).setLong(parameterIndex, x);
345             if (parameterIndex <= this.currentParams.length) {
346                 this.currentParams[parameterIndex - 1] = new Long(x);
347             }
348         } catch (SQLException e) {
349             manageException(e);
350             throw generateException(e);
351         }
352     }
353 
354     /***
355      * Sets the designated parameter to the given Java <code>float</code>
356      * value. The driver converts this to an SQL <code>FLOAT</code> value when
357      * it sends it to the database.
358      * 
359      * @param parameterIndex
360      *            the first parameter is 1, the second is 2, ...
361      * @param x
362      *            the parameter value
363      * @exception SQLException
364      *                if a database access error occurs
365      */
366     public void setFloat(int parameterIndex, float x) throws SQLException {
367         try {
368             ((PreparedStatement) this.realStatement)
369                     .setFloat(parameterIndex, x);
370             if (parameterIndex <= this.currentParams.length) {
371                 this.currentParams[parameterIndex - 1] = new Double(x);
372             }
373         } catch (SQLException e) {
374             manageException(e);
375             throw generateException(e);
376         }
377     }
378 
379     /***
380      * Sets the designated parameter to the given Java <code>double</code>
381      * value. The driver converts this to an SQL <code>DOUBLE</code> value
382      * when it sends it to the database.
383      * 
384      * @param parameterIndex
385      *            the first parameter is 1, the second is 2, ...
386      * @param x
387      *            the parameter value
388      * @exception SQLException
389      *                if a database access error occurs
390      */
391     public void setDouble(int parameterIndex, double x) throws SQLException {
392         try {
393             ((PreparedStatement) this.realStatement).setDouble(parameterIndex,
394                     x);
395             if (parameterIndex <= this.currentParams.length) {
396                 this.currentParams[parameterIndex - 1] = new Double(x);
397             }
398         } catch (SQLException e) {
399             manageException(e);
400             throw generateException(e);
401         }
402     }
403 
404     /***
405      * Sets the designated parameter to the given
406      * <code>java.math.BigDecimal</code> value. The driver converts this to an
407      * SQL <code>NUMERIC</code> value when it sends it to the database.
408      * 
409      * @param parameterIndex
410      *            the first parameter is 1, the second is 2, ...
411      * @param x
412      *            the parameter value
413      * @exception SQLException
414      *                if a database access error occurs
415      */
416     public void setBigDecimal(int parameterIndex, BigDecimal x)
417             throws SQLException {
418         try {
419             ((PreparedStatement) this.realStatement).setBigDecimal(
420                     parameterIndex, x);
421             if (parameterIndex <= this.currentParams.length) {
422                 this.currentParams[parameterIndex - 1] = x;
423             }
424         } catch (SQLException e) {
425             manageException(e);
426             throw generateException(e);
427         }
428     }
429 
430     /***
431      * Sets the designated parameter to the given Java <code>String</code>
432      * value. The driver converts this to an SQL <code>VARCHAR</code> or
433      * <code>LONGVARCHAR</code> value (depending on the argument's size
434      * relative to the driver's limits on <code>VARCHAR</code> values) when it
435      * sends it to the database.
436      * 
437      * @param parameterIndex
438      *            the first parameter is 1, the second is 2, ...
439      * @param x
440      *            the parameter value
441      * @exception SQLException
442      *                if a database access error occurs
443      */
444     public void setString(int parameterIndex, String x) throws SQLException {
445         try {
446             ((PreparedStatement) this.realStatement).setString(parameterIndex,
447                     x);
448             if (parameterIndex <= this.currentParams.length) {
449                 if (x != null) {
450                     this.currentParams[parameterIndex - 1] = new String(x);
451                 } else {
452                     this.currentParams[parameterIndex - 1] = null;
453                 }
454             }
455         } catch (SQLException e) {
456             manageException(e);
457             throw generateException(e);
458         }
459     }
460 
461     /***
462      * Sets the designated parameter to the given Java array of bytes. The
463      * driver converts this to an SQL <code>VARBINARY</code> or
464      * <code>LONGVARBINARY</code> (depending on the argument's size relative
465      * to the driver's limits on <code>VARBINARY</code> values) when it sends
466      * it to the database.
467      * 
468      * @param parameterIndex
469      *            the first parameter is 1, the second is 2, ...
470      * @param x
471      *            the parameter value
472      * @exception SQLException
473      *                if a database access error occurs
474      */
475     public void setBytes(int parameterIndex, byte[] x) throws SQLException {
476         try {
477             ((PreparedStatement) this.realStatement)
478                     .setBytes(parameterIndex, x);
479             if (parameterIndex <= this.currentParams.length) {
480                 if (x != null) {
481                     this.currentParams[parameterIndex - 1] = x;
482                 } else {
483                     this.currentParams[parameterIndex - 1] = null;
484                 }
485             }
486         } catch (SQLException e) {
487             manageException(e);
488             throw generateException(e);
489         }
490     }
491 
492     /***
493      * Sets the designated parameter to the given <code>java.sql.Date</code>
494      * value. The driver converts this to an SQL <code>DATE</code> value when
495      * it sends it to the database.
496      * 
497      * @param parameterIndex
498      *            the first parameter is 1, the second is 2, ...
499      * @param x
500      *            the parameter value
501      * @exception SQLException
502      *                if a database access error occurs
503      */
504     public void setDate(int parameterIndex, Date x) throws SQLException {
505         try {
506             ((PreparedStatement) this.realStatement).setDate(parameterIndex, x);
507             if (parameterIndex <= this.currentParams.length) {
508                 if (x != null) {
509                     this.currentParams[parameterIndex - 1] = x.clone();
510                 } else {
511                     this.currentParams[parameterIndex - 1] = null;
512                 }
513             }
514         } catch (SQLException e) {
515             manageException(e);
516             throw generateException(e);
517         }
518     }
519 
520     /***
521      * Sets the designated parameter to the given <code>java.sql.Time</code>
522      * value. The driver converts this to an SQL <code>TIME</code> value when
523      * it sends it to the database.
524      * 
525      * @param parameterIndex
526      *            the first parameter is 1, the second is 2, ...
527      * @param x
528      *            the parameter value
529      * @exception SQLException
530      *                if a database access error occurs
531      */
532     public void setTime(int parameterIndex, Time x) throws SQLException {
533         try {
534             ((PreparedStatement) this.realStatement).setTime(parameterIndex, x);
535             if (parameterIndex <= this.currentParams.length) {
536                 if (x != null) {
537                     this.currentParams[parameterIndex - 1] = x.clone();
538                 } else {
539                     this.currentParams[parameterIndex - 1] = null;
540                 }
541             }
542         } catch (SQLException e) {
543             manageException(e);
544             throw generateException(e);
545         }
546     }
547 
548     /***
549      * Sets the designated parameter to the given
550      * <code>java.sql.Timestamp</code> value. The driver converts this to an
551      * SQL <code>TIMESTAMP</code> value when it sends it to the database.
552      * 
553      * @param parameterIndex
554      *            the first parameter is 1, the second is 2, ...
555      * @param x
556      *            the parameter value
557      * @exception SQLException
558      *                if a database access error occurs
559      */
560     public void setTimestamp(int parameterIndex, Timestamp x)
561             throws SQLException {
562         try {
563             ((PreparedStatement) this.realStatement).setTimestamp(
564                     parameterIndex, x);
565             if (parameterIndex <= this.currentParams.length) {
566                 if (x != null) {
567                     this.currentParams[parameterIndex - 1] = x.clone();
568                 } else {
569                     this.currentParams[parameterIndex - 1] = null;
570                 }
571             }
572         } catch (SQLException e) {
573             manageException(e);
574             throw generateException(e);
575         }
576     }
577 
578     /***
579      * Sets the designated parameter to the given input stream, which will have
580      * the specified number of bytes. When a very large ASCII value is input to
581      * a <code>LONGVARCHAR</code> parameter, it may be more practical to send
582      * it via a <code>java.io.InputStream</code>. Data will be read from the
583      * stream as needed until end-of-file is reached. The JDBC driver will do
584      * any necessary conversion from ASCII to the database char format.
585      * 
586      * <P>
587      * <B>Note: </B> This stream object can either be a standard Java stream
588      * object or your own subclass that implements the standard interface.
589      * 
590      * @param parameterIndex
591      *            the first parameter is 1, the second is 2, ...
592      * @param x
593      *            the Java input stream that contains the ASCII parameter value
594      * @param length
595      *            the number of bytes in the stream
596      * @exception SQLException
597      *                if a database access error occurs
598      */
599     public void setAsciiStream(int parameterIndex, InputStream x, int length)
600             throws SQLException {
601         try {
602             ((PreparedStatement) this.realStatement).setAsciiStream(
603                     parameterIndex, x, length);
604             if (parameterIndex <= this.currentParams.length) {
605                 this.currentParams[parameterIndex - 1] = "From Ascii Stream";
606             }
607         } catch (SQLException e) {
608             manageException(e);
609             throw generateException(e);
610         }
611     }
612 
613     /***
614      * Sets the designated parameter to the given input stream, which will have
615      * the specified number of bytes. A Unicode character has two bytes, with
616      * the first byte being the high byte, and the second being the low byte.
617      * 
618      * When a very large Unicode value is input to a <code>LONGVARCHAR</code>
619      * parameter, it may be more practical to send it via a
620      * <code>java.io.InputStream</code> object. The data will be read from the
621      * stream as needed until end-of-file is reached. The JDBC driver will do
622      * any necessary conversion from Unicode to the database char format.
623      * 
624      * <P>
625      * <B>Note: </B> This stream object can either be a standard Java stream
626      * object or your own subclass that implements the standard interface.
627      * 
628      * @param parameterIndex
629      *            the first parameter is 1, the second is 2, ...
630      * @param x
631      *            a <code>java.io.InputStream</code> object that contains the
632      *            Unicode parameter value as two-byte Unicode characters
633      * @param length
634      *            the number of bytes in the stream
635      * @exception SQLException
636      *                if a database access error occurs
637      * @deprecated
638      */
639     public void setUnicodeStream(int parameterIndex, InputStream x, int length)
640             throws SQLException {
641         try {
642             ((PreparedStatement) this.realStatement).setUnicodeStream(
643                     parameterIndex, x, length);
644             if (parameterIndex <= this.currentParams.length) {
645                 this.currentParams[parameterIndex - 1] = "From Unicode Stream";
646             }
647         } catch (SQLException e) {
648             manageException(e);
649             throw generateException(e);
650         }
651     }
652 
653     /***
654      * Sets the designated parameter to the given input stream, which will have
655      * the specified number of bytes. When a very large binary value is input to
656      * a <code>LONGVARBINARY</code> parameter, it may be more practical to
657      * send it via a <code>java.io.InputStream</code> object. The data will be
658      * read from the stream as needed until end-of-file is reached.
659      * 
660      * <P>
661      * <B>Note: </B> This stream object can either be a standard Java stream
662      * object or your own subclass that implements the standard interface.
663      * 
664      * @param parameterIndex
665      *            the first parameter is 1, the second is 2, ...
666      * @param x
667      *            the java input stream which contains the binary parameter
668      *            value
669      * @param length
670      *            the number of bytes in the stream
671      * @exception SQLException
672      *                if a database access error occurs
673      */
674     public void setBinaryStream(int parameterIndex, InputStream x, int length)
675             throws SQLException {
676         try {
677             ((PreparedStatement) this.realStatement).setBinaryStream(
678                     parameterIndex, x, length);
679             if (parameterIndex <= this.currentParams.length) {
680                 this.currentParams[parameterIndex - 1] = "From Binary Stream";
681             }
682         } catch (SQLException e) {
683             manageException(e);
684             throw generateException(e);
685         }
686     }
687 
688     /***
689      * Clears the current parameter values immediately.
690      * <P>
691      * In general, parameter values remain in force for repeated use of a
692      * statement. Setting a parameter value automatically clears its previous
693      * value. However, in some cases it is useful to immediately release the
694      * resources used by the current parameter values; this can be done by
695      * calling the method <code>clearParameters</code>.
696      * 
697      * @exception SQLException
698      *                if a database access error occurs
699      */
700     public void clearParameters() throws SQLException {
701         try {
702             ((PreparedStatement) this.realStatement).clearParameters();
703             for (int i = 0; i < this.currentParams.length; i++) {
704                 this.currentParams[i] = null;
705             }
706         } catch (SQLException e) {
707             manageException(e);
708             throw generateException(e);
709         }
710     }
711 
712     /***
713      * <p>
714      * Sets the value of the designated parameter with the given object. The
715      * second argument must be an object type; for integral values, the
716      * <code>java.lang</code> equivalent objects should be used.
717      * 
718      * <p>
719      * The given Java object will be converted to the given targetSqlType before
720      * being sent to the database.
721      * 
722      * If the object has a custom mapping (is of a class implementing the
723      * interface <code>SQLData</code>), the JDBC driver should call the
724      * method <code>SQLData.writeSQL</code> to write it to the SQL data
725      * stream. If, on the other hand, the object is of a class implementing
726      * <code>Ref</code>,<code>Blob</code>,<code>Clob</code>,
727      * <code>Struct</code>, or <code>Array</code>, the driver should pass
728      * it to the database as a value of the corresponding SQL type.
729      * 
730      * <p>
731      * Note that this method may be used to pass database-specific abstract data
732      * types.
733      * 
734      * @param parameterIndex
735      *            the first parameter is 1, the second is 2, ...
736      * @param x
737      *            the object containing the input parameter value
738      * @param targetSqlType
739      *            the SQL type (as defined in java.sql.Types) to be sent to the
740      *            database. The scale argument may further qualify this type.
741      * @param scale
742      *            for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types,
743      *            this is the number of digits after the decimal point. For all
744      *            other types, this value will be ignored.
745      * @exception SQLException
746      *                if a database access error occurs
747      */
748     public void setObject(int parameterIndex, Object x, int targetSqlType,
749             int scale) throws SQLException {
750         try {
751             ((PreparedStatement) this.realStatement).setObject(parameterIndex,
752                     x, targetSqlType, scale);
753             if (parameterIndex <= this.currentParams.length) {
754                 this.currentParams[parameterIndex - 1] = x;
755             }
756         } catch (SQLException e) {
757             manageException(e);
758             throw generateException(e);
759         }
760     }
761 
762     /***
763      * Sets the value of the designated parameter with the given object. This
764      * method is like the method <code>setObject</code> above, except that it
765      * assumes a scale of zero.
766      * 
767      * @param parameterIndex
768      *            the first parameter is 1, the second is 2, ...
769      * @param x
770      *            the object containing the input parameter value
771      * @param targetSqlType
772      *            the SQL type (as defined in java.sql.Types) to be sent to the
773      *            database
774      * @exception SQLException
775      *                if a database access error occurs
776      */
777     public void setObject(int parameterIndex, Object x, int targetSqlType)
778             throws SQLException {
779         try {
780             ((PreparedStatement) this.realStatement).setObject(targetSqlType,
781                     x, targetSqlType);
782             if (parameterIndex <= this.currentParams.length) {
783                 this.currentParams[parameterIndex - 1] = x;
784             }
785         } catch (SQLException e) {
786             manageException(e);
787             throw generateException(e);
788         }
789     }
790 
791     /***
792      * <p>
793      * Sets the value of the designated parameter using the given object. The
794      * second parameter must be of type <code>Object</code>; therefore, the
795      * <code>java.lang</code> equivalent objects should be used for built-in
796      * types.
797      * 
798      * <p>
799      * The JDBC specification specifies a standard mapping from Java
800      * <code>Object</code> types to SQL types. The given argument will be
801      * converted to the corresponding SQL type before being sent to the
802      * database.
803      * 
804      * <p>
805      * Note that this method may be used to pass datatabase- specific abstract
806      * data types, by using a driver-specific Java type.
807      * 
808      * If the object is of a class implementing the interface
809      * <code>SQLData</code>, the JDBC driver should call the method
810      * <code>SQLData.writeSQL</code> to write it to the SQL data stream. If,
811      * on the other hand, the object is of a class implementing <code>Ref</code>,
812      * <code>Blob</code>,<code>Clob</code>,<code>Struct</code>, or
813      * <code>Array</code>, the driver should pass it to the database as a
814      * value of the corresponding SQL type.
815      * <P>
816      * This method throws an exception if there is an ambiguity, for example, if
817      * the object is of a class implementing more than one of the interfaces
818      * named above.
819      * 
820      * @param parameterIndex
821      *            the first parameter is 1, the second is 2, ...
822      * @param x
823      *            the object containing the input parameter value
824      * @exception SQLException
825      *                if a database access error occurs or the type of the given
826      *                object is ambiguous
827      */
828     public void setObject(int parameterIndex, Object x) throws SQLException {
829         try {
830             ((PreparedStatement) this.realStatement).setObject(parameterIndex,
831                     x);
832             if (parameterIndex <= this.currentParams.length) {
833                 this.currentParams[parameterIndex - 1] = x;
834             }
835         } catch (SQLException e) {
836             manageException(e);
837             throw generateException(e);
838         }
839     }
840 
841     /***
842      * Executes the SQL statement in this <code>PreparedStatement</code>
843      * object, which may be any kind of SQL statement. Some prepared statements
844      * return multiple results; the <code>execute</code> method handles these
845      * complex statements as well as the simpler form of statements handled by
846      * the methods <code>executeQuery</code> and <code>executeUpdate</code>.
847      * <P>
848      * The <code>execute</code> method returns a <code>boolean</code> to
849      * indicate the form of the first result. You must call either the method
850      * <code>getResultSet</code> or <code>getUpdateCount</code> to retrieve
851      * the result; you must call <code>getMoreResults</code> to move to any
852      * subsequent result(s).
853      * 
854      * @return <code>true</code> if the first result is a
855      *         <code>ResultSet</code> object; <code>false</code> if the
856      *         first result is an update count or there is no result
857      * @exception SQLException
858      *                if a database access error occurs or an argument is
859      *                supplied to this method
860      */
861     public boolean execute() throws SQLException {
862         try {
863             return ((PreparedStatement) this.realStatement).execute();
864         } catch (SQLException e) {
865             CremeAction redo = null;
866             try {
867                 redo = new CremeAction(getClass().getMethod("execute",
868                         new Class[0]));
869                 redo.setSubject(this);
870             } catch (NoSuchMethodException ex) {
871                 ex.printStackTrace();
872             } catch (IllegalArgumentException ex) {
873                 ex.printStackTrace();
874             }
875             manageException(e, redo);
876             if ((redo != null) && (redo.isSuccessfull())) {
877                 return ((Boolean) redo.getResult()).booleanValue();
878             }
879             throw generateException(e);
880         }
881     }
882 
883     /***
884      * Adds a set of parameters to this <code>PreparedStatement</code>
885      * object's batch of commands.
886      * 
887      * @exception SQLException
888      *                if a database access error occurs
889      * @see Statement#addBatch
890      * @since 1.2
891      */
892     public void addBatch() throws SQLException {
893         try {
894             ((PreparedStatement) this.realStatement).addBatch();
895             this.batchRequests.add(this.currentParams);
896             this.currentParams = new Object[this.currentParams.length];
897         } catch (SQLException e) {
898             throw generateException(e);
899         }
900     }
901 
902     /***
903      * This method enables to access the batched queries.
904      * 
905      * @param index
906      *            the index of the batch request.
907      * @return a string that represents the batch request at the given index.
908      */
909     protected String getBatchRequestAt(int index) {
910         String result = null;
911         Object obj = this.batchRequests.elementAt(index);
912         if (obj instanceof String) {
913             result = (String) obj;
914         } else {
915             Object[] params = this.currentParams;
916             this.currentParams = (Object[]) obj;
917             result = buildActualQuery();
918             this.currentParams = params;
919         }
920         return result;
921     }
922 
923     /***
924      * Sets the designated parameter to the given <code>Reader</code> object,
925      * which is the given number of characters long. When a very large UNICODE
926      * value is input to a <code>LONGVARCHAR</code> parameter, it may be more
927      * practical to send it via a <code>java.io.Reader</code> object. The data
928      * will be read from the stream as needed until end-of-file is reached. The
929      * JDBC driver will do any necessary conversion from UNICODE to the database
930      * char format.
931      * 
932      * <P>
933      * <B>Note: </B> This stream object can either be a standard Java stream
934      * object or your own subclass that implements the standard interface.
935      * 
936      * @param parameterIndex
937      *            the first parameter is 1, the second is 2, ...
938      * @param reader
939      *            the <code>java.io.Reader</code> object that contains the
940      *            Unicode data
941      * @param length
942      *            the number of characters in the stream
943      * @exception SQLException
944      *                if a database access error occurs
945      * @since 1.2
946      */
947     public void setCharacterStream(int parameterIndex, Reader reader, int length)
948             throws SQLException {
949         try {
950             ((PreparedStatement) this.realStatement).setCharacterStream(
951                     parameterIndex, reader, length);
952             if (parameterIndex <= this.currentParams.length) {
953                 this.currentParams[parameterIndex - 1] = "From Character Stream";
954             }
955         } catch (SQLException e) {
956             manageException(e);
957             throw generateException(e);
958         }
959     }
960 
961     /***
962      * Sets the designated parameter to the given
963      * <code>REF(&lt;structured-type&gt;)</code> value. The driver converts
964      * this to an SQL <code>REF</code> value when it sends it to the database.
965      * 
966      * @param i
967      *            the first parameter is 1, the second is 2, ...
968      * @param x
969      *            an SQL <code>REF</code> value
970      * @exception SQLException
971      *                if a database access error occurs
972      * @since 1.2
973      */
974     public void setRef(int i, Ref x) throws SQLException {
975         try {
976             ((PreparedStatement) this.realStatement).setRef(i, x);
977             if (i <= this.currentParams.length) {
978                 this.currentParams[i - 1] = x;
979             }
980         } catch (SQLException e) {
981             manageException(e);
982             throw generateException(e);
983         }
984     }
985 
986     /***
987      * Sets the designated parameter to the given <code>Blob</code> object.
988      * The driver converts this to an SQL <code>BLOB</code> value when it
989      * sends it to the database.
990      * 
991      * @param i
992      *            the first parameter is 1, the second is 2, ...
993      * @param x
994      *            a <code>Blob</code> object that maps an SQL
995      *            <code>BLOB</code> value
996      * @exception SQLException
997      *                if a database access error occurs
998      * @since 1.2
999      */
1000     public void setBlob(int i, Blob x) throws SQLException {
1001         try {
1002             ((PreparedStatement) this.realStatement).setBlob(i, x);
1003             if (i <= this.currentParams.length) {
1004                 this.currentParams[i - 1] = x;
1005             }
1006         } catch (SQLException e) {
1007             manageException(e);
1008             throw generateException(e);
1009         }
1010     }
1011 
1012     /***
1013      * Sets the designated parameter to the given <code>Clob</code> object.
1014      * The driver converts this to an SQL <code>CLOB</code> value when it
1015      * sends it to the database.
1016      * 
1017      * @param i
1018      *            the first parameter is 1, the second is 2, ...
1019      * @param x
1020      *            a <code>Clob</code> object that maps an SQL
1021      *            <code>CLOB</code> value
1022      * @exception SQLException
1023      *                if a database access error occurs
1024      * @since 1.2
1025      */
1026     public void setClob(int i, Clob x) throws SQLException {
1027         try {
1028             ((PreparedStatement) this.realStatement).setClob(i, x);
1029             if (i <= this.currentParams.length) {
1030                 this.currentParams[i - 1] = x;
1031             }
1032         } catch (SQLException e) {
1033             manageException(e);
1034             throw generateException(e);
1035         }
1036     }
1037 
1038     /***
1039      * Sets the designated parameter to the given <code>Array</code> object.
1040      * The driver converts this to an SQL <code>ARRAY</code> value when it
1041      * sends it to the database.
1042      * 
1043      * @param i
1044      *            the first parameter is 1, the second is 2, ...
1045      * @param x
1046      *            an <code>Array</code> object that maps an SQL
1047      *            <code>ARRAY</code> value
1048      * @exception SQLException
1049      *                if a database access error occurs
1050      * @since 1.2
1051      */
1052     public void setArray(int i, Array x) throws SQLException {
1053         try {
1054             ((PreparedStatement) this.realStatement).setArray(i, x);
1055             if (i <= this.currentParams.length) {
1056                 this.currentParams[i - 1] = x;
1057             }
1058         } catch (SQLException e) {
1059             manageException(e);
1060             throw generateException(e);
1061         }
1062     }
1063 
1064     /***
1065      * Retrieves a <code>ResultSetMetaData</code> object that contains
1066      * information about the columns of the <code>ResultSet</code> object that
1067      * will be returned when this <code>PreparedStatement</code> object is
1068      * executed.
1069      * <P>
1070      * Because a <code>PreparedStatement</code> object is precompiled, it is
1071      * possible to know about the <code>ResultSet</code> object that it will
1072      * return without having to execute it. Consequently, it is possible to
1073      * invoke the method <code>getMetaData</code> on a
1074      * <code>PreparedStatement</code> object rather than waiting to execute it
1075      * and then invoking the <code>ResultSet.getMetaData</code> method on the
1076      * <code>ResultSet</code> object that is returned.
1077      * <P>
1078      * <B>NOTE: </B> Using this method may be expensive for some drivers due to
1079      * the lack of underlying DBMS support.
1080      * 
1081      * @return the description of a <code>ResultSet</code> object's columns or
1082      *         <code>null</code> if the driver cannot return a
1083      *         <code>ResultSetMetaData</code> object
1084      * @exception SQLException
1085      *                if a database access error occurs
1086      * @since 1.2
1087      */
1088     public ResultSetMetaData getMetaData() throws SQLException {
1089         try {
1090             return ((PreparedStatement) this.realStatement).getMetaData();
1091         } catch (SQLException e) {
1092             manageException(e);
1093             throw generateException(e);
1094         }
1095     }
1096 
1097     /***
1098      * Sets the designated parameter to the given <code>java.sql.Date</code>
1099      * value, using the given <code>Calendar</code> object. The driver uses
1100      * the <code>Calendar</code> object to construct an SQL <code>DATE</code>
1101      * value, which the driver then sends to the database. With a a
1102      * <code>Calendar</code> object, the driver can calculate the date taking
1103      * into account a custom timezone. If no <code>Calendar</code> object is
1104      * specified, the driver uses the default timezone, which is that of the
1105      * virtual machine running the application.
1106      * 
1107      * @param parameterIndex
1108      *            the first parameter is 1, the second is 2, ...
1109      * @param x
1110      *            the parameter value
1111      * @param cal
1112      *            the <code>Calendar</code> object the driver will use to
1113      *            construct the date
1114      * @exception SQLException
1115      *                if a database access error occurs
1116      * @since 1.2
1117      */
1118     public void setDate(int parameterIndex, Date x, Calendar cal)
1119             throws SQLException {
1120         try {
1121             ((PreparedStatement) this.realStatement).setDate(parameterIndex, x,
1122                     cal);
1123             if (parameterIndex <= this.currentParams.length) {
1124                 this.currentParams[parameterIndex - 1] = x;
1125             }
1126         } catch (SQLException e) {
1127             manageException(e);
1128             throw generateException(e);
1129         }
1130     }
1131 
1132     /***
1133      * Sets the designated parameter to the given <code>java.sql.Time</code>
1134      * value, using the given <code>Calendar</code> object. The driver uses
1135      * the <code>Calendar</code> object to construct an SQL <code>TIME</code>
1136      * value, which the driver then sends to the database. With a a
1137      * <code>Calendar</code> object, the driver can calculate the time taking
1138      * into account a custom timezone. If no <code>Calendar</code> object is
1139      * specified, the driver uses the default timezone, which is that of the
1140      * virtual machine running the application.
1141      * 
1142      * @param parameterIndex
1143      *            the first parameter is 1, the second is 2, ...
1144      * @param x
1145      *            the parameter value
1146      * @param cal
1147      *            the <code>Calendar</code> object the driver will use to
1148      *            construct the time
1149      * @exception SQLException
1150      *                if a database access error occurs
1151      * @since 1.2
1152      */
1153     public void setTime(int parameterIndex, Time x, Calendar cal)
1154             throws SQLException {
1155         try {
1156             ((PreparedStatement) this.realStatement).setTime(parameterIndex, x,
1157                     cal);
1158             if (parameterIndex <= this.currentParams.length) {
1159                 this.currentParams[parameterIndex - 1] = x;
1160             }
1161         } catch (SQLException e) {
1162             manageException(e);
1163             throw generateException(e);
1164         }
1165     }
1166 
1167     /***
1168      * Sets the designated parameter to the given
1169      * <code>java.sql.Timestamp</code> value, using the given
1170      * <code>Calendar</code> object. The driver uses the <code>Calendar</code>
1171      * object to construct an SQL <code>TIMESTAMP</code> value, which the
1172      * driver then sends to the database. With a <code>Calendar</code> object,
1173      * the driver can calculate the timestamp taking into account a custom
1174      * timezone. If no <code>Calendar</code> object is specified, the driver
1175      * uses the default timezone, which is that of the virtual machine running
1176      * the application.
1177      * 
1178      * @param parameterIndex
1179      *            the first parameter is 1, the second is 2, ...
1180      * @param x
1181      *            the parameter value
1182      * @param cal
1183      *            the <code>Calendar</code> object the driver will use to
1184      *            construct the timestamp
1185      * @exception SQLException
1186      *                if a database access error occurs
1187      * @since 1.2
1188      */
1189     public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
1190             throws SQLException {
1191         try {
1192             ((PreparedStatement) this.realStatement).setTimestamp(
1193                     parameterIndex, x, cal);
1194             if (parameterIndex <= this.currentParams.length) {
1195                 this.currentParams[parameterIndex - 1] = x;
1196             }
1197         } catch (SQLException e) {
1198             manageException(e);
1199             throw generateException(e);
1200         }
1201     }
1202 
1203     /***
1204      * Sets the designated parameter to SQL <code>NULL</code>. This version
1205      * of the method <code>setNull</code> should be used for user-defined
1206      * types and REF type parameters. Examples of user-defined types include:
1207      * STRUCT, DISTINCT, JAVA_OBJECT, and named array types.
1208      * 
1209      * <P>
1210      * <B>Note: </B> To be portable, applications must give the SQL type code
1211      * and the fully-qualified SQL type name when specifying a NULL user-defined
1212      * or REF parameter. In the case of a user-defined type the name is the type
1213      * name of the parameter itself. For a REF parameter, the name is the type
1214      * name of the referenced type. If a JDBC driver does not need the type code
1215      * or type name information, it may ignore it.
1216      * 
1217      * Although it is intended for user-defined and Ref parameters, this method
1218      * may be used to set a null parameter of any JDBC type. If the parameter
1219      * does not have a user-defined or REF type, the given typeName is ignored.
1220      * 
1221      * 
1222      * @param paramIndex
1223      *            the first parameter is 1, the second is 2, ...
1224      * @param sqlType
1225      *            a value from <code>java.sql.Types</code>
1226      * @param typeName
1227      *            the fully-qualified name of an SQL user-defined type; ignored
1228      *            if the parameter is not a user-defined type or REF
1229      * @exception SQLException
1230      *                if a database access error occurs
1231      * @since 1.2
1232      */
1233     public void setNull(int paramIndex, int sqlType, String typeName)
1234             throws SQLException {
1235         try {
1236             ((PreparedStatement) this.realStatement).setNull(paramIndex,
1237                     sqlType, typeName);
1238             if (paramIndex <= this.currentParams.length) {
1239                 this.currentParams[paramIndex - 1] = null;
1240             }
1241         } catch (SQLException e) {
1242             manageException(e);
1243             throw generateException(e);
1244         }
1245     }
1246 
1247     /***
1248      * Sets the designated parameter to the given <code>java.net.URL</code>
1249      * value. The driver converts this to an SQL <code>DATALINK</code> value
1250      * when it sends it to the database.
1251      * 
1252      * @param parameterIndex
1253      *            the first parameter is 1, the second is 2, ...
1254      * @param x
1255      *            the <code>java.net.URL</code> object to be set
1256      * @exception SQLException
1257      *                if a database access error occurs
1258      * @since 1.4
1259      */
1260     public void setURL(int parameterIndex, URL x) throws SQLException {
1261         try {
1262             ((PreparedStatement) this.realStatement).setURL(parameterIndex, x);
1263             if (parameterIndex <= this.currentParams.length) {
1264                 this.currentParams[parameterIndex - 1] = x;
1265             }
1266         } catch (SQLException e) {
1267             manageException(e);
1268             throw generateException(e);
1269         }
1270     }
1271 
1272     /***
1273      * Retrieves the number, types and properties of this
1274      * <code>PreparedStatement</code> object's parameters.
1275      * 
1276      * @return a <code>ParameterMetaData</code> object that contains
1277      *         information about the number, types and properties of this
1278      *         <code>PreparedStatement</code> object's parameters
1279      * @exception SQLException
1280      *                if a database access error occurs
1281      * @see ParameterMetaData
1282      * @since 1.4
1283      *  
1284      */
1285     public ParameterMetaData getParameterMetaData() throws SQLException {
1286         try {
1287             return ((PreparedStatement) this.realStatement)
1288                     .getParameterMetaData();
1289         } catch (SQLException e) {
1290             manageException(e);
1291             throw generateException(e);
1292         }
1293     }
1294 }