You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by dj...@apache.org on 2006/02/24 01:14:18 UTC

svn commit: r380278 - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ client/org/apache/derby/client/net/ drda/org/apache/derby/impl/drda/

Author: djd
Date: Thu Feb 23 16:14:16 2006
New Revision: 380278

URL: http://svn.apache.org/viewcvs?rev=380278&view=rev
Log:
DERBY-996 DERBY-1005 1) Change DRDAStatement to use the EngineConnection.prepareStatement() method that has a holdability parameter. This ensures prepares on a connection that was obtained from a XADataSource (or a ConnectionPoolDataSource) do not lose the holdability requested by the application.

2) Change the client's state of holdability to match the embedded in that a Connection's holdability is set to close cursors on commit when it has an active global XA transaction.

Patch addresses this issue completely.

Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Connection.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/DatabaseMetaData.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/SectionManager.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Connection.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/Connection.java?rev=380278&r1=380277&r2=380278&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Connection.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Connection.java Thu Feb 23 16:14:16 2006
@@ -21,6 +21,7 @@
 package org.apache.derby.client.am;
 
 import org.apache.derby.jdbc.ClientDataSource;
+import org.apache.derby.shared.common.reference.JDBC30Translation;
 import org.apache.derby.shared.common.reference.SQLState;
 
 import java.sql.SQLException;
@@ -53,7 +54,14 @@
     public transient String user_;
     public boolean retrieveMessageText_;
     protected boolean jdbcReadOnly_;
-    public int resultSetHoldability_;
+    /**
+     * Holdabilty for created statements.
+     * Only access through the holdability method
+     * to ensure the correct value is returned for an
+     * XA connection.
+     */
+    private int holdability = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
+    
     public String databaseName_;
 
     // Holds the Product-Specific Identifier which specifies
@@ -108,7 +116,7 @@
     //public static final int XA_RECOVER = 14;
 
 
-    protected int xaState_ = XA_T0_NOT_ASSOCIATED;
+    private int xaState_ = XA_T0_NOT_ASSOCIATED;
 
     // XA Host Type
     public int xaHostVersion_ = 0;
@@ -236,6 +244,8 @@
 
             loginTimeout_ = ds.getLoginTimeout();
             dataSource_ = ds;
+            
+            holdability = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
         }
 
         
@@ -341,7 +351,7 @@
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceEntry(this, "createStatement");
             }
-            Statement s = createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_);
+            Statement s = createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, holdability());
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceExit(this, "createStatement", s);
             }
@@ -362,7 +372,7 @@
             PreparedStatement ps = prepareStatementX(sql,
                     java.sql.ResultSet.TYPE_FORWARD_ONLY,
                     java.sql.ResultSet.CONCUR_READ_ONLY,
-                    resultSetHoldability_,
+                    holdability(),
                     java.sql.Statement.NO_GENERATED_KEYS,
                     null);
             if (agent_.loggingEnabled()) {
@@ -400,7 +410,7 @@
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceEntry(this, "prepareCall", sql);
             }
-            CallableStatement cs = prepareCallX(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_);
+            CallableStatement cs = prepareCallX(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, holdability());
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceExit(this, "prepareCall", cs);
             }
@@ -413,7 +423,7 @@
     }
 
     synchronized PreparedStatement prepareDynamicCatalogQuery(String sql) throws SqlException {
-        PreparedStatement ps = newPreparedStatement_(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_, java.sql.Statement.NO_GENERATED_KEYS, null);
+        PreparedStatement ps = newPreparedStatement_(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, holdability(), java.sql.Statement.NO_GENERATED_KEYS, null);
         ps.isCatalogQuery_ = true;
         ps.prepare();
         openStatements_.add(ps);
@@ -908,7 +918,7 @@
                 setTransactionIsolationStmt =
                         createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                                 java.sql.ResultSet.CONCUR_READ_ONLY,
-                                resultSetHoldability_);
+                                holdability());
             }
             setTransactionIsolationStmt.executeUpdate("SET CURRENT ISOLATION = " + levelString);
 
