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 be...@apache.org on 2006/02/13 13:44:17 UTC

svn commit: r377367 - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ client/org/apache/derby/client/net/ drda/org/apache/derby/impl/drda/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/functionTe...

Author: bernt
Date: Mon Feb 13 04:44:07 2006
New Revision: 377367

URL: http://svn.apache.org/viewcvs?rev=377367&view=rev
Log:
DERBY-821 Client driver: Implicitly close exhausted result sets on the server.
Submitted by Knut Anders Hatlen


Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/SqlCode.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/NetCursor.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetResultSet.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetSqldta.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementRequest.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePointNameTable.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAResultSet.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/forupdate.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/holdCursorIJ.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorIJ.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorJava.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/procedure.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/updatableResultSet.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/updatableResultSet.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/forupdate.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorIJ.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorJava.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/j9_foundation/holdCursorJava.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/testProtocol.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/protocol.tests
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/setTransactionIsolation.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forupdate.sql
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorIJ.sql
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorJava.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java Mon Feb 13 04:44:07 2006
@@ -69,7 +69,7 @@
     // This flag indicates that the server has returned all the rows, and is positioned
     // after last, for both scrollable and forward-only cursors.
     // For singleton cursors, this memeber will be set to true as soon as next is called.
-    public boolean allRowsReceivedFromServer_;
+    private boolean allRowsReceivedFromServer_;
 
     // Total number of rows read so far.
     // This should never exceed this.statement.maxRows
@@ -116,7 +116,7 @@
     public Cursor(Agent agent, byte[] dataBuffer) {
         this(agent);
         dataBuffer_ = dataBuffer;
-        allRowsReceivedFromServer_ = false;
+        setAllRowsReceivedFromServer(false);
     }
 
     public void setNumberOfColumns(int numberOfColumns) {
@@ -133,9 +133,16 @@
         jdbcTypes_ = new int[numberOfColumns];
     }
 
-    // Makes the next row the current row.
-    // Returns true if the current row position is a valid row position.
-    public boolean next() throws SqlException {
+    /**
+     * Makes the next row the current row. Returns true if the current
+     * row position is a valid row position.
+     *
+     * @param allowServerFetch if false, don't fetch more data from
+     * the server even if more data is needed
+     * @return <code>true</code> if current row position is valid
+     * @exception SqlException if an error occurs
+     */
+    protected boolean stepNext(boolean allowServerFetch) throws SqlException {
         // local variable usd to hold the returned value from calculateColumnOffsetsForRow()
         boolean rowPositionIsValid = true;
 
@@ -162,17 +169,45 @@
         // The parameter passed in here is used as an index into the cached rowset for
         // scrollable cursors, for the arrays to be reused.  It is not used for forward-only
         // cursors, so just pass in 0.
-        rowPositionIsValid = calculateColumnOffsetsForRow_(0);  // readFetchedRows()
+        rowPositionIsValid = calculateColumnOffsetsForRow_(0, allowServerFetch);
         markNextRowPosition();
         return rowPositionIsValid;
     }
 
+    /**
+     * Makes the next row the current row. Returns true if the current
+     * row position is a valid row position.
+     *
+     * @return <code>true</code> if current row position is valid
+     * @exception SqlException if an error occurs
+     */
+    public boolean next() throws SqlException {
+        return stepNext(true);
+    }
+
     //--------------------------reseting cursor state-----------------------------
 
-    public final void setAllRowsReceivedFromServer(boolean b) {
+    /**
+     * Set the value of value of allRowsReceivedFromServer_.
+     *
+     * @param b a <code>boolean</code> value indicating whether all
+     * rows are received from the server
+     */
+    public void setAllRowsReceivedFromServer(boolean b) {
         allRowsReceivedFromServer_ = b;
     }
 
+    /**
+     * Return <code>true</code> if all rows are received from the
+     * server.
+     *
+     * @return <code>true</code> if all rows are received from the
+     * server.
+     */
+    public final boolean allRowsReceivedFromServer() {
+        return allRowsReceivedFromServer_;
+    }
+
     public final boolean currentRowPositionIsEqualToNextRowPosition() {
         return (currentRowPosition_ == nextRowPosition_);
     }
@@ -186,7 +221,7 @@
         lastValidBytePosition_ = 0;
         currentRowPosition_ = 0;
         nextRowPosition_ = 0;
-        allRowsReceivedFromServer_ = false;
+        setAllRowsReceivedFromServer(false);
         dataBufferStream_.reset();
     }
 
@@ -194,7 +229,20 @@
         return (lastValidBytePosition_ - position_) > 0;
     }
 
-    protected abstract boolean calculateColumnOffsetsForRow_(int row) throws SqlException, DisconnectException;
+    /**
+     * Calculate the column offsets for a row.
+     *
+     * @param row row index
+     * @param allowServerFetch if true, allow fetching more data from
+     * server
+     * @return <code>true</code> if the current row position is a
+     * valid row position.
+     * @exception SqlException
+     * @exception DisconnectException
+     */
+    protected abstract boolean
+        calculateColumnOffsetsForRow_(int row, boolean allowServerFetch)
+        throws SqlException, DisconnectException;
 
     protected abstract void clearLobData_();
 

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java Mon Feb 13 04:44:07 2006
@@ -420,6 +420,7 @@
         if (!openOnClient_) {
             return;
         }
+        preClose_();
         try {
             if (openOnServer_) {
                 flowCloseAndAutoCommitIfNotAutoCommitted();
@@ -2264,7 +2265,7 @@
         // for forward-only cursors, getRow() should return 0 if cursor is not on a valid row,
         // i.e. afterlast.
         {
-            row = (cursor_.allRowsReceivedFromServer_ &&
+            row = (cursor_.allRowsReceivedFromServer() &&
                     cursor_.currentRowPositionIsEqualToNextRowPosition()) ? 0 : cursor_.rowsRead_;
         } else {
             if (rowCountIsUnknown()) {
@@ -4184,7 +4185,10 @@
         }
     }
 
-    void markClosedOnServer() {
+    /**
+     * Mark this ResultSet as closed on the server.
+     */
+    public void markClosedOnServer() {
         openOnServer_ = false;
     }
 
@@ -4214,19 +4218,6 @@
         return sqlcode;
     }
 
-    public void setCloseOnlyStateForSingletonCursors() {
-        markClosedOnServer();
-    }
-
-    // If autocommit is on, the commit was already flowed with the execute() that
-    // generated the singleton cursor.  The correct state needs to be set into
-    // the result set now.
-    public void setAutoCommitStateForSingletonCursors() {
-        if (connection_.autoCommit_) {
-            markAutoCommitted();
-        }
-    }
-
     // Set rowCount.
     public void setRowCountEvent(long rowCount) throws DisconnectException {
         // Only set the row count if it's unknown, to prevent clobbering of a valid value.
@@ -4650,7 +4641,8 @@
 
             // This method is only called after open query to parse out the very first rowset
             // received.
-            if (cursor_.allRowsReceivedFromServer_ && rowsReceivedInCurrentRowset_ == 0) {
+            if (cursor_.allRowsReceivedFromServer() &&
+                rowsReceivedInCurrentRowset_ == 0) {
                 setRowsetNoRowsEvent();
             }
         }
@@ -4756,7 +4748,7 @@
             if (resultSetContainsNoRows() || isAfterLastX()) {
                 return false;
             } else if (firstRowInRowset_ + currentRowInRowset_ == lastRowInRowset_ &&
-                    cursor_.allRowsReceivedFromServer_) {
+                    cursor_.allRowsReceivedFromServer()) {
                 isAfterLast_ = true;
                 setRowsetAfterLastEvent();
                 return false;
@@ -4789,7 +4781,8 @@
 
         // If no row was received but received sqlcode +100, then the cursor is
         // positioned after last.
-        if (rowsReceivedInCurrentRowset_ == 0 && cursor_.allRowsReceivedFromServer_) {
+        if (rowsReceivedInCurrentRowset_ == 0 &&
+            cursor_.allRowsReceivedFromServer()) {
             isAfterLast_ = true;
             setRowsetAfterLastEvent();
             return false;
@@ -4861,8 +4854,8 @@
 
         // If no row was received but received sqlcode +100, then the cursor is
         // positioned before first.
-        if (rowsReceivedInCurrentRowset_ == 0 && cursor_.allRowsReceivedFromServer_) {
-            //cursor_.beginningOfResultSetIsReached_ = true;
+        if (rowsReceivedInCurrentRowset_ == 0 &&
+            cursor_.allRowsReceivedFromServer()) {
             isBeforeFirst_ = true;
             setRowsetBeforeFirstEvent();
             return false;
@@ -4911,7 +4904,8 @@
 
         // If no row was received but received sqlcode +100, then the cursor is
         // positioned after last or before first.
-        if ((rowsReceivedInCurrentRowset_ == 0 && cursor_.allRowsReceivedFromServer_) ||
+        if ((rowsReceivedInCurrentRowset_ == 0 &&
+             cursor_.allRowsReceivedFromServer()) ||
                 orientation == scrollOrientation_before__) {
             if (row > 0) {
                 setRowsetAfterLastEvent();
@@ -4940,7 +4934,8 @@
 
     private boolean getRelativeRowset(long rows) throws SqlException {
         if (rows == 0 &&
-                (cursor_.allRowsReceivedFromServer_ || absolutePosition_ > rowCount_)) {
+                (cursor_.allRowsReceivedFromServer() ||
+                 absolutePosition_ > rowCount_)) {
             setRowsetAfterLastEvent();
             isAfterLast_ = true;
             return false;
@@ -4949,7 +4944,8 @@
         flowGetRowset(scrollOrientation_relative__, rows);
         parseRowset_();
 
-        if (rowsReceivedInCurrentRowset_ == 0 && cursor_.allRowsReceivedFromServer_) {
+        if (rowsReceivedInCurrentRowset_ == 0 &&
+            cursor_.allRowsReceivedFromServer()) {
             if (rows > 0) {
                 setRowsetAfterLastEvent();
                 isAfterLast_ = true;
@@ -4979,7 +4975,8 @@
         parseRowset_();
 
         // If no row was received but received sqlcode +100, then no row in the result set
-        if (rowsReceivedInCurrentRowset_ == 0 && cursor_.allRowsReceivedFromServer_) {
+        if (rowsReceivedInCurrentRowset_ == 0 &&
+            cursor_.allRowsReceivedFromServer()) {
             resetRowsetFlags();
             this.setRowsetNoRowsEvent();
             return false;
@@ -5022,7 +5019,8 @@
         }
         parseRowset_();
 
-        if (rowsReceivedInCurrentRowset_ == 0 && cursor_.allRowsReceivedFromServer_) {
+        if (rowsReceivedInCurrentRowset_ == 0 &&
+            cursor_.allRowsReceivedFromServer()) {
             isAfterLast_ = true;
             setRowsetAfterLastEvent();
             return false;
@@ -5070,7 +5068,7 @@
     }
 
     private void setAbsolutePositionBasedOnAllRowsReceived() {
-        absolutePosition_ = (cursor_.allRowsReceivedFromServer_) ?
+        absolutePosition_ = (cursor_.allRowsReceivedFromServer()) ?
                 lastRowInRowset_ + 1 : lastRowInRowset_;
     }
 
@@ -5103,6 +5101,15 @@
     protected abstract void parseRowset_() throws SqlException;
 
     public abstract void setFetchSize_(int rows);
+
+    /**
+     * Method that is invoked by <code>closeX()</code> before the
+     * result set is actually being closed. Subclasses may override
+     * this method if work needs to be done before closing.
+     *
+     * @exception SqlException
+     */
+    protected abstract void preClose_() throws SqlException;
 
     public ConnectionCallbackInterface getConnectionCallbackInterface() {
         return connection_;

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/SqlCode.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/SqlCode.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/SqlCode.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/SqlCode.java Mon Feb 13 04:44:07 2006
@@ -34,7 +34,12 @@
         code_ = code;
     }
 
-    int getCode() {
+    /**
+     * Return the SQL code represented by this instance.
+     *
+     * @return an SQL code
+     */
+    public final int getCode() {
         return code_;
     }
 
@@ -48,4 +53,7 @@
 
     public final static SqlCode undefinedError = new SqlCode(-99999);
 
+    /** SQL code for SQL state 02000 (end of data). DRDA does not
+     * specify the SQL code for this SQL state, but Derby uses 100. */
+    public final static SqlCode END_OF_DATA = new SqlCode(100);
 }

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=377367&r1=377366&r2=377367&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 Mon Feb 13 04:44:07 2006
@@ -1523,5 +1523,18 @@
 	public void setConnectionNull(boolean connectionNull) {
 		this.connectionNull = connectionNull;
 	}
+
+    /**
+     * Check whether the server has full support for the QRYCLSIMP
+     * parameter in OPNQRY.
+     *
+     * @return true if QRYCLSIMP is fully supported
+     */
+    public final boolean serverSupportsQryclsimp() {
+        NetDatabaseMetaData metadata =
+            (NetDatabaseMetaData) databaseMetaData_;
+        return metadata.serverSupportsQryclsimp();
+    }
+
 }
 

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java Mon Feb 13 04:44:07 2006
@@ -28,6 +28,7 @@
 import org.apache.derby.client.am.SqlException;
 import org.apache.derby.client.am.SqlWarning;
 import org.apache.derby.client.am.Types;
+import org.apache.derby.client.am.SqlCode;
 
 public class NetCursor extends org.apache.derby.client.am.Cursor {
 
@@ -55,6 +56,10 @@
 
     boolean rtnextrow_ = true;
 
+    /** Flag indicating whether the result set on the server is
+     * implicitly closed when end-of-data is received. */
+    private boolean qryclsimpEnabled_;
+
     //-----------------------------constants--------------------------------------
 
     //---------------------constructors/finalizer---------------------------------
@@ -80,18 +85,42 @@
     }
     //-----------------------------parsing the data buffer------------------------
 
-    // Pseudo-code:
-    //   parse thru the current row in dataBuffer computing column offsets
-    //   if (we hit the super.lastValidBytePosition, ie. encounter partial row) {
-    //     shift partial row bytes to beginning of dataBuffer (this.shiftPartialRowToBeginning())
-    //     reset current row position (also done by this.shiftPartialRowToBeginning())
-    //     send and recv continue-query into commBuffer (rs.flowContinueQuery())
-    //     parse commBuffer up to QRYDTA (rs.flowContinueQuery())
-    //     copy query data from reply's commBuffer to our dataBuffer (this.copyQrydta())
-    //   }
-    // Returns true if the current row position is a valid row position.
-    // rename this to parse*()
-    protected boolean calculateColumnOffsetsForRow_(int rowIndex) throws SqlException, org.apache.derby.client.am.DisconnectException {
+    /**
+     * Calculate the column offsets for a row.
+     * <p>
+     * Pseudo-code:
+     * <ol>
+     * <li>parse thru the current row in dataBuffer computing column
+     * offsets</li>
+     * <li>if (we hit the super.lastValidBytePosition, ie. encounter
+     * partial row)
+     *   <ol>
+     *     <li>shift partial row bytes to beginning of dataBuffer
+     *     (this.shiftPartialRowToBeginning())</li>
+     *     <li>reset current row position (also done by
+     *     this.shiftPartialRowToBeginning())</li>
+     *     <li>send and recv continue-query into commBuffer
+     *     (rs.flowContinueQuery())</li>
+     *     <li>parse commBuffer up to QRYDTA
+     *     (rs.flowContinueQuery())</li>
+     *     <li>copy query data from reply's commBuffer to our
+     *     dataBuffer (this.copyQrydta())</li>
+     *   </ol>
+     * </ol>
+     *
+     * @param rowIndex row index
+     * @param allowServerFetch if true, allow fetching more data from
+     * server
+     * @return <code>true</code> if the current row position is a
+     * valid row position.
+     * @exception SqlException
+     * @exception DisconnectException
+     */
+    protected
+        boolean calculateColumnOffsetsForRow_(int rowIndex,
+                                              boolean allowServerFetch)
+        throws SqlException, DisconnectException
+    {
         int daNullIndicator = CodePoint.NULLDATA;
         int colNullIndicator = CodePoint.NULLDATA;
         int length;
@@ -117,8 +146,8 @@
                 throw new SqlException(netAgent_.logWriter_, netSqlca);
             } else {
                 if (sqlcode > 0) {
-                    if (sqlcode == 100) {
-                        allRowsReceivedFromServer_ = true;
+                    if (sqlcode == SqlCode.END_OF_DATA.getCode()) {
+                        setAllRowsReceivedFromServer(true);
                         if (netResultSet_ != null && netSqlca.containsSqlcax()) {
                             netResultSet_.setRowCountEvent(netSqlca.getRowCount(qrydscTypdef_));
                         }
@@ -146,7 +175,8 @@
         // since it's only resetting nextRowPosition_ to position_ and position_ will
         // not change again from this point.
 
-        if (allRowsReceivedFromServer_ && (position_ == lastValidBytePosition_)) {
+        if (allRowsReceivedFromServer() &&
+            (position_ == lastValidBytePosition_)) {
             markNextRowPosition();
             makeNextRowPositionCurrent();
             return false;
@@ -266,16 +296,19 @@
             columnDataComputedLength_ = columnDataComputedLength;
             isNull_ = columnDataIsNull;
 
-            if (!allRowsReceivedFromServer_) {
+            if (!allRowsReceivedFromServer()) {
                 calculateLobColumnPositionsForRow();
                 // Flow another CNTQRY if we are blocking, are using rtnextrow, and expect
                 // non-trivial EXTDTAs for forward only cursors.  Note we do not support
                 // EXTDTA retrieval for scrollable cursors.
                 // if qryrowset was sent on excsqlstt for a sp call, which is only the case
                 if (blocking_ && rtnextrow_ &&
-                        extdtaPositions_.size() > 0 && !netResultSet_.scrollable_) {
-                    if (!extdtaPositions_.isEmpty()) {
+                    !netResultSet_.scrollable_ &&
+                    !extdtaPositions_.isEmpty()) {
+                    if (allowServerFetch) {
                         netResultSet_.flowFetch();
+                    } else {
+                        return false;
                     }
                 }
             }
@@ -294,13 +327,29 @@
         // the flag for allRowsReceivedFromServer_ is set, we still want to continue to parse through
         // the data in the dataBuffer.
         // But in the case where fixed row protocol is used,
-        if (!blocking_ && allRowsReceivedFromServer_ && daNullIndicator == 0xFF) {
+        if (!blocking_ && allRowsReceivedFromServer() &&
+            daNullIndicator == 0xFF) {
             return false;
         } else {
             return true;
         }
     }
 
+    /**
+     * Scan the data buffer to see if end of data (SQL state 02000)
+     * has been received. This method should only be called when the
+     * cursor is being closed since the pointer to the current row can
+     * be modified.
+     *
+     * @exception SqlException
+     */
+    void scanDataBufferForEndOfData() throws SqlException {
+        while (!allRowsReceivedFromServer() &&
+               (position_ != lastValidBytePosition_)) {
+            stepNext(false);
+        }
+    }
+
     protected boolean isDataBufferNull() {
         if (dataBuffer_ == null) {
             return true;
@@ -1047,4 +1096,34 @@
         return (((fdocaLength_[index] >> 8) & 0xff) + 2) / 2;
     }
 
+    /**
+     * Set the value of value of allRowsReceivedFromServer_.
+     *
+     * @param b a <code>boolean</code> value indicating whether all
+     * rows are received from the server
+     */
+    public final void setAllRowsReceivedFromServer(boolean b) {
+        if (b && qryclsimpEnabled_) {
+            netResultSet_.markClosedOnServer();
+        }
+        super.setAllRowsReceivedFromServer(b);
+    }
+
+    /**
+     * Set a flag indicating whether QRYCLSIMP is enabled.
+     *
+     * @param flag true if QRYCLSIMP is enabled
+     */
+    final void setQryclsimpEnabled(boolean flag) {
+        qryclsimpEnabled_ = flag;
+    }
+
+    /**
+     * Check whether QRYCLSIMP is enabled on this cursor.
+     *
+     * @return true if QRYCLSIMP is enabled
+     */
+    final boolean getQryclsimpEnabled() {
+        return qryclsimpEnabled_;
+    }
 }

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=377367&r1=377366&r2=377367&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 Mon Feb 13 04:44:07 2006
@@ -28,6 +28,8 @@
 
     private final NetAgent netAgent_;
 
+    /** True if the server supports QRYCLSIMP. */
+    private boolean supportsQryclsimp_;
 
     public NetDatabaseMetaData(NetAgent netAgent, NetConnection netConnection) {
         // Consider setting product level during parse
@@ -61,17 +63,47 @@
     // Support for a specific server version can be set as follows. For example
     // if (productLevel_.greaterThanOrEqualTo(11,1,0))
     //  supportsTheBestThingEver = true
+    //
+    // WARNING WARNING WARNING !!!!
+    //
+    // If you define an instance variable of NetDatabaseMetaData that
+    // you want computeFeatureSet_() to compute, DO NOT assign an
+    // initial value to the variable in the
+    // declaration. NetDatabaseMetaData's constructor will invoke
+    // DatabaseMetaData's constructor, which then invokes
+    // computeFeatureSet_(). Initialization of instance variables in
+    // NetDatabaseMetaData will happen *after* the invocation of
+    // computeFeatureSet_() and will therefore overwrite the computed
+    // values. So, LEAVE INSTANCE VARIABLES UNINITIALIZED!
+    //
+    // 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)) {
+            supportsQryclsimp_ = true;
+        } else {
+            supportsQryclsimp_ = false;
+        }
     }
 
 
     public void setDefaultResultSetHoldability() {
         connection_.resultSetHoldability_ = org.apache.derby.jdbc.ClientDataSource.HOLD_CURSORS_OVER_COMMIT;
+    }
+
+    /**
+     * Check whether the server has full support for the QRYCLSIMP
+     * parameter in OPNQRY.
+     *
+     * @return true if QRYCLSIMP is fully supported
+     */
+    final boolean serverSupportsQryclsimp() {
+        return supportsQryclsimp_;
     }
 
 }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetResultSet.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetResultSet.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetResultSet.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetResultSet.java Mon Feb 13 04:44:07 2006
@@ -112,7 +112,7 @@
         // Parse all the rows received in the rowset
         // The index we are passing will keep track of which row in the rowset we are parsing
         // so we can reuse the columnDataPosition/Length/IsNull arrays.
-        while (netCursor_.calculateColumnOffsetsForRow_(row)) {
+        while (netCursor_.calculateColumnOffsetsForRow_(row, true)) {
             rowsReceivedInCurrentRowset_++;
             row++;
         }
@@ -124,10 +124,10 @@
         //    the end of data is returned or when an error occurs.  all successfully fetched rows
         //    are returned to the user.  the specific error is not returned until the next fetch.
         while (rowsReceivedInCurrentRowset_ != fetchSize_ &&
-                !netCursor_.allRowsReceivedFromServer_ && !isRowsetCursor_ &&
+                !netCursor_.allRowsReceivedFromServer() && !isRowsetCursor_ &&
                 sensitivity_ != sensitivity_sensitive_dynamic__) {
             flowFetchToCompleteRowset();
-            while (netCursor_.calculateColumnOffsetsForRow_(row)) {
+            while (netCursor_.calculateColumnOffsetsForRow_(row, true)) {
                 rowsReceivedInCurrentRowset_++;
                 row++;
             }
@@ -219,5 +219,20 @@
 
     public void readCursorClose_() throws SqlException {
         netAgent_.resultSetReply_.readCursorClose(this);
+    }
+
+    /**
+     * Method that is invoked by <code>closeX()</code> before the
+     * result set is actually being closed. If QRYCLSIMP is enabled on
+     * the cursor, scan data buffer for end of data (SQL state
+     * 02000). If end of data is received, the result set is closed on
+     * the server.
+     *
+     * @exception SqlException
+     */
+    protected void preClose_() throws SqlException {
+        if (netCursor_.getQryclsimpEnabled()) {
+            netCursor_.scanDataBufferForEndOfData();
+        }
     }
 }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetSqldta.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetSqldta.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetSqldta.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetSqldta.java Mon Feb 13 04:44:07 2006
@@ -31,10 +31,10 @@
     }
 
     public boolean next() throws org.apache.derby.client.am.SqlException {
-        if (allRowsReceivedFromServer_) {
+        if (allRowsReceivedFromServer()) {
             return false;
         } else {
-            allRowsReceivedFromServer_ = true;
+            setAllRowsReceivedFromServer(true);
             return true;
         }
     }
@@ -128,7 +128,7 @@
             }
         }
 
-        if (!allRowsReceivedFromServer_) {
+        if (!allRowsReceivedFromServer()) {
             calculateLobColumnPositionsForRow();
         }
 

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java Mon Feb 13 04:44:07 2006
@@ -397,7 +397,7 @@
     protected NetResultSet parseResultSetCursor(StatementCallbackInterface statementI,
                                                 Section section) throws DisconnectException {
         // The first item returne is an OPNQRYRM.
-        NetResultSet netResultSet = parseOPNQRYRM(statementI);
+        NetResultSet netResultSet = parseOPNQRYRM(statementI, false);
 
         // The next to be returned is an OBJDSS so check for any TYPDEF overrides.
         int peekCP = parseTypdefsOrMgrlvlovrs();
@@ -439,7 +439,7 @@
     }
 
     protected void parseOpenQuery(StatementCallbackInterface statementI) throws DisconnectException {
-        NetResultSet netResultSet = parseOPNQRYRM(statementI);
+        NetResultSet netResultSet = parseOPNQRYRM(statementI, true);
 
         NetSqlca sqlca = null;
         int peekCP = peekCodePoint();
@@ -694,13 +694,26 @@
 
     //-----------------------------parse DDM Reply Messages-----------------------
 
-    // Open Query Complete Reply Message indicates to the requester that
-    // an OPNQRY or EXCSQLSTT command completed normally and that the query
-    // process has been initiated.  It also indicates the type of query protocol
-    // and cursor used for the query.
-    // When an EXCSQLSTT contains an SQL statement that invokes a stored procedure,
-    // and the procedure completes, an OPNQRYRM is returned for each answer set.
-    protected NetResultSet parseOPNQRYRM(StatementCallbackInterface statementI) throws DisconnectException {
+    /**
+     * Open Query Complete Reply Message indicates to the requester
+     * that an OPNQRY or EXCSQLSTT command completed normally and that
+     * the query process has been initiated.  It also indicates the
+     * type of query protocol and cursor used for the query.
+     * <p>
+     * When an EXCSQLSTT contains an SQL statement that invokes a
+     * stored procedure, and the procedure completes, an OPNQRYRM is
+     * returned for each answer set.
+     *
+     * @param statementI statement callback interface
+     * @param isOPNQRYreply If true, parse a reply to an OPNQRY
+     * command. Otherwise, parse a reply to an EXCSQLSTT command.
+     * @return a <code>NetResultSet</code> value
+     * @exception DisconnectException
+     */
+    protected NetResultSet parseOPNQRYRM(StatementCallbackInterface statementI,
+                                         boolean isOPNQRYreply)
+        throws DisconnectException
+    {
         // these need to be initialized to the correct default values.
         int svrcod = CodePoint.SVRCOD_INFO;
         boolean svrcodReceived = false;
@@ -851,6 +864,13 @@
                     calculateResultSetConcurrency(qryattupd, statement.resultSetConcurrency_),
                     calculateResultSetHoldability(sqlcsrhld));
         }
+
+        // QRYCLSIMP only applies to OPNQRY, not EXCSQLSTT
+        final boolean qryclsimp =
+            isOPNQRYreply &&
+            (rs.resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) &&
+            netAgent_.netConnection_.serverSupportsQryclsimp();
+        rs.netCursor_.setQryclsimpEnabled(qryclsimp);
 
         return rs;
     }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementRequest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementRequest.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementRequest.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementRequest.java Mon Feb 13 04:44:07 2006
@@ -339,6 +339,13 @@
             buildQRYROWSET(fetchSize);
         }
 
+        // Tell the server to close forward-only result sets
+        // implicitly when they are exhausted. The server will ignore
+        // this parameter if the result set is scrollable.
+        if (netAgent_.netConnection_.serverSupportsQryclsimp()) {
+            buildQRYCLSIMP();
+        }
+
         updateLengthBytes();  // opnqry is complete
     }
 
@@ -1448,6 +1455,14 @@
         }
     }
 
+    /**
+     * Build QRYCLSIMP (Query Close Implicit). Query Close Implicit
+     * controls whether the target server implicitly closes a
+     * non-scrollable query upon end of data (SQLSTATE 02000).
+     */
+    private void buildQRYCLSIMP() {
+        writeScalar1Byte(CodePoint.QRYCLSIMP, CodePoint.QRYCLSIMP_YES);
+    }
 
     // helper method to buildFDODTA to build the actual data length
     private void setFDODTALobLength(int[][] protocolTypesAndLengths, int i, long dataLength) throws SqlException {

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java Mon Feb 13 04:44:07 2006
@@ -133,6 +133,17 @@
 	}
 
 	/**
+	 * Check if the client expects QRYCLSIMP to be supported when the
+	 * protocol is LMTBLKPRC.
+	 *
+	 * @return <code>true</code> if QRYCLSIMP is supported for
+	 * LMTBLKPRC
+	 */
+	protected final boolean supportsQryclsimpForLmtblkprc() {
+		return clientType == DNC_CLIENT;
+	}
+
+	/**
 	 * Check if provided JCC version level is greaterThanOrEqualTo current level
 	 *
 	 * @param vLevel	Version level

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePointNameTable.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePointNameTable.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePointNameTable.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePointNameTable.java Mon Feb 13 04:44:07 2006
@@ -65,6 +65,7 @@
     put (new Integer (CodePoint.EXCSQLSET), "EXCSQLSET");
     put (new Integer (CodePoint.EXCSQLSTT), "EXCSQLSTT");
     put (new Integer (CodePoint.EXTNAM), "EXTNAM");
+    put (new Integer (CodePoint.FRCFIXROW), "FRCFIXROW");
     put (new Integer (CodePoint.MAXBLKEXT), "MAXBLKEXT");
     put (new Integer (CodePoint.MAXRSLCNT), "MAXRSLCNT");
     put (new Integer (CodePoint.MGRDEPRM), "MGRDEPRM");
@@ -93,6 +94,7 @@
     put (new Integer (CodePoint.QRYBLKCTL), "QRYBLKCTL");
     put (new Integer (CodePoint.QRYBLKRST), "QRYBLKRST");
     put (new Integer (CodePoint.QRYBLKSZ), "QRYBLKSZ");
+    put (new Integer (CodePoint.QRYCLSIMP), "QRYCLSIMP");
     put (new Integer (CodePoint.QRYCLSRLS), "QRYCLSRLS");
     put (new Integer (CodePoint.QRYDSC), "QRYDSC");
     put (new Integer (CodePoint.QRYDTA), "QRYDTA");

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Mon Feb 13 04:44:07 2006
@@ -6043,9 +6043,12 @@
 		if (! sentExtData)
 			writer.endDdmAndDss();
 
-		if( (!stmt.hasdata()) &&
-			stmt.isRSCloseImplicit()) {
-			stmt.rsClose();
+		if (!stmt.hasdata()) {
+			final boolean qryclsOnLmtblkprc =
+				appRequester.supportsQryclsimpForLmtblkprc();
+			if (stmt.isRSCloseImplicit(qryclsOnLmtblkprc)) {
+				stmt.rsClose();
+			}
 		}
 	}
 
@@ -6416,8 +6419,9 @@
 			}
 			else  // non-scrollable cursor
 			{
-				if (stmt.isRSCloseImplicit())
-				{
+				final boolean qryclsOnLmtblkprc =
+					appRequester.supportsQryclsimpForLmtblkprc();
+				if (stmt.isRSCloseImplicit(qryclsOnLmtblkprc)) {
 					stmt.rsClose();
 					stmt.rsSuspend();
 				}

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAResultSet.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAResultSet.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAResultSet.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAResultSet.java Mon Feb 13 04:44:07 2006
@@ -59,7 +59,7 @@
 	protected int blksize;				// Query block size
 	protected int maxblkext;			// Maximum number of extra blocks
 	protected int outovropt;			// Output Override option
-	private int qryclsimp; // Implicit Query Close Setting
+	protected int qryclsimp;			// Implicit Query Close Setting
 	protected boolean qryrelscr;		// Query relative scrolling
 	protected long qryrownbr;			// Query row number
 	protected boolean qryrfrtbl;		// Query refresh answer set table
@@ -92,6 +92,10 @@
 	protected DRDAResultSet()
 	{
 		state = NOT_OPENED;
+		// Initialize qryclsimp to NO. Only result sets requested by
+		// an OPNQRY command should be implicitly closed. OPNQRY will
+		// set qryclsimp later in setOPNQRYOptions().
+		qryclsimp = CodePoint.QRYCLSIMP_NO;
 	}
 
 	/**
@@ -487,19 +491,6 @@
 				return "UNKNOWN_STATE";
 		}
 
-	}
-	
-	/**
-	 * Method to decide weather the ResultSet should be closed implicitly.
-	 * When the protocol type is Limited Block Query Protocol we should not
-	 * close implicitly even if qryclsimp is set to YES.
-	 * 
-	 * @return close implicit boolean
-	 * @throws SQLException
-	 */
-	boolean isRSCloseImplicit() throws SQLException {
-		return qryclsimp == CodePoint.QRYCLSIMP_YES && 
-			getQryprctyp() != CodePoint.LMTBLKPRC;
 	}
 	
 	/**

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=377367&r1=377366&r2=377367&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 Mon Feb 13 04:44:07 2006
@@ -1623,14 +1623,23 @@
 	}
 	
 	/**
-	 * Delegation method to call DRDAResultSet.isRSCloseImplicit()
-	 * 
-	 * @see DRDAResultSet#isRSCloseImplicit()
+	 * Method to decide whether the ResultSet should be closed
+	 * implicitly based on the QRYCLSIMP value sent from the
+	 * client. Only forward-only result sets should be implicitly
+	 * closed. Some clients do not expect result sets to be closed
+	 * implicitly if the protocol is LMTBLKPRC.
+	 *
+	 * @param lmtblkprcOK <code>true</code> if the client expects
+	 * QRYCLSIMP to be respected for the LMTBLKPRC protocol
 	 * @return implicit close boolean
-	 * @throws SQLException
+	 * @exception SQLException
 	 */
-	boolean isRSCloseImplicit() throws SQLException {
-		return currentDrdaRs.isRSCloseImplicit();
+	boolean isRSCloseImplicit(boolean lmtblkprcOK) throws SQLException {
+		return
+			(currentDrdaRs.qryclsimp == CodePoint.QRYCLSIMP_YES) &&
+			!isScrollable() &&
+			(lmtblkprcOK ||
+			 (currentDrdaRs.getQryprctyp() != CodePoint.LMTBLKPRC));
 	}
 }
 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/forupdate.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/forupdate.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/forupdate.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/forupdate.out Mon Feb 13 04:44:07 2006
@@ -121,18 +121,22 @@
 ij> -- unions are not updatable
 select * from t1 union all select * from t1 for update;
 ERROR 42Y90: FOR UPDATE is not permitted in this type of statement.  
+ij> insert into t1 (i) values (1);
+1 row inserted/updated/deleted
 ij> -- . table with/without correlation name
 ----- the idea is that the delete is against the table name, not the correlation name
 ----- we've already seen the without correlation name case in previous tests
 get cursor c4 as 'select i from t1 s1 for update';
 ij> next c4;
-No current row
+I          
+-----------
+1          
 ij> -- this will get a target table mismatch error, it uses the correlation name:
 delete from s1 where current of c4;
-ERROR (no SQLState): Invalid cursor name "C4" in the Update/Delete statement.
-ij> -- this will compile and get a 'no current row' error, it uses the table name:
+ERROR 42X28: Delete table 'S1' is not target of cursor 'SQL_CURSH200C1'.
+ij> -- this will compile and succeed, it uses the table name:
 delete from t1 where current of c4;
-ERROR (no SQLState): Invalid cursor name "C4" in the Update/Delete statement.
+1 row inserted/updated/deleted
 ij> close c4;
 ij> -- . list columns in order same/different from appearance in table
 ----- the columns are 'found' regardless of their order.

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/holdCursorIJ.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/holdCursorIJ.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/holdCursorIJ.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/holdCursorIJ.out Mon Feb 13 04:44:07 2006
@@ -94,13 +94,16 @@
 -----
 1 |1          
 ij> -- wont' be able to drop table because of cursors jdk1 and jdk4
+-- in DerbyNetClient, cursor is closed on server and DROP TABLE succeeds
 drop table t1;
 ERROR X0X95: Operation 'DROP TABLE' cannot be performed on object 'T1' because there is an open ResultSet dependent on that object.
 ij> commit;
 ij> -- drop table still won't work because jdk4 is still open after commit
+-- in DerbyNetClient, the table is already dropped
 drop table t1;
 ERROR X0X95: Operation 'DROP TABLE' cannot be performed on object 'T1' because there is an open ResultSet dependent on that object.
 ij> -- close cursor jdk4 and try then deleting the table
+-- in DerbyNetClient, the table is already dropped
 close jdk4;
 ij> drop table t1;
 0 rows inserted/updated/deleted
@@ -126,10 +129,12 @@
 -----
 1 |1          
 ij> -- try to change the isolation level. will give error because of jdk1 and jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set current isolation RR;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> commit;
 ij> -- attempt to change isolation level should give error because of jdk4 hold cursor
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation = REPEATABLE READ;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> -- close jdk4 and then should be able to change isolation
@@ -151,9 +156,11 @@
 -----
 1 |1          
 ij> -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation RS;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation UR;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> close jdk4;

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out Mon Feb 13 04:44:07 2006
@@ -937,3 +937,4 @@
 CALL LITT.TY_VARCHAR ('12.34', ?)=>12.34<
 JIRA-491 Successful.
 JIRA-492 successful -- no hang!
+testImplicitClose(): PASSED

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out Mon Feb 13 04:44:07 2006
@@ -56,7 +56,7 @@
 ij> -- the delete will get a 'cursor not updatable' execution error, but won't get
 ----- a compile time error
 delete from t1 where current of c1;
-ERROR 42X23: Cursor SQL_CURLH000C1 is not updatable.
+ERROR 42X30: Cursor 'SQL_CURLH000C1' not found. Verify that autocommit is OFF.
 ij> close c1;
 ij> -- . read only for read only cursor spec
 ----- we know because the delete is refused with a 'cursor not updatable' message
@@ -121,18 +121,22 @@
 ij> -- unions are not updatable
 select * from t1 union all select * from t1 for update;
 ERROR 42Y90: FOR UPDATE is not permitted in this type of statement.  
+ij> insert into t1 (i) values (1);
+1 row inserted/updated/deleted
 ij> -- . table with/without correlation name
 ----- the idea is that the delete is against the table name, not the correlation name
 ----- we've already seen the without correlation name case in previous tests
 get cursor c4 as 'select i from t1 s1 for update';
 ij> next c4;
-No current row
+I          
+-----
+1          
 ij> -- this will get a target table mismatch error, it uses the correlation name:
 delete from s1 where current of c4;
 ERROR 42X28: Delete table 'S1' is not target of cursor 'SQL_CURLH000C1'.
-ij> -- this will compile and get a 'no current row' error, it uses the table name:
+ij> -- this will compile and succeed, it uses the table name:
 delete from t1 where current of c4;
-ERROR XCL08: Cursor 'SQL_CURLH000C1' is not on a row.
+1 row inserted/updated/deleted
 ij> close c4;
 ij> -- . list columns in order same/different from appearance in table
 ----- the columns are 'found' regardless of their order.

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorIJ.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorIJ.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorIJ.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorIJ.out Mon Feb 13 04:44:07 2006
@@ -94,16 +94,19 @@
 -----
 1 |1          
 ij> -- wont' be able to drop table because of cursors jdk1 and jdk4
+-- in DerbyNetClient, cursor is closed on server and DROP TABLE succeeds
 drop table t1;
-ERROR X0X95: Operation 'DROP TABLE' cannot be performed on object 'T1' because there is an open ResultSet dependent on that object.
+0 rows inserted/updated/deleted
 ij> commit;
 ij> -- drop table still won't work because jdk4 is still open after commit
+-- in DerbyNetClient, the table is already dropped
 drop table t1;
-ERROR X0X95: Operation 'DROP TABLE' cannot be performed on object 'T1' because there is an open ResultSet dependent on that object.
+ERROR 42Y55: 'DROP TABLE' cannot be performed on 'T1' because it does not exist.
 ij> -- close cursor jdk4 and try then deleting the table
+-- in DerbyNetClient, the table is already dropped
 close jdk4;
 ij> drop table t1;
-0 rows inserted/updated/deleted
+ERROR 42Y55: 'DROP TABLE' cannot be performed on 'T1' because it does not exist.
 ij> -- clean up.
 close jdk1;
 ij> -- recreate and populate the table for next test
@@ -126,12 +129,14 @@
 -----
 1 |1          
 ij> -- try to change the isolation level. will give error because of jdk1 and jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set current isolation RR;
-ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
+0 rows inserted/updated/deleted
 ij> commit;
 ij> -- attempt to change isolation level should give error because of jdk4 hold cursor
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation = REPEATABLE READ;
-ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
+0 rows inserted/updated/deleted
 ij> -- close jdk4 and then should be able to change isolation
 close jdk4;
 ij> set isolation to serializable;
@@ -151,11 +156,13 @@
 -----
 1 |1          
 ij> -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation RS;
-ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
+0 rows inserted/updated/deleted
 ij> -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation UR;
-ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
+0 rows inserted/updated/deleted
 ij> close jdk4;
 ij> -- should be able to change the isolation now
 set isolation READ UNCOMMITTED;

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorJava.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorJava.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorJava.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/holdCursorJava.out Mon Feb 13 04:44:07 2006
@@ -48,3 +48,4 @@
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 PASS: Can't change isolation if they are open cursor
 Isolation level change test over
+testCloseCursor()

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/procedure.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/procedure.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/procedure.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/procedure.out Mon Feb 13 04:44:07 2006
@@ -939,3 +939,4 @@
 MultipleRSNoCommit: PASS. 
 JIRA-491 Successful.
 JIRA-492 successful -- no hang!
+testImplicitClose(): PASSED

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/updatableResultSet.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/updatableResultSet.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/updatableResultSet.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/updatableResultSet.out Mon Feb 13 04:44:07 2006
@@ -67,8 +67,8 @@
 SQL State : null
 Got expected exception Invalid operation to update at current cursor position
 ResultSet is positioned after the last row. attempt to deleteRow at this point should fail!
-SQL State : XCL08
-Got expected exception Cursor '<xxx-cursor-name-xxx>' is not on a row.
+SQL State : XCL07
+Got expected exception Cursor '<xxx-cursor-name-xxx>' is closed. Verify that autocommit is OFF.
 ResultSet is positioned after the last row. attempt to updateRow at this point should fail!
 SQL State : null
 Got expected exception Invalid operation to update at current cursor position
@@ -396,8 +396,8 @@
 Positive Test13a - Another test case for delete trigger
 column 1 on this row is 1
 this delete row will fire the delete trigger which will delete all the rows from the table and from the resultset
-SQL State : XCL08
-Got expected exception Cursor '<xxx-cursor-name-xxx>' is not on a row.
+SQL State : XCL07
+Got expected exception Cursor '<xxx-cursor-name-xxx>' is closed. Verify that autocommit is OFF.
 Verify that delete trigger got fired by verifying the row count to be 0 in table1WithTriggers
 	 1
 	 -
@@ -430,8 +430,8 @@
 	{e4,e3}
 column 1 on this row is e1
 this delete row will cause the delete cascade constraint to delete all the rows from the table and from the resultset
-SQL State : XCL08
-Got expected exception Cursor '<xxx-cursor-name-xxx>' is not on a row.
+SQL State : XCL07
+Got expected exception Cursor '<xxx-cursor-name-xxx>' is closed. Verify that autocommit is OFF.
 Verify that delete trigger got fired by verifying the row count to be 0 in selfReferencingT1
 	 1
 	 -

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out Mon Feb 13 04:44:07 2006
@@ -939,3 +939,4 @@
 MultipleRSNoCommit: PASS. 
 JIRA-491 Successful.
 JIRA-492 successful -- no hang!
+testImplicitClose(): PASSED

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/updatableResultSet.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/updatableResultSet.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/updatableResultSet.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/updatableResultSet.out Mon Feb 13 04:44:07 2006
@@ -67,8 +67,8 @@
 SQL State : null
 Got expected exception Invalid operation to update at current cursor position
 ResultSet is positioned after the last row. attempt to deleteRow at this point should fail!
-SQL State : XCL08
-Got expected exception Cursor '<xxx-cursor-name-xxx>' is not on a row.
+SQL State : XCL07
+Got expected exception Cursor '<xxx-cursor-name-xxx>' is closed. Verify that autocommit is OFF.
 ResultSet is positioned after the last row. attempt to updateRow at this point should fail!
 SQL State : null
 Got expected exception Invalid operation to update at current cursor position
@@ -396,8 +396,8 @@
 Positive Test13a - Another test case for delete trigger
 column 1 on this row is 1
 this delete row will fire the delete trigger which will delete all the rows from the table and from the resultset
-SQL State : XCL08
-Got expected exception Cursor '<xxx-cursor-name-xxx>' is not on a row.
+SQL State : XCL07
+Got expected exception Cursor '<xxx-cursor-name-xxx>' is closed. Verify that autocommit is OFF.
 Verify that delete trigger got fired by verifying the row count to be 0 in table1WithTriggers
 	 1
 	 -
@@ -430,8 +430,8 @@
 	{e4,e3}
 column 1 on this row is e1
 this delete row will cause the delete cascade constraint to delete all the rows from the table and from the resultset
-SQL State : XCL08
-Got expected exception Cursor '<xxx-cursor-name-xxx>' is not on a row.
+SQL State : XCL07
+Got expected exception Cursor '<xxx-cursor-name-xxx>' is closed. Verify that autocommit is OFF.
 Verify that delete trigger got fired by verifying the row count to be 0 in selfReferencingT1
 	 1
 	 -

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/forupdate.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/forupdate.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/forupdate.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/forupdate.out Mon Feb 13 04:44:07 2006
@@ -121,18 +121,22 @@
 ij> -- unions are not updatable
 select * from t1 union all select * from t1 for update;
 ERROR 42Y90: FOR UPDATE is not permitted in this type of statement.  
+ij> insert into t1 (i) values (1);
+1 row inserted/updated/deleted
 ij> -- . table with/without correlation name
 -- the idea is that the delete is against the table name, not the correlation name
 -- we've already seen the without correlation name case in previous tests
 get cursor c4 as 'select i from t1 s1 for update';
 ij> next c4;
-No current row
+I          
+-----------
+1          
 ij> -- this will get a target table mismatch error, it uses the correlation name:
 delete from s1 where current of c4;
 ERROR 42X28: Delete table 'S1' is not target of cursor 'C4'.
-ij> -- this will compile and get a 'no current row' error, it uses the table name:
+ij> -- this will compile and succeed, it uses the table name:
 delete from t1 where current of c4;
-ERROR XCL08: Cursor 'C4' is not on a row.
+1 row inserted/updated/deleted
 ij> close c4;
 ij> -- . list columns in order same/different from appearance in table
 -- the columns are 'found' regardless of their order.

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorIJ.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorIJ.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorIJ.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorIJ.out Mon Feb 13 04:44:07 2006
@@ -94,13 +94,16 @@
 -----------------------
 1          |1          
 ij> -- wont' be able to drop table because of cursors jdk1 and jdk4
+-- in DerbyNetClient, cursor is closed on server and DROP TABLE succeeds
 drop table t1;
 ERROR X0X95: Operation 'DROP TABLE' cannot be performed on object 'T1' because there is an open ResultSet dependent on that object.
 ij> commit;
 ij> -- drop table still won't work because jdk4 is still open after commit
+-- in DerbyNetClient, the table is already dropped
 drop table t1;
 ERROR X0X95: Operation 'DROP TABLE' cannot be performed on object 'T1' because there is an open ResultSet dependent on that object.
 ij> -- close cursor jdk4 and try then deleting the table
+-- in DerbyNetClient, the table is already dropped
 close jdk4;
 ij> drop table t1;
 0 rows inserted/updated/deleted
@@ -126,10 +129,12 @@
 -----------------------
 1          |1          
 ij> -- try to change the isolation level. will give error because of jdk1 and jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set current isolation RR;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> commit;
 ij> -- attempt to change isolation level should give error because of jdk4 hold cursor
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation = REPEATABLE READ;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> -- close jdk4 and then should be able to change isolation
@@ -151,9 +156,11 @@
 -----------------------
 1          |1          
 ij> -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation RS;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation UR;
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 ij> close jdk4;

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorJava.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorJava.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorJava.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/holdCursorJava.out Mon Feb 13 04:44:07 2006
@@ -48,3 +48,4 @@
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 PASS: Can't change isolation if they are open cursor
 Isolation level change test over
+testCloseCursor()

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/j9_foundation/holdCursorJava.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/j9_foundation/holdCursorJava.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/j9_foundation/holdCursorJava.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/j9_foundation/holdCursorJava.out Mon Feb 13 04:44:07 2006
@@ -10,3 +10,4 @@
 ERROR X0X03: Invalid transaction state - held cursor requires same isolation level
 PASS: Can't change isolation if they are open cursor
 Isolation level change test over
+testCloseCursor()

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out Mon Feb 13 04:44:07 2006
@@ -1015,3 +1015,4 @@
 MultipleRSNoCommit: PASS. 
 JIRA-491 Successful.
 JIRA-492 successful -- no hang!
+testImplicitClose(): PASSED

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/testProtocol.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/testProtocol.out?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/testProtocol.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/testProtocol.out Mon Feb 13 04:44:07 2006
@@ -289,3 +289,5 @@
 Test for missing SQLSTT in EXCSQLSET - PKGNAMCT is ignored
 PASSED
 PASSED
+Test explicitly closing implicitly closed cursor
+PASSED

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/protocol.tests
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/protocol.tests?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/protocol.tests (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/protocol.tests Mon Feb 13 04:44:07 2006
@@ -3186,5 +3186,101 @@
 skipDss // ENDUOWRM
 skipDss //SQLCARD for commit
 endTest
+//
+DISPLAY "Test explicitly closing implicitly closed cursor"
+include connect.inc
+// prepare statement
+createDssRequest
+startDdm PRPSQLSTT
+startDdm PKGNAMCSN
+writePaddedString "test" 18
+writePaddedString "rdbcolid" 18
+writePaddedString "pkgid"  18
+writeBytes "0x0101010101010101"
+writeShort 1
+endDdm
+endDdm
+endDss
+createDssObject 
+startDdm SQLSTT
+writeByte 0	// null indicator
+writeEncodedLDString "values(1)" "UTF-8" 4
+writeByte 255 // null indicator
+endDdm
+endDss
+flush
+checkSQLCard 0 "     "
+// execute query
+createDssRequest
+startDdm OPNQRY
+startDdm PKGNAMCSN
+writePaddedString "test" 18
+writePaddedString "rdbcolid" 18
+writePaddedString "pkgid"  18
+writeBytes "0x0101010101010101"
+writeShort 1
+endDdm
+writeScalar1Byte QRYCLSIMP 1
+startDdm QRYBLKSZ
+writeInt 32767
+endDdm
+writeScalar2Bytes QRYBLKCTL FRCFIXROW
+endDdm
+endDss
+flush
+readReplyDss
+readLengthAndCodepoint OPNQRYRM
+skipBytes
+readReplyDss
+readLengthAndCodepoint QRYDSC
+skipBytes
+// fetch data
+createDssRequest
+startDdm CNTQRY
+startDdm PKGNAMCSN
+writePaddedString "test" 18
+writePaddedString "rdbcolid" 18
+writePaddedString "pkgid"  18
+writeBytes "0x0101010101010101"
+writeShort 1
+endDdm
+startDdm QRYBLKSZ
+writeInt 32767
+endDdm
+startDdm QRYINSID
+writeInt 0
+writeInt 1
+endDdm
+endDdm
+endDss
+flush
+readReplyDss
+readLengthAndCodepoint QRYDTA
+skipBytes
+// all rows are fetched, cursor is implicitly closed on server
+// close result set explicitly
+createDssRequest
+startDdm CLSQRY
+startDdm PKGNAMCSN
+writePaddedString "test" 18
+writePaddedString "rdbcolid" 18
+writePaddedString "pkgid"  18
+writeBytes "0x0101010101010101"
+writeShort 1
+endDdm
+startDdm QRYINSID
+writeInt 0
+writeInt 1
+endDdm
+endDdm
+endDss
+flush
+// DRDA says QRYNOPRM is to be expected here
+//readReplyDss
+//readLengthAndCodepoint QRYNOPRM
+// but JCC expects SQLCARD and we're nice guys...
+checkSQLCard 0 "     "
+endTest
+//
 completeTest
 //

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/setTransactionIsolation.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/setTransactionIsolation.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/setTransactionIsolation.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/setTransactionIsolation.java Mon Feb 13 04:44:07 2006
@@ -83,9 +83,27 @@
 
 
     System.out.println("Creating table...");
-    stmt.executeUpdate( "CREATE TABLE TAB1 (c11 int, c12 int)" );
-    stmt.executeUpdate("INSERT INTO TAB1 VALUES(1,1)");
-    stmt.executeUpdate("INSERT INTO TAB1 VALUES(2,1)");
+    final int stringLength = 400;
+    stmt.executeUpdate("CREATE TABLE TAB1 (c11 int, " +
+                       "c12 varchar(" + stringLength + "))");
+    PreparedStatement insertStmt =
+        conn.prepareStatement("INSERT INTO TAB1 VALUES(?,?)");
+    // We need to ensure that there is more data in the table than the
+    // client can fetch in one message (about 32K). Otherwise, the
+    // cursor might be closed on the server and we are not testing the
+    // same thing in embedded mode and client/server mode.
+    final int rows = 40000 / stringLength;
+    StringBuffer buff = new StringBuffer(stringLength);
+    for (int i = 0; i < stringLength; i++) {
+        buff.append(" ");
+    }
+    for (int i = 1; i <= rows; i++) {
+        insertStmt.setInt(1, i);
+        insertStmt.setString(2, buff.toString());
+        insertStmt.executeUpdate();
+    }
+    insertStmt.close();
+
 	stmt.execute("create table t1(I int, B char(15))");
 	stmt.execute("create table t1copy(I int, B char(15))");
 	

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forupdate.sql
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forupdate.sql?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forupdate.sql (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forupdate.sql Mon Feb 13 04:44:07 2006
@@ -105,6 +105,7 @@
 -- unions are not updatable
 select * from t1 union all select * from t1 for update;
 
+insert into t1 (i) values (1);
 -- . table with/without correlation name
 -- the idea is that the delete is against the table name, not the correlation name
 -- we've already seen the without correlation name case in previous tests
@@ -112,7 +113,7 @@
 next c4;
 -- this will get a target table mismatch error, it uses the correlation name:
 delete from s1 where current of c4;
--- this will compile and get a 'no current row' error, it uses the table name:
+-- this will compile and succeed, it uses the table name:
 delete from t1 where current of c4;
 close c4;
 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorIJ.sql
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorIJ.sql?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorIJ.sql (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorIJ.sql Mon Feb 13 04:44:07 2006
@@ -73,13 +73,16 @@
 next jdk1;
 next jdk4;
 -- wont' be able to drop table because of cursors jdk1 and jdk4
+-- in DerbyNetClient, cursor is closed on server and DROP TABLE succeeds
 drop table t1;
 commit;
 
 -- drop table still won't work because jdk4 is still open after commit
+-- in DerbyNetClient, the table is already dropped
 drop table t1;
 
 -- close cursor jdk4 and try then deleting the table
+-- in DerbyNetClient, the table is already dropped
 close jdk4;
 drop table t1;
 
@@ -99,11 +102,13 @@
 next jdk4;
 
 -- try to change the isolation level. will give error because of jdk1 and jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set current isolation RR;
 
 commit;
 
 -- attempt to change isolation level should give error because of jdk4 hold cursor
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation = REPEATABLE READ;
 
 -- close jdk4 and then should be able to change isolation
@@ -120,8 +125,10 @@
 next jdk4;
 next jdk1;
 -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation RS;
 -- following should fail because of cursor jdk4
+-- no error in DerbyNetClient because cursor is closed on server
 set isolation UR;
 close jdk4;
 -- should be able to change the isolation now

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorJava.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorJava.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorJava.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/holdCursorJava.java Mon Feb 13 04:44:07 2006
@@ -76,6 +76,8 @@
     
 		testHoldCursorOnMultiTableQuery(conn);
 		testIsolationLevelChange(conn);
+		testCloseCursor(conn);
+		testDropTable(conn);
 
 		conn.rollback();
                 conn.setAutoCommit(true);
@@ -100,9 +102,26 @@
     TestUtil.cleanUpTest(stmt, databaseObjects);
 
     System.out.println("Creating table...");
-    stmt.executeUpdate( "CREATE TABLE T1 (c11 int, c12 int)" );
-    stmt.executeUpdate("INSERT INTO T1 VALUES(1,1)");
-    stmt.executeUpdate("INSERT INTO T1 VALUES(2,1)");
+    final int stringLength = 400;
+    stmt.executeUpdate("CREATE TABLE T1 (c11 int, c12 int, junk varchar(" +
+                       stringLength + "))");
+    PreparedStatement insertStmt =
+        conn.prepareStatement("INSERT INTO T1 VALUES(?,1,?)");
+    // We need to ensure that there is more data in the table than the
+    // client can fetch in one message (about 32K). Otherwise, the
+    // cursor might be closed on the server and we are not testing the
+    // same thing in embedded mode and client/server mode.
+    final int rows = 40000 / stringLength;
+    StringBuffer buff = new StringBuffer(stringLength);
+    for (int i = 0; i < stringLength; i++) {
+        buff.append(" ");
+    }
+    for (int i = 1; i <= rows; i++) {
+        insertStmt.setInt(1, i);
+        insertStmt.setString(2, buff.toString());
+        insertStmt.executeUpdate();
+    }
+    insertStmt.close();
     stmt.executeUpdate( "CREATE TABLE T2 (c21 int, c22 int)" );
     stmt.executeUpdate("INSERT INTO T2 VALUES(1,1)");
     stmt.executeUpdate("INSERT INTO T2 VALUES(1,2)");
@@ -242,6 +261,56 @@
 	conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
   }
 
+    /**
+     * Test that drop table cannot be performed when there is an open
+     * cursor on that table.
+     *
+     * @param conn a <code>Connection</code> object
+     * @exception SQLException if an error occurs
+     */
+    private static void testDropTable(Connection conn) throws SQLException {
+        conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
+        final String dropTable = "DROP TABLE T1";
+        Statement stmt1 = conn.createStatement();
+        Statement stmt2 = conn.createStatement();
+        ResultSet rs = stmt1.executeQuery("SELECT * FROM T1");
+        rs.next();
+
+        // dropping t1 should fail because there is an open cursor on t1
+        boolean ok = false;
+        try {
+            stmt2.executeUpdate(dropTable);
+        } catch (SQLException sqle) {
+            ok = true;
+        }
+        if (!ok) {
+            System.out.println("FAIL: Expected DROP TABLE to fail " +
+                               "because of open cursor.");
+        }
+
+        conn.commit();
+
+        // cursors are held over commit, so dropping should still fail
+        ok = false;
+        try {
+            stmt2.executeUpdate(dropTable);
+        } catch (SQLException sqle) {
+            ok = true;
+        }
+        if (!ok) {
+            System.out.println("FAIL: Expected DROP TABLE to fail " +
+                               "because of held cursor.");
+        }
+
+        rs.close();
+
+        // cursor is closed, so this one should succeed
+        stmt2.executeUpdate(dropTable);
+        stmt1.close();
+        stmt2.close();
+        conn.rollback();
+    }
+
 	//set connection holdability and test holdability of statements inside and outside procedures
 	//test that holdability of statements always overrides holdability of connection
 	private static void testHoldability(Connection conn,int holdability) throws SQLException{
@@ -303,6 +372,36 @@
 		
 		cs1.close();
 		cs2.close();
+	}
+
+	// DERBY-821: Test that cursors are closed when close() is
+	// called. Since the network server implicitly closes a
+	// forward-only result set when all rows are read, the call to
+	// close() might be a no-op.
+	private static void testCloseCursor(Connection conn)
+		throws SQLException
+	{
+		System.out.println("\ntestCloseCursor()\n");
+		// Run this test on one large table (T1) where the network
+		// server won't close the cursor implicitly, and on one small
+		// table (T2) where the network server will close the cursor
+		// implicitly.
+		final String[] tables = { "T1", "T2" };
+		Statement stmt1 = conn.createStatement();
+		Statement stmt2 = conn.createStatement();
+		for (int i = 0; i < tables.length; i++) {
+			String table = tables[i];
+			ResultSet rs = stmt1.executeQuery("SELECT * FROM " + table);
+			rs.next();
+			rs.close();
+			// Cursor is closed, so this should succeed. If the cursor
+			// is open, it will fail because an table cannot be
+			// dropped when there are open cursors depending on it.
+			stmt2.executeUpdate("DROP TABLE " + table);
+		}
+		stmt1.close();
+		stmt2.close();
+		conn.rollback();
 	}
 	
 	//check if resultset is accessible 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java Mon Feb 13 04:44:07 2006
@@ -88,6 +88,7 @@
             
             multipleRSTests(conn);
                         jira_491_492(conn);
+            testImplicitClose(conn);
 			cleanUp(conn);
 		} catch (SQLException sqle) {
 			org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(System.out, sqle);
@@ -1818,8 +1819,49 @@
         cs.close();
     }
 
-    
-    
+    // DERBY-821: Test that the result set is not implicitly closed on
+    // the server when EXCSQLSTT is used to open the result set.
+    private static void testImplicitClose(Connection conn) throws SQLException {
+		System.out.print("testImplicitClose(): ");
+		final String proc =
+			"org.apache.derbyTesting.functionTests.util.ProcedureTest." +
+			"selectRows";
+		boolean savedAutoCommit = conn.getAutoCommit();
+		conn.setAutoCommit(false);
+		Statement stmt = conn.createStatement();
+		stmt.executeUpdate("create table derby821 (id int)");
+		stmt.executeUpdate("insert into derby821 (id) values (1), (2)");
+		stmt.execute("create procedure jira821 (name varchar(50)) " +
+					 "parameter style java language java external name " +
+					 "'" + proc + "' dynamic result sets 1 reads sql data");
+		CallableStatement cs = conn.prepareCall("call jira821 (?)");
+		cs.setString(1, "derby821");
+		cs.execute();
+		ResultSet rs = cs.getResultSet();
+		rs.next();
+		boolean passed = false;
+		try {
+			// We expect the result set to be open, so dropping the
+			// table should fail.
+			stmt.executeUpdate("drop table derby821");
+		} catch (SQLException sqle) {
+			if (sqle.getSQLState().equals("X0X95")) {
+				System.out.println("PASSED");
+				passed = true;
+			} else {
+				System.out.println("FAILED");
+				throw sqle;
+			}
+		}
+		if (!passed) {
+			// Table was successfully dropped, hence the result set
+			// must have been implicitly closed.
+			System.out.println("FAILED (no exception thrown)");
+		}
+		conn.rollback();
+		conn.setAutoCommit(savedAutoCommit);
+	}
+
     /**
      * Checks to see if there is a lock on a table by attempting to modify the
      * same table. If the first connection was serializable then it will 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java?rev=377367&r1=377366&r2=377367&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java Mon Feb 13 04:44:07 2006
@@ -192,6 +192,16 @@
 		conn.close();
 	}
 
+	// select all rows from a table
+	public static void selectRows(String table, ResultSet[] rs)
+		throws SQLException
+	{
+		Connection conn = DriverManager.getConnection("jdbc:default:connection");
+		Statement stmt = conn.createStatement();
+		rs[0] = stmt.executeQuery("SELECT * FROM " + table);
+		conn.close();
+	}
+
 	public static void fivejp(ResultSet[] data1, ResultSet[] data2, ResultSet[] data3, ResultSet[] data4, ResultSet[] data5) throws SQLException {
 
 		Connection conn = DriverManager.getConnection("jdbc:default:connection");