001/*
002 * #%L
003 * Netarchivesuite - common - test
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.testutils;
025
026import java.sql.Array;
027import java.sql.Blob;
028import java.sql.CallableStatement;
029import java.sql.Clob;
030import java.sql.Connection;
031import java.sql.DatabaseMetaData;
032import java.sql.NClob;
033import java.sql.PreparedStatement;
034import java.sql.ResultSet;
035import java.sql.SQLClientInfoException;
036import java.sql.SQLException;
037import java.sql.SQLWarning;
038import java.sql.SQLXML;
039import java.sql.Savepoint;
040import java.sql.Statement;
041import java.sql.Struct;
042import java.util.Properties;
043import java.util.Stack;
044import java.util.concurrent.Executor;
045
046/**
047 * A wrapper around another SQL connection that changes the following:
048 * <p>
049 * 1) Commits are blithely ignored 2) prepareStatement calls keep their string available
050 */
051public class TestDBConnection implements Connection {
052    /** The connection that most calls are forwarded to */
053    private Connection conn;
054    private String lastStatement;
055    /**
056     * We need to track the savepoints so we can release them as the (undocumented) sideeffect of commit().
057     */
058    private Stack<Savepoint> savepoints = new Stack<Savepoint>();
059
060    public TestDBConnection(Connection conn) {
061        this.conn = conn;
062    }
063
064    /**
065     * Creates a <code>Statement</code> object for sending SQL statements to the database. SQL statements without
066     * parameters are normally executed using <code>Statement</code> objects. If the same SQL statement is executed many
067     * times, it may be more efficient to use a <code>PreparedStatement</code> object.
068     * <p>
069     * Result sets created using the returned <code>Statement</code> object will by default be type
070     * <code>TYPE_FORWARD_ONLY</code> and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
071     *
072     * @return a new default <code>Statement</code> object
073     * @throws SQLException if a database access error occurs
074     */
075    public Statement createStatement() throws SQLException {
076        return conn.createStatement();
077    }
078
079    /**
080     * Creates a <code>PreparedStatement</code> object for sending parameterized SQL statements to the database.
081     * <p>
082     * A SQL statement with or without IN parameters can be pre-compiled and stored in a <code>PreparedStatement</code>
083     * object. This object can then be used to efficiently execute this statement multiple times.
084     * <p>
085     * <p>
086     * <B>Note:</B> This method is optimized for handling parametric SQL statements that benefit from precompilation. If
087     * the driver supports precompilation, the method <code>prepareStatement</code> will send the statement to the
088     * database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be
089     * sent to the database until the <code>PreparedStatement</code> object is executed. This has no direct effect on
090     * users; however, it does affect which methods throw certain <code>SQLException</code> objects.
091     * <p>
092     * Result sets created using the returned <code>PreparedStatement</code> object will by default be type
093     * <code>TYPE_FORWARD_ONLY</code> and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
094     *
095     * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders
096     * @return a new default <code>PreparedStatement</code> object containing the pre-compiled SQL statement
097     * @throws SQLException if a database access error occurs
098     */
099    public PreparedStatement prepareStatement(String sql) throws SQLException {
100        lastStatement = sql;
101        return conn.prepareStatement(sql);
102    }
103
104    /**
105     * Creates a <code>CallableStatement</code> object for calling database stored procedures. The
106     * <code>CallableStatement</code> object provides methods for setting up its IN and OUT parameters, and methods for
107     * executing the call to a stored procedure.
108     * <p>
109     * <p>
110     * <B>Note:</B> This method is optimized for handling stored procedure call statements. Some drivers may send the
111     * call statement to the database when the method <code>prepareCall</code> is done; others may wait until the
112     * <code>CallableStatement</code> object is executed. This has no direct effect on users; however, it does affect
113     * which method throws certain SQLExceptions.
114     * <p>
115     * Result sets created using the returned <code>CallableStatement</code> object will by default be type
116     * <code>TYPE_FORWARD_ONLY</code> and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
117     *
118     * @param sql an SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is
119     * a JDBC function call escape string.
120     * @return a new default <code>CallableStatement</code> object containing the pre-compiled SQL statement
121     * @throws SQLException if a database access error occurs
122     */
123    public CallableStatement prepareCall(String sql) throws SQLException {
124        lastStatement = sql;
125        return conn.prepareCall(sql);
126    }
127
128    /**
129     * Converts the given SQL statement into the system's native SQL grammar. A driver may convert the JDBC SQL grammar
130     * into its system's native SQL grammar prior to sending it. This method returns the native form of the statement
131     * that the driver would have sent.
132     *
133     * @param sql an SQL statement that may contain one or more '?' parameter placeholders
134     * @return the native form of this statement
135     * @throws SQLException if a database access error occurs
136     */
137    public String nativeSQL(String sql) throws SQLException {
138        lastStatement = sql;
139        return conn.nativeSQL(sql);
140    }
141
142    /**
143     * Sets this connection's auto-commit mode to the given state. If a connection is in auto-commit mode, then all its
144     * SQL statements will be executed and committed as individual transactions. Otherwise, its SQL statements are
145     * grouped into transactions that are terminated by a call to either the method <code>commit</code> or the method
146     * <code>rollback</code>. By default, new connections are in auto-commit mode.
147     * <p>
148     * The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of
149     * statements returning a <code>ResultSet</code> object, the statement completes when the last row of the
150     * <code>ResultSet</code> object has been retrieved or the <code>ResultSet</code> object has been closed. In
151     * advanced cases, a single statement may return multiple results as well as output parameter values. In these
152     * cases, the commit occurs when all results and output parameter values have been retrieved.
153     * <p>
154     * <B>NOTE:</B> If this method is called during a transaction, the transaction is committed.
155     *
156     * @param autoCommit <code>true</code> to enable auto-commit mode; <code>false</code> to disable it
157     * @throws SQLException if a database access error occurs
158     * @see #getAutoCommit
159     */
160    public void setAutoCommit(boolean autoCommit) throws SQLException {
161        conn.setAutoCommit(autoCommit);
162    }
163
164    /**
165     * Retrieves the current auto-commit mode for this <code>Connection</code> object.
166     *
167     * @return the current state of this <code>Connection</code> object's auto-commit mode
168     * @throws SQLException if a database access error occurs
169     * @see #setAutoCommit
170     */
171    public boolean getAutoCommit() throws SQLException {
172        return conn.getAutoCommit();
173    }
174
175    /**
176     * Makes all changes made since the previous commit/rollback permanent and releases any database locks currently
177     * held by this <code>Connection</code> object. This method should be used only when auto-commit mode has been
178     * disabled.
179     * <p>
180     * In the TestDBConnection 'implementation', commit is ignored, but the savepoints are still forgotten locally -- we
181     * will still be able to roll back the entire test.
182     *
183     * @throws SQLException if a database access error occurs or this <code>Connection</code> object is in auto-commit
184     * mode
185     * @see #setAutoCommit
186     */
187    public void commit() throws SQLException {
188        // conn.commit();
189        while (!savepoints.isEmpty()) {
190            conn.releaseSavepoint(savepoints.pop());
191        }
192    }
193
194    /**
195     * Undoes all changes made in the current transaction and releases any database locks currently held by this
196     * <code>Connection</code> object. This method should be used only when auto-commit mode has been disabled.
197     *
198     * @throws SQLException if a database access error occurs or this <code>Connection</code> object is in auto-commit
199     * mode
200     * @see #setAutoCommit
201     */
202    public void rollback() throws SQLException {
203        savepoints.clear();
204        conn.rollback();
205    }
206
207    /**
208     * Releases this <code>Connection</code> object's database and JDBC resources immediately instead of waiting for
209     * them to be automatically released.
210     * <p>
211     * Calling the method <code>close</code> on a <code>Connection</code> object that is already closed is a no-op.
212     * <p>
213     * <B>Note:</B> A <code>Connection</code> object is automatically closed when it is garbage collected. Certain fatal
214     * errors also close a <code>Connection</code> object.
215     *
216     * @throws SQLException if a database access error occurs
217     */
218    public void close() throws SQLException {
219        savepoints.clear();
220        conn.close();
221    }
222
223    /**
224     * Retrieves whether this <code>Connection</code> object has been closed. A connection is closed if the method
225     * <code>close</code> has been called on it or if certain fatal errors have occurred. This method is guaranteed to
226     * return <code>true</code> only when it is called after the method <code>Connection.close</code> has been called.
227     * <p>
228     * This method generally cannot be called to determine whether a connection to a database is valid or invalid. A
229     * typical client can determine that a connection is invalid by catching any exceptions that might be thrown when an
230     * operation is attempted.
231     *
232     * @return <code>true</code> if this <code>Connection</code> object is closed; <code>false</code> if it is still
233     * open
234     * @throws SQLException if a database access error occurs
235     */
236    public boolean isClosed() throws SQLException {
237        return conn.isClosed();
238    }
239
240    // ======================================================================
241    // Advanced features:
242
243    /**
244     * Retrieves a <code>DatabaseMetaData</code> object that contains metadata about the database to which this
245     * <code>Connection</code> object represents a connection. The metadata includes information about the database's
246     * tables, its supported SQL grammar, its stored procedures, the capabilities of this connection, and so on.
247     *
248     * @return a <code>DatabaseMetaData</code> object for this <code>Connection</code> object
249     * @throws SQLException if a database access error occurs
250     */
251    public DatabaseMetaData getMetaData() throws SQLException {
252        return conn.getMetaData();
253    }
254
255    /**
256     * Puts this connection in read-only mode as a hint to the driver to enable database optimizations.
257     * <p>
258     * <p>
259     * <B>Note:</B> This method cannot be called during a transaction.
260     *
261     * @param readOnly <code>true</code> enables read-only mode; <code>false</code> disables it
262     * @throws SQLException if a database access error occurs or this method is called during a transaction
263     */
264    public void setReadOnly(boolean readOnly) throws SQLException {
265        conn.setReadOnly(readOnly);
266    }
267
268    /**
269     * Retrieves whether this <code>Connection</code> object is in read-only mode.
270     *
271     * @return <code>true</code> if this <code>Connection</code> object is read-only; <code>false</code> otherwise
272     * @throws SQLException if a database access error occurs
273     */
274    public boolean isReadOnly() throws SQLException {
275        return conn.isReadOnly();
276    }
277
278    /**
279     * Sets the given catalog name in order to select a subspace of this <code>Connection</code> object's database in
280     * which to work.
281     * <p>
282     * If the driver does not support catalogs, it will silently ignore this request.
283     *
284     * @param catalog the name of a catalog (subspace in this <code>Connection</code> object's database) in which to
285     * work
286     * @throws SQLException if a database access error occurs
287     * @see #getCatalog
288     */
289    public void setCatalog(String catalog) throws SQLException {
290        conn.setCatalog(catalog);
291    }
292
293    /**
294     * Retrieves this <code>Connection</code> object's current catalog name.
295     *
296     * @return the current catalog name or <code>null</code> if there is none
297     * @throws SQLException if a database access error occurs
298     * @see #setCatalog
299     */
300    public String getCatalog() throws SQLException {
301        return conn.getCatalog();
302    }
303
304    /**
305     * Attempts to change the transaction isolation level for this <code>Connection</code> object to the one given. The
306     * constants defined in the interface <code>Connection</code> are the possible transaction isolation levels.
307     * <p>
308     * <B>Note:</B> If this method is called during a transaction, the result is implementation-defined.
309     *
310     * @param level one of the following <code>Connection</code> constants:
311     * <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>, <code>Connection.TRANSACTION_READ_COMMITTED</code>,
312     * <code>Connection.TRANSACTION_REPEATABLE_READ</code>, or <code>Connection.TRANSACTION_SERIALIZABLE</code>. (Note
313     * that <code>Connection.TRANSACTION_NONE</code> cannot be used because it specifies that transactions are not
314     * supported.)
315     * @throws SQLException if a database access error occurs or the given parameter is not one of the
316     * <code>Connection</code> constants
317     * @see DatabaseMetaData#supportsTransactionIsolationLevel
318     * @see #getTransactionIsolation
319     */
320    public void setTransactionIsolation(int level) throws SQLException {
321        conn.setTransactionIsolation(level);
322    }
323
324    /**
325     * Retrieves this <code>Connection</code> object's current transaction isolation level.
326     *
327     * @return the current transaction isolation level, which will be one of the following constants:
328     * <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>, <code>Connection.TRANSACTION_READ_COMMITTED</code>,
329     * <code>Connection.TRANSACTION_REPEATABLE_READ</code>, <code>Connection.TRANSACTION_SERIALIZABLE</code>, or
330     * <code>Connection.TRANSACTION_NONE</code>.
331     * @throws SQLException if a database access error occurs
332     * @see #setTransactionIsolation
333     */
334    public int getTransactionIsolation() throws SQLException {
335        return conn.getTransactionIsolation();
336    }
337
338    /**
339     * Retrieves the first warning reported by calls on this <code>Connection</code> object. If there is more than one
340     * warning, subsequent warnings will be chained to the first one and can be retrieved by calling the method
341     * <code>SQLWarning.getNextWarning</code> on the warning that was retrieved previously.
342     * <p>
343     * This method may not be called on a closed connection; doing so will cause an <code>SQLException</code> to be
344     * thrown.
345     * <p>
346     * <p>
347     * <B>Note:</B> Subsequent warnings will be chained to this SQLWarning.
348     *
349     * @return the first <code>SQLWarning</code> object or <code>null</code> if there are none
350     * @throws SQLException if a database access error occurs or this method is called on a closed connection
351     * @see SQLWarning
352     */
353    public SQLWarning getWarnings() throws SQLException {
354        return conn.getWarnings();
355    }
356
357    /**
358     * Clears all warnings reported for this <code>Connection</code> object. After a call to this method, the method
359     * <code>getWarnings</code> returns <code>null</code> until a new warning is reported for this
360     * <code>Connection</code> object.
361     *
362     * @throws SQLException if a database access error occurs
363     */
364    public void clearWarnings() throws SQLException {
365        conn.clearWarnings();
366    }
367
368    // --------------------------JDBC 2.0-----------------------------
369
370    /**
371     * Creates a <code>Statement</code> object that will generate <code>ResultSet</code> objects with the given type and
372     * concurrency. This method is the same as the <code>createStatement</code> method above, but it allows the default
373     * result set type and concurrency to be overridden.
374     *
375     * @param resultSetType a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
376     * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
377     * @param resultSetConcurrency a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
378     * <code>ResultSet.CONCUR_UPDATABLE</code>
379     * @return a new <code>Statement</code> object that will generate <code>ResultSet</code> objects with the given type
380     * and concurrency
381     * @throws SQLException if a database access error occurs or the given parameters are not <code>ResultSet</code>
382     * constants indicating type and concurrency
383     */
384    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
385        return conn.createStatement(resultSetType, resultSetConcurrency);
386    }
387
388    /**
389     * Creates a <code>PreparedStatement</code> object that will generate <code>ResultSet</code> objects with the given
390     * type and concurrency. This method is the same as the <code>prepareStatement</code> method above, but it allows
391     * the default result set type and concurrency to be overridden.
392     *
393     * @param sql a <code>String</code> object that is the SQL statement to be sent to the database; may contain one or
394     * more ? IN parameters
395     * @param resultSetType a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
396     * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
397     * @param resultSetConcurrency a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
398     * <code>ResultSet.CONCUR_UPDATABLE</code>
399     * @return a new PreparedStatement object containing the pre-compiled SQL statement that will produce
400     * <code>ResultSet</code> objects with the given type and concurrency
401     * @throws SQLException if a database access error occurs or the given parameters are not <code>ResultSet</code>
402     * constants indicating type and concurrency
403     */
404    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
405            throws SQLException {
406        lastStatement = sql;
407        return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
408    }
409
410    /**
411     * Creates a <code>CallableStatement</code> object that will generate <code>ResultSet</code> objects with the given
412     * type and concurrency. This method is the same as the <code>prepareCall</code> method above, but it allows the
413     * default result set type and concurrency to be overridden.
414     *
415     * @param sql a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or
416     * more ? parameters
417     * @param resultSetType a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
418     * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
419     * @param resultSetConcurrency a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
420     * <code>ResultSet.CONCUR_UPDATABLE</code>
421     * @return a new <code>CallableStatement</code> object containing the pre-compiled SQL statement that will produce
422     * <code>ResultSet</code> objects with the given type and concurrency
423     * @throws SQLException if a database access error occurs or the given parameters are not <code>ResultSet</code>
424     * constants indicating type and concurrency
425     */
426    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
427        lastStatement = sql;
428        return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
429    }
430
431    /**
432     * Retrieves the <code>Map</code> object associated with this <code>Connection</code> object. Unless the application
433     * has added an entry, the type map returned will be empty.
434     *
435     * @return the <code>java.util.Map</code> object associated with this <code>Connection</code> object
436     * @throws SQLException if a database access error occurs
437     * @see #setTypeMap
438     */
439    public java.util.Map<String, Class<?>> getTypeMap() throws SQLException {
440        return conn.getTypeMap();
441    }
442
443    /**
444     * Installs the given <code>TypeMap</code> object as the type map for this <code>Connection</code> object. The type
445     * map will be used for the custom mapping of SQL structured types and distinct types.
446     *
447     * @param map the <code>java.util.Map</code> object to install as the replacement for this <code>Connection</code>
448     * object's default type map
449     * @throws SQLException if a database access error occurs or the given parameter is not a <code>java.util.Map</code>
450     * object
451     * @see #getTypeMap
452     */
453    public void setTypeMap(java.util.Map<String, Class<?>> map) throws SQLException {
454        conn.setTypeMap(map);
455    }
456
457    // --------------------------JDBC 3.0-----------------------------
458
459    /**
460     * Changes the holdability of <code>ResultSet</code> objects created using this <code>Connection</code> object to
461     * the given holdability.
462     *
463     * @param holdability a <code>ResultSet</code> holdability constant; one of
464     * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
465     * @throws SQLException if a database access occurs, the given parameter is not a <code>ResultSet</code> constant
466     * indicating holdability, or the given holdability is not supported
467     * @see #getHoldability
468     * @see ResultSet
469     */
470    public void setHoldability(int holdability) throws SQLException {
471        conn.setHoldability(holdability);
472    }
473
474    /**
475     * Retrieves the current holdability of <code>ResultSet</code> objects created using this <code>Connection</code>
476     * object.
477     *
478     * @return the holdability, one of <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
479     * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
480     * @throws SQLException if a database access occurs
481     * @see #setHoldability
482     * @see ResultSet
483     */
484    public int getHoldability() throws SQLException {
485        return conn.getHoldability();
486    }
487
488    /**
489     * Creates an unnamed savepoint in the current transaction and returns the new <code>Savepoint</code> object that
490     * represents it.
491     *
492     * @return the new <code>Savepoint</code> object
493     * @throws SQLException if a database access error occurs or this <code>Connection</code> object is currently in
494     * auto-commit mode
495     * @see Savepoint
496     */
497    public Savepoint setSavepoint() throws SQLException {
498        return setSavepoint("__internal__TestDBConnection");
499    }
500
501    /**
502     * Creates a savepoint with the given name in the current transaction and returns the new <code>Savepoint</code>
503     * object that represents it.
504     *
505     * @param name a <code>String</code> containing the name of the savepoint
506     * @return the new <code>Savepoint</code> object
507     * @throws SQLException if a database access error occurs or this <code>Connection</code> object is currently in
508     * auto-commit mode
509     * @see Savepoint
510     */
511    public Savepoint setSavepoint(String name) throws SQLException {
512        return savepoints.push(conn.setSavepoint(name));
513    }
514
515    /**
516     * Undoes all changes made after the given <code>Savepoint</code> object was set.
517     * <p>
518     * This method should be used only when auto-commit has been disabled.
519     *
520     * @param savepoint the <code>Savepoint</code> object to roll back to
521     * @throws SQLException if a database access error occurs, the <code>Savepoint</code> object is no longer valid, or
522     * this <code>Connection</code> object is currently in auto-commit mode
523     * @see Savepoint
524     * @see #rollback
525     */
526    public void rollback(Savepoint savepoint) throws SQLException {
527        while (!savepoints.isEmpty() && savepoints.peek() != savepoint) {
528            savepoints.pop();
529        }
530        if (!savepoints.isEmpty() && savepoints.peek() == savepoint) {
531            savepoints.pop();
532        }
533        conn.rollback(savepoint);
534    }
535
536    /**
537     * Removes the given <code>Savepoint</code> object from the current transaction. Any reference to the savepoint
538     * after it have been removed will cause an <code>SQLException</code> to be thrown.
539     *
540     * @param savepoint the <code>Savepoint</code> object to be removed
541     * @throws SQLException if a database access error occurs or the given <code>Savepoint</code> object is not a valid
542     * savepoint in the current transaction
543     */
544    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
545        while (!savepoints.isEmpty() && savepoints.peek() != savepoint) {
546            savepoints.pop();
547        }
548        if (!savepoints.isEmpty() && savepoints.peek() == savepoint) {
549            savepoints.pop();
550        }
551        conn.releaseSavepoint(savepoint);
552    }
553
554    /**
555     * Creates a <code>Statement</code> object that will generate <code>ResultSet</code> objects with the given type,
556     * concurrency, and holdability. This method is the same as the <code>createStatement</code> method above, but it
557     * allows the default result set type, concurrency, and holdability to be overridden.
558     *
559     * @param resultSetType one of the following <code>ResultSet</code> constants:
560     * <code>ResultSet.TYPE_FORWARD_ONLY</code>, <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
561     * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
562     * @param resultSetConcurrency one of the following <code>ResultSet</code> constants:
563     * <code>ResultSet.CONCUR_READ_ONLY</code> or <code>ResultSet.CONCUR_UPDATABLE</code>
564     * @param resultSetHoldability one of the following <code>ResultSet</code> constants:
565     * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
566     * @return a new <code>Statement</code> object that will generate <code>ResultSet</code> objects with the given
567     * type, concurrency, and holdability
568     * @throws SQLException if a database access error occurs or the given parameters are not <code>ResultSet</code>
569     * constants indicating type, concurrency, and holdability
570     * @see ResultSet
571     */
572    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
573            throws SQLException {
574        return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
575    }
576
577    /**
578     * Creates a <code>PreparedStatement</code> object that will generate <code>ResultSet</code> objects with the given
579     * type, concurrency, and holdability.
580     * <p>
581     * This method is the same as the <code>prepareStatement</code> method above, but it allows the default result set
582     * type, concurrency, and holdability to be overridden.
583     *
584     * @param sql a <code>String</code> object that is the SQL statement to be sent to the database; may contain one or
585     * more ? IN parameters
586     * @param resultSetType one of the following <code>ResultSet</code> constants:
587     * <code>ResultSet.TYPE_FORWARD_ONLY</code>, <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
588     * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
589     * @param resultSetConcurrency one of the following <code>ResultSet</code> constants:
590     * <code>ResultSet.CONCUR_READ_ONLY</code> or <code>ResultSet.CONCUR_UPDATABLE</code>
591     * @param resultSetHoldability one of the following <code>ResultSet</code> constants:
592     * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
593     * @return a new <code>PreparedStatement</code> object, containing the pre-compiled SQL statement, that will
594     * generate <code>ResultSet</code> objects with the given type, concurrency, and holdability
595     * @throws SQLException if a database access error occurs or the given parameters are not <code>ResultSet</code>
596     * constants indicating type, concurrency, and holdability
597     * @see ResultSet
598     */
599    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
600            int resultSetHoldability) throws SQLException {
601        lastStatement = sql;
602        return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
603    }
604
605    /**
606     * Creates a <code>CallableStatement</code> object that will generate <code>ResultSet</code> objects with the given
607     * type and concurrency. This method is the same as the <code>prepareCall</code> method above, but it allows the
608     * default result set type, result set concurrency type and holdability to be overridden.
609     *
610     * @param sql a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or
611     * more ? parameters
612     * @param resultSetType one of the following <code>ResultSet</code> constants:
613     * <code>ResultSet.TYPE_FORWARD_ONLY</code>, <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
614     * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
615     * @param resultSetConcurrency one of the following <code>ResultSet</code> constants:
616     * <code>ResultSet.CONCUR_READ_ONLY</code> or <code>ResultSet.CONCUR_UPDATABLE</code>
617     * @param resultSetHoldability one of the following <code>ResultSet</code> constants:
618     * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
619     * @return a new <code>CallableStatement</code> object, containing the pre-compiled SQL statement, that will
620     * generate <code>ResultSet</code> objects with the given type, concurrency, and holdability
621     * @throws SQLException if a database access error occurs or the given parameters are not <code>ResultSet</code>
622     * constants indicating type, concurrency, and holdability
623     * @see ResultSet
624     */
625    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
626            int resultSetHoldability) throws SQLException {
627        lastStatement = sql;
628        return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
629    }
630
631    /**
632     * Creates a default <code>PreparedStatement</code> object that has the capability to retrieve auto-generated keys.
633     * The given constant tells the driver whether it should make auto-generated keys available for retrieval. This
634     * parameter is ignored if the SQL statement is not an <code>INSERT</code> statement.
635     * <p>
636     * <B>Note:</B> This method is optimized for handling parametric SQL statements that benefit from precompilation. If
637     * the driver supports precompilation, the method <code>prepareStatement</code> will send the statement to the
638     * database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be
639     * sent to the database until the <code>PreparedStatement</code> object is executed. This has no direct effect on
640     * users; however, it does affect which methods throw certain SQLExceptions.
641     * <p>
642     * Result sets created using the returned <code>PreparedStatement</code> object will by default be type
643     * <code>TYPE_FORWARD_ONLY</code> and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
644     *
645     * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders
646     * @param autoGeneratedKeys a flag indicating whether auto-generated keys should be returned; one of
647     * <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>
648     * @return a new <code>PreparedStatement</code> object, containing the pre-compiled SQL statement, that will have
649     * the capability of returning auto-generated keys
650     * @throws SQLException if a database access error occurs or the given parameter is not a <code>Statement</code>
651     * constant indicating whether auto-generated keys should be returned
652     */
653    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
654        lastStatement = sql;
655        return conn.prepareStatement(sql, autoGeneratedKeys);
656    }
657
658    /**
659     * Creates a default <code>PreparedStatement</code> object capable of returning the auto-generated keys designated
660     * by the given array. This array contains the indexes of the columns in the target table that contain the
661     * auto-generated keys that should be made available. This array is ignored if the SQL statement is not an
662     * <code>INSERT</code> statement.
663     * <p>
664     * An SQL statement with or without IN parameters can be pre-compiled and stored in a <code>PreparedStatement</code>
665     * object. This object can then be used to efficiently execute this statement multiple times.
666     * <p>
667     * <B>Note:</B> This method is optimized for handling parametric SQL statements that benefit from precompilation. If
668     * the driver supports precompilation, the method <code>prepareStatement</code> will send the statement to the
669     * database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be
670     * sent to the database until the <code>PreparedStatement</code> object is executed. This has no direct effect on
671     * users; however, it does affect which methods throw certain SQLExceptions.
672     * <p>
673     * Result sets created using the returned <code>PreparedStatement</code> object will by default be type
674     * <code>TYPE_FORWARD_ONLY</code> and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
675     *
676     * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders
677     * @param columnIndexes an array of column indexes indicating the columns that should be returned from the inserted
678     * row or rows
679     * @return a new <code>PreparedStatement</code> object, containing the pre-compiled statement, that is capable of
680     * returning the auto-generated keys designated by the given array of column indexes
681     * @throws SQLException if a database access error occurs
682     */
683    public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException {
684        lastStatement = sql;
685        return conn.prepareStatement(sql, columnIndexes);
686    }
687
688    /**
689     * Creates a default <code>PreparedStatement</code> object capable of returning the auto-generated keys designated
690     * by the given array. This array contains the names of the columns in the target table that contain the
691     * auto-generated keys that should be returned. This array is ignored if the SQL statement is not an
692     * <code>INSERT</code> statement.
693     * <p>
694     * An SQL statement with or without IN parameters can be pre-compiled and stored in a <code>PreparedStatement</code>
695     * object. This object can then be used to efficiently execute this statement multiple times.
696     * <p>
697     * <B>Note:</B> This method is optimized for handling parametric SQL statements that benefit from precompilation. If
698     * the driver supports precompilation, the method <code>prepareStatement</code> will send the statement to the
699     * database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be
700     * sent to the database until the <code>PreparedStatement</code> object is executed. This has no direct effect on
701     * users; however, it does affect which methods throw certain SQLExceptions.
702     * <p>
703     * Result sets created using the returned <code>PreparedStatement</code> object will by default be type
704     * <code>TYPE_FORWARD_ONLY</code> and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
705     *
706     * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders
707     * @param columnNames an array of column names indicating the columns that should be returned from the inserted row
708     * or rows
709     * @return a new <code>PreparedStatement</code> object, containing the pre-compiled statement, that is capable of
710     * returning the auto-generated keys designated by the given array of column names
711     * @throws SQLException if a database access error occurs
712     */
713    public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException {
714        lastStatement = sql;
715        return conn.prepareStatement(sql, columnNames);
716    }
717
718    public String toString() {
719        return conn.toString() + " with last statement: \n" + lastStatement;
720    }
721
722    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
723        return null;
724    }
725
726    public Blob createBlob() throws SQLException {
727        return null;
728    }
729
730    public Clob createClob() throws SQLException {
731        return null;
732    }
733
734    public NClob createNClob() throws SQLException {
735        return null;
736    }
737
738    public SQLXML createSQLXML() throws SQLException {
739        return null;
740    }
741
742    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
743        return null;
744    }
745
746    public Properties getClientInfo() throws SQLException {
747        return null;
748    }
749
750    public String getClientInfo(String name) throws SQLException {
751        return null;
752    }
753
754    public boolean isValid(int timeout) throws SQLException {
755        return false;
756    }
757
758    public void setClientInfo(Properties properties) throws SQLClientInfoException {
759    }
760
761    public void setClientInfo(String name, String value) throws SQLClientInfoException {
762    }
763
764    public boolean isWrapperFor(Class<?> iface) throws SQLException {
765        return false;
766    }
767
768    public <T> T unwrap(Class<T> iface) throws SQLException {
769        return null;
770    }
771
772    public void setSchema(String schema) throws SQLException {
773    }
774
775    public String getSchema() throws SQLException {
776        return null;
777    }
778
779    public void abort(Executor executor) throws SQLException {
780    }
781
782    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
783    }
784
785    public int getNetworkTimeout() throws SQLException {
786        return 0;
787    }
788
789}