@@ -1052,7 +1062,7 @@
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceEntry(this, "createStatement", resultSetType, resultSetConcurrency);
             }
-            Statement s = createStatementX(resultSetType, resultSetConcurrency, resultSetHoldability_);
+            Statement s = createStatementX(resultSetType, resultSetConcurrency, holdability());
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceExit(this, "createStatement", s);
             }
@@ -1075,7 +1085,7 @@
             PreparedStatement ps = prepareStatementX(sql,
                     resultSetType,
                     resultSetConcurrency,
-                    resultSetHoldability_,
+                    holdability(),
                     java.sql.Statement.NO_GENERATED_KEYS,
                     null);
             if (agent_.loggingEnabled()) {
@@ -1097,7 +1107,7 @@
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceEntry(this, "prepareCall", sql, resultSetType, resultSetConcurrency);
             }
-            CallableStatement cs = prepareCallX(sql, resultSetType, resultSetConcurrency, resultSetHoldability_);
+            CallableStatement cs = prepareCallX(sql, resultSetType, resultSetConcurrency, holdability());
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceExit(this, "prepareCall", cs);
             }
@@ -1112,7 +1122,7 @@
     synchronized public CallableStatement prepareMessageProc(String sql) throws SqlException {
         checkForClosedConnection();
 
-        CallableStatement cs = prepareCallX(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_);
+        CallableStatement cs = prepareCallX(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, holdability());
         return cs;
     }
 
@@ -1182,8 +1192,9 @@
                 agent_.logWriter_.traceEntry(this, "setHoldability", holdability);
             }
             checkForClosedConnection();
