001    package org.rakeshv.dbutils;
002    
003    import java.io.InputStream;
004    import java.io.Reader;
005    import java.math.BigDecimal;
006    import java.net.URL;
007    import java.util.Calendar;
008    
009    import java.sql.Array;
010    import java.sql.Blob;
011    import java.sql.Clob;
012    import java.sql.Date;
013    import java.sql.ParameterMetaData;
014    import java.sql.PreparedStatement;
015    import java.sql.Ref;
016    import java.sql.ResultSet;
017    import java.sql.ResultSetMetaData;
018    import java.sql.SQLException;
019    import java.sql.Time;
020    import java.sql.Timestamp;
021    
022    import org.rakeshv.Statistics;
023    
024    /**
025     * A decorator around a <code>PreparedStatement</code> to enable caching
026     * and reuse of <code>PreparedStatement</code> objects.  These work
027     * only if the underlying <code>Connection</code> is kept open, as is
028     * the case with connection pools or when using the {@link
029     * ConnectionDecorator}.
030     *
031     * <p>Copyright 2005 Rakesh Vidyadharan</p>
032     * @author Rakesh Vidyadharan 2005-11-18
033     * @version $Id: ConnectionFactory.java,v 1.2 2005/10/29 22:27:38 rakesh Exp $
034     */
035    public class PreparedStatementDecorator extends StatementDecorator
036      implements PreparedStatement
037    {
038      /**
039       * The <code>PreparedStatement</code> that this object decorates.
040       */
041      private PreparedStatement statement;
042    
043      /**
044       * Statistics for this statement.
045       */
046      protected Statistics statistics;
047    
048      /**
049       * Default constructor.  Cannot be instantiated.
050       */
051      protected PreparedStatementDecorator()
052      {
053        statistics = new Statistics();
054      }
055    
056      /**
057       * Create a new instance of the class using the specified 
058       * PreparedStatement  object that will be decorated.
059       *
060       * @param statement The PreparedStatement that is to be decorated.
061       */
062      public PreparedStatementDecorator( PreparedStatement statement )
063      {
064        this();
065        this.statement = statement;
066      }
067    
068      /**
069       * Executes the SQL query in this PreparedStatement object and 
070       * returns the ResultSet object generated by the query. 
071       *
072       * @return ResultSet A ResultSet object that contains the data 
073       *   produced by the query; never null 
074       * @throws SQLException If a database access error occurs or the SQL 
075       *   statement does not return a ResultSet object
076       */
077      public ResultSet executeQuery() throws SQLException
078      {
079        statistics.update();
080        return getStatement().executeQuery();
081      }
082    
083      /** 
084       * Executes the SQL statement in this PreparedStatement object, which 
085       * must be an SQL INSERT, UPDATE or DELETE statement; or an SQL 
086       * statement that returns nothing, such as a DDL getStatement(). 
087       *
088       * @return int Either (1) the row count for INSERT, UPDATE, or DELETE 
089       *   statements or (2) 0 for SQL statements that return nothing 
090       * @throws SQLException If a database access error occurs or the SQL 
091       *   statement returns a ResultSet object
092       */
093      public int executeUpdate() throws SQLException
094      {
095        statistics.update();
096        return getStatement().executeUpdate();
097      }
098    
099      /**
100       * Sets the designated parameter to SQL NULL. 
101       *
102       * <p><b>Note:</b> You must specify the parameter's SQL type.</p>
103       *
104       * @param parameterIndex The first parameter is 1, the second is 2, ...  
105       * @param sqlType The SQL type code defined in java.sql.Types 
106       * @throws SQLException If a database access error occurs
107       */
108      public void setNull( int parameterIndex, int sqlType )
109        throws SQLException
110      {
111        getStatement().setNull( parameterIndex, sqlType );
112      }
113    
114      /**
115       * Sets the designated parameter to the given Java boolean value. The 
116       * driver converts this to an SQL BIT value when it sends it to the 
117       * database. 
118       *
119       * @param parameterIndex The first parameter is 1, the second is 2, ...
120       * @param x the parameter value 
121       * @throws SQLException If a database access error occurs
122       */
123      public void setBoolean( int parameterIndex, boolean x )
124        throws SQLException
125      {
126        getStatement().setBoolean( parameterIndex, x );
127      }
128    
129      /**
130       * Sets the designated parameter to the given Java byte value. The 
131       * driver converts this to an SQL TINYINT value when it sends it to 
132       * the database. 
133       *
134       * @param parameterIndex The first parameter is 1, the second is 2, ...
135       * @param x The parameter value 
136       * @throws SQLException If a database access error occurs
137       */
138      public void setByte(int parameterIndex, byte x) throws SQLException
139      {
140        getStatement().setByte( parameterIndex, x );
141      }
142    
143      /**
144       * Sets the designated parameter to the given Java short value. The 
145       * driver converts this to an SQL SMALLINT value when it sends it to 
146       * the database. 
147       *
148       * @param parameterIndex The first parameter is 1, the second is 2, ...
149       * @param x the parameter value 
150       * @throws SQLException If a database access error occurs
151       */
152      public void setShort(int parameterIndex, short x) throws SQLException
153      {
154        getStatement().setShort( parameterIndex, x );
155      }
156    
157      /**
158       * Sets the designated parameter to the given Java int value. The 
159       * driver converts this to an SQL INTEGER value when it sends it to 
160       * the database. 
161       *
162       * @param parameterIndex The first parameter is 1, the second is 2, ...
163       * @param x The parameter value 
164       * @throws SQLException If a database access error occurs
165       */
166      public void setInt(int parameterIndex, int x) throws SQLException
167      {
168        getStatement().setInt( parameterIndex, x );
169      }
170    
171      /** 
172       * Sets the designated parameter to the given Java long value. The 
173       * driver converts this to an SQL BIGINT value when it sends it to 
174       * the database. 
175       *
176       * @param parameterIndex The first parameter is 1, the second is 2, ...
177       * @param x The parameter value 
178       * @throws SQLException If a database access error occurs
179       */
180      public void setLong(int parameterIndex, long x) throws SQLException
181      {
182        getStatement().setLong( parameterIndex, x );
183      }
184    
185      /**
186       * Sets the designated parameter to the given Java float value. The 
187       * driver converts this to an SQL FLOAT value when it sends it to the 
188       * database. 
189       *
190       * @param parameterIndex The first parameter is 1, the second is 2, ...
191       * @param x The parameter value 
192       * @throws SQLException If a database access error occurs
193       */
194      public void setFloat(int parameterIndex, float x) throws SQLException
195      {
196        getStatement().setFloat( parameterIndex, x );
197      }
198    
199      /**
200       * Sets the designated parameter to the given Java double value. The 
201       * driver converts this to an SQL DOUBLE value when it sends it to 
202       * the database. 
203       *
204       * @param parameterIndex The first parameter is 1, the second is 2, ...
205       * @param x the parameter value 
206       * @throws SQLException If a database access error occurs
207       */
208      public void setDouble(int parameterIndex, double x) throws SQLException
209      {
210        getStatement().setDouble( parameterIndex, x );
211      }
212    
213      /** 
214       * Sets the designated parameter to the given java.math.BigDecimal 
215       * value. The driver converts this to an SQL NUMERIC value when it 
216       * sends it to the database. 
217       *
218       * @param parameterIndex The first parameter is 1, the second is 2, ...
219       * @param x the parameter value 
220       * @throws SQLException If a database access error occurs
221       */
222      public void setBigDecimal(int parameterIndex, BigDecimal x) 
223        throws SQLException
224      {
225        getStatement().setBigDecimal( parameterIndex, x );
226      }
227    
228      /**
229       * Sets the designated parameter to the given Java String value. The 
230       * driver converts this to an SQL VARCHAR or LONGVARCHAR value 
231       * (depending on the argument's size relative to the driver's limits 
232       * on VARCHAR values) when it sends it to the database. 
233       *
234       * @param parameterIndex The first parameter is 1, the second is 2, ...
235       * @param x the parameter value 
236       * @throws SQLException If a database access error occurs
237       */
238      public void setString(int parameterIndex, String x) throws SQLException
239      {
240        getStatement().setString( parameterIndex, x );
241      }
242    
243      /**
244       * Sets the designated parameter to the given Java array of bytes. 
245       * The driver converts this to an SQL VARBINARY or LONGVARBINARY 
246       * (depending on the argument's size relative to the driver's limits 
247       * on VARBINARY values) when it sends it to the database. 
248       *
249       * @param parameterIndex The first parameter is 1, the second is 2, ...
250       * @param x The parameter value 
251       * @throws SQLException If a database access error occurs
252       */
253      public void setBytes(int parameterIndex, byte[] x) throws SQLException
254      {
255        getStatement().setBytes( parameterIndex, x );
256      }
257    
258      /**
259       * Sets the designated parameter to the given java.sql.Date value. 
260       * The driver converts this to an SQL DATE value when it sends it to 
261       * the database. 
262       *
263       * @param parameterIndex The first parameter is 1, the second is 2, ...
264       * @param x The parameter value 
265       * @throws SQLException If a database access error occurs
266       */
267      public void setDate(int parameterIndex, Date x) throws SQLException
268      {
269        getStatement().setDate( parameterIndex, x );
270      }
271    
272      /**
273       * Sets the designated parameter to the given java.sql.Time value. 
274       * The driver converts this to an SQL TIME value when it sends it to 
275       * the database. 
276       *
277       * @param parameterIndex The first parameter is 1, the second is 2, ...
278       * @param x the parameter value 
279       * @throws SQLException If a database access error occurs
280       */
281      public void setTime(int parameterIndex, Time x) throws SQLException
282      {
283        getStatement().setTime( parameterIndex, x );
284      }
285    
286      /**
287       * Sets the designated parameter to the given java.sql.Timestamp 
288       * value. The driver converts this to an SQL TIMESTAMP value when it 
289       * sends it to the database. 
290       *
291       * @param parameterIndex The first parameter is 1, the second is 2, ...
292       * @param x The parameter value 
293       * @throws SQLException If a database access error occurs
294       */
295      public void setTimestamp(int parameterIndex, Timestamp x) 
296        throws SQLException
297      {
298        getStatement().setTimestamp( parameterIndex, x );
299      }
300    
301      /**
302       * Sets the designated parameter to the given input stream, which 
303       * will have the specified number of bytes. When a very large ASCII 
304       * value is input to a LONGVARCHAR parameter, it may be more practical
305       * to send it via a java.io.InputStream. Data will be read from the 
306       * stream as needed until end-of-file is reached. The JDBC driver 
307       * will do any necessary conversion from ASCII to the database char 
308       * format. 
309       *
310       * <p><b>Note:</b> This stream object can either be a standard Java 
311       * stream object or your own subclass that implements the standard 
312       * interface.</p>
313       *
314       * @param parameterIndex The first parameter is 1, the second is 2, ...
315       * @param x The Java input stream that contains the ASCII parameter value
316       * @param length The number of bytes in the stream 
317       * @throws SQLException If a database access error occurs
318       */
319      public void setAsciiStream(int parameterIndex, InputStream x,
320          int length) throws SQLException
321      {
322        getStatement().setAsciiStream( parameterIndex, x, length );
323      }
324    
325      /**
326       * Sets the designated parameter to the given input stream, which 
327       * will have the specified number of bytes. A Unicode character has 
328       * two bytes, with the first byte being the high byte, and the second 
329       * being the low byte. When a very large Unicode value is input to a 
330       * LONGVARCHAR parameter, it may be more practical to send it via a 
331       * java.io.InputStream object. The data will be read from the stream 
332       * as needed until end-of-file is reached. The JDBC driver will do 
333       * any necessary conversion from Unicode to the database char format. 
334       *
335       * <p><b>Note:</b> This stream object can either be a standard Java 
336       * stream object or your own subclass that implements the standard 
337       * interface.</p>
338       *
339       * @deprecated
340       * @param parameterIndex The first parameter is 1, the second is 2, ...
341       * @param x A java.io.InputStream object that contains the Unicode 
342       *   parameter value as two-byte Unicode characters
343       * @param length The number of bytes in the stream 
344       * @throws SQLException If a database access error occurs
345       */
346      @Deprecated public void setUnicodeStream(int parameterIndex, 
347          InputStream x, int length) throws SQLException
348      {
349        getStatement().setUnicodeStream( parameterIndex, x, length );
350      }
351    
352      /**
353       * Sets the designated parameter to the given input stream, which 
354       * will have the specified number of bytes. When a very large binary 
355       * value is input to a LONGVARBINARY parameter, it may be more 
356       * practical to send it via a java.io.InputStream object. The data 
357       * will be read from the stream as needed until end-of-file is 
358       * reached. 
359       *
360       * <p><b>Note:</b> This stream object can either be a standard Java 
361       * stream object or your own subclass that implements the standard 
362       * interface.</p>
363       *
364       * @param parameterIndex The first parameter is 1, the second is 2, ...
365       * @param x The java input stream which contains the binary parameter value
366       * @param length The number of bytes in the stream 
367       * @throws SQLException If a database access error occurs
368       */
369      public void setBinaryStream(int parameterIndex, InputStream x, 
370          int length) throws SQLException
371      {
372        getStatement().setBinaryStream( parameterIndex, x, length );
373      }
374    
375      /**
376       * Clears the current parameter values immediately. 
377       *
378       * <p>In general, parameter values remain in force for repeated use 
379       * of a getStatement(). Setting a parameter value automatically clears its 
380       * previous value. However, in some cases it is useful to immediately 
381       * release the resources used by the current parameter values; this 
382       * can be done by calling the method clearParameters.</p>
383       *
384       * @throws SQLException If a database access error occurs
385       */
386      public void clearParameters() throws SQLException
387      {
388        getStatement().clearParameters();
389      }
390    
391      /**
392       * Sets the value of the designated parameter with the given object. 
393       * The second argument must be an object type; for integral values, 
394       * the java.lang equivalent objects should be used. 
395       *
396       * <p>The given Java object will be converted to the given 
397       * targetSqlType before being sent to the database. If the object has 
398       * a custom mapping (is of a class implementing the interface 
399       * SQLData), the JDBC driver should call the method SQLData.writeSQL 
400       * to write it to the SQL data stream. If, on the other hand, the 
401       * object is of a class implementing Ref, Blob, Clob, Struct, or 
402       * Array, the driver should pass it to the database as a value of the 
403       * corresponding SQL type.</p>
404       *
405       * <p>Note that this method may be used to pass database-specific 
406       * abstract data types.</p>
407       *
408       * @param parameterIndex The first parameter is 1, the second is 2, ...
409       * @param x The object containing the input parameter value
410       * @param targetSqlType The SQL type (as defined in java.sql.Types) 
411       *   to be sent to the database. The scale argument may further 
412       *   qualify this type.
413       * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC 
414       *   types, this is the number of digits after the decimal point. For 
415       *   all other types, this value will be ignored. 
416       * @throws SQLException If a database access error occurs
417       */
418      public void setObject(int parameterIndex, Object x, 
419          int targetSqlType, int scale) throws SQLException
420      {
421        getStatement().setObject( parameterIndex, x, targetSqlType );
422      }
423    
424      /**
425       * Sets the value of the designated parameter with the given object. 
426       * This method is like the method setObject above, except that it 
427       * assumes a scale of zero. 
428       *
429       * @param parameterIndex The first parameter is 1, the second is 2, ...
430       * @param x The object containing the input parameter value
431       * @param targetSqlType The SQL type (as defined in java.sql.Types) 
432       *   to be sent to the database 
433       * @throws SQLException If a database access error occurs
434       */
435      public void setObject(int parameterIndex, Object x, 
436          int targetSqlType) throws SQLException
437      {
438        getStatement().setObject( parameterIndex, x, targetSqlType );
439      }
440    
441      /**
442       * Sets the value of the designated parameter using the given object. 
443       * The second parameter must be of type Object; therefore, the 
444       * java.lang equivalent objects should be used for built-in types. 
445       *
446       * <p>The JDBC specification specifies a standard mapping from Java 
447       * Object types to SQL types. The given argument will be converted to 
448       * the corresponding SQL type before being sent to the database.</p>
449       *
450       * <p>Note that this method may be used to pass datatabase- specific 
451       * abstract data types, by using a driver-specific Java type. If the 
452       * object is of a class implementing the interface SQLData, the JDBC 
453       * driver should call the method SQLData.writeSQL to write it to the 
454       * SQL data stream. If, on the other hand, the object is of a class 
455       * implementing Ref, Blob, Clob, Struct, or Array, the driver should 
456       * pass it to the database as a value of the corresponding SQL type.
457       * </p>
458       *
459       * <p>This method throws an exception if there is an ambiguity, for 
460       * example, if the object is of a class implementing more than one of 
461       * the interfaces named above.</p>
462       *
463       * @param parameterIndex The first parameter is 1, the second is 2, ...
464       * @param x The object containing the input parameter value 
465       * @throws SQLException If a database access error occurs or the type 
466       *   of the given object is ambiguous
467       */
468      public void setObject(int parameterIndex, Object x) throws SQLException
469      {
470        getStatement().setObject( parameterIndex, x );
471      }
472    
473      /**
474       * Executes the SQL statement in this PreparedStatement object, which 
475       * may be any kind of SQL getStatement(). Some prepared statements return 
476       * multiple results; the execute method handles these complex 
477       * statements as well as the simpler form of statements handled by 
478       * the methods executeQuery and executeUpdate. 
479       *
480       * <p>The execute method returns a boolean to indicate the form of 
481       * the first result. You must call either the method getResultSet or 
482       * getUpdateCount to retrieve the result; you must call 
483       * getMoreResults to move to any subsequent result(s).</p>
484       *
485       * @return boolean <code>true</code> if the first result is a 
486       *   ResultSet object; false if the first result is an update count 
487       *   or there is no result 
488       * @throws SQLException If a database access error occurs or an 
489       *   argument is supplied to this method
490       */
491      public boolean execute() throws SQLException
492      {
493        statistics.update();
494        return getStatement().execute();
495      }
496    
497      /**
498       * Adds a set of parameters to this PreparedStatement object's batch 
499       * of commands. 
500       *
501       * @throws SQLException If a database access error occurs
502       */
503      public void addBatch() throws SQLException
504      {
505        getStatement().addBatch();
506      }
507    
508      /**
509       * Sets the designated parameter to the given Reader object, which 
510       * is the given number of characters long. When a very large UNICODE 
511       * value is input to a LONGVARCHAR parameter, it may be more 
512       * practical to send it via a java.io.Reader object. The data will be 
513       * read from the stream as needed until end-of-file is reached. The 
514       * JDBC driver will do any necessary conversion from UNICODE to the 
515       * database char format. 
516       *
517       * <p><b>Note:</b> This stream object can either be a standard Java 
518       * stream object or your own subclass that implements the standard 
519       * interface.</p>
520       *
521       * @param parameterIndex The first parameter is 1, the second is 2, ...
522       * @param reader The java.io.Reader object that contains the Unicode 
523       *   data
524       * @param length The number of characters in the stream 
525       * @throws SQLException If a database access error occurs
526       */
527      public void setCharacterStream(int parameterIndex, Reader reader, 
528          int length) throws SQLException
529      {
530        getStatement().setCharacterStream( parameterIndex, reader, length );
531      }
532    
533      /**
534       * Sets the designated parameter to the given REF(<structured-type>) 
535       * value. The driver converts this to an SQL REF value when it sends 
536       * it to the database. 
537       *
538       * @param i The first parameter is 1, the second is 2, ...
539       * @param x An SQL REF value 
540       * @throws SQLException If a database access error occurs
541       */
542      public void setRef(int i, Ref x) throws SQLException
543      {
544        getStatement().setRef( i, x );
545      }
546    
547      /**
548       * Sets the designated parameter to the given Blob object. The driver 
549       * converts this to an SQL BLOB value when it sends it to the 
550       * database. 
551       *
552       * @param i The first parameter is 1, the second is 2, ...
553       * @param x A Blob object that maps an SQL BLOB value 
554       * @throws SQLException If a database access error occurs
555       */
556      public void setBlob(int i, Blob x) throws SQLException
557      {
558        getStatement().setBlob( i, x );
559      }
560    
561      /**
562       * Sets the designated parameter to the given Clob object. The driver 
563       * converts this to an SQL CLOB value when it sends it to the 
564       * database. 
565       *
566       * @param i The first parameter is 1, the second is 2, ...
567       * @param x A Clob object that maps an SQL CLOB value 
568       * @throws SQLException If a database access error occurs
569       */
570      public void setClob(int i, Clob x) throws SQLException
571      {
572        getStatement().setClob( i, x );
573      }
574    
575      /**
576       * Sets the designated parameter to the given Array object. The 
577       * driver converts this to an SQL ARRAY value when it sends it to 
578       * the database. 
579       *
580       * @param i The first parameter is 1, the second is 2, ...
581       * @param x An Array object that maps an SQL ARRAY value 
582       * @throws SQLException If a database access error occurs
583       */
584      public void setArray(int i, Array x) throws SQLException
585      {
586        getStatement().setArray( i, x );
587      }
588    
589      /**
590       * Retrieves a ResultSetMetaData object that contains information 
591       * about the columns of the ResultSet object that will be returned 
592       * when this PreparedStatement object is executed. 
593       *
594       * <p>Because a PreparedStatement object is precompiled, it is 
595       * possible to know about the ResultSet object that it will return 
596       * without having to execute it. Consequently, it is possible to 
597       * invoke the method getMetaData on a PreparedStatement object rather 
598       * than waiting to execute it and then invoking the 
599       * <code>ResultSet.getMetaData</code> method on the ResultSet object 
600       * that is returned.</p>
601       *
602       * <p><b>NOTE:</b> Using this method may be expensive for some 
603       * drivers due to the lack of underlying DBMS support.</p>
604       *
605       * @return ResultSetMetaData The description of a ResultSet object's 
606       *   columns or null if the driver cannot return a ResultSetMetaData 
607       *   object 
608       * @throws SQLException If a database access error occurs
609       */
610      public ResultSetMetaData getMetaData() throws SQLException
611      {
612        return getStatement().getMetaData();
613      }
614    
615      /**
616       * Sets the designated parameter to the given java.sql.Date value, 
617       * using the given Calendar object. The driver uses the Calendar 
618       * object to construct an SQL DATE value, which the driver then sends 
619       * to the database. With a Calendar object, the driver can calculate 
620       * the date taking into account a custom timezone. If no Calendar 
621       * object is specified, the driver uses the default timezone, which 
622       * is that of the virtual machine running the application. 
623       *
624       * @param parameterIndex The first parameter is 1, the second is 2, ...
625       * @param x The parameter value
626       * @param cal The Calendar object the driver will use to construct 
627       *   the date 
628       * @throws SQLException If a database access error occurs
629       */
630      public void setDate(int parameterIndex, Date x, Calendar cal) 
631        throws SQLException
632      {
633        getStatement().setDate( parameterIndex, x, cal );
634      }
635    
636      /**
637       * Sets the designated parameter to the given java.sql.Time value, 
638       * using the given Calendar object. The driver uses the Calendar 
639       * object to construct an SQL TIME value, which the driver then sends 
640       * to the database. With a Calendar object, the driver can calculate 
641       * the time taking into account a custom timezone. If no Calendar 
642       * object is specified, the driver uses the default timezone, which 
643       * is that of the virtual machine running the application. 
644       *
645       * @param parameterIndex The first parameter is 1, the second is 2, ...
646       * @param x The parameter value
647       * @param cal The Calendar object the driver will use to construct 
648       *   the time 
649       * @throws SQLException If a database access error occurs
650       */
651      public void setTime(int parameterIndex, Time x, Calendar cal)
652        throws SQLException
653      {
654        getStatement().setTime( parameterIndex, x, cal );
655      }
656    
657      /**
658       * Sets the designated parameter to the given java.sql.Timestamp 
659       * value, using the given Calendar object. The driver uses the 
660       * Calendar object to construct an SQL TIMESTAMP value, which the 
661       * driver then sends to the database. With a Calendar object, the 
662       * driver can calculate the timestamp taking into account a custom 
663       * timezone. If no Calendar object is specified, the driver uses the 
664       * default timezone, which is that of the virtual machine running the 
665       * application. 
666       *
667       * @param parameterIndex The first parameter is 1, the second is 2, ...
668       * @param x The parameter value
669       * @param cal The Calendar object the driver will use to construct 
670       *   the timestamp 
671       * @throws SQLException If a database access error occurs
672       */
673      public void setTimestamp(int parameterIndex, Timestamp x, 
674          Calendar cal) throws SQLException
675      {
676        getStatement().setTimestamp( parameterIndex, x, cal );
677      }
678    
679      /**
680       * Sets the designated parameter to SQL NULL. This version of the 
681       * method setNull should be used for user-defined types and REF type 
682       * parameters. Examples of user-defined types include: STRUCT, 
683       * DISTINCT, JAVA_OBJECT, and named array types. 
684       *
685       * <p><b>Note:</b> To be portable, applications must give the SQL 
686       * type code and the fully-qualified SQL type name when specifying a 
687       * NULL user-defined or REF parameter. In the case of a user-defined 
688       * type the name is the type name of the parameter itself. For a REF 
689       * parameter, the name is the type name of the referenced type. If a 
690       * JDBC driver does not need the type code or type name information, 
691       * it may ignore it. Although it is intended for user-defined and 
692       * Ref parameters, this method may be used to set a null parameter of 
693       * any JDBC type. If the parameter does not have a user-defined or 
694       * REF type, the given typeName is ignored.</p>
695       *
696       * @param paramIndex - The first parameter is 1, the second is 2, ...
697       * @param sqlType A value from java.sql.Types
698       * @param typeName The fully-qualified name of an SQL user-defined 
699       *   type; ignored if the parameter is not a user-defined type or REF 
700       * @throws SQLException If a database access error occurs
701       */
702      public void setNull(int paramIndex, int sqlType, String typeName)
703        throws SQLException
704      {
705        getStatement().setNull( paramIndex, sqlType, typeName );
706      }
707    
708      /**
709       * Sets the designated parameter to the given java.net.URL value. The 
710       * driver converts this to an SQL DATALINK value when it sends it to 
711       * the database. 
712       *
713       * @param parameterIndex The first parameter is 1, the second is 2, ...
714       * @param x The java.net.URL object to be set 
715       * @throws SQLException If a database access error occurs
716       */
717      public void setURL(int parameterIndex, URL x) throws SQLException
718      {
719        getStatement().setURL( parameterIndex, x );
720      }
721    
722      /**
723       * Retrieves the number, types and properties of this 
724       * PreparedStatement object's parameters. 
725       *
726       * @return ParameterMetaData A ParameterMetaData object that contains 
727       *   information about the number, types and properties of this 
728       *   PreparedStatement object's parameters 
729       * @throws SQLException If a database access error occurs
730       */
731      public ParameterMetaData getParameterMetaData() throws SQLException
732      {
733        return getStatement().getParameterMetaData();
734      }
735    
736      /**
737       * Over-ridden to not close the getStatement().  Clears the parameters
738       * using {@link #clearParameters}.
739       *
740       * @throws SQLException If a database access error occurs
741       */
742      @Override
743      public void close() throws SQLException
744      {
745        clearParameters();
746      }
747      
748      /**
749       * Returns the {@link #statement} object this class decorates.
750       *
751       * @return PreparedStatement The value/reference of/to statement
752       */
753      public PreparedStatement getStatement()
754      {
755        return statement;
756      }
757      
758      /**
759       * Returns {@link #statistics}.
760       *
761       * @return Statistics The value/reference of/to statistics.
762       */
763      public final Statistics getStatistics()
764      {
765        return statistics;
766      }
767      
768      /**
769       * Set {@link #statistics}.
770       *
771       * @param statistics The value to set.
772       */
773      protected final void setStatistics( Statistics statistics )
774      {
775        this.statistics = statistics;
776      }
777    }