db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From banda...@apache.org
Subject svn commit: r178803 - in /incubator/derby/code/trunk/java: engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/impl/store/raw/data/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/functionTests/master/DerbyNet/ testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/ testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/
Date Fri, 27 May 2005 18:00:39 GMT
Author: bandaram
Date: Fri May 27 11:00:37 2005
New Revision: 178803

URL: http://svn.apache.org/viewcvs?rev=178803&view=rev
Log:
Derby-265: In Network Server retrieving BLOB values with autocommit off causes NullPointerException
in INSANE build / AssertFailure in  BaseContainerHandle.getTransaction in SANE Build

Fix submitted by Sunitha Kambhampati (ksunithaghm@gmail.com)

The problem
-- Basically, in autocommit mode, when getBlob is called on a resultset after the transaction
in which it was created is committed throws an NPE. Per the jdbc api and spec, getBlob is
valid only for the duration of the transaction in which it was created.  So it is incorrect
to call getBlob as in this repro for derby-265.
-- On a getBlob for overflow columns,  we initiliaze the stream by reopening the container.
In here, the transaction of the containerhandle ends up being null and an NPE is thrown.
-- The problem is not specific to network server as such, but is reproducible in embedded
mode also.


Fix includes
--    Adds check in  OverflowInputStream.initStream  to see if transaction of the container
handle is null and throws a StandardException with SQLState.DATA_CONTAINER_CLOSED
--    And at  the jdbc layer, this exception is wrapped with a user exception with an existing
 SQLState XJ073             (SQLState.BLOB_ACCESSED_AFTER_COMMIT) for both getBlob and getClob.
The error message corresponding to this sqlstate is  "The data in this Blob or Clob is no
longer available. Possible reasons are that its transaction committed, or its  connection
closed."
--   Removed the ASSERT in BaseContainerHandle.getTransaction() 


Modified:
    incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
    incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java
    incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseContainerHandle.java
    incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/OverflowInputStream.java
    incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/blobclob4BLOB.out
    incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/blobclob4BLOB.out
    incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/blobclob4BLOB.out
    incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/blobclob4BLOB.java

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java Fri May
27 11:00:37 2005
@@ -125,8 +125,16 @@
             if (SanityManager.DEBUG)
                 SanityManager.ASSERT(myStream instanceof Resetable);
 
-            ((Resetable)myStream).initStream();
-            // set up the buffer for trashing the bytes to set the position of the
+            try {
+                ((Resetable) myStream).initStream();
+            } catch (StandardException se) {
+                if (se.getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED)) {
+                    throw StandardException
+                            .newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
+                }
+            }
+            // set up the buffer for trashing the bytes to set the position of
+            // the
             // stream, only need a buffer when we have a long column
             buf = new byte[BLOB_BUF_SIZE];
         }

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java Fri May
27 11:00:37 2005
@@ -113,8 +113,14 @@
             if (SanityManager.DEBUG)
                 SanityManager.ASSERT(myStream instanceof Resetable);
 
