Clover coverage report - gsbase - 2.0.1
Coverage timestamp: Sat Jan 1 2005 12:30:02 EST
file stats: LOC: 1,071   Methods: 44
NCLOC: 306   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ConnectionWrapper.java 72.2% 90.3% 90.9% 88.8%
coverage coverage
 1    /*
 2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved.
 3    *
 4    * Redistribution and use in source and binary forms, with or without
 5    * modification, are permitted provided that the following conditions are met:
 6    *
 7    * 1. Redistributions of source code must retain the above copyright notice,
 8    * this list of conditions and the following disclaimer.
 9    * 2. Redistributions in binary form must reproduce the above copyright notice,
 10    * this list of conditions and the following disclaimer in the documentation
 11    * and/or other materials provided with the distribution.
 12    * 3. The end-user documentation included with the redistribution, if any, must
 13    * include the following acknowledgment:
 14    *
 15    * "This product includes software developed by Gargoyle Software Inc.
 16    * (http://www.GargoyleSoftware.com/)."
 17    *
 18    * Alternately, this acknowledgment may appear in the software itself, if
 19    * and wherever such third-party acknowledgments normally appear.
 20    * 4. The name "Gargoyle Software" must not be used to endorse or promote
 21    * products derived from this software without prior written permission.
 22    * For written permission, please contact info@GargoyleSoftware.com.
 23    * 5. Products derived from this software may not be called "GSBase", nor may
 24    * "GSBase" appear in their name, without prior written permission of
 25    * Gargoyle Software Inc.
 26    *
 27    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 28    * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 29    * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
 30    * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 31    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 32    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 33    * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 34    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 35    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 36    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37    */
 38    package com.gargoylesoftware.base.resource.jdbc;
 39   
 40    import com.gargoylesoftware.base.resource.ManagedResource;
 41    import java.sql.CallableStatement;
 42    import java.sql.Connection;
 43    import java.sql.DatabaseMetaData;
 44    import java.sql.PreparedStatement;
 45    import java.sql.Savepoint;
 46    import java.sql.SQLException;
 47    import java.sql.SQLWarning;
 48    import java.sql.Statement;
 49    import java.util.ArrayList;
 50    import java.util.Collections;
 51    import java.util.Iterator;
 52    import java.util.List;
 53    import java.util.Map;
 54   
 55    /**
 56    * A wrapper for java.sql.Connection objects.<p>
 57    *
 58    * The contract with JDBC says that result sets must be closed before
 59    * statements and statements must be closed before connections but java does
 60    * not enforce this contract. It is quite possible to close a connection while
 61    * statements and result sets are still open. While some database drivers
 62    * handle this condition nicely, others will start failing in undefined ways
 63    * when this happens.<p>
 64    *
 65    * This wrapper class is a solution to this problem. If the connection is only
 66    * accessed through the wrapper then the wrapper will ensure that everything is
 67    * closed in the correct order. It will also ensure that the various jdbc
 68    * objects (connections, statements, result sets and metadata) cannot be used
 69    * after they are closed.<p>
 70    *
 71    * This class was created for the {@link JDBCResourceFactory} but can be used
 72    * by itself.
 73    *
 74    * @version $Revision: 1.5 $
 75    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 76    */
 77    public final class ConnectionWrapper implements Connection, ManagedResource {
 78   
 79    private Connection delegate_ = null;
 80    private boolean isOpen_ = true;
 81    private String resourceFactoryName_;
 82   
 83    private final List openStatements_ = Collections.synchronizedList(new ArrayList());
 84    private final List openDatabaseMetaData_ = Collections.synchronizedList(new ArrayList());
 85   
 86   
 87    /**
 88    * Create a new connection wrapper
 89    *
 90    * @param connection The connection that we are wrapping
 91    */
 92  44 public ConnectionWrapper( final Connection connection ) {
 93  44 if( connection == null ) {
 94  1 throw new NullPointerException();
 95    }
 96  43 delegate_ = connection;
 97    }
 98   
 99   
 100    /**
 101    * Set the name of the factory that allocated this connection
 102    *
 103    * @param name The name of the factory
 104    */
 105  0 public final void setResourceFactoryName( final String name ) {
 106  0 resourceFactoryName_ = name;
 107    }
 108   
 109   
 110    /**
 111    * Sets this connection's auto-commit mode. If a connection is in
 112    * auto-commit mode, then all its SQL statements will be executed and
 113    * committed as individual transactions. Otherwise, its SQL statements are
 114    * grouped into transactions that are terminated by a call to either the
 115    * method <code>commit</code> or the method <code>rollback</code>. By
 116    * default, new connections are in auto-commit mode. <p>
 117    *
 118    * The commit occurs when the statement completes or the next execute
 119    * occurs, whichever comes first. In the case of statements returning a
 120    * ResultSet, the statement completes when the last row of the ResultSet
 121    * has been retrieved or the ResultSet has been closed. In advanced cases,
 122    * a single statement may return multiple results as well as output
 123    * parameter values. In these cases the commit occurs when all results and
 124    * output parameter values have been retrieved.
 125    *
 126    * @param autoCommit true enables auto-commit; false disables auto-commit.
 127    * @exception SQLException if a database access error occurs
 128    */
 129  2 public void setAutoCommit( boolean autoCommit )
 130    throws SQLException {
 131  2 checkConnection();
 132  1 delegate_.setAutoCommit( autoCommit );
 133    }
 134   
 135   
 136    /**
 137    * Puts this connection in read-only mode as a hint to enable database
 138    * optimizations. <P>
 139    *
 140    * <B>Note:</B> This method cannot be called while in the middle of a
 141    * transaction.
 142    *
 143    * @param readOnly true enables read-only mode; false disables read-only
 144    * mode.
 145    * @exception SQLException if a database access error occurs
 146    */
 147  2 public void setReadOnly( boolean readOnly )
 148    throws SQLException {
 149  2 checkConnection();
 150  1 delegate_.setReadOnly( readOnly );
 151    }
 152   
 153   
 154    /**
 155    * Sets a catalog name in order to select a subspace of this Connection's
 156    * database in which to work. If the driver does not support catalogs, it
 157    * will silently ignore this request.
 158    *
 159    * @param catalog The catalog name
 160    * @exception SQLException if a database access error occurs
 161    */
 162  2 public void setCatalog( String catalog )
 163    throws SQLException {
 164  2 checkConnection();
 165  1 delegate_.setCatalog( catalog );
 166    }
 167   
 168   
 169    /**
 170    * Attempts to change the transaction isolation level to the one given. The
 171    * constants defined in the interface <code>Connection</code> are the
 172    * possible transaction isolation levels. <P>
 173    *
 174    * <B>Note:</B> This method cannot be called while in the middle of a
 175    * transaction.
 176    *
 177    * @param level one of the TRANSACTION_* isolation values with the
 178    * exception of TRANSACTION_NONE; some databases may not support other
 179    * values
 180    * @exception SQLException if a database access error occurs
 181    */
 182  2 public void setTransactionIsolation( int level )
 183    throws SQLException {
 184  2 checkConnection();
 185  1 delegate_.setTransactionIsolation( level );
 186    }
 187   
 188   
 189    /**
 190    * Installs the given type map as the type map for this connection. The
 191    * type map will be used for the custom mapping of SQL structured types and
 192    * distinct types.
 193    *
 194    * @param map the <code>java.util.Map</code> object to install as the
 195    * replacement for this <code>Connection</code> object's default type
 196    * map
 197    * @exception SQLException If a sql error occurs
 198    * @since 1.2
 199    */
 200  2 public void setTypeMap( final Map map )
 201    throws SQLException {
 202  2 checkConnection();
 203  1 delegate_.setTypeMap( map );
 204    }
 205   
 206   
 207    /**
 208    * Return the name of the factory that allocated this connection
 209    *
 210    * @return The name of the factory
 211    */
 212  0 public final String getResourceFactoryName() {
 213  0 return resourceFactoryName_;
 214    }
 215   
 216   
 217    /**
 218    * Return the wrapped connection
 219    *
 220    * @return The wrapped connection
 221    */
 222  0 public final Connection getDelegate() {
 223  0 return delegate_;
 224    }
 225   
 226   
 227    /**
 228    * Gets the current auto-commit state.
 229    *
 230    * @return the current state of auto-commit mode
 231    * @exception SQLException if a database access error occurs
 232    * @see #setAutoCommit
 233    */
 234  2 public boolean getAutoCommit()
 235    throws SQLException {
 236  2 checkConnection();
 237  1 return delegate_.getAutoCommit();
 238    }
 239   
 240   
 241    /**
 242    * Tests to see if a Connection is closed.
 243    *
 244    * @return true if the connection is closed; false if it's still open
 245    * @exception SQLException if a database access error occurs
 246    */
 247  1 public boolean isClosed()
 248    throws SQLException {
 249   
 250  1 if( delegate_ == null ) {
 251  1 return true;
 252    }
 253   
 254  0 return delegate_.isClosed();
 255    }
 256   
 257    //======================================================================
 258    // Advanced features:
 259   
 260    /**
 261    * Gets the metadata regarding this connection's database. A Connection's
 262    * database is able to provide information describing its tables, its
 263    * supported SQL grammar, its stored procedures, the capabilities of this
 264    * connection, and so on. This information is made available through a
 265    * DatabaseMetaData object.
 266    *
 267    * @return a DatabaseMetaData object for this Connection
 268    * @exception SQLException if a database access error occurs
 269    */
 270  1 public DatabaseMetaData getMetaData()
 271    throws SQLException {
 272  1 checkConnection();
 273  1 final DatabaseMetaDataWrapper wrapper
 274    = new DatabaseMetaDataWrapper( delegate_.getMetaData() );
 275  1 wrapper.setConnection( this );
 276  1 openDatabaseMetaData_.add( wrapper );
 277  1 return wrapper;
 278    }
 279   
 280   
 281    /**
 282    * Tests to see if the connection is in read-only mode.
 283    *
 284    * @return true if connection is read-only and false otherwise
 285    * @exception SQLException if a database access error occurs
 286    */
 287  2 public boolean isReadOnly()
 288    throws SQLException {
 289  2 checkConnection();
 290  1 return delegate_.isReadOnly();
 291    }
 292   
 293   
 294    /**
 295    * Returns the Connection's current catalog name.
 296    *
 297    * @return the current catalog name or null
 298    * @exception SQLException if a database access error occurs
 299    */
 300  2 public String getCatalog()
 301    throws SQLException {
 302  2 checkConnection();
 303  1 return delegate_.getCatalog();
 304    }
 305   
 306   
 307    /**
 308    * Gets this Connection's current transaction isolation level.
 309    *
 310    * @return the current TRANSACTION_* mode value
 311    * @exception SQLException if a database access error occurs
 312    */
 313  2 public int getTransactionIsolation()
 314    throws SQLException {
 315  2 checkConnection();
 316  1 return delegate_.getTransactionIsolation();
 317    }
 318   
 319   
 320    /**
 321    * Returns the first warning reported by calls on this Connection. <P>
 322    *
 323    * <B>Note:</B> Subsequent warnings will be chained to this SQLWarning.
 324    *
 325    * @return the first SQLWarning or null
 326    * @exception SQLException if a database access error occurs
 327    */
 328  2 public SQLWarning getWarnings()
 329    throws SQLException {
 330  2 checkConnection();
 331  1 return delegate_.getWarnings();
 332    }
 333   
 334   
 335    /**
 336    * Gets the type map object associated with this connection. Unless the
 337    * application has added an entry to the type map, the map returned will be
 338    * empty.
 339    *
 340    * @return the <code>java.util.Map</code> object associated with this
 341    * <code>Connection</code> object
 342    * @exception SQLException If a sql error occurs
 343    * @since 1.2
 344    */
 345  2 public Map getTypeMap()
 346    throws SQLException {
 347  2 checkConnection();
 348  1 return delegate_.getTypeMap();
 349    }
 350   
 351   
 352    /**
 353    * Creates a <code>Statement</code> object for sending SQL statements to
 354    * the database. SQL statements without parameters are normally executed
 355    * using Statement objects. If the same SQL statement is executed many
 356    * times, it is more efficient to use a <code>PreparedStatement</code>
 357    * object. <P>
 358    *
 359    * Result sets created using the returned <code>Statement</code> object
 360    * will by default have forward-only type and read-only concurrency.
 361    *
 362    * @return a new Statement object
 363    * @exception SQLException if a database access error occurs
 364    */
 365  4 public Statement createStatement()
 366    throws SQLException {
 367  4 checkConnection();
 368  3 final StatementWrapper wrapper = new StatementWrapper( delegate_.createStatement() );
 369  3 wrapper.setConnection( this );
 370  3 openStatements_.add( wrapper );
 371  3 return wrapper;
 372    }
 373   
 374   
 375    /**
 376    * Creates a <code>PreparedStatement</code> object for sending
 377    * parameterized SQL statements to the database. A SQL statement with or
 378    * without IN parameters can be pre-compiled and stored in a
 379    * PreparedStatement object. This object can then be used to efficiently
 380    * execute this statement multiple times. <P>
 381    *
 382    * <B>Note:</B> This method is optimized for handling parametric SQL
 383    * statements that benefit from precompilation. If the driver supports
 384    * precompilation, the method <code>prepareStatement</code> will send the
 385    * statement to the database for precompilation. Some drivers may not
 386    * support precompilation. In this case, the statement may not be sent to
 387    * the database until the <code>PreparedStatement</code> is executed. This
 388    * has no direct effect on users; however, it does affect which method
 389    * throws certain SQLExceptions. <p>
 390    *
 391    * Result sets created using the returned PreparedStatement will have
 392    * forward-only type and read-only concurrency, by default.
 393    *
 394    * @param sql a SQL statement that may contain one or more '?' IN parameter
 395    * placeholders
 396    * @return a new PreparedStatement object containing the pre-compiled
 397    * statement
 398    * @exception SQLException if a database access error occurs
 399    */
 400  3 public PreparedStatement prepareStatement( String sql )
 401    throws SQLException {
 402  3 checkConnection();
 403  2 final PreparedStatement statement = new PreparedStatementWrapper( delegate_.prepareStatement( sql ) );
 404  2 openStatements_.add( statement );
 405  2 return statement;
 406    }
 407   
 408   
 409    /**
 410    * Creates a <code>CallableStatement</code> object for calling database
 411    * stored procedures. The <code>CallableStatement</code> object provides
 412    * methods for setting up its IN and OUT parameters, and methods for
 413    * executing the call to a stored procedure. <P>
 414    *
 415    * <B>Note:</B> This method is optimized for handling stored procedure call
 416    * statements. Some drivers may send the call statement to the database
 417    * when the method <code>prepareCall</code> is done; others may wait until
 418    * the <code>CallableStatement</code> object is executed. This has no
 419    * direct effect on users; however, it does affect which method throws
 420    * certain SQLExceptions. Result sets created using the returned
 421    * CallableStatement will have forward-only type and read-only concurrency,
 422    * by default.
 423    *
 424    * @param sql a SQL statement that may contain one or more '?' parameter
 425    * placeholders. Typically this statement is a JDBC function call
 426    * escape string.
 427    * @return a new CallableStatement object containing the pre-compiled SQL
 428    * statement
 429    * @exception SQLException if a database access error occurs
 430    */
 431  3 public CallableStatement prepareCall( String sql )
 432    throws SQLException {
 433  3 checkConnection();
 434  2 final CallableStatement statement
 435    = new CallableStatementWrapper( delegate_.prepareCall( sql ) );
 436  2 openStatements_.add( statement );
 437  2 return statement;
 438    }
 439   
 440   
 441    /**
 442    * Converts the given SQL statement into the system's native SQL grammar. A
 443    * driver may convert the JDBC sql grammar into its system's native SQL
 444    * grammar prior to sending it; this method returns the native form of the
 445    * statement that the driver would have sent.
 446    *
 447    * @param sql a SQL statement that may contain one or more '?' parameter
 448    * placeholders
 449    * @return the native form of this statement
 450    * @exception SQLException if a database access error occurs
 451    */
 452  2 public String nativeSQL( String sql )
 453    throws SQLException {
 454  2 checkConnection();
 455  1 return delegate_.nativeSQL( sql );
 456    }
 457   
 458   
 459    /**
 460    * Makes all changes made since the previous commit/rollback permanent and
 461    * releases any database locks currently held by the Connection. This
 462    * method should be used only when auto-commit mode has been disabled.
 463    *
 464    * @exception SQLException if a database access error occurs
 465    * @see #setAutoCommit
 466    */
 467  2 public void commit()
 468    throws SQLException {
 469  2 checkConnection();
 470  1 delegate_.commit();
 471    }
 472   
 473   
 474    /**
 475    * Drops all changes made since the previous commit/rollback and releases
 476    * any database locks currently held by this Connection. This method should
 477    * be used only when auto- commit has been disabled.
 478    *
 479    * @exception SQLException if a database access error occurs
 480    * @see #setAutoCommit
 481    */
 482  2 public void rollback()
 483    throws SQLException {
 484  2 checkConnection();
 485  1 delegate_.rollback();
 486    }
 487   
 488   
 489    /**
 490    * Releases a Connection's database and JDBC resources immediately instead
 491    * of waiting for them to be automatically released. <P>
 492    *
 493    * <B>Note:</B> A Connection is automatically closed when it is garbage
 494    * collected. Certain fatal errors also result in a closed Connection.
 495    *
 496    * @exception SQLException if a database access error occurs
 497    */
 498  44 public void close()
 499    throws SQLException {
 500  44 if( isOpen_ ) {
 501  43 closeAnyOpenStatements();
 502  43 closeAnyOpenMetaDatas();
 503   
 504  43 delegate_.close();
 505  43 delegate_ = null;
 506    }
 507    else {
 508  1 throw new AlreadyClosedException( "Connection is closed" );
 509    }
 510  43 isOpen_ = false;
 511    }
 512   
 513   
 514    /**
 515    * Close any open statements
 516    *
 517    * @exception SQLException If an error occurs
 518    */
 519  43 public void closeAnyOpenStatements()
 520    throws SQLException {
 521  43 StatementWrapper statement;
 522  43 Iterator iterator = openStatements_.iterator();
 523  43 while( iterator.hasNext() ) {
 524  19 statement = ( StatementWrapper )iterator.next();
 525  19 if( statement.isClosed() == false ) {
 526  18 statement.close();
 527    }
 528    }
 529  43 openStatements_.clear();
 530    }
 531   
 532   
 533    /**
 534    * Close any open DatabaseMetaData objects
 535    *
 536    * @exception SQLException If an error occurs
 537    */
 538  43 public void closeAnyOpenMetaDatas()
 539    throws SQLException {
 540  43 final Iterator iterator = openDatabaseMetaData_.iterator();
 541  43 while( iterator.hasNext() ) {
 542  1 ( ( DatabaseMetaDataWrapper )iterator.next() ).close();
 543    }
 544  43 openDatabaseMetaData_.clear();
 545    }
 546   
 547   
 548    /**
 549    * Clears all warnings reported for this <code>Connection</code> object.
 550    * After a call to this method, the method <code>getWarnings</code> returns
 551    * null until a new warning is reported for this Connection.
 552    *
 553    * @exception SQLException if a database access error occurs
 554    */
 555  2 public void clearWarnings()
 556    throws SQLException {
 557  2 checkConnection();
 558  1 delegate_.clearWarnings();
 559    }
 560   
 561   
 562    //--------------------------JDBC 2.0-----------------------------
 563   
 564    /**
 565    * Creates a <code>Statement</code> object that will generate <code>ResultSet</code>
 566    * objects with the given type and concurrency. This method is the same as
 567    * the <code>createStatement</code> method above, but it allows the default
 568    * result set type and result set concurrency type to be overridden.
 569    *
 570    * @param resultSetType a result set type; see ResultSet.TYPE_XXX
 571    * @param resultSetConcurrency a concurrency type; see ResultSet.CONCUR_XXX
 572    * @return a new Statement object
 573    * @exception SQLException if a database access error occurs
 574    * @since 1.2
 575    */
 576  3 public Statement createStatement( int resultSetType, int resultSetConcurrency )
 577    throws
 578    SQLException {
 579   
 580  3 checkConnection();
 581  2 final StatementWrapper wrapper
 582    = new StatementWrapper( delegate_.createStatement( resultSetType, resultSetConcurrency ) );
 583  2 openStatements_.add( wrapper );
 584  2 return wrapper;
 585    }
 586   
 587   
 588    /**
 589    * Creates a <code>PreparedStatement</code> object that will generate
 590    * <code>ResultSet</code> objects with the given type and concurrency. This
 591    * method is the same as the <code>prepareStatement</code> method above,
 592    * but it allows the default result set type and result set concurrency
 593    * type to be overridden.
 594    *
 595    * @param sql a SQL statement that may contain one or more '?' parameter
 596    * placeholders. Typically this statement is a JDBC function call
 597    * escape string.
 598    * @param resultSetType a result set type; see ResultSet.TYPE_XXX
 599    * @param resultSetConcurrency a concurrency type; see ResultSet.CONCUR_XXX
 600    * @return a new PreparedStatement object containing the pre-compiled SQL
 601    * statement
 602    * @exception SQLException if a database access error occurs
 603    * @since 1.2
 604    */
 605  3 public PreparedStatement prepareStatement(
 606    final String sql,
 607    final int resultSetType,
 608    final int resultSetConcurrency )
 609    throws
 610    SQLException {
 611   
 612  3 checkConnection();
 613  2 final PreparedStatement statement
 614    = new PreparedStatementWrapper(
 615    delegate_.prepareStatement( sql, resultSetType, resultSetConcurrency ) );
 616  2 openStatements_.add( statement );
 617  2 return statement;
 618    }
 619   
 620   
 621    /**
 622    * Creates a <code>CallableStatement</code> object that will generate
 623    * <code>ResultSet</code> objects with the given type and concurrency. This
 624    * method is the same as the <code>prepareCall</code> method above, but it
 625    * allows the default result set type and result set concurrency type to be
 626    * overridden.
 627    *
 628    * @param sql a SQL statement that may contain one or more '?' parameter
 629    * placeholders. Typically this statement is a JDBC function call
 630    * escape string.
 631    * @param resultSetType a result set type; see ResultSet.TYPE_XXX
 632    * @param resultSetConcurrency a concurrency type; see ResultSet.CONCUR_XXX
 633    * @return a new CallableStatement object containing the pre-compiled SQL
 634    * statement
 635    * @exception SQLException if a database access error occurs
 636    * @since 1.2
 637    */
 638  3 public CallableStatement prepareCall( String sql, int resultSetType,
 639    int resultSetConcurrency )
 640    throws SQLException {
 641  3 checkConnection();
 642  2 final CallableStatement statement
 643    = new CallableStatementWrapper( delegate_.prepareCall( sql, resultSetType, resultSetConcurrency ) );
 644  2 openStatements_.add( statement );
 645  2 return statement;
 646    }
 647   
 648   
 649    /**
 650    * Check to see if the connection is still open. If not, throw an
 651    * exception.
 652    *
 653    * @exception SQLException
 654    */
 655  74 private void checkConnection()
 656    throws SQLException {
 657  74 if( isOpen_ == false ) {
 658  33 throw new SQLException( "Methods cannot be invoked on a closed connection" );
 659    }
 660    }
 661   
 662   
 663    /**
 664    * Return the number of statements that are currently open. Useful for debugging purposes.
 665    *
 666    * @return The number of statements that are currently open.
 667    */
 668  0 public int getOpenStatementCount() {
 669  0 synchronized(openStatements_) {
 670  0 int count = 0;
 671  0 final Iterator iterator = openStatements_.iterator();
 672  0 while( iterator.hasNext() ) {
 673  0 final StatementWrapper statement = (StatementWrapper)iterator.next();
 674  0 if( statement.isClosed() ) {
 675  0 iterator.remove();
 676    }
 677    else {
 678  0 count++;
 679    }
 680    }
 681   
 682  0 return count;
 683    }
 684    }
 685   
 686   
 687    /**
 688    * Changes the holdability of <code>ResultSet</code> objects
 689    * created using this <code>Connection</code> object to the given
 690    * holdability.
 691    *
 692    * @param holdability a <code>ResultSet</code> holdability constant; one of
 693    * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
 694    * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
 695    * @throws SQLException if a database access occurs, the given parameter
 696    * is not a <code>ResultSet</code> constant indicating holdability,
 697    * or the given holdability is not supported
 698    * @see #getHoldability
 699    * @see java.sql.ResultSet
 700    * @since 1.4
 701    */
 702  2 public void setHoldability(int holdability) throws SQLException {
 703  2 checkConnection();
 704  1 delegate_.setHoldability(holdability);
 705    }
 706   
 707   
 708    /**
 709    * Retrieves the current holdability of <code>ResultSet</code> objects
 710    * created using this <code>Connection</code> object.
 711    *
 712    * @return the holdability, one of
 713    * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
 714    * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
 715    * @throws SQLException if a database access occurs
 716    * @see #setHoldability
 717    * @see java.sql.ResultSet
 718    * @since 1.4
 719    */
 720  2 public int getHoldability() throws SQLException {
 721  2 checkConnection();
 722  1 return delegate_.getHoldability();
 723    }
 724   
 725   
 726    /**
 727    * Creates an unnamed savepoint in the current transaction and
 728    * returns the new <code>Savepoint</code> object that represents it.
 729    *
 730    * @return the new <code>Savepoint</code> object
 731    * @exception SQLException if a database access error occurs
 732    * or this <code>Connection</code> object is currently in
 733    * auto-commit mode
 734    * @see Savepoint
 735    * @since 1.4
 736    */
 737  2 public Savepoint setSavepoint() throws SQLException {
 738  2 checkConnection();
 739  1 return delegate_.setSavepoint();
 740    }
 741   
 742   
 743    /**
 744    * Creates a savepoint with the given name in the current transaction
 745    * and returns the new <code>Savepoint</code> object that represents it.
 746    *
 747    * @param name a <code>String</code> containing the name of the savepoint
 748    * @return the new <code>Savepoint</code> object
 749    * @exception SQLException if a database access error occurs
 750    * or this <code>Connection</code> object is currently in
 751    * auto-commit mode
 752    * @see Savepoint
 753    * @since 1.4
 754    */
 755  2 public Savepoint setSavepoint(String name) throws SQLException {
 756  2 checkConnection();
 757  1 return delegate_.setSavepoint(name);
 758    }
 759   
 760   
 761    /**
 762    * Undoes all changes made after the given <code>Savepoint</code> object
 763    * was set.
 764    * <P>
 765    * This method should be used only when auto-commit has been disabled.
 766    *
 767    * @param savepoint the <code>Savepoint</code> object to roll back to
 768    * @exception SQLException if a database access error occurs,
 769    * the <code>Savepoint</code> object is no longer valid,
 770    * or this <code>Connection</code> object is currently in
 771    * auto-commit mode
 772    * @see Savepoint
 773    * @since 1.4
 774    */
 775  2 public void rollback(Savepoint savepoint) throws SQLException {
 776  2 checkConnection();
 777  1 delegate_.rollback(savepoint);
 778    }
 779   
 780   
 781    /**
 782    * Removes the given <code>Savepoint</code> object from the current
 783    * transaction. Any reference to the savepoint after it have been removed
 784    * will cause an <code>SQLException</code> to be thrown.
 785    *
 786    * @param savepoint the <code>Savepoint</code> object to be removed
 787    * @exception SQLException if a database access error occurs or
 788    * the given <code>Savepoint</code> object is not a valid
 789    * savepoint in the current transaction
 790    * @since 1.4
 791    */
 792  2 public void releaseSavepoint(Savepoint savepoint) throws SQLException {
 793  2 checkConnection();
 794  1 delegate_.releaseSavepoint(savepoint);
 795    }
 796   
 797   
 798    /**
 799    * Creates a <code>Statement</code> object that will generate
 800    * <code>ResultSet</code> objects with the given type, concurrency,
 801    * and holdability.
 802    * This method is the same as the <code>createStatement</code> method
 803    * above, but it allows the default result set
 804    * type, concurrency, and holdability to be overridden.
 805    *
 806    * @param resultSetType one of the following <code>ResultSet</code>
 807    * constants:
 808    * <code>ResultSet.TYPE_FORWARD_ONLY</code>,
 809    * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
 810    * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
 811    * @param resultSetConcurrency one of the following <code>ResultSet</code>
 812    * constants:
 813    * <code>ResultSet.CONCUR_READ_ONLY</code> or
 814    * <code>ResultSet.CONCUR_UPDATABLE</code>
 815    * @param resultSetHoldability one of the following <code>ResultSet</code>
 816    * constants:
 817    * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
 818    * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
 819    * @return a new <code>Statement</code> object that will generate
 820    * <code>ResultSet</code> objects with the given type,
 821    * concurrency, and holdability
 822    * @exception SQLException if a database access error occurs
 823    * or the given parameters are not <code>ResultSet</code>
 824    * constants indicating type, concurrency, and holdability
 825    * @see java.sql.ResultSet
 826    * @since 1.4
 827    */
 828  2 public Statement createStatement(int resultSetType, int resultSetConcurrency,
 829    int resultSetHoldability) throws SQLException {
 830  2 checkConnection();
 831   
 832  1 final Statement statement = new StatementWrapper(
 833    delegate_.createStatement( resultSetType, resultSetConcurrency, resultSetHoldability ) );
 834  1 openStatements_.add( statement );
 835  1 return statement;
 836    }
 837   
 838   
 839    /**
 840    * Creates a <code>PreparedStatement</code> object that will generate
 841    * <code>ResultSet</code> objects with the given type, concurrency,
 842    * and holdability.
 843    * <P>
 844    * This method is the same as the <code>prepareStatement</code> method
 845    * above, but it allows the default result set
 846    * type, concurrency, and holdability to be overridden.
 847    *
 848    * @param sql a <code>String</code> object that is the SQL statement to
 849    * be sent to the database; may contain one or more ? IN
 850    * parameters
 851    * @param resultSetType one of the following <code>ResultSet</code>
 852    * constants:
 853    * <code>ResultSet.TYPE_FORWARD_ONLY</code>,
 854    * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
 855    * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
 856    * @param resultSetConcurrency one of the following <code>ResultSet</code>
 857    * constants:
 858    * <code>ResultSet.CONCUR_READ_ONLY</code> or
 859    * <code>ResultSet.CONCUR_UPDATABLE</code>
 860    * @param resultSetHoldability one of the following <code>ResultSet</code>
 861    * constants:
 862    * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
 863    * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
 864    * @return a new <code>PreparedStatement</code> object, containing the
 865    * pre-compiled SQL statement, that will generate
 866    * <code>ResultSet</code> objects with the given type,
 867    * concurrency, and holdability
 868    * @exception SQLException if a database access error occurs
 869    * or the given parameters are not <code>ResultSet</code>
 870    * constants indicating type, concurrency, and holdability
 871    * @see java.sql.ResultSet
 872    * @since 1.4
 873    */
 874  2 public PreparedStatement prepareStatement(String sql, int resultSetType,
 875    int resultSetConcurrency, int resultSetHoldability) throws SQLException {
 876  2 checkConnection();
 877   
 878  1 final PreparedStatement statement = new PreparedStatementWrapper(
 879    delegate_.prepareStatement( sql, resultSetType, resultSetConcurrency, resultSetHoldability ) );
 880  1 openStatements_.add( statement );
 881  1 return statement;
 882    }
 883   
 884   
 885    /**
 886    * Creates a <code>CallableStatement</code> object that will generate
 887    * <code>ResultSet</code> objects with the given type and concurrency.
 888    * This method is the same as the <code>prepareCall</code> method
 889    * above, but it allows the default result set
 890    * type, result set concurrency type and holdability to be overridden.
 891    *
 892    * @param sql a <code>String</code> object that is the SQL statement to
 893    * be sent to the database; may contain on or more ? parameters
 894    * @param resultSetType one of the following <code>ResultSet</code>
 895    * constants:
 896    * <code>ResultSet.TYPE_FORWARD_ONLY</code>,
 897    * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
 898    * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
 899    * @param resultSetConcurrency one of the following <code>ResultSet</code>
 900    * constants:
 901    * <code>ResultSet.CONCUR_READ_ONLY</code> or
 902    * <code>ResultSet.CONCUR_UPDATABLE</code>
 903    * @param resultSetHoldability one of the following <code>ResultSet</code>
 904    * constants:
 905    * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
 906    * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
 907    * @return a new <code>CallableStatement</code> object, containing the
 908    * pre-compiled SQL statement, that will generate
 909    * <code>ResultSet</code> objects with the given type,
 910    * concurrency, and holdability
 911    * @exception SQLException if a database access error occurs
 912    * or the given parameters are not <code>ResultSet</code>
 913    * constants indicating type, concurrency, and holdability
 914    * @see java.sql.ResultSet
 915    * @since 1.4
 916    */
 917  2 public CallableStatement prepareCall(String sql, int resultSetType,
 918    int resultSetConcurrency, int resultSetHoldability) throws SQLException {
 919  2 checkConnection();
 920   
 921  1 final CallableStatement statement = new CallableStatementWrapper(
 922    delegate_.prepareCall( sql, resultSetType, resultSetConcurrency, resultSetHoldability) );
 923  1 openStatements_.add( statement );
 924  1 return statement;
 925    }
 926   
 927   
 928    /**
 929    * Creates a default <code>PreparedStatement</code> object that has
 930    * the capability to retrieve auto-generated keys. The given constant
 931    * tells the driver whether it should make auto-generated keys
 932    * available for retrieval. This parameter is ignored if the SQL
 933    * statement is not an <code>INSERT</code> statement.
 934    * <P>
 935    * <B>Note:</B> This method is optimized for handling
 936    * parametric SQL statements that benefit from precompilation. If
 937    * the driver supports precompilation,
 938    * the method <code>prepareStatement</code> will send
 939    * the statement to the database for precompilation. Some drivers
 940    * may not support precompilation. In this case, the statement may
 941    * not be sent to the database until the <code>PreparedStatement</code>
 942    * object is executed. This has no direct effect on users; however, it does
 943    * affect which methods throw certain SQLExceptions.
 944    * <P>
 945    * Result sets created using the returned <code>PreparedStatement</code>
 946    * object will by default be type <code>TYPE_FORWARD_ONLY</code>
 947    * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
 948    *
 949    * @param sql an SQL statement that may contain one or more '?' IN
 950    * parameter placeholders
 951    * @param autoGeneratedKeys a flag indicating whether auto-generated keys
 952    * should be returned; one of
 953    * <code>Statement.RETURN_GENERATED_KEYS</code> or
 954    * <code>Statement.NO_GENERATED_KEYS</code>
 955    * @return a new <code>PreparedStatement</code> object, containing the
 956    * pre-compiled SQL statement, that will have the capability of
 957    * returning auto-generated keys
 958    * @exception SQLException if a database access error occurs
 959    * or the given parameter is not a <code>Statement</code>
 960    * constant indicating whether auto-generated keys should be
 961    * returned
 962    * @since 1.4
 963    */
 964  2 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
 965  2 checkConnection();
 966   
 967  1 final PreparedStatement statement
 968    = new PreparedStatementWrapper( delegate_.prepareStatement( sql, autoGeneratedKeys ) );
 969  1 openStatements_.add( statement );
 970  1 return statement;
 971    }
 972   
 973   
 974    /**
 975    * Creates a default <code>PreparedStatement</code> object capable
 976    * of returning the auto-generated keys designated by the given array.
 977    * This array contains the indexes of the columns in the target
 978    * table that contain the auto-generated keys that should be made
 979    * available. This array is ignored if the SQL
 980    * statement is not an <code>INSERT</code> statement.
 981    * <P>
 982    * An SQL statement with or without IN parameters can be
 983    * pre-compiled and stored in a <code>PreparedStatement</code> object. This
 984    * object can then be used to efficiently execute this statement
 985    * multiple times.
 986    * <P>
 987    * <B>Note:</B> This method is optimized for handling
 988    * parametric SQL statements that benefit from precompilation. If
 989    * the driver supports precompilation,
 990    * the method <code>prepareStatement</code> will send
 991    * the statement to the database for precompilation. Some drivers
 992    * may not support precompilation. In this case, the statement may
 993    * not be sent to the database until the <code>PreparedStatement</code>
 994    * object is executed. This has no direct effect on users; however, it does
 995    * affect which methods throw certain SQLExceptions.
 996    * <P>
 997    * Result sets created using the returned <code>PreparedStatement</code>
 998    * object will by default be type <code>TYPE_FORWARD_ONLY</code>
 999    * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
 1000    *
 1001    * @param sql an SQL statement that may contain one or more '?' IN
 1002    * parameter placeholders
 1003    * @param columnIndexes an array of column indexes indicating the columns
 1004    * that should be returned from the inserted row or rows
 1005    * @return a new <code>PreparedStatement</code> object, containing the
 1006    * pre-compiled statement, that is capable of returning the
 1007    * auto-generated keys designated by the given array of column
 1008    * indexes
 1009    * @exception SQLException if a database access error occurs
 1010    *
 1011    * @since 1.4
 1012    */
 1013  2 public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException {
 1014  2 checkConnection();
 1015   
 1016  1 final PreparedStatement statement
 1017    = new PreparedStatementWrapper( delegate_.prepareStatement( sql, columnIndexes ) );
 1018  1 openStatements_.add( statement );
 1019  1 return statement;
 1020    }
 1021   
 1022   
 1023    /**
 1024    * Creates a default <code>PreparedStatement</code> object capable
 1025    * of returning the auto-generated keys designated by the given array.
 1026    * This array contains the names of the columns in the target
 1027    * table that contain the auto-generated keys that should be returned.
 1028    * This array is ignored if the SQL
 1029    * statement is not an <code>INSERT</code> statement.
 1030    * <P>
 1031    * An SQL statement with or without IN parameters can be
 1032    * pre-compiled and stored in a <code>PreparedStatement</code> object. This
 1033    * object can then be used to efficiently execute this statement
 1034    * multiple times.
 1035    * <P>
 1036    * <B>Note:</B> This method is optimized for handling
 1037    * parametric SQL statements that benefit from precompilation. If
 1038    * the driver supports precompilation,
 1039    * the method <code>prepareStatement</code> will send
 1040    * the statement to the database for precompilation. Some drivers
 1041    * may not support precompilation. In this case, the statement may
 1042    * not be sent to the database until the <code>PreparedStatement</code>
 1043    * object is executed. This has no direct effect on users; however, it does
 1044    * affect which methods throw certain SQLExceptions.
 1045    * <P>
 1046    * Result sets created using the returned <code>PreparedStatement</code>
 1047    * object will by default be type <code>TYPE_FORWARD_ONLY</code>
 1048    * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
 1049    *
 1050    * @param sql an SQL statement that may contain one or more '?' IN
 1051    * parameter placeholders
 1052    * @param columnNames an array of column names indicating the columns
 1053    * that should be returned from the inserted row or rows
 1054    * @return a new <code>PreparedStatement</code> object, containing the
 1055    * pre-compiled statement, that is capable of returning the
 1056    * auto-generated keys designated by the given array of column
 1057    * names
 1058    * @exception SQLException if a database access error occurs
 1059    *
 1060    * @since 1.4
 1061    */
 1062  2 public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException {
 1063  2 checkConnection();
 1064   
 1065  1 final PreparedStatement statement
 1066    = new PreparedStatementWrapper( delegate_.prepareStatement( sql, columnNames ) );
 1067  1 openStatements_.add( statement );
 1068  1 return statement;
 1069    }
 1070    }
 1071