db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r545495 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/jdbc/ testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/
Date Fri, 08 Jun 2007 12:46:26 GMT
Author: kristwaa
Date: Fri Jun  8 05:46:25 2007
New Revision: 545495

URL: http://svn.apache.org/viewvc?view=rev&rev=545495
Log:
DERBY-2711: If large blob is updated after InputStream is fetched (using getBinaryStream),
the stream continues to point ot old data. Stream will now point to new data.
Patch file: derby-2711v2.diff

Patch contributed by Anurag Shekhar.

Added:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UpdateableBlobStream.java 
 (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobUpdateableStreamTest.java
  (with props)
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java?view=diff&rev=545495&r1=545494&r2=545495
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java Fri Jun  8 05:46:25
2007
@@ -457,7 +457,7 @@
                         setupContextStack();
 
                     setPosition(0);
-                    return biStream;
+                    return new UpdateableBlobStream (this, biStream);
                 }
             }
         }
@@ -954,5 +954,13 @@
         getEmbedConnection().checkIfClosed();
         if(!isValid)
             throw newSQLException(SQLState.LOB_OBJECT_INVALID);
+    }
+    
+    /**
+     * Returns if blob data is stored locally (using LOBStreamControl).
+     * @return true if materialized else false
+     */
+    boolean isMaterialized () {
+        return materialized;
     }
 }

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UpdateableBlobStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UpdateableBlobStream.java?view=auto&rev=545495
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UpdateableBlobStream.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UpdateableBlobStream.java Fri
Jun  8 05:46:25 2007
@@ -0,0 +1,193 @@
+/* 
+
+   Derby - Class org.apache.derby.impl.jdbc.UpdateableBlobStream
+
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+
+ */
+
+package org.apache.derby.impl.jdbc;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.sql.SQLException;
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.i18n.MessageService;
+
+/**
+ * Updateable blob stream is a wrapper stream over dvd stream 
+ * and LOBInputStream. It detects if blob data has moved from 
+ * dvd to clob control update itself to point to LOBInputStream.
+ */
+class UpdateableBlobStream extends InputStream {
+    //flag to check if its using stream from LOBStreamControl
+    //or from DVD.
+    private boolean materialized;
+    private InputStream stream;
+    private long pos;
+    private EmbedBlob blob;
+    
+    /**
+     * Constructs UpdateableBlobStream using the the InputStream receives as the
+     * parameter. The initial position is set to the pos.
+     * @param blob EmbedBlob this stream is associated with.
+     * @param is InputStream this class is going to use internally.
+     * @throws IOException
+     */
+    UpdateableBlobStream (EmbedBlob blob, InputStream is) {
+        stream = is;        
+        this.pos = 0;
+        this.blob = blob;
+    }
+    
+    //Checks if this object is using materialized blob
+    //if not it checks if the blob was materialized since
+    //this stream was last access. If the blob was materialized 
+    //(due to one of the set methods) it gets the stream again and 
+    //sets the position to current read position
+    private void updateIfRequired () throws IOException {
+        if (materialized)
+            return;
+        if (blob.isMaterialized()) {
+            materialized = true;
+            try {
+                stream = blob.getBinaryStream();
+            } catch (SQLException ex) {
+                IOException ioe = new IOException (ex.getMessage());
+                ioe.initCause (ex);
+            }
+            long leftToSkip = pos;
+            while (leftToSkip > 0) {
+                long skipped = stream.skip (leftToSkip);
+                if (skipped == 0) {
+                    //skipping zero byte check stream has reached eof
+                    if (stream.read() < 0) {
+                         throw new IOException (
+                                 MessageService.getCompleteMessage (
+                                 SQLState.STREAM_EOF, new Object [0]));
+                    }
+                    else {
+                        skipped = 1;
+                    }
+                }
+                leftToSkip -= skipped;
+                
+            }
+        }
+    }
+    
+    /**
+     * Reads the next byte of data from the input stream. The value byte is
+     * returned as an <code>int</code> in the range <code>0</code>
to
+     * <code>255</code>. If no byte is available because the end of the stream
+     * has been reached, the value <code>-1</code> is returned. This method
+     * blocks until input data is available, the end of the stream is detected,
+     * or an exception is thrown.
+     * 
+     * <p> A subclass must provide an implementation of this method.
+     * 
+     * @return the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception IOException  if an I/O error occurs.
+     */
+    public int read() throws IOException {
+        updateIfRequired();        
+        int ret = stream.read();
+        if (ret >= 0)
+            pos++;
+        return ret;
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from the input stream into
+     * an array of bytes.  An attempt is made to read as many as
+     * <code>len</code> bytes, but a smaller number may be read.
+     * The number of bytes actually read is returned as an integer.
+     * 
+     * 
+     * @param b     the buffer into which the data is read.
+     * @param off   the start offset in array <code>b</code>
+     *                   at which the data is written.
+     * @param len   the maximum number of bytes to read.
+     * @return the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception IOException If the first byte cannot be read for any reason
+     * other than end of file, or if the input stream has been closed, or if
+     * some other I/O error occurs.
+     * @exception NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception IndexOutOfBoundsException If <code>off</code> is negative,

+     * <code>len</code> is negative, or <code>len</code> is greater
than 
+     * <code>b.length - off</code>
+     * @see java.io.InputStream#read()
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        updateIfRequired();        
+        int retValue = super.read(b, off, len);
+        if (retValue > 0)
+            pos += retValue;
+        return retValue;
+    }
+
+    /**
+     * Reads some number of bytes from the input stream and stores them into
+     * the buffer array <code>b</code>. The number of bytes actually read is
+     * returned as an integer.  This method blocks until input data is
+     * available, end of file is detected, or an exception is thrown.
+     * 
+     * @param b   the buffer into which the data is read.
+     * @return the total number of bytes read into the buffer, or
+     *             <code>-1</code> is there is no more data because the end of
+     *             the stream has been reached.
+     * @exception IOException  If the first byte cannot be read for any reason
+     * other than the end of the file, if the input stream has been closed, or
+     * if some other I/O error occurs.
+     * @exception NullPointerException  if <code>b</code> is <code>null</code>.
+     * @see java.io.InputStream#read(byte[], int, int)
+     */
+    public int read(byte[] b) throws IOException {
+        updateIfRequired();
+        int retValue = stream.read(b);
+        if (retValue > 0)
+            pos += retValue;
+        return retValue;
+    }
+
+    /**
+     * Skips over and discards <code>n</code> bytes of data from this input
+     * stream. The <code>skip</code> method may, for a variety of reasons, end
+     * up skipping over some smaller number of bytes, possibly <code>0</code>.
+     * This may result from any of a number of conditions; reaching end of file
+     * before <code>n</code> bytes have been skipped is only one possibility.
+     * The actual number of bytes skipped is returned.  If <code>n</code> is
+     * negative, no bytes are skipped.
+     * 
+     * @param n   the number of bytes to be skipped.
+     * @return the actual number of bytes skipped.
+     * @exception IOException  if the stream does not support seek,
+     *                      or if some other I/O error occurs.
+     * @see java.io.InputStream#skip(long)
+     */
+    public long skip(long n) throws IOException {
+        updateIfRequired();
+        long retValue = stream.skip(n);
+        if (retValue > 0)
+            pos += retValue;
+        return retValue;
+    }        
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UpdateableBlobStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobUpdateableStreamTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobUpdateableStreamTest.java?view=auto&rev=545495
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobUpdateableStreamTest.java
(added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobUpdateableStreamTest.java
Fri Jun  8 05:46:25 2007
@@ -0,0 +1,102 @@
+/*
+ *
+ * Derby - Class 
+ *   org.apache.derbyTesting.functionTests.tests.jdbcapi.BlobUpdateableStreamTest
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ */
+package org.apache.derbyTesting.functionTests.tests.jdbcapi;
+
+import java.io.InputStream;
+import java.sql.Blob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import junit.framework.Test;
+import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.TestConfiguration;
+
+/**
+ * Test if blob stream updates itself to point to LOBInputStream 
+ * if the blob is updated after fetching the stream.
+ */
+public class BlobUpdateableStreamTest extends BaseJDBCTestCase {
+    public BlobUpdateableStreamTest (String name) {
+        super (name);
+    }
+    
+    public void testUpdateableBlob () throws Exception {
+        getConnection().setAutoCommit (false);
+        PreparedStatement ps = prepareStatement ("insert into testblob " +
+                "values (?)");
+        //insert a large blob to ensure dvd gives out a stream and not 
+        //a byte array
+        ps.setBinaryStream (1, new LoopingAlphabetStream (1024 * 1024), 1024 * 1024);
+        ps.executeUpdate();
+        ps.close();
+        Statement stmt = createStatement ();
+        ResultSet rs = stmt.executeQuery("select * from testblob");
+        rs.next();
+        Blob blob = rs.getBlob (1);
+        InputStream is = blob.getBinaryStream();
+        long l = is.skip (20);
+        //truncate blob after accessing original stream
+        blob.truncate (l);
+        int ret = is.read();
+        //should not be able to read after truncated value
+        assertEquals ("stream update falield", -1, ret);
+        byte [] buffer = new byte [1024];
+        for (int i = 0; i < buffer.length; i++)
+            buffer [i] = (byte) (i % 255);
+        blob.setBytes (blob.length() + 1, buffer);
+        byte [] buff = new byte [1024];
+        int toRead = 1024;
+        while (toRead != 0 ) {
+            long read = is.read (buff, 1024 - toRead, toRead);
+            if (read < 0)
+                fail ("couldn't retrieve updated value");
+            toRead -= read;
+        }
+        for (int i = 0; i < buffer.length; i++) {
+            assertEquals ("value retrieved is not same as updated value",
+                buffer [i], buff [i]);
+        }
+        blob = null;
+        rs.close();
+        stmt.close();
+        commit();
+    }
+    
+    public static Test suite () {
+        return TestConfiguration.embeddedSuite (
+                BlobUpdateableStreamTest.class);
+    }
+    
+    public void setUp() throws  Exception {
+        Statement stmt = createStatement();
+        stmt.execute ("create table testblob (data blob)");
+        stmt.close();
+    }    
+
+    protected void tearDown() throws Exception {
+        Statement stmt = createStatement();
+        stmt.execute ("drop table testblob");
+        stmt.close();
+        commit ();
+        super.tearDown();
+    }       
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobUpdateableStreamTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java?view=diff&rev=545495&r1=545494&r2=545495
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java
Fri Jun  8 05:46:25 2007
@@ -76,6 +76,7 @@
 		suite.addTest(AuthenticationTest.suite());
 		suite.addTest(DriverTest.suite());
         suite.addTest(ClobTest.suite());
+        suite.addTest(BlobUpdateableStreamTest.suite());
 
         // Old harness .java tests that run using the HarnessJavaTest
         // adapter and continue to use a single master file.



Mime
View raw message