-            resultSetHoldability_ = holdability;
-        }
+            this.holdability = holdability;
+            
+       }
         catch ( SqlException se )
         {
             throw se.getSQLException();
@@ -1195,9 +1206,9 @@
         {
             checkForClosedConnection();
             if (agent_.loggingEnabled()) {
-                agent_.logWriter_.traceExit(this, "getHoldability", resultSetHoldability_);
+                agent_.logWriter_.traceExit(this, "getHoldability", holdability());
             }
-            return resultSetHoldability_;
+            return holdability();
         }
         catch ( SqlException se )
         {
@@ -1263,7 +1274,7 @@
         try {
             stmt = (Statement) createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                     java.sql.ResultSet.CONCUR_READ_ONLY,
-                    resultSetHoldability_);
+                    holdability());
             String savepointName;
             try {
                 savepointName = savepoint.getSavepointName();
@@ -1320,7 +1331,7 @@
             try {
                 stmt = createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                         java.sql.ResultSet.CONCUR_READ_ONLY,
-                        resultSetHoldability_);
+                        holdability());
                 String savepointName;
                 try {
                     savepointName = ((Savepoint) savepoint).getSavepointName();
@@ -1378,7 +1389,7 @@
             try {
                 stmt = (Statement) createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                         java.sql.ResultSet.CONCUR_READ_ONLY,
-                        resultSetHoldability_);
+                        holdability());
                 String savepointName;
                 try {
                     savepointName = ((Savepoint) savepoint).getSavepointName();
@@ -1551,7 +1562,7 @@
             PreparedStatement ps = prepareStatementX(sql,
                     java.sql.ResultSet.TYPE_FORWARD_ONLY,
                     java.sql.ResultSet.CONCUR_READ_ONLY,
-                    resultSetHoldability_,
+                    holdability(),
                     autoGeneratedKeys,
                     null);
             if (agent_.loggingEnabled()) {
@@ -1589,7 +1600,7 @@
             PreparedStatement ps = prepareStatementX(sql,
                     java.sql.ResultSet.TYPE_FORWARD_ONLY,
                     java.sql.ResultSet.CONCUR_READ_ONLY,
-                    resultSetHoldability_,
+                    holdability(),
                     java.sql.Statement.RETURN_GENERATED_KEYS,
                     columnNames);
             if (agent_.loggingEnabled()) {
@@ -1887,6 +1898,19 @@
 
     public void setInUnitOfWork(boolean inUnitOfWork) {
         inUnitOfWork_ = inUnitOfWork;
+    }
+    
+    /**
+     * Return the holdabilty for the Connection. Matches the
+     * embedded driver in the restriction that while in a
+     * global (XA) transaction the holdability is CLOSE_CURSORS_AT_COMMIT.
+     * Otherwise return the holdability set by the user.
+     */
+    final int holdability()
+    {
+        if (this.isXAConnection_ && this.xaState_ == XA_T1_ASSOCIATED)
+            return JDBC30Translation.CLOSE_CURSORS_AT_COMMIT;
+        return holdability;
     }
 
 }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/DatabaseMetaData.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/DatabaseMetaData.java?rev=380278&r1=380277&r2=380278&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/DatabaseMetaData.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/DatabaseMetaData.java Thu Feb 23 16:14:16 2006
@@ -1282,7 +1282,7 @@
         cs.setStringX(3, "");
         cs.setStringX(4, "%");
         int cursorHold;
-        if (connection_.resultSetHoldability_ == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
+        if (connection_.holdability() == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
             cursorHold = 1;
         } else {
             cursorHold = 0;
@@ -1629,7 +1629,7 @@
         cs.setStringX(6, table);
         // We're passing the keyword EXPORTEDKEY, but this support may not be in the GA version of SPs.
         // As a workaround in getCrossReference(), we'll just "select * where 0=1" when primaryTable==""
-        if (connection_.resultSetHoldability_ == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
+        if (connection_.holdability() == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
             cs.setStringX(7, "DATATYPE='JDBC';IMPORTEDKEY=1; CURSORHOLD=1");
         } else {
             cs.setStringX(7, "DATATYPE='JDBC';IMPORTEDKEY=1; CURSORHOLD=0");
@@ -1682,7 +1682,7 @@
         cs.setStringX(6, "");
         // We're passing the keyword EXPORTEDKEY, but this support may not be in the GA version of SPs.
         // As a workaround in getCrossReference(), we'll just "select * where 0=1" when foreignTable==""
-        if (connection_.resultSetHoldability_ == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
+        if (connection_.holdability() == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
             cs.setStringX(7, "DATATYPE='JDBC';EXPORTEDKEY=1; CURSORHOLD=1");
         } else {
             cs.setStringX(7, "DATATYPE='JDBC';EXPORTEDKEY=1; CURSORHOLD=0");
@@ -1911,7 +1911,7 @@
     // helper method for the catalog queries only
     private String getOptions() {
         int cursorHold;
-        if (connection_.resultSetHoldability_ == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
+        if (connection_.holdability() == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
             cursorHold = 1;
         } else {
             cursorHold = 0;
@@ -2315,7 +2315,7 @@
                 connection_.prepareStatementX("CALL " + cmd,
                         java.sql.ResultSet.TYPE_FORWARD_ONLY,
                         java.sql.ResultSet.CONCUR_READ_ONLY,
-                        connection_.resultSetHoldability_,
+                        connection_.holdability(),
                         java.sql.Statement.NO_GENERATED_KEYS,
                         null);
         return ps;

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/SectionManager.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/SectionManager.java?rev=380278&r1=380277&r2=380278&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/SectionManager.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/SectionManager.java Thu Feb 23 16:14:16 2006
@@ -147,7 +147,7 @@
     // A positioned update section must come from the same package as its query section.
     Section getPositionedUpdateSection(Section querySection) throws SqlException {
         Connection connection = agent_.connection_;
-        return getDynamicSection(connection.resultSetHoldability_);
+        return getDynamicSection(connection.holdability());
     }
 
     // Get a section for a jdbc 1 positioned update/delete for the corresponding query.

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java?rev=380278&r1=380277&r2=380278&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java Thu Feb 23 16:14:16 2006
@@ -1447,7 +1447,7 @@
         }
         if (connection_.autoCommit_ && requiresAutocommit) { // for the auto-commit;
             if (connection_.isXAConnection_) {
-                return (connection_.xaState_ == Connection.XA_T0_NOT_ASSOCIATED) ;
+                return (connection_.getXAState() == Connection.XA_T0_NOT_ASSOCIATED) ;
             } else {
                 return true;
             }
@@ -1526,7 +1526,7 @@
         if (connection_.autoCommit_ && requiresAutocommit && isAutoCommittableStatement_) {
             connection_.writeAutoCommit();
             if (connection_.isXAConnection_) {
-                return (connection_.xaState_ == Connection.XA_T0_NOT_ASSOCIATED) ;
+                return (connection_.getXAState() == Connection.XA_T0_NOT_ASSOCIATED) ;
             } else {
                 return true;
             }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java?rev=380278&r1=380277&r2=380278&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java Thu Feb 23 16:14:16 2006
@@ -270,9 +270,7 @@
                 securityMechanism_ = ds.getSecurityMechanism();
             }
             resetConnectionAtFirstSql_ = false;
-            if (resultSetHoldability_ == 0) {
-                ((org.apache.derby.client.net.NetDatabaseMetaData) databaseMetaData_).setDefaultResultSetHoldability();
-            }
+
         }
         if (password != null) {
             deferredResetPassword_ = null;
@@ -322,10 +320,6 @@
                 securityMechanism_ = ds.getSecurityMechanism();
             }
             resetConnectionAtFirstSql_ = false;
-
-            if (resultSetHoldability_ == 0) {
-                ((org.apache.derby.client.net.NetDatabaseMetaData) databaseMetaData_).setDefaultResultSetHoldability();
-            }
         }
         // properties prddta_ and crrtkn_ will be initialized by
         // calls to constructPrddta() and constructCrrtkn()
@@ -1378,7 +1372,7 @@
     // Allow local COMMIT/ROLLBACK only if we are not in an XA transaction
     protected boolean allowLocalCommitRollback_() throws org.apache.derby.client.am.SqlException {
        
-    	if (xaState_ == XA_T0_NOT_ASSOCIATED) {
+    	if (getXAState() == XA_T0_NOT_ASSOCIATED) {
             return true;
         }
         return false;

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java?rev=380278&r1=380277&r2=380278&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java Thu Feb 23 16:14:16 2006
@@ -79,10 +79,6 @@
     //
     // END OF WARNING
     protected void computeFeatureSet_() {
-        if (connection_.resultSetHoldability_ == 0)  // property not set
-        {
-            setDefaultResultSetHoldability();
-        }
 
         // Support for QRYCLSIMP was added in 10.2.0
         if (productLevel_.greaterThanOrEqualTo(10, 2, 0)) {
@@ -90,11 +86,6 @@
         } else {
             supportsQryclsimp_ = false;
         }
-    }
-
-
-    public void setDefaultResultSetHoldability() {
-        connection_.resultSetHoldability_ = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
     }
 
     /**

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java?rev=380278&r1=380277&r2=380278&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java Thu Feb 23 16:14:16 2006
@@ -37,6 +37,7 @@
 
 import org.apache.derby.iapi.jdbc.BrokeredConnection;
 import org.apache.derby.iapi.jdbc.BrokeredPreparedStatement;
+import org.apache.derby.iapi.jdbc.EngineConnection;
 import org.apache.derby.iapi.reference.JDBC30Translation;
 import org.apache.derby.iapi.sql.execute.ExecutionContext;
 import org.apache.derby.iapi.util.StringUtil;
@@ -65,7 +66,7 @@
 	protected ConsistencyToken pkgcnstkn;       // Consistency token for the first result set
  	protected String pkgid;              // package id
  	protected int pkgsn;		// section number
-	protected int withHoldCursor = -1;	 // hold cursor after commit attribute.
+	int withHoldCursor = -1;	 // hold cursor after commit attribute.
 	protected int isolationLevel;         //JCC isolation level for Statement
 	protected String cursorName;
 	protected int scrollType = ResultSet.TYPE_FORWARD_ONLY;			// Sensitive or Insensitive scroll attribute
@@ -510,11 +511,7 @@
 			return ps;
 		}
 		parsePkgidToFindHoldability();
-		Connection conn = database.getConnection();
-		if (conn instanceof BrokeredConnection)
-			ps = conn.prepareStatement(sqlStmt, scrollType, concurType);
-		else
-			ps = prepareStatementJDBC3(sqlStmt, scrollType, concurType, 
+		ps = prepareStatementJDBC3(sqlStmt, scrollType, concurType, 
 									   withHoldCursor);
 		// beetle 3849  -  Need to change the cursor name to what
 		// JCC thinks it will be, since there is no way in the 
@@ -1459,17 +1456,18 @@
 	{
 		if (withHoldCursor != -1)
 			return;
+        
 		//First, check if holdability was passed as a SQL attribute "WITH HOLD" for this prepare. If yes, then withHoldCursor
 		//should not get overwritten by holdability from package name and that is why the check for -1
 		if (isDynamicPkgid(pkgid))
-		{
+		{       
 			if(pkgid.charAt(4) == 'N')
 				withHoldCursor = JDBC30Translation.CLOSE_CURSORS_AT_COMMIT;
 			else  
 				withHoldCursor = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
 		}
 		else 
-		{
+		{            
 			withHoldCursor = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
 		
 		}
@@ -1477,10 +1475,8 @@
 
 
 	/**
-	 *  prepare a statement using reflection so that server can run on jdk131
-	 *  and still pass holdability.  
-	 *  parameters are passed on to either the EmbedConnection or 
-	 *  BrokeredConnection prepareStatement() method.
+	 *  prepare a statement using EngineConnection.prepareStatement
+     *  so that server can run on jdk131 and still pass holdability.  
 	 *  @param sqlStmt - SQL statement text
 	 *  @param scrollType - scroll type
 	 *  @param concurType - concurrency type
@@ -1494,26 +1490,17 @@
 													scrollType, int concurType,
 													int withHoldCursor) throws SQLException
 	{
-		PreparedStatement lps = null;
-
-		// If holdability is still uninitialized, default is HOLD_CURSORS_OVER_COMMIT
-		int resultSetHoldability = (withHoldCursor == -1) ? 
-			resultSetHoldability = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT :
-			withHoldCursor;
-
-		//prepareStatement takes 4 parameters
-		Class[] PREP_STMT_PARAM = { String.class, Integer.TYPE, Integer.TYPE, Integer.TYPE };
-		Object[] PREP_STMT_ARG = { sqlStmt, new Integer(scrollType),
-								   new Integer(concurType), new Integer(resultSetHoldability)};
-		try {
-			//create a prepared statement with hold cursor over commit using reflection.
-			Method sh = database.getConnection().getClass().getMethod("prepareStatement", PREP_STMT_PARAM);
-			lps = (PreparedStatement) (sh.invoke(database.getConnection(), PREP_STMT_ARG));
-		} catch (Exception e) {
-			handleReflectionException(e);
-		} 
-
-		return lps;
+        EngineConnection conn = database.getConnection();
+        if (withHoldCursor == -1) {
+            // Holdability not explictly set, let the
+            // connection provide the default.
+            return conn.prepareStatement(sqlStmt,
+                    scrollType, concurType);
+        }
+        
+        // Holdability explictly set. 
+        return conn.prepareStatement(sqlStmt,
+                scrollType, concurType, withHoldCursor);
 	}