KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > driver > PreparedStatement


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2005 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): Nicolas Modrzyk, Jaco Swart.
23  */

24
25 package org.objectweb.cjdbc.driver;
26
27 import java.io.ByteArrayInputStream JavaDoc;
28 import java.io.ByteArrayOutputStream JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.io.InputStream JavaDoc;
31 import java.io.ObjectInputStream JavaDoc;
32 import java.io.ObjectOutputStream JavaDoc;
33 import java.io.Serializable JavaDoc;
34 import java.math.BigDecimal JavaDoc;
35 import java.net.MalformedURLException JavaDoc;
36 import java.net.URL JavaDoc;
37 import java.sql.Array JavaDoc;
38 import java.sql.BatchUpdateException JavaDoc;
39 import java.sql.Date JavaDoc;
40 import java.sql.ParameterMetaData JavaDoc;
41 import java.sql.Ref JavaDoc;
42 import java.sql.SQLException JavaDoc;
43 import java.sql.Time JavaDoc;
44 import java.sql.Timestamp JavaDoc;
45 import java.sql.Types JavaDoc;
46 import java.text.ParseException JavaDoc;
47 import java.text.SimpleDateFormat JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.Vector JavaDoc;
50
51 import org.objectweb.cjdbc.common.exceptions.NotImplementedException;
52 import org.objectweb.cjdbc.common.sql.filters.HexaBlobFilter;
53 import org.objectweb.cjdbc.common.util.Strings;
54
55 /**
56  * A SQL Statement is pre-compiled and stored in a
57  * <code>PreparedStatement</code> object. This object can then be used to
58  * efficiently execute this statement multiple times.
59  * <p>
60  * <b>Note: </b> The setXXX methods for setting IN parameter values must specify
61  * types that are compatible with the defined SQL type of the input parameter.
62  * For instance, if the IN parameter has SQL type Integer, then setInt should be
63  * used.
64  * <p>
65  * If arbitrary parameter type conversions are required, then the setObject
66  * method should be used with a target SQL type.
67  * <p>
68  * In the old days, this was just a dirty copy/paste from the PostgreSQL driver.
69  * Some irrelevant comments are left-over here and there.
70  * <p>
71  * This class could maybe be splitted into DriverProcessedPreparedStatement and
72  * ProxyModeProcessedStatement
73  *
74  * @see DriverResultSet
75  * @see java.sql.PreparedStatement
76  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
77  * @author <a HREF="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
78  * @author <a HREF="mailto:marc.wick@monte-bre.ch">Marc Wick </a>
79  * @author <a HREF="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
80  * @version 1.0
81  */

82 public class PreparedStatement extends Statement
83     implements
84       java.sql.PreparedStatement JavaDoc
85 {
86   /** Could we use {@link java.sql.Types} instead ? */
87
88   /**
89    * All tags must have the same length
90    * {@link #setPreparedStatement(String, java.sql.PreparedStatement)}
91    */

92   /** Tag for a byte parameter */
93   public static final String JavaDoc BYTE_TAG = "b|";
94   /** Tag for a bytes (used for Blob) parameter */
95   public static final String JavaDoc BYTES_TAG = "B|";
96   /** Tag for a BLOB (used for null Blob) parameter */
97   public static final String JavaDoc BLOB_TAG = "c|";
98   /** Tag for a CLOB (used for null Clob) parameter */
99   public static final String JavaDoc CLOB_TAG = "C|";
100   /** Tag for a boolean parameter */
101   public static final String JavaDoc BOOLEAN_TAG = "0|";
102   /** Tag for a big decimal parameter */
103   public static final String JavaDoc BIG_DECIMAL_TAG = "1|";
104   /** Tag for a date parameter */
105   public static final String JavaDoc DATE_TAG = "d|";
106   /** Tag for a double parameter */
107   public static final String JavaDoc DOUBLE_TAG = "D|";
108   /** Tag for a float parameter */
109   public static final String JavaDoc FLOAT_TAG = "F|";
110   /** Tag for a integer parameter */
111   public static final String JavaDoc INTEGER_TAG = "I|";
112   /** Tag for a long parameter */
113   public static final String JavaDoc LONG_TAG = "L|";
114   /** Tag for a setNull call */
115   public static final String JavaDoc NULL_TAG = "N|";
116   /** Tag for a Null string parameter */
117   public static final String JavaDoc NULL_STRING_TAG = "n|";
118   /** Tag for an object parameter */
119   public static final String JavaDoc OBJECT_TAG = "O|";
120   /** Tag for a Ref parameter */
121   public static final String JavaDoc REF_TAG = "R|";
122   /** Tag for a short parameter */
123   public static final String JavaDoc SHORT_TAG = "s|";
124   /** Tag for a string parameter */
125   public static final String JavaDoc STRING_TAG = "S|";
126   /** Tag for a time parameter */
127   public static final String JavaDoc TIME_TAG = "t|";
128   /** Tag for a timestamp parameter */
129   public static final String JavaDoc TIMESTAMP_TAG = "T|";
130   /** Tag for an URL parameter */
131   public static final String JavaDoc URL_TAG = "U|";
132
133   /** Tag maker for parameters */
134   public static final String JavaDoc TAG_MARKER = "!%";
135   /** Escape for tag maker */
136   public static final String JavaDoc TAG_MARKER_ESCAPE = TAG_MARKER + ";";
137   /** Tag for parameters start delimiter */
138   public static final String JavaDoc START_PARAM_TAG = "<" + TAG_MARKER;
139   /** Tag for parameters end delimiter */
140   public static final String JavaDoc END_PARAM_TAG = "|" + TAG_MARKER + ">";
141
142   /** original, untouched request (only trimmed) */
143   protected String JavaDoc sql;
144   /** IN parameters, ready to be inlined in the request */
145   private String JavaDoc[] inStrings;
146   /** segments: the request splitted by question marks placeholders */
147   private String JavaDoc[] templateStrings;
148
149   // Some performance caches
150
private StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
151
152   /**
153    * Constructor. Parses/Splits the SQL statement into segments - string parts
154    * separated by question mark placeholders. When we rebuild the thing with the
155    * arguments, we can substitute the args by joining segments and parameters
156    * back together.
157    *
158    * @param connection the instanatiating connection
159    * @param sqlStatement the SQL statement with ? for IN markers
160    * @exception SQLException if something bad occurs
161    */

162   public PreparedStatement(Connection connection, String JavaDoc sqlStatement)
163       throws SQLException JavaDoc
164   {
165     super(connection);
166
167     /** temporary array for segments */
168     ArrayList JavaDoc segs = new ArrayList JavaDoc();
169     int lastParmEnd = 0;
170
171     // The following two boolean switches are used to make sure we're not
172
// counting "?" in either strings or metadata strings. For instance the
173
// following query:
174
// select '?' "A ? value" from dual
175
// doesn't have any parameters.
176

177     boolean inString = false;
178     boolean inMetaString = false;
179
180     this.sql = sqlStatement.trim();
181     this.connection = connection;
182     for (int i = 0; i < sql.length(); ++i)
183     {
184       if (sql.charAt(i) == '\'')
185         inString = !inString;
186       if (sql.charAt(i) == '"')
187         inMetaString = !inMetaString;
188       if ((sql.charAt(i) == '?') && (!(inString || inMetaString)))
189       {
190         segs.add(sql.substring(lastParmEnd, i));
191         lastParmEnd = i + 1;
192       }
193     }
194     segs.add(sql.substring(lastParmEnd, sql.length()));
195
196     int size = segs.size();
197     templateStrings = new String JavaDoc[size];
198     inStrings = new String JavaDoc[size - 1];
199     clearParameters();
200
201     for (int i = 0; i < size; ++i)
202       templateStrings[i] = (String JavaDoc) segs.get(i);
203   }
204
205   /**
206    * Release objects for garbage collection and call Statement.close().
207    *
208    * @throws SQLException if an error occurs
209    */

210   public void close() throws SQLException JavaDoc
211   {
212     sql = null;
213     templateStrings = null;
214     inStrings = null;
215
216     super.close();
217   }
218
219   /**
220    * A Prepared SQL query is executed and its <code>ResultSet</code> is
221    * returned.
222    *
223    * @return a <code>ResultSet</code> that contains the data produced by the *
224    * query - never <code>null</code>.
225    * @exception SQLException if a database access error occurs
226    */

227   public java.sql.ResultSet JavaDoc executeQuery() throws SQLException JavaDoc
228   {
229     return super.executeQuery(sql, compileQuery()); // in Statement class
230
}
231
232   /**
233    * Execute a SQL INSERT, UPDATE or DELETE statement. In addition, SQL
234    * statements that return nothing such as SQL DDL statements can be executed.
235    *
236    * @return either the row count for <code>INSERT</code>,
237    * <code>UPDATE</code> or <code>DELETE</code>; or 0 for SQL
238    * statements that return nothing.
239    * @exception SQLException if a database access error occurs
240    */

241   public int executeUpdate() throws SQLException JavaDoc
242   {
243     return super.executeUpdateWithSkeleton(sql, compileQuery());
244     // in Statement class
245
}
246
247   /**
248    * Helper - this compiles the SQL query, inlining the parameters in the
249    * request String. This is identical to <code>this.toString()</code> except
250    * it throws an exception if a parameter was not set.
251    *
252    * @return the compiled query
253    * @throws SQLException if an error occurs
254    */

255   protected synchronized String JavaDoc compileQuery() throws SQLException JavaDoc
256   {
257     sbuf.setLength(0);
258     int i;
259
260     for (i = 0; i < inStrings.length; ++i)
261     {
262       if (inStrings[i] == null)
263         throw new SQLException JavaDoc("Parameter " + (i + 1) + " is incorrect");
264       sbuf.append(templateStrings[i]).append(inStrings[i]);
265     }
266     sbuf.append(templateStrings[inStrings.length]);
267     return sbuf.toString();
268   }
269
270   /**
271    * Escape the input string. <br>
272    * <char>' </char> is replaced by <char>\' </char> <br>
273    * <char>\ </char> is replaced by <char>\\' </char> <br>
274    * if connection.escapeProcessing is set to true, surround the new string with
275    * <char>\' </char>
276    *
277    * @param x the string to process
278    * @return escaped string
279    */

280   protected String JavaDoc doEscapeProcessing(String JavaDoc x)
281   {
282     // use the shared buffer object. Should never clash but this
283
// makes us thread safe!
284
synchronized (sbuf)
285     {
286       sbuf.setLength(0);
287       int i;
288       sbuf.append(connection.getEscapeChar());
289       for (i = 0; i < x.length(); ++i)
290       {
291         char c = x.charAt(i);
292         if ((c == '\'' && connection.isEscapeSingleQuote())
293             || (c == '\\' && connection.isEscapeBackslash()))
294           sbuf.append(c);
295         sbuf.append(c);
296       }
297       sbuf.append(connection.getEscapeChar());
298     }
299     return sbuf.toString();
300   }
301
302   /**
303    * Sets a parameter to SQL NULL.
304    * <p>
305    * <b>Note: </b> you must specify the parameters SQL type but we ignore it.
306    *
307    * @param parameterIndex the first parameter is 1, etc...
308    * @param sqlType the SQL type code defined in java.sql.Types
309    * @exception SQLException if a database access error occurs
310    */

311   public void setNull(int parameterIndex, int sqlType) throws SQLException JavaDoc
312   {
313     if (connection.isDriverProcessed())
314       set(parameterIndex, "null");
315     else
316       setWithTag(parameterIndex, NULL_TAG, String.valueOf(sqlType));
317   }
318
319   /**
320    * Sets a parameter to a Java boolean value. The driver converts this to a SQL
321    * BIT value when it sends it to the database.
322    *
323    * @param parameterIndex the first parameter is 1...
324    * @param x the parameter value
325    * @exception SQLException if a database access error occurs
326    */

327   public void setBoolean(int parameterIndex, boolean x) throws SQLException JavaDoc
328   {
329     if (connection.isDriverProcessed())
330     {
331       set(parameterIndex, x
332           ? connection.getPreparedStatementBooleanTrue()
333           : connection.getPreparedStatementBooleanFalse());
334     }
335     else
336     {
337       setWithTag(parameterIndex, BOOLEAN_TAG, String.valueOf(x));
338     }
339   }
340
341   /**
342    * Sets a parameter to a Java byte value.
343    *
344    * @param parameterIndex the first parameter is 1...
345    * @param x the parameter value
346    * @exception SQLException if a database access error occurs
347    */

348   public void setByte(int parameterIndex, byte x) throws SQLException JavaDoc
349   {
350     if (connection.isDriverProcessed())
351     {
352       set(parameterIndex, Integer.toString(x));
353     }
354     else
355     {
356       setWithTag(parameterIndex, BYTE_TAG, Integer.toString(x));
357     }
358   }
359
360   /**
361    * Sets a parameter to a Java short value. The driver converts this to a SQL
362    * SMALLINT value when it sends it to the database.
363    *
364    * @param parameterIndex the first parameter is 1...
365    * @param x the parameter value
366    * @exception SQLException if a database access error occurs
367    */

368   public void setShort(int parameterIndex, short x) throws SQLException JavaDoc
369   {
370     if (connection.isDriverProcessed())
371     {
372       set(parameterIndex, Integer.toString(x));
373     }
374     else
375     {
376       setWithTag(parameterIndex, SHORT_TAG, Integer.toString(x));
377     }
378   }
379
380   /**
381    * Sets a parameter to a Java int value. The driver converts this to a SQL
382    * INTEGER value when it sends it to the database.
383    *
384    * @param parameterIndex the first parameter is 1...
385    * @param x the parameter value
386    * @exception SQLException if a database access error occurs
387    */

388   public void setInt(int parameterIndex, int x) throws SQLException JavaDoc
389   {
390     if (connection.isDriverProcessed())
391     {
392       set(parameterIndex, Integer.toString(x));
393     }
394     else
395     {
396       setWithTag(parameterIndex, INTEGER_TAG, Integer.toString(x));
397     }
398   }
399
400   /**
401    * Sets a parameter to a Java long value. The driver converts this to a SQL
402    * BIGINT value when it sends it to the database.
403    *
404    * @param parameterIndex the first parameter is 1...
405    * @param x the parameter value
406    * @exception SQLException if a database access error occurs
407    */

408   public void setLong(int parameterIndex, long x) throws SQLException JavaDoc
409   {
410     if (connection.isDriverProcessed())
411     {
412       set(parameterIndex, Long.toString(x));
413     }
414     else
415     {
416       setWithTag(parameterIndex, LONG_TAG, Long.toString(x));
417     }
418   }
419
420   /**
421    * Sets a parameter to a Java float value. The driver converts this to a SQL
422    * FLOAT value when it sends it to the database.
423    *
424    * @param parameterIndex the first parameter is 1...
425    * @param x the parameter value
426    * @exception SQLException if a database access error occurs
427    */

428   public void setFloat(int parameterIndex, float x) throws SQLException JavaDoc
429   {
430     if (connection.isDriverProcessed())
431     {
432       set(parameterIndex, Float.toString(x));
433     }
434     else
435     {
436       setWithTag(parameterIndex, FLOAT_TAG, Float.toString(x));
437     }
438   }
439
440   /**
441    * Sets a parameter to a Java double value. The driver converts this to a SQL
442    * DOUBLE value when it sends it to the database.
443    *
444    * @param parameterIndex the first parameter is 1...
445    * @param x the parameter value
446    * @exception SQLException if a database access error occurs
447    */

448   public void setDouble(int parameterIndex, double x) throws SQLException JavaDoc
449   {
450     if (connection.isDriverProcessed())
451     {
452       set(parameterIndex, Double.toString(x));
453     }
454     else
455     {
456       setWithTag(parameterIndex, DOUBLE_TAG, Double.toString(x));
457     }
458   }
459
460   /**
461    * Sets a parameter to a java.lang.BigDecimal value. The driver converts this
462    * to a SQL NUMERIC value when it sends it to the database.
463    *
464    * @param parameterIndex the first parameter is 1...
465    * @param x the parameter value
466    * @exception SQLException if a database access error occurs
467    */

468   public void setBigDecimal(int parameterIndex, BigDecimal JavaDoc x)
469       throws SQLException JavaDoc
470   {
471     if (connection.isDriverProcessed())
472     {
473       if (x == null)
474         setNull(parameterIndex, Types.DECIMAL);
475       else
476         set(parameterIndex, x.toString());
477     }
478     else
479     {
480       if (x == null)
481         setWithTag(parameterIndex, BIG_DECIMAL_TAG, NULL_TAG);
482       else
483         setWithTag(parameterIndex, BIG_DECIMAL_TAG, x.toString());
484     }
485   }
486
487   /**
488    * Sets a parameter to a Java String value. The driver converts this to a SQL
489    * VARCHAR or LONGVARCHAR value (depending on the arguments size relative to
490    * the driver's limits on VARCHARs) when it sends it to the database.
491    *
492    * @param parameterIndex the first parameter is 1...
493    * @param x the parameter value
494    * @exception SQLException if a database access error occurs
495    */

496   public void setString(int parameterIndex, String JavaDoc x) throws SQLException JavaDoc
497   {
498     if (connection.isDriverProcessed())
499     {
500       if (x == null)
501         // if the passed string is null, then set this column to null
502
setNull(parameterIndex, Types.VARCHAR);
503       else
504       {
505         if (escapeProcessing
506             && (connection.isEscapeBackslash() || connection
507                 .isEscapeSingleQuote()))
508           set(parameterIndex, doEscapeProcessing(x));
509         else
510           // No escape processing
511
set(parameterIndex, x);
512       }
513     }
514     else
515     {
516       if (x == null)
517         setWithTag(parameterIndex, STRING_TAG, NULL_TAG);
518       else
519       {
520         if (NULL_TAG.equals(x))
521         { // Someone is trying to set a String that matches our NULL tag, a real
522
// bad luck, use our special NULL_STRING_TAG!
523
setWithTag(parameterIndex, NULL_STRING_TAG, x);
524         }
525         else
526         { // No escape processing is needed for queries not being parsed into
527
// statements.
528
setWithTag(parameterIndex, STRING_TAG, x);
529         }
530       }
531     }
532   }
533
534   /**
535    * Sets a parameter to a Java array of bytes.
536    * <p>
537    *
538    * @param parameterIndex the first parameter is 1...
539    * @param x the parameter value
540    * @exception SQLException if a database access error occurs
541    */

542   public void setBytes(int parameterIndex, byte[] x) throws SQLException JavaDoc
543   {
544     String JavaDoc blob;
545     try
546     {
547       synchronized (sbuf)
548       {
549         if (connection.isDriverProcessed())
550         {
551           /* Encoded for database storage */
552           blob = connection.getBlobFilter().encode(x);
553           sbuf.setLength(0);
554           sbuf.append(connection.escapeChar);
555           sbuf.append(blob);
556           sbuf.append(connection.escapeChar);
557           set(parameterIndex, sbuf.toString());
558         }
559         else
560         {
561           /**
562            * Encoded only for request inlining. Decoded right away by the
563            * controller at static
564            * {@link #setPreparedStatement(String, java.sql.PreparedStatement)}
565            */

566           blob = new HexaBlobFilter().encode(x);
567           setWithTag(parameterIndex, BYTES_TAG, blob);
568         }
569       }
570     }
571     catch (OutOfMemoryError JavaDoc oome)
572     {
573       blob = null;
574       sbuf = null;
575       System.gc();
576       throw new SQLException JavaDoc("Out of memory");
577     }
578   }
579
580   /**
581    * Sets a parameter to a java.sql.Date value. The driver converts this to a
582    * SQL DATE value when it sends it to the database.
583    *
584    * @param parameterIndex the first parameter is 1...
585    * @param x the parameter value
586    * @exception SQLException if a database access error occurs
587    */

588   public void setDate(int parameterIndex, java.sql.Date JavaDoc x) throws SQLException JavaDoc
589   {
590     if (connection.isDriverProcessed())
591     {
592       if (x == null)
593         setNull(parameterIndex, Types.DATE);
594       else
595         set(parameterIndex, "'" + new java.sql.Date JavaDoc(x.getTime()).toString()
596             + "'");
597     }
598     else
599     {
600       if (x == null)
601         setWithTag(parameterIndex, DATE_TAG, NULL_TAG);
602       else
603         setWithTag(parameterIndex, DATE_TAG, new java.sql.Date JavaDoc(x.getTime())
604             .toString());
605     }
606   }
607
608   /**
609    * Sets a parameter to a <code>java.sql.Time</code> value. The driver
610    * converts this to a SQL TIME value when it sends it to the database.
611    *
612    * @param parameterIndex the first parameter is 1...));
613    * @param x the parameter value
614    * @exception SQLException if a database access error occurs
615    */

616   public void setTime(int parameterIndex, Time JavaDoc x) throws SQLException JavaDoc
617   {
618     if (connection.isDriverProcessed())
619     {
620       if (x == null)
621         setNull(parameterIndex, Types.TIME);
622       else
623         set(parameterIndex, "{t '" + x.toString() + "'}");
624     }
625     else
626     {
627       if (x == null)
628         setWithTag(parameterIndex, TIME_TAG, NULL_TAG);
629       else
630         setWithTag(parameterIndex, TIME_TAG, x.toString());
631     }
632   }
633
634   /**
635    * Sets a parameter to a <code>java.sql.Timestamp</code> value. The driver
636    * converts this to a SQL TIMESTAMP value when it sends it to the database.
637    *
638    * @param parameterIndex the first parameter is 1...
639    * @param x the parameter value
640    * @exception SQLException if a database access error occurs
641    */

642   public void setTimestamp(int parameterIndex, Timestamp JavaDoc x) throws SQLException JavaDoc
643   {
644     if (connection.isDriverProcessed())
645     {
646       if (x == null)
647         setNull(parameterIndex, Types.TIMESTAMP);
648       else
649       {
650         // Be careful don't use instanceof here since it would match derived
651
// classes.
652
if (x.getClass().equals(Timestamp JavaDoc.class))
653           set(parameterIndex, "'" + x.toString() + "'");
654         else
655           set(parameterIndex, "'" + new Timestamp JavaDoc(x.getTime()).toString() + "'");
656       }
657     }
658     else
659     {
660       if (x == null)
661         setWithTag(parameterIndex, TIMESTAMP_TAG, NULL_TAG);
662       else
663       {
664         if (x.getClass().equals(Timestamp JavaDoc.class))
665           setWithTag(parameterIndex, TIMESTAMP_TAG, x.toString());
666         else
667           setWithTag(parameterIndex, TIMESTAMP_TAG, new Timestamp JavaDoc(x.getTime())
668               .toString());
669       }
670     }
671   }
672
673   /**
674    * When a very large ASCII value is input to a LONGVARCHAR parameter, it may
675    * be more practical to send it via a java.io.InputStream. JDBC will read the
676    * data from the stream as needed, until it reaches end-of-file. The JDBC
677    * driver will do any necessary conversion from ASCII to the database char
678    * format.
679    * <p>
680    * <b>Note: </b> this stream object can either be a standard Java stream
681    * object or your own subclass that implements the standard interface.
682    *
683    * @param parameterIndex the first parameter is 1...
684    * @param x the parameter value
685    * @param length the number of bytes in the stream
686    * @exception SQLException if a database access error occurs
687    */

688   public void setAsciiStream(int parameterIndex, InputStream JavaDoc x, int length)
689       throws SQLException JavaDoc
690   {
691     setBinaryStream(parameterIndex, x, length);
692   }
693
694   /**
695    * When a very large Unicode value is input to a LONGVARCHAR parameter, it may
696    * be more practical to send it via a java.io.InputStream. JDBC will read the
697    * data from the stream as needed, until it reaches end-of-file. The JDBC
698    * driver will do any necessary conversion from UNICODE to the database char
699    * format.
700    * <p>** DEPRECIATED IN JDBC 2 **
701    * <p>
702    * <b>Note: </b> this stream object can either be a standard Java stream
703    * object or your own subclass that implements the standard interface.
704    *
705    * @param parameterIndex the first parameter is 1...
706    * @param x the parameter value
707    * @param length the parameter length
708    * @exception SQLException if a database access error occurs
709    * @deprecated
710    */

711   public void setUnicodeStream(int parameterIndex, InputStream JavaDoc x, int length)
712       throws SQLException JavaDoc
713   {
714     setBinaryStream(parameterIndex, x, length);
715   }
716
717   /**
718    * Stores a binary stream into parameters array, using an intermediate byte[].
719    * When a very large binary value is input to a LONGVARBINARY parameter, it
720    * may be more practical to send it via a java.io.InputStream. JDBC will read
721    * the data from the stream as needed, until it reaches end-of-file. This
722    * should be more or less equivalent to setBytes(blob.getBytes()).
723    * <p>
724    * <b>Note: </b> This stream object can either be a standard Java stream
725    * object or your own subclass that implements the standard interface.
726    *
727    * @param parameterIndex the first parameter is 1...
728    * @param inStreamArg the parameter value
729    * @param length the parameter length
730    * @exception SQLException if a database access error occurs
731    * @see java.sql.PreparedStatement#setBinaryStream(int, java.io.InputStream,
732    * int)
733    */

734   public void setBinaryStream(int parameterIndex, InputStream JavaDoc inStreamArg,
735       int length) throws SQLException JavaDoc
736   {
737     byte[] data = new byte[length];
738     try
739     {
740       inStreamArg.read(data, 0, length);
741     }
742     catch (Exception JavaDoc ioe)
743     {
744       throw new SQLException JavaDoc("Problem with streaming of data");
745     }
746     setBytes(parameterIndex, data);
747   }
748
749   /**
750    * In general, parameter values remain in force for repeated used of a
751    * <code>Statement</code>. Setting a parameter value automatically clears
752    * its previous value. However, in coms cases, it is useful to immediately
753    * release the resources used by the current parameter values; this can be
754    * done by calling <code>clearParameters()</code>.
755    *
756    * @exception SQLException if a database access error occurs
757    */

758   public void clearParameters() throws SQLException JavaDoc
759   {
760     int i;
761
762     for (i = 0; i < inStrings.length; i++)
763       inStrings[i] = null;
764   }
765
766   /**
767    * Sets the value of a parameter using an object; use the
768    * <code>java.lang</code> equivalent objects for integral values.
769    * <p>
770    * The given Java object will be converted to the targetSqlType before being
771    * sent to the database.
772    * <p>
773    * Note that this method may be used to pass database-specific abstract data
774    * types. This is done by using a Driver-specific Java type and using a
775    * <code>targetSqlType</code> of <code>java.sql.Types.OTHER</code>.
776    *
777    * @param parameterIndex the first parameter is 1...
778    * @param x the object containing the input parameter value
779    * @param targetSqlType The SQL type to be send to the database
780    * @param scale for <code>java.sql.Types.DECIMAL</code> or
781    * <code>java.sql.Types.NUMERIC</code> types this is the number of
782    * digits after the decimal. For all other types this value will be
783    * ignored.
784    * @exception SQLException if a database access error or an incompatible type
785    * match occurs
786    * @see java.sql.PreparedStatement#setObject(int, java.lang.Object, int, int)
787    */

788   public void setObject(int parameterIndex, Object JavaDoc x, int targetSqlType,
789       int scale) throws SQLException JavaDoc
790   {
791     if (x == null)
792     {
793       setNull(parameterIndex, targetSqlType);
794       return;
795     }
796
797     try
798     {
799       boolean failed = false;
800       switch (targetSqlType)
801       {
802         /**
803          * Reference is table "Conversions Performed by setObject()..." in JDBC
804          * Reference Book (table 47.9.5 in 2nd edition, 50.5 in 3rd edition).
805          * Also available online in Sun's "JDBC Technology Guide: Getting
806          * Started", section "Mapping SQL and Java Types".
807          */

808         // using else setXXX( .toString()) below is a lax hack
809
case Types.TINYINT :
810         case Types.SMALLINT :
811         case Types.INTEGER :
812           if (x instanceof Number JavaDoc)
813             setInt(parameterIndex, ((Number JavaDoc) x).intValue());
814           else if (x instanceof Boolean JavaDoc)
815             setInt(parameterIndex, ((Boolean JavaDoc) x).booleanValue() ? 1 : 0);
816           else if (x instanceof String JavaDoc)
817             setInt(parameterIndex, Integer.parseInt((String JavaDoc) x));
818           else
819             failed = true;
820           break;
821         case Types.BIGINT :
822           if (x instanceof Number JavaDoc)
823             setLong(parameterIndex, ((Number JavaDoc) x).longValue());
824           else if (x instanceof String JavaDoc)
825             setLong(parameterIndex, Long.parseLong((String JavaDoc) x));
826           else if (x instanceof Boolean JavaDoc)
827             setLong(parameterIndex, ((Boolean JavaDoc) x).booleanValue() ? 1 : 0);
828           else
829             failed = true;
830           break;
831         case Types.REAL :
832         case Types.FLOAT :
833         case Types.DOUBLE :
834         case Types.DECIMAL :
835         case Types.NUMERIC :
836           // Cast to Number is not necessary. -- EC
837
// Hum, this is a lax shortcut to lower level code -- MH
838
if (connection.isDriverProcessed())
839             set(parameterIndex, x.toString());
840           else
841             setWithTag(parameterIndex, STRING_TAG, x.toString());
842           break;
843         case Types.BIT :
844         case Types.BOOLEAN :
845           if (x instanceof Number JavaDoc)
846             setBoolean(parameterIndex, 0 != ((Number JavaDoc) x).longValue());
847           else if (x instanceof Boolean JavaDoc)
848             setBoolean(parameterIndex, ((Boolean JavaDoc) x).booleanValue());
849           else if (x instanceof String JavaDoc)
850             setBoolean(parameterIndex, Boolean.valueOf((String JavaDoc) x)
851                 .booleanValue());
852           else
853             failed = true;
854           break;
855         case Types.CHAR :
856         case Types.VARCHAR :
857         case Types.LONGVARCHAR :
858           setString(parameterIndex, x.toString());
859           break;
860         case Types.BINARY :
861         case Types.VARBINARY :
862         case Types.LONGVARBINARY :
863           if (x instanceof byte[])
864             setBytes(parameterIndex, (byte[]) x);
865           else if (x instanceof Blob)
866             setBlob(parameterIndex, (Blob) x);
867           else if (x instanceof Serializable JavaDoc)
868             // Try it as an Object (serialized in bytes in setObject below)
869
setObject(parameterIndex, x);
870           else
871             failed = true;
872           break;
873         case Types.DATE :
874           if (x instanceof String JavaDoc)
875             setDate(parameterIndex, java.sql.Date.valueOf((String JavaDoc) x));
876           else if (x instanceof java.sql.Date JavaDoc)
877             setDate(parameterIndex, (java.sql.Date JavaDoc) x);
878           else if (x instanceof Timestamp JavaDoc)
879             setDate(parameterIndex,
880                 new java.sql.Date JavaDoc(((Timestamp JavaDoc) x).getTime()));
881           else
882             failed = true;
883           break;
884         case Types.TIME :
885           if (x instanceof String JavaDoc)
886             setTime(parameterIndex, Time.valueOf((String JavaDoc) x));
887           else if (x instanceof Time JavaDoc)
888             setTime(parameterIndex, (Time JavaDoc) x);
889           else if (x instanceof Timestamp JavaDoc)
890             setTime(parameterIndex, new Time JavaDoc(((Timestamp JavaDoc) x).getTime()));
891           else
892             failed = true;
893           break;
894         case Types.TIMESTAMP :
895           if (x instanceof String JavaDoc)
896             setTimestamp(parameterIndex, Timestamp.valueOf((String JavaDoc) x));
897           else if (x instanceof Date JavaDoc)
898             setTimestamp(parameterIndex, new Timestamp JavaDoc(((Date JavaDoc) x).getTime()));
899           else if (x instanceof Timestamp JavaDoc)
900             setTimestamp(parameterIndex, (Timestamp JavaDoc) x);
901           else
902             failed = true;
903           break;
904         case Types.BLOB :
905           if (x instanceof Blob)
906             setBlob(parameterIndex, (Blob) x);
907           else
908             failed = true;
909           break;
910         case Types.DATALINK :
911           if (x instanceof java.net.URL JavaDoc)
912             setURL(parameterIndex, (java.net.URL JavaDoc) x);
913           else
914             setURL(parameterIndex, new java.net.URL JavaDoc(x.toString()));
915           break;
916         case Types.JAVA_OBJECT :
917         case Types.OTHER :
918           setObject(parameterIndex, x);
919           break;
920         default :
921           throw new SQLException JavaDoc("Unsupported type value");
922       }
923       if (true == failed)
924         throw new IllegalArgumentException JavaDoc(
925             "Attempt to perform an illegal conversion");
926     }
927     catch (Exception JavaDoc e)
928     {
929       SQLException JavaDoc outE = new SQLException JavaDoc("Exception while converting type "
930           + x.getClass() + " to SQL type " + targetSqlType);
931       outE.initCause(e);
932       throw outE;
933     }
934   }
935
936   /**
937    * @see java.sql.PreparedStatement#setObject(int, java.lang.Object, int)
938    */

939   public void setObject(int parameterIndex, Object JavaDoc x, int targetSqlType)
940       throws SQLException JavaDoc
941   {
942     setObject(parameterIndex, x, targetSqlType, 0);
943   }
944
945   /**
946    * This stores an Object parameter into the parameters array.
947    *
948    * @param parameterIndex the first parameter is 1...
949    * @param x the object to set
950    * @exception SQLException if a database access error occurs
951    */

952   public void setObject(int parameterIndex, Object JavaDoc x) throws SQLException JavaDoc
953   {
954     if (x == null)
955     {
956       if (connection.isDriverProcessed())
957         setNull(parameterIndex, Types.JAVA_OBJECT);
958       else
959         setWithTag(parameterIndex, OBJECT_TAG, NULL_TAG);
960     }
961     else
962     {
963       if (x instanceof String JavaDoc)
964         setString(parameterIndex, (String JavaDoc) x);
965       else if (x instanceof BigDecimal JavaDoc)
966         setBigDecimal(parameterIndex, (BigDecimal JavaDoc) x);
967       else if (x instanceof Short JavaDoc)
968         setShort(parameterIndex, ((Short JavaDoc) x).shortValue());
969       else if (x instanceof Integer JavaDoc)
970         setInt(parameterIndex, ((Integer JavaDoc) x).intValue());
971       else if (x instanceof Long JavaDoc)
972         setLong(parameterIndex, ((Long JavaDoc) x).longValue());
973       else if (x instanceof Float JavaDoc)
974         setFloat(parameterIndex, ((Float JavaDoc) x).floatValue());
975       else if (x instanceof Double JavaDoc)
976         setDouble(parameterIndex, ((Double JavaDoc) x).doubleValue());
977       else if (x instanceof byte[])
978         setBytes(parameterIndex, (byte[]) x);
979       else if (x instanceof java.sql.Date JavaDoc)
980         setDate(parameterIndex, (java.sql.Date JavaDoc) x);
981       else if (x instanceof Time JavaDoc)
982         setTime(parameterIndex, (Time JavaDoc) x);
983       else if (x instanceof Timestamp JavaDoc)
984         setTimestamp(parameterIndex, (Timestamp JavaDoc) x);
985       else if (x instanceof Boolean JavaDoc)
986         setBoolean(parameterIndex, ((Boolean JavaDoc) x).booleanValue());
987       else if (x instanceof Blob)
988         setBlob(parameterIndex, (Blob) x);
989       else if (x instanceof java.net.URL JavaDoc)
990         setURL(parameterIndex, (java.net.URL JavaDoc) x);
991       else if (x instanceof Serializable JavaDoc)
992       {
993         ByteArrayOutputStream JavaDoc byteOutputStream = new ByteArrayOutputStream JavaDoc();
994         try
995         {
996           // Serialize object to byte array
997
ObjectOutputStream JavaDoc objectOutputStream = new ObjectOutputStream JavaDoc(
998               byteOutputStream);
999           objectOutputStream.writeObject(x);
1000          objectOutputStream.flush();
1001          objectOutputStream.close();
1002          if (connection.isDriverProcessed())
1003            setBytes(parameterIndex, byteOutputStream.toByteArray());
1004          else
1005            synchronized (sbuf)
1006            {
1007              sbuf.setLength(0);
1008              sbuf.append(byteOutputStream);
1009              setWithTag(parameterIndex, OBJECT_TAG, sbuf.toString());
1010            }
1011        }
1012        catch (IOException JavaDoc e)
1013        {
1014          throw new SQLException JavaDoc("Failed to serialize object: " + e);
1015        }
1016      }
1017      else
1018        throw new SQLException JavaDoc("Objects of type " + x.getClass()
1019            + " are not supported.");
1020    }
1021  }
1022
1023  /**
1024   * Some prepared statements return multiple results; the execute method
1025   * handles these complex statements as well as the simpler form of statements
1026   * handled by <code>executeQuery()</code> and <code>executeUpdate()</code>.
1027   *
1028   * @return <code>true</code> if the next result is a
1029   * <code>ResultSet<code>; <code>false<code> if it is an update count
1030   * or there are no more results
1031   * @exception SQLException if a database access error occurs
1032   */

1033  public boolean execute() throws SQLException JavaDoc
1034  {
1035    int start = 0;
1036    try
1037    {
1038      // Ignore any leading parenthesis
1039
while (sql.charAt(start) == '(')
1040        start++;
1041    }
1042    catch (IndexOutOfBoundsException JavaDoc e)
1043    {
1044      // Probably a buggy request, let it go through and let thefollowing code
1045
// to report an accurate error if any.
1046
start = 0;
1047    }
1048
1049    if (sql.regionMatches(true, start, "select", 0, 6)
1050        || (sql.regionMatches(true, start, "{call", 0, 5)))
1051    {
1052      result = executeQuery(sql, compileQuery());
1053      return true;
1054    }
1055    else
1056    {
1057      updateCount = executeUpdateWithSkeleton(sql, compileQuery());
1058      return false;
1059    }
1060  }
1061
1062  /**
1063   * Returns the SQL statement with the current template values substituted.
1064   * <p>
1065   * <b>Note: </b>: This is identical to <code>compileQuery()</code> except
1066   * instead of throwing SQLException if a parameter is <code>null</code>, it
1067   * places ? instead.
1068   *
1069   * @return the SQL statement
1070   */

1071  public String JavaDoc toString()
1072  {
1073    synchronized (sbuf)
1074    {
1075      sbuf.setLength(0);
1076      int i;
1077
1078      for (i = 0; i < inStrings.length; ++i)
1079      {
1080        if (inStrings[i] == null)
1081          sbuf.append('?');
1082        else
1083          sbuf.append(templateStrings[i]);
1084        sbuf.append(inStrings[i]);
1085      }
1086      sbuf.append(templateStrings[inStrings.length]);
1087      return sbuf.toString();
1088    }
1089  }
1090
1091  // ** JDBC 2 Extensions **
1092

1093  /**
1094   * This parses the query and adds it to the current batch
1095   *
1096   * @throws SQLException if an error occurs
1097   */

1098  public synchronized void addBatch() throws SQLException JavaDoc
1099  {
1100    if (batch == null)
1101      batch = new Vector JavaDoc();
1102    batch.addElement(new BatchElement(sql, compileQuery()));
1103  }
1104
1105  /**
1106   * Execute a batch of commands
1107   *
1108   * @return an array containing update count that corresponding to the commands
1109   * that executed successfully
1110   * @exception BatchUpdateException if an error occurs on one statement (the
1111   * number of updated rows for the successfully executed
1112   * statements can be found in
1113   * BatchUpdateException.getUpdateCounts())
1114   */

1115  public int[] executeBatch() throws BatchUpdateException JavaDoc
1116  {
1117    if (batch == null || batch.isEmpty())
1118      return new int[0];
1119
1120    int size = batch.size();
1121    int[] nbsRowsUpdated = new int[size];
1122    int i = 0;
1123
1124    try
1125    {
1126      for (i = 0; i < size; i++)
1127      {
1128        BatchElement be = (BatchElement) batch.elementAt(i);
1129        nbsRowsUpdated[i] = this.executeUpdateWithSkeleton(be.getSqlTemplate(),
1130            be.getCompiledSql());
1131      }
1132      return nbsRowsUpdated;
1133    }
1134    catch (SQLException JavaDoc e)
1135    {
1136      String JavaDoc message = "Batch failed for request " + i + ": "
1137          + ((BatchElement) batch.elementAt(i)).getCompiledSql() + " (" + e
1138          + ")";
1139
1140      // shrink the returned array
1141
int[] updateCounts = new int[i];
1142      System.arraycopy(nbsRowsUpdated, 0, updateCounts, 0, i);
1143
1144      throw new BatchUpdateException JavaDoc(message, updateCounts);
1145    }
1146    finally
1147    {
1148      batch.removeAllElements();
1149    }
1150  }
1151
1152  /**
1153   * Returns the <code>MetaData</code> for the last <code>ResultSet</code>
1154   * returned.
1155   *
1156   * @return The ResultSet Metadata
1157   * @throws SQLException if an error occurs
1158   */

1159  public java.sql.ResultSetMetaData JavaDoc getMetaData() throws SQLException JavaDoc
1160  {
1161    java.sql.ResultSet JavaDoc rs = getResultSet();
1162    if (rs != null)
1163      return rs.getMetaData();
1164
1165    // Does anyone really know what this method does?
1166
return null;
1167  }
1168
1169  /**
1170   * @see java.sql.PreparedStatement#setArray(int, java.sql.Array)
1171   */

1172  public void setArray(int i, Array JavaDoc x) throws SQLException JavaDoc
1173  {
1174    throw new NotImplementedException("setArray()");
1175  }
1176
1177  /**
1178   * @see java.sql.PreparedStatement#setBlob(int, java.sql.Blob)
1179   */

1180  public void setBlob(int paramIndex, java.sql.Blob JavaDoc sqlBlobParam)
1181      throws SQLException JavaDoc
1182  {
1183    if (sqlBlobParam == null)
1184    {
1185      if (connection.isDriverProcessed())
1186        setNull(paramIndex, Types.BLOB);
1187      else
1188        setWithTag(paramIndex, BLOB_TAG, NULL_TAG);
1189      return;
1190    }
1191
1192    // sqlBlobParam.getBytes() seems limited in size ?
1193
// So we use .getBinaryStream()
1194
InputStream JavaDoc blobBinStream = sqlBlobParam.getBinaryStream();
1195
1196    if (connection.isDriverProcessed())
1197      setBinaryStream(paramIndex, blobBinStream, (int) sqlBlobParam.length());
1198    else
1199    {
1200      byte[] data = new byte[(int) sqlBlobParam.length()];
1201      try
1202      {
1203        blobBinStream.read(data, 0, (int) sqlBlobParam.length());
1204      }
1205      catch (Exception JavaDoc ioe)
1206      {
1207        throw new SQLException JavaDoc("Problem with data streaming");
1208      }
1209      try
1210      {
1211        synchronized (this.sbuf)
1212        {
1213          this.sbuf.setLength(0);
1214          /**
1215           * Encoded only for request inlining. Decoded right away by the
1216           * controller at static
1217           * {@link #setPreparedStatement(String, java.sql.PreparedStatement)}
1218           */

1219          this.sbuf.append(new HexaBlobFilter().encode(data));
1220          setWithTag(paramIndex, BLOB_TAG, this.sbuf.toString());
1221        }
1222      }
1223      catch (OutOfMemoryError JavaDoc oome)
1224      {
1225        this.sbuf = null;
1226        System.gc();
1227        throw new SQLException JavaDoc("Out of memory");
1228      }
1229
1230    }
1231  }
1232
1233  /**
1234   * @see java.sql.PreparedStatement#setCharacterStream(int, java.io.Reader,
1235   * int)
1236   */

1237  public void setCharacterStream(int i, java.io.Reader JavaDoc x, int length)
1238      throws SQLException JavaDoc
1239  {
1240    char[] data = new char[length];
1241    try
1242    {
1243      x.read(data, 0, length);
1244    }
1245    catch (Exception JavaDoc ioe)
1246    {
1247      throw new SQLException JavaDoc("Problem with streaming of data");
1248    }
1249    setString(i, new String JavaDoc(data));
1250  }
1251
1252  /**
1253   * @see java.sql.PreparedStatement#setClob(int, java.sql.Clob)
1254   */

1255  public void setClob(int i, java.sql.Clob JavaDoc clobArg) throws SQLException JavaDoc
1256  {
1257    if (clobArg == null)
1258    {
1259      if (connection.isDriverProcessed())
1260        setNull(i, Types.CLOB);
1261      else
1262        setWithTag(i, CLOB_TAG, NULL_TAG);
1263      return;
1264    }
1265    if (connection.isDriverProcessed())
1266      setString(i, clobArg.getSubString(0, (int) clobArg.length()));
1267    else
1268      setWithTag(i, CLOB_TAG, clobArg.getSubString(0, (int) clobArg.length()));
1269  }
1270
1271  /**
1272   * @see java.sql.PreparedStatement#setNull(int, int, java.lang.String)
1273   */

1274  public void setNull(int i, int t, String JavaDoc s) throws SQLException JavaDoc
1275  {
1276    setNull(i, t);
1277  }
1278
1279  /**
1280   * @see java.sql.PreparedStatement#setRef(int, java.sql.Ref)
1281   */

1282  public void setRef(int i, Ref JavaDoc x) throws SQLException JavaDoc
1283  {
1284    if (connection.isDriverProcessed())
1285    {
1286      if (x == null)
1287        setNull(i, Types.REF);
1288      else
1289        set(i, x.toString());
1290    }
1291    else
1292    {
1293      if (x == null)
1294        setWithTag(i, REF_TAG, NULL_TAG);
1295      else
1296        setWithTag(i, REF_TAG, x.toString());
1297    }
1298  }
1299
1300  /**
1301   * @see java.sql.PreparedStatement#setDate(int, java.sql.Date,
1302   * java.util.Calendar)
1303   */

1304  public void setDate(int i, java.sql.Date JavaDoc d, java.util.Calendar JavaDoc cal)
1305      throws SQLException JavaDoc
1306  {
1307    if (d == null)
1308    {
1309      if (connection.isDriverProcessed())
1310        setNull(i, Types.DATE);
1311      else
1312        setWithTag(i, DATE_TAG, NULL_TAG);
1313      return;
1314    }
1315    else
1316    {
1317      if (cal == null)
1318        setDate(i, d);
1319      else
1320      {
1321        cal.setTime(d);
1322        setDate(i, new java.sql.Date JavaDoc(cal.getTime().getTime()));
1323      }
1324    }
1325  }
1326
1327  /**
1328   * @see java.sql.PreparedStatement#setTime(int, java.sql.Time,
1329   * java.util.Calendar)
1330   */

1331  public void setTime(int i, Time JavaDoc t, java.util.Calendar JavaDoc cal)
1332      throws SQLException JavaDoc
1333  {
1334    if (t == null)
1335    {
1336      if (connection.isDriverProcessed())
1337        setNull(i, Types.TIME);
1338      else
1339        setWithTag(i, TIME_TAG, NULL_TAG);
1340      return;
1341    }
1342    else
1343    {
1344      if (cal == null)
1345        setTime(i, t);
1346      else
1347      {
1348        cal.setTime(t);
1349        setTime(i, new java.sql.Time JavaDoc(cal.getTime().getTime()));
1350      }
1351    }
1352  }
1353
1354  /**
1355   * @see java.sql.PreparedStatement#setTimestamp(int, java.sql.Timestamp,
1356   * java.util.Calendar)
1357   */

1358  public void setTimestamp(int i, Timestamp JavaDoc t, java.util.Calendar JavaDoc cal)
1359      throws SQLException JavaDoc
1360  {
1361    if (t == null)
1362    {
1363      if (connection.isDriverProcessed())
1364        setNull(i, Types.TIMESTAMP);
1365      else
1366        setWithTag(i, TIMESTAMP_TAG, NULL_TAG);
1367      return;
1368    }
1369    else
1370    {
1371      if (cal == null)
1372        setTimestamp(i, t);
1373      else
1374      {
1375        cal.setTime(t);
1376        setTimestamp(i, new java.sql.Timestamp JavaDoc(cal.getTime().getTime()));
1377      }
1378    }
1379  }
1380
1381  // ------------------------- JDBC 3.0 -----------------------------------
1382

1383  /**
1384   * Sets the designated parameter to the given <code>java.net.URL</code>
1385   * value. The driver converts this to an SQL <code>DATALINK</code> value
1386   * when it sends it to the database.
1387   *
1388   * @param parameterIndex the first parameter is 1, the second is 2, ...
1389   * @param x the <code>java.net.URL</code> object to be set
1390   * @exception SQLException if a database access error occurs
1391   * @since JDK 1.4
1392   */

1393  public void setURL(int parameterIndex, java.net.URL JavaDoc x) throws SQLException JavaDoc
1394  {
1395    if (connection.isDriverProcessed())
1396    {
1397      if (x == null)
1398        setNull(parameterIndex, Types.OTHER);
1399      else
1400        set(parameterIndex, x.toString());
1401    }
1402    else
1403    {
1404      if (x == null)
1405        setWithTag(parameterIndex, URL_TAG, NULL_TAG);
1406      else
1407        setWithTag(parameterIndex, URL_TAG, x.toString());
1408    }
1409  }
1410
1411  /**
1412   * Retrieves the number, types and properties of this
1413   * <code>PreparedStatement</code> object's parameters.
1414   *
1415   * @return a <code>ParameterMetaData</code> object that contains information
1416   * about the number, types and properties of this
1417   * <code>PreparedStatement</code> object's parameters
1418   * @exception SQLException if a database access error occurs
1419   * @see ParameterMetaData
1420   * @since JDK 1.4
1421   */

1422  public ParameterMetaData JavaDoc getParameterMetaData() throws SQLException JavaDoc
1423  {
1424    throw new NotImplementedException("getParameterMetaData");
1425  }
1426
1427  // **************************************************************
1428
// END OF PUBLIC INTERFACE
1429
// **************************************************************
1430

1431  /**
1432   * Actually stores the IN parameter into parameters String array. Called by
1433   * most setXXX() methods.
1434   *
1435   * @param paramIndex the index into the inString
1436   * @param s a string to be stored
1437   * @exception SQLException if something goes wrong
1438   */

1439  private void set(int paramIndex, String JavaDoc s) throws SQLException JavaDoc
1440  {
1441    if (paramIndex < 1 || paramIndex > inStrings.length)
1442      throw new SQLException JavaDoc("Parameter index out of range.");
1443    inStrings[paramIndex - 1] = s;
1444  }
1445
1446  /**
1447   * Stores parameter and its type as a <em>quoted</em> String, so the
1448   * controller can decode them back. Used when driverProcessed is false.
1449   * <p>
1450   * When isDriverProcessed() is false, we could avoid inlining the arguments
1451   * and just tag them and send them apart as an object list. But this would
1452   * imply a couple of changes elsewhere, among other: macro-handling,
1453   * recoverylog,...
1454   *
1455   * @param paramIndex the index into the inString
1456   * @param typeTag type of the parameter
1457   * @param param the parameter string to be stored
1458   * @exception SQLException if something goes wrong
1459   * @see #setPreparedStatement(String, java.sql.PreparedStatement)
1460   */

1461  private void setWithTag(int paramIndex, String JavaDoc typeTag, String JavaDoc param)
1462      throws SQLException JavaDoc
1463  {
1464    /**
1465     * insert TAGS so the controller can parse and "unset" the request using
1466     * {@link #setPreparedStatement(String, java.sql.PreparedStatement)
1467     */

1468    set(paramIndex, START_PARAM_TAG + typeTag
1469        + Strings.replace(param, TAG_MARKER, TAG_MARKER_ESCAPE) + END_PARAM_TAG);
1470  }
1471
1472  /**
1473   * Set the auto generated key flag defined in Statement
1474   *
1475   * @param autoGeneratedKeys usually
1476   * <code>Statement.RETURN_GENERATED_KEYS</code>
1477   * @see Connection#prepareStatement(String, int)
1478   */

1479  protected void setGeneratedKeysFlag(int autoGeneratedKeys)
1480  {
1481    generatedKeysFlag = autoGeneratedKeys;
1482  }
1483
1484  /**
1485   * Static method to initialize a backend PreparedStatement by calling the
1486   * appropriate setXXX methods on the request skeleton. Has to extract the
1487   * tagged and inlined parameters from the sql String beforehand. Used by the
1488   * controller, only when isDriverProcessed() is false.
1489   *
1490   * @param quotedRequest SQL statement with parameters to replace
1491   * @param backendPS the preparedStatement to set
1492   * @throws SQLException if an error occurs
1493   * @see #setWithTag(int, String, String)
1494   */

1495  public static void setPreparedStatement(String JavaDoc quotedRequest,
1496      java.sql.PreparedStatement JavaDoc backendPS) throws SQLException JavaDoc
1497  {
1498    int i = 0;
1499    int paramIdx = 0;
1500
1501    // Set all parameters
1502
while ((i = quotedRequest.indexOf(START_PARAM_TAG, i)) > -1)
1503    {
1504      paramIdx++;
1505
1506      int typeStart = i + START_PARAM_TAG.length();
1507
1508      // Here we assume that all tags have the same length as the boolean tag.
1509
String JavaDoc paramType = quotedRequest.substring(typeStart, typeStart
1510          + BOOLEAN_TAG.length());
1511      String JavaDoc paramValue = quotedRequest.substring(typeStart
1512          + BOOLEAN_TAG.length(), quotedRequest.indexOf(END_PARAM_TAG, i));
1513      paramValue = Strings.replace(paramValue, TAG_MARKER_ESCAPE, TAG_MARKER);
1514
1515      // Test tags in alphabetical order (to make the code easier to read)
1516
if (paramType.equals(BIG_DECIMAL_TAG))
1517      {
1518        if (paramValue.equals(NULL_TAG))
1519          backendPS.setBigDecimal(paramIdx, null);
1520        else
1521        {
1522          BigDecimal JavaDoc t = new BigDecimal JavaDoc(paramValue);
1523          backendPS.setBigDecimal(paramIdx, t);
1524        }
1525      }
1526      else if (paramType.equals(BOOLEAN_TAG))
1527        backendPS.setBoolean(paramIdx, Boolean.valueOf(paramValue)
1528            .booleanValue());
1529      else if (paramType.equals(BYTE_TAG))
1530      {
1531        byte t = new Integer JavaDoc(paramValue).byteValue();
1532        backendPS.setByte(paramIdx, t);
1533      }
1534      else if (paramType.equals(BYTES_TAG))
1535      {
1536        /**
1537         * encoded by the driver at {@link #setBytes(int, byte[])}in order to
1538         * inline it in the request (no database encoding here).
1539         */

1540        byte[] t = new HexaBlobFilter().decode(paramValue);
1541        backendPS.setBytes(paramIdx, t);
1542      }
1543      else if (paramType.equals(BLOB_TAG))
1544      {
1545        if (paramValue.equals(NULL_TAG))
1546          backendPS.setBlob(paramIdx, null);
1547        else
1548        {
1549          /**
1550           * encoded by the driver at {@link #setBlob(int, java.sql.Blob)}
1551           */

1552          Blob b = new Blob(new HexaBlobFilter().decode(paramValue));
1553          backendPS.setBlob(paramIdx, b);
1554        }
1555      }
1556      else if (paramType.equals(CLOB_TAG))
1557      {
1558        if (paramValue.equals(NULL_TAG))
1559          backendPS.setClob(paramIdx, null);
1560        else
1561        {
1562          Clob c = new Clob(paramValue);
1563          backendPS.setClob(paramIdx, c);
1564        }
1565      }
1566      else if (paramType.equals(DATE_TAG))
1567      {
1568        if (paramValue.equals(NULL_TAG))
1569          backendPS.setDate(paramIdx, null);
1570        else
1571          try
1572          {
1573            SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc("yyyy-MM-dd");
1574            Date JavaDoc t = new Date JavaDoc(sdf.parse(paramValue).getTime());
1575            backendPS.setDate(paramIdx, t);
1576          }
1577          catch (ParseException JavaDoc p)
1578          {
1579            backendPS.setDate(paramIdx, null);
1580            throw new SQLException JavaDoc("Couldn't format date!!!");
1581          }
1582      }
1583      else if (paramType.equals(DOUBLE_TAG))
1584        backendPS.setDouble(paramIdx, Double.valueOf(paramValue).doubleValue());
1585      else if (paramType.equals(FLOAT_TAG))
1586        backendPS.setFloat(paramIdx, Float.valueOf(paramValue).floatValue());
1587      else if (paramType.equals(INTEGER_TAG))
1588        backendPS.setInt(paramIdx, Integer.valueOf(paramValue).intValue());
1589      else if (paramType.equals(LONG_TAG))
1590        backendPS.setLong(paramIdx, Long.valueOf(paramValue).longValue());
1591      else if (paramType.equals(NULL_TAG))
1592        backendPS.setNull(paramIdx, Integer.valueOf(paramValue).intValue());
1593      else if (paramType.equals(OBJECT_TAG))
1594      {
1595        if (paramValue.equals(NULL_TAG))
1596          backendPS.setObject(paramIdx, null);
1597        else
1598        {
1599          try
1600          {
1601            ObjectInputStream JavaDoc in = new ObjectInputStream JavaDoc(
1602                new ByteArrayInputStream JavaDoc(paramValue.getBytes()));
1603            backendPS.setObject(paramIdx, in.readObject());
1604            in.close();
1605          }
1606          catch (Exception JavaDoc e)
1607          {
1608            throw new SQLException JavaDoc("Failed to rebuild object from stream " + e);
1609          }
1610        }
1611      }
1612      else if (paramType.equals(REF_TAG))
1613      {
1614        if (paramValue.equals(NULL_TAG))
1615          backendPS.setRef(paramIdx, null);
1616        else
1617          throw new SQLException JavaDoc("Ref type not supported");
1618      }
1619      else if (paramType.equals(SHORT_TAG))
1620      {
1621        short t = new Integer JavaDoc(paramValue).shortValue();
1622        backendPS.setShort(paramIdx, t);
1623      }
1624      else if (paramType.equals(STRING_TAG))
1625      { // Value is not null, null values are handled by NULL_STRING_TAG
1626
backendPS.setString(paramIdx, paramValue);
1627      }
1628      else if (paramType.equals(NULL_STRING_TAG))
1629      {
1630        backendPS.setString(paramIdx, null);
1631      }
1632      else if (paramType.equals(TIME_TAG))
1633      {
1634        if (paramValue.equals(NULL_TAG))
1635          backendPS.setTime(paramIdx, null);
1636        else
1637          try
1638          {
1639            SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc("HH:mm:ss");
1640            Time JavaDoc t = new Time JavaDoc(sdf.parse(paramValue).getTime());
1641            backendPS.setTime(paramIdx, t);
1642          }
1643          catch (ParseException JavaDoc p)
1644          {
1645            backendPS.setTime(paramIdx, null);
1646            throw new SQLException JavaDoc("Couldn't format time!!!");
1647          }
1648      }
1649      else if (paramType.equals(TIMESTAMP_TAG))
1650      {
1651        if (paramValue.equals(NULL_TAG))
1652          backendPS.setTimestamp(paramIdx, null);
1653        else
1654          try
1655          {
1656            SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc("yyyy-MM-dd HH:mm:ss.S");
1657            Timestamp JavaDoc t = new Timestamp JavaDoc(sdf.parse(paramValue).getTime());
1658            backendPS.setTimestamp(paramIdx, t);
1659          }
1660          catch (ParseException JavaDoc p)
1661          {
1662            backendPS.setTimestamp(paramIdx, null);
1663            throw new SQLException JavaDoc("Couldn't format timestamp!!!");
1664          }
1665      }
1666      else if (paramType.equals(URL_TAG))
1667      {
1668        if (paramValue.equals(NULL_TAG))
1669          backendPS.setURL(paramIdx, null);
1670        else
1671          try
1672          {
1673            backendPS.setURL(paramIdx, new URL JavaDoc(paramValue));
1674          }
1675          catch (MalformedURLException JavaDoc e)
1676          {
1677            throw new SQLException JavaDoc("Unable to create URL " + paramValue + " ("
1678                + e + ")");
1679          }
1680      }
1681      else
1682      {
1683        // invalid parameter, we want to be able to store strings like
1684
// <?xml version="1.0" encoding="ISO-8859-1"?>
1685
paramIdx--;
1686      }
1687      i = typeStart;
1688    }
1689  }
1690
1691  /**
1692   * This class defines a BatchElement used for the batch update vector of
1693   * PreparedStatements to execute.
1694   *
1695   * @author <a HREF="mailto:emmanuel.cecchet@emicnetworks.com">Emmanuel Cecchet
1696   * </a>
1697   * @version 1.0
1698   */

1699  private class BatchElement
1700  {
1701    private String JavaDoc sqlTemplate;
1702    private String JavaDoc compiledSql;
1703
1704    /**
1705     * Creates a new <code>BatchElement</code> object
1706     *
1707     * @param sqlTemplate SQL query template (aka skeleton)
1708     * @param compiledSql compiled SQL statement
1709     */

1710    public BatchElement(String JavaDoc sqlTemplate, String JavaDoc compiledSql)
1711    {
1712      this.sqlTemplate = sqlTemplate;
1713      this.compiledSql = compiledSql;
1714    }
1715
1716    /**
1717     * Returns the compiledSql value.
1718     *
1719     * @return Returns the compiledSql.
1720     */

1721    public String JavaDoc getCompiledSql()
1722    {
1723      return compiledSql;
1724    }
1725
1726    /**
1727     * Returns the sqlTemplate value.
1728     *
1729     * @return Returns the sqlTemplate.
1730     */

1731    public String JavaDoc getSqlTemplate()
1732    {
1733      return sqlTemplate;
1734    }
1735  }
1736}
1737
Popular Tags