-            ((Resetable)myStream).initStream();
-
+            try {
+                ((Resetable) myStream).initStream();
+            } catch (StandardException se) {
+                if (se.getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED)) {
+                    throw StandardException
+                            .newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
+                }
+            }
         }
     }
 

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseContainerHandle.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseContainerHandle.java?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseContainerHandle.java
(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseContainerHandle.java
Fri May 27 11:00:37 2005
@@ -848,12 +848,6 @@
 	*/
 	public final RawTransaction getTransaction() 
     {
-
-		if (SanityManager.DEBUG) 
-        {
-			SanityManager.ASSERT(xact != null);
-		}
-
 		return xact;
 	}
 

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/OverflowInputStream.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/OverflowInputStream.java?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/OverflowInputStream.java
(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/OverflowInputStream.java
Fri May 27 11:00:37 2005
@@ -21,6 +21,7 @@
 package org.apache.derby.impl.store.raw.data;
 
 import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.SQLState;
 
 import org.apache.derby.iapi.store.raw.RecordHandle;
 
@@ -138,6 +139,12 @@
     */
     public void initStream() throws StandardException
     {
+        // it is possible that the transaction in which the stream was 
+        // created is committed and no longer valid
+        // dont want to get NPE but instead throw error that
+        // container was not opened
+        if (owner.getTransaction() == null)
+            throw StandardException.newException(SQLState.DATA_CONTAINER_CLOSED);
         /*
         We might want to use the mode and isolation level of the container.
         This would have the advantage that, if the isolation level

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/blobclob4BLOB.out
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/blobclob4BLOB.out?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/blobclob4BLOB.out
(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/blobclob4BLOB.out
Fri May 27 11:00:37 2005
@@ -717,5 +717,9 @@
 Expect to get an IOException, container has been closed
 10000 total bytes read
 clobTestSelfDestructive2 finished
+-----
+Expected Exception The data in this Blob or Clob is no longer available. Possible reasons
are that its transaction committed, or its connection closed.
+-----
+Expected Exception The data in this Blob or Clob is no longer available. Possible reasons
are that its transaction committed, or its connection closed.
 FINISHED TEST blobclob :-)
 Test blobclob finished

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/blobclob4BLOB.out
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/blobclob4BLOB.out?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/blobclob4BLOB.out
(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/blobclob4BLOB.out
Fri May 27 11:00:37 2005
@@ -717,5 +717,9 @@
 Expect to get an IOException, container has been closed
 10000 total bytes read
 clobTestSelfDestructive2 finished
+-----
+Expected Exception The data in this Blob or Clob is no longer available. Possible reasons
are that its transaction committed, or its connection closed.
+-----
+Expected Exception The data in this Blob or Clob is no longer available. Possible reasons
are that its transaction committed, or its connection closed.
 FINISHED TEST blobclob :-)
 Test blobclob finished

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/blobclob4BLOB.out
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/blobclob4BLOB.out?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/blobclob4BLOB.out
(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/blobclob4BLOB.out
Fri May 27 11:00:37 2005
@@ -784,5 +784,9 @@
 After drop
 Expect to get an IOException, container has been closed
 EXPECTED IO Exception:ERROR 40XD0: Container has been closed
+-----------------------------
+Expected Exception The data in this Blob or Clob is no longer available. Possible reasons
are that its transaction committed, or its connection closed.
+-----------------------------
+Expected Exception The data in this Blob or Clob is no longer available. Possible reasons
are that its transaction committed, or its connection closed.
 FINISHED TEST blobclob :-)
 Test blobclob finished

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/blobclob4BLOB.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/blobclob4BLOB.java?rev=178803&r1=178802&r2=178803&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/blobclob4BLOB.java
(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/blobclob4BLOB.java
Fri May 27 11:00:37 2005
@@ -167,6 +167,8 @@
             clobTestSelfDestructive2(conn);
 
             conn.commit();
+            clobNegativeTest_Derby265(conn);
+            blobNegativeTest_Derby265(conn);
             conn.close();
             System.out.println("FINISHED TEST blobclob :-)");
 
@@ -3785,6 +3787,144 @@
 		}
     }
 
+    
+    
+    /**
+     * Test fix for derby-265.
+     * Test that if getBlob is called after the transaction 
+     * in which it was created is committed, a proper user error
+     * is thrown instead of an NPE. 
+     * Basically per the spec, getBlob is valid only for the duration of 
+     * the transaction in it was created in
+     * @param conn
+     * @throws SQLException
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    private static void blobNegativeTest_Derby265(Connection conn)
+            throws SQLException, FileNotFoundException,IOException {
+        // basically setup the tables for clob and blob
+        Statement s = conn.createStatement();
+        s.execute("create table \"MAPS_BLOB\"(MAP_ID int, MAP_NAME varchar(20),REGION varchar(20),AREA
varchar(20), PHOTO_FORMAT varchar(20),PICTURE blob(2G))");
+        conn.setAutoCommit(false);
+        PreparedStatement ps = conn.prepareStatement("insert into \"MAPS_BLOB\" values(?,?,?,?,?,?)");
+        
+        for (int i = 0; i < 3; i++) {
+            FileInputStream fis = new FileInputStream(fileName[4]);
+            ps.setInt(1, i);
+            ps.setString(2, "x" + i);
+            ps.setString(3, "abc");
+            ps.setString(4, "abc");
+            ps.setString(5, "abc");
+            ps.setBinaryStream(6, new java.io.BufferedInputStream(fis), 300000);
+            ps.executeUpdate();
+            fis.close();
+        }
+        conn.commit();
+
+        conn.setAutoCommit(true);
+        System.out.println("-----------------------------");
+
+        s = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                ResultSet.CONCUR_READ_ONLY);
+        s.execute("SELECT \"MAP_ID\", \"MAP_NAME\", \"REGION\", \"AREA\", \"PHOTO_FORMAT\",
\"PICTURE\" FROM \"MAPS_BLOB\"");
+        ResultSet rs1 = s.getResultSet();
+        Statement s2 = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                ResultSet.CONCUR_READ_ONLY);
+        s2.executeQuery("SELECT \"MAP_ID\", \"MAP_NAME\", \"REGION\", \"AREA\", \"PHOTO_FORMAT\",
\"PICTURE\" FROM \"MAPS_BLOB\"");
+        ResultSet rs2 = s2.getResultSet();
+        rs2.next();
+
+        Blob b2 = rs2.getBlob(6);
+        rs1.next();
+        Blob b1 = rs1.getBlob(6);
+        try {
+            rs1.close();
+            rs2.next();
+            rs2.getBlob(6);
+        } catch (SQLException sqle) {
+            if ("XJ073".equals(sqle.getSQLState()))
+                System.out.println("Expected Exception " + sqle.getMessage());
+            else
+                System.out.println("FAIL -- unexpected exception:"
+                        + sqle.toString());
+        }
+        finally {
+            rs2.close();
+            s2.close();
+            s.close();
+            ps.close();
+        }
+
+    }
+
+    /**
+     * Test fix for derby-265.
+     * Test that if getClob is called after the transaction 
+     * in which it was created is committed, a proper user error
+     * is thrown instead of an NPE. 
+     * Basically per the spec, getClob is valid only for the duration of 
+     * the transaction in it was created in
+     * @param conn
+     * @throws SQLException
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    private static void clobNegativeTest_Derby265(Connection conn)
+            throws SQLException, FileNotFoundException,IOException {
+
+        // basically setup the tables for clob 
+        Statement s = conn.createStatement();
+        s.execute("create table \"MAPS\"(MAP_ID int, MAP_NAME varchar(20),REGION varchar(20),AREA
varchar(20), PHOTO_FORMAT varchar(20),PICTURE clob(2G))");
+        conn.setAutoCommit(false);
+        PreparedStatement ps = conn.prepareStatement("insert into \"MAPS\" values(?,?,?,?,?,?)");
+        for (int i = 0; i < 3; i++) {
+            FileReader fr = new FileReader(fileName[4]);
+            ps.setInt(1, i);
+            ps.setString(2, "x" + i);
+            ps.setString(3, "abc");
+            ps.setString(4, "abc");
+            ps.setString(5, "abc");
+            ps.setCharacterStream(6, new java.io.BufferedReader(fr),300000);
+            ps.executeUpdate();
+            fr.close();
+        }
+        conn.commit();
+
+        conn.setAutoCommit(true);
+        System.out.println("-----------------------------");
+        s = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                ResultSet.CONCUR_READ_ONLY);
+        s.execute("SELECT \"MAP_ID\", \"MAP_NAME\", \"REGION\", \"AREA\", \"PHOTO_FORMAT\",
\"PICTURE\" FROM \"MAPS\"");
+        ResultSet rs1 = s.getResultSet();
+        Statement s2 = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                ResultSet.CONCUR_READ_ONLY);
+        s2.executeQuery("SELECT \"MAP_ID\", \"MAP_NAME\", \"REGION\", \"AREA\", \"PHOTO_FORMAT\",
\"PICTURE\" FROM \"MAPS\"");
+        ResultSet rs2 = s2.getResultSet();
+        rs2.next();
+
+        Clob b2 = rs2.getClob(6); // should be fine
+        rs1.next();
+        Clob b1 = rs1.getClob(6);
+        try {
+            rs1.close(); // this commits the transaction
+            rs2.next();
+            rs2.getClob(6); // no longer valid
+        } catch (SQLException sqle) {
+            if ("XJ073".equals(sqle.getSQLState()))
+                System.out.println("Expected Exception " + sqle.getMessage());
+            else
+                System.out.println("FAIL -- unexpected exception:"
+                        + sqle.toString());
+        }
+        finally {
+            rs2.close();
+            s2.close();
+            s.close();
+            ps.close();
+        }
+
+    }
     static void printInterval(Clob clob, long pos, int length,
         int testNum, int iteration, int clobLength)
     {



Mime
View raw message