Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / jdbc / EmbedBlob.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
new file mode 100644 (file)
index 0000000..3d40ce7
--- /dev/null
@@ -0,0 +1,1010 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.jdbc.EmbedBlob\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+\r
+package org.apache.derby.impl.jdbc;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.jdbc.EngineLOB;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.Resetable;\r
+import org.apache.derby.iapi.services.io.NewByteArrayInputStream;\r
+import org.apache.derby.iapi.services.io.InputStreamUtil;\r
+import org.apache.derby.iapi.services.io.ArrayInputStream;\r
+\r
+import java.sql.SQLException;\r
+import java.sql.Blob;\r
+import java.io.InputStream;\r
+import java.io.EOFException;\r
+import java.io.IOException;\r
+\r
+/**\r
+    Implements java.sql.Blob (see the JDBC 2.0 spec).\r
+    A blob sits on top of a BINARY, VARBINARY or LONG VARBINARY column.\r
+    If its data is small (less than 1 page) it is a byte array taken from\r
+    the SQLBit class. If it is large (more than 1 page) it is a long column\r
+    in the database. The long column is accessed as a stream, and is implemented\r
+    in store as an OverflowInputStream.  The Resetable interface allows sending\r
+    messages to that stream to initialize itself (reopen its container and\r
+    lock the corresponding row) and to reset itself to the beginning. \r
+\r
+    NOTE: In the case that the data is large, it is represented as a stream.\r
+    This stream is returned to the user in the getBinaryStream() method.\r
+    This means that we have limited control over the state of the stream,\r
+    since the user can read bytes from it at any time.  Thus all methods\r
+    here reset the stream to the beginning before doing any work.\r
+    CAVEAT: The methods may not behave correctly if a user sets up\r
+    multiple threads and sucks data from the stream (returned from\r
+    getBinaryStream()) at the same time as calling the Blob methods.\r
+\r
+  <P><B>Supports</B>\r
+   <UL>\r
+   <LI> JSR169 - no subsetting for java.sql.Blob\r
+   <LI> JDBC 2.0\r
+   <LI> JDBC 3.0 - no new dependencies on new JDBC 3.0 or JDK 1.4 classes,\r
+        new update methods can safely be added into implementation.\r
+   </UL>\r
+\r
+ */\r
+\r
+final class EmbedBlob extends ConnectionChild implements Blob, EngineLOB\r
+{\r
+    // blob is either materialized or still in stream\r
+    private boolean         materialized;\r
+    private InputStream     myStream;\r
+    \r
+    // locator key for lob. used by Network Server.\r
+    private int             locator;\r
+    \r
+    /*\r
+     * Length of the BLOB if known. Set to -1 if\r
+     * the current length of the BLOB is not known.\r
+     */\r
+    private long myLength = -1;\r
+    \r
+    // note: cannot control position of the stream since user can do a getBinaryStream\r
+    private long            pos;\r
+    // this stream sits on top of myStream\r
+    private BinaryToRawStream biStream;\r
+\r
+    // buffer for reading in blobs from a stream (long column)\r
+    // and trashing them (to set the position of the stream etc.)\r
+    private static int BLOB_BUF_SIZE = 4096;\r
+    private byte buf[];\r
+    \r
+    //This boolean variable indicates whether the Blob object has\r
+    //been invalidated by calling free() on it\r
+    private boolean isValid = true;\r
+\r
+    private LOBStreamControl control;\r
+\r
+     /**\r
+     * This constructor is used to create a empty Blob object. It is used by the\r
+     * Connection interface method createBlob().\r
+     * \r
+     * @param blobBytes A byte array containing the data to be stores in the \r
+     *        Blob.\r
+     *\r
+     * @param con The EmbedConnection object associated with this Blob object.\r
+     *\r
+     */\r
+    \r
+     EmbedBlob(byte [] blobBytes,EmbedConnection con) throws SQLException {\r
+        super(con);\r
+         try {\r
+             control = new LOBStreamControl (con.getDBName(), blobBytes);\r
+             materialized = true;\r
+             //add entry in connection so it can be cleared \r
+             //when transaction is not valid\r
+             con.addLOBReference (this);\r
+         }\r
+         catch (IOException e) {\r
+             throw Util.setStreamFailure (e);\r
+         }\r
+         catch (StandardException se) {\r
+            throw Util.generateCsSQLException (se);\r
+         }\r
+     }\r
+     \r
+    /*\r
+      This constructor should only be called by EmbedResultSet.getBlob\r
+    */\r
+    protected EmbedBlob(DataValueDescriptor dvd, EmbedConnection con)\r
+        throws StandardException\r
+    {\r
+        super(con);\r
+        // if the underlying column is null, ResultSet.getBlob will return null,\r
+        // never should get this far\r
+        if (SanityManager.DEBUG)\r
+            SanityManager.ASSERT(!dvd.isNull(), "blob is created on top of a null column");\r
+\r
+        myStream = dvd.getStream();\r
+        if (myStream == null)\r
+        {\r
+            materialized = true;\r
+            // copy bytes into memory so that blob can live after result set\r
+            // is closed\r
+            byte[] dvdBytes = dvd.getBytes();\r
+\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(dvdBytes != null,"blob has a null value underneath");\r
+            try {\r
+                control = new LOBStreamControl (\r
+                            getEmbedConnection().getDBName(), dvdBytes);\r
+            }\r
+            catch (SQLException e) {\r
+                throw StandardException.newException (e.getSQLState());\r
+            }\r
+            catch (IOException e) {\r
+                throw StandardException.newException (\r
+                                        SQLState.SET_STREAM_FAILURE, e);\r
+            }\r
+        }\r
+        else\r
+        {\r
+            materialized = false;\r
+\r
+            /*\r
+             We are expecting this stream to be a FormatIdInputStream with an\r
+             OverflowInputStream inside. FormatIdInputStream implements\r
+             Resetable. This should be the case when retrieving\r
+             data from a long column. However, SQLBit, which is the class\r
+             implementing the getStream() method for dvd.getStream(), does not\r
+             guarantee this for us\r
+             */\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(myStream instanceof Resetable);\r
+            //make myStream a position aware stream\r
+            myStream = new PositionedStoreStream (myStream);\r
+            try {\r
+                ((Resetable) myStream).initStream();\r
+            } catch (StandardException se) {\r
+                if (se.getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED)) {\r
+                    throw StandardException\r
+                            .newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);\r
+                }\r
+            }\r
+            // set up the buffer for trashing the bytes to set the position of\r
+            // the\r
+            // stream, only need a buffer when we have a long column\r
+            buf = new byte[BLOB_BUF_SIZE];\r
+        }\r
+        pos = 0;\r
+        //add entry in connection so it can be cleared \r
+        //when transaction is not valid\r
+        con.addLOBReference (this);\r
+    }\r
+\r
+\r
+    /*\r
+        Sets the position of the stream to position newPos, where position 0 is\r
+        the beginning of the stream.\r
+\r
+        @param newPos the position to set to\r
+        @exception StandardException (BLOB_SETPOSITION_FAILED) throws this if\r
+        the stream runs out before we get to newPos\r
+    */\r
+    private void setPosition(long newPos)\r
+        throws StandardException, IOException\r
+    {\r
+        if (SanityManager.DEBUG)\r
+            SanityManager.ASSERT(newPos >= 0);\r
+        if (materialized)\r
+            pos = newPos;\r
+        else {\r
+            // Always resets the stream to the beginning first, because user can\r
+            // influence the state of the stream without letting us know.\r
+            ((Resetable)myStream).resetStream();\r
+            // PT could try to save creating a new object each time\r
+            biStream = new BinaryToRawStream(myStream, this);\r
+            pos = 0;\r
+            while (pos < newPos)\r
+            {\r
+                int size = biStream.read(\r
+                    buf,0,(int) Math.min((newPos-pos), (long) BLOB_BUF_SIZE));\r
+                if (size <= 0)   // ran out of stream\r
+                    throw StandardException.newException(SQLState.BLOB_LENGTH_TOO_LONG);\r
+                pos += size;\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    /*\r
+        Reads one byte, either from the byte array or else from the stream.\r
+    */\r
+    private int read() throws IOException, SQLException {\r
+        int c;\r
+        if (materialized)\r
+        {\r
+            try {\r
+                if (pos >= control.getLength())\r
+                    return -1;\r
+                else\r
+                    c = control.read (pos);\r
+            }\r
+            catch (StandardException se) {\r
+                throw Util.generateCsSQLException (se);\r
+            }\r
+        }\r
+        else\r
+            c = biStream.read();\r
+        pos++;\r
+        return c;\r
+    }\r
+\r
+  /**\r
+   * Returns the number of bytes in the <code>BLOB</code> value\r
+   * designated by this <code>Blob</code> object.\r
+   * @return length of the <code>BLOB</code> in bytes\r
+   * @exception SQLException if there is an error accessing the\r
+   * length of the <code>BLOB</code>\r
+   */\r
+    // PT stream part may get pushed to store\r
+    public long length()\r
+        throws SQLException\r
+    {\r
+        //call checkValidity to exit by throwing a SQLException if\r
+        //the Blob object has been freed by calling free() on it\r
+        checkValidity();\r
+        try {\r
+            if (materialized)\r
+                return control.getLength ();\r
+        }\r
+        catch (IOException e) {\r
+            throw Util.setStreamFailure (e);\r
+        }\r
+        if (myLength != -1)\r
+            return myLength;\r
+        \r
+        boolean pushStack = false;\r
+        try\r
+        {\r
+           // we have a stream\r
+            synchronized (getConnectionSynchronization())\r
+            {\r
+                pushStack = !getEmbedConnection().isClosed();\r
+                if (pushStack)\r
+                    setupContextStack();\r
+\r
+                setPosition(0);\r
+                // If possible get the length from the encoded\r
+                // length at the front of the raw stream.\r
+                if ((myLength = biStream.getLength()) != -1) {\r
+                    biStream.close();\r
+                   return myLength;\r
+                }\r
+                \r
+                // Otherwise have to read the entire stream!\r
+                for (;;)\r
+                {\r
+                    int size = biStream.read(buf);\r
+                    if (size == -1)\r
+                        break;\r
+                    pos += size;\r
+                }\r
+                // Save for future uses.\r
+                myLength = pos;\r
+                biStream.close();\r
+                return pos;\r
+            }\r
+        }\r
+        catch (Throwable t)\r
+        {\r
+                       throw handleMyExceptions(t);\r
+        }\r
+        finally\r
+        {\r
+            if (pushStack)\r
+                restoreContextStack();\r
+        }\r
+    }\r
+\r
+\r
+  /**\r
+   * Returns as an array of bytes part or all of the <code>BLOB</code>\r
+   * value that this <code>Blob</code> object designates.  The byte\r
+   * array contains up to <code>length</code> consecutive bytes\r
+   * starting at position <code>startPos</code>.\r
+   * The starting position must be between 1 and the length\r
+   * of the BLOB plus 1. This allows for zero-length BLOB values, from\r
+   * which only zero-length byte arrays can be returned. \r
+   * If a larger length is requested than there are bytes available,\r
+   * characters from the start position to the end of the BLOB are returned.\r
+   * @param startPos the ordinal position of the first byte in the\r
+   * <code>BLOB</code> value to be extracted; the first byte is at\r
+   * position 1\r
+   * @param length is the number of consecutive bytes to be copied\r
+   * @return a byte array containing up to <code>length</code>\r
+   * consecutive bytes from the <code>BLOB</code> value designated\r
+   * by this <code>Blob</code> object, starting with the\r
+   * byte at position <code>startPos</code>.\r
+   * @exception SQLException if there is an error accessing the\r
+   * <code>BLOB</code>\r
+   * NOTE: If the starting position is the length of the BLOB plus 1,\r
+   * zero bytess are returned regardless of the length requested.\r
+   */\r
+    public byte[] getBytes(long startPos, int length)\r
+        throws SQLException\r
+    {\r
+        //call checkValidity to exit by throwing a SQLException if\r
+        //the Blob object has been freed by calling free() on it\r
+        checkValidity();\r
+        \r
+        boolean pushStack = false;\r
+        try\r
+        {\r
+            if (startPos < 1)\r
+                throw StandardException.newException(\r
+                    SQLState.BLOB_BAD_POSITION, new Long(startPos));\r
+            if (length < 0)\r
+                throw StandardException.newException(\r
+                    SQLState.BLOB_NONPOSITIVE_LENGTH, new Integer(length));\r
+\r
+            byte[] result;\r
+            // if the blob is materialized\r
+            if (materialized) {\r
+                 result = new byte [length];\r
+                 int sz = control.read (result, 0, result.length, startPos - 1);\r
+                 if (sz == -1)\r
+                     return new byte [0];\r
+                 if (sz < length) {\r
+                     byte [] tmparray = new byte [sz];\r
+                     System.arraycopy (result, 0, tmparray, 0, sz);\r
+                     result = tmparray;\r
+                 }\r
+            }\r
+            else // we have a stream\r
+            {\r
+                synchronized (getConnectionSynchronization())\r
+                {\r
+                    pushStack = !getEmbedConnection().isClosed();\r
+                    if (pushStack)\r
+                        setupContextStack();\r
+\r
+                    setPosition(startPos-1);\r
+                    // read length bytes into a string\r
+                    result = new byte[length];\r
+                    int n = InputStreamUtil.readLoop(biStream,result,0,length);\r
+                    pos += n;\r
+                    /*\r
+                     According to the spec, if there are only n < length bytes\r
+                     to return, we should just return these bytes. Rather than\r
+                     return them in an array of size length, where the trailing\r
+                     bytes are not initialized, and the user cannot tell how\r
+                     many bytes were actually returned, we should return an\r
+                     array of n bytes.\r
+                     */\r
+                    if (n < length)\r
+                    {\r
+                        byte[] result2 = new byte[n];\r
+                        System.arraycopy(result,0,result2,0,n);\r
+                        return result2;\r
+                    }\r
+                }\r
+            }\r
+            return result;\r
+        }\r
+        catch (StandardException e)\r
+        {  // if this is a setPosition exception then we ran out of Blob\r
+            if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))\r
+                e = StandardException.newException(\r
+                    SQLState.BLOB_POSITION_TOO_LARGE, new Long(startPos));\r
+            throw handleMyExceptions(e);\r
+        }\r
+        catch (Throwable t)\r
+        {\r
+                       throw handleMyExceptions(t);\r
+        }\r
+        finally\r
+        {\r
+            if (pushStack)\r
+                restoreContextStack();\r
+        }\r
+\r
+    }\r
+\r
+\r
+  /**\r
+   * Retrieves the <code>BLOB</code> designated by this\r
+   * <code>Blob</code> instance as a stream.\r
+   * @return a stream containing the <code>BLOB</code> data\r
+   * @exception SQLException if there is an error accessing the\r
+   * <code>BLOB</code>\r
+   */\r
+    public java.io.InputStream getBinaryStream()\r
+        throws SQLException\r
+    {\r
+        //call checkValidity to exit by throwing a SQLException if\r
+        //the Blob object has been freed by calling free() on it\r
+        checkValidity();\r
+        \r
+        boolean pushStack = false;\r
+        try\r
+        {\r
+            // if we have byte array, not a stream\r
+            if (materialized)\r
+            {\r
+                return control.getInputStream(0);\r
+            }\r
+            else\r
+            { \r
+                // have a stream\r
+\r
+                synchronized (getConnectionSynchronization())\r
+                {\r
+                    pushStack = !getEmbedConnection().isClosed();\r
+                    if (pushStack)\r
+                        setupContextStack();\r
+\r
+                    ((Resetable)myStream).resetStream();\r
+                    return new UpdatableBlobStream (this, \r
+                            new AutoPositioningStream (this, myStream, this));\r
+                }\r
+            }\r
+        }\r
+        catch (Throwable t)\r
+        {\r
+                       throw handleMyExceptions(t);\r
+        }\r
+        finally\r
+        {\r
+            if (pushStack)\r
+                restoreContextStack();\r
+        }\r
+    }\r
+\r
+\r
+  /**\r
+   * Determines the byte position at which the specified byte\r
+   * <code>pattern</code> begins within the <code>BLOB</code>\r
+   * value that this <code>Blob</code> object represents.  The\r
+   * search for <code>pattern</code. begins at position\r
+   * <code>start</code>\r
+   * @param pattern the byte array for which to search\r
+   * @param start the position at which to begin searching; the\r
+   *        first position is 1\r
+   * @return the position at which the pattern appears, else -1.\r
+   * @exception SQLException if there is an error accessing the\r
+   * <code>BLOB</code>\r
+   */\r
+    public long position(byte[] pattern, long start)\r
+        throws SQLException\r
+    {\r
+        //call checkValidity to exit by throwing a SQLException if\r
+        //the Blob object has been freed by calling free() on it\r
+        checkValidity();\r
+        \r
+        boolean pushStack = false;\r
+        try\r
+        {\r
+            if (start < 1)\r
+                throw StandardException.newException(\r
+                    SQLState.BLOB_BAD_POSITION, new Long(start));\r
+            if (pattern == null)\r
+                throw StandardException.newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);\r
+            if (pattern.length == 0)\r
+                return start; // match DB2's SQL LOCATE function\r
+\r
+            synchronized (getConnectionSynchronization())\r
+            {\r
+                pushStack = !getEmbedConnection().isClosed();\r
+                if (pushStack)\r
+                    setupContextStack();\r
+\r
+                setPosition(start-1);\r
+                // look for first character\r
+                int lookFor = pattern[0];\r
+                long curPos;\r
+                int c;\r
+                while (true)\r
+                {\r
+                    c = read();\r
+                    if (c == -1)  // run out of stream\r
+                        return -1;\r
+                    if (c == lookFor)\r
+                    {\r
+                        curPos = pos;\r
+                        if (checkMatch(pattern))\r
+                            return curPos;\r
+                        else\r
+                            setPosition(curPos);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        catch (StandardException e)\r
+        {  // if this is a setPosition exception then not found\r
+            if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))\r
+                return -1;\r
+            else\r
+                throw handleMyExceptions(e);\r
+        }\r
+        catch (Throwable t)\r
+        {\r
+                       throw handleMyExceptions(t);\r
+        }\r
+        finally\r
+        {\r
+            if (pushStack)\r
+                restoreContextStack();\r
+        }\r
+\r
+    }\r
+\r
+\r
+    /*\r
+     check whether pattern (starting from the second byte) appears inside\r
+     posStream (at the current position)\r
+     @param posStream the stream to search inside\r
+     @param pattern the byte array passed in by the user to search with\r
+     @return true if match, false otherwise\r
+     */\r
+    private boolean checkMatch(byte[] pattern)\r
+        throws IOException, SQLException {\r
+       // check whether rest matches\r
+       // might improve performance by reading more\r
+        for (int i = 1; i < pattern.length; i++)\r
+        {\r
+            int b = read();\r
+            if ((b < 0) || (b != pattern[i]))  // mismatch or stream runs out\r
+                return false;\r
+        }\r
+        return true;\r
+    }\r
+\r
+  /**\r
+   * Determines the byte position in the <code>BLOB</code> value\r
+   * designated by this <code>Blob</code> object at which\r
+   * <code>pattern</code> begins.  The search begins at position\r
+   * <code>start</code>.\r
+   * @param pattern the <code>Blob</code> object designating\r
+   * the <code>BLOB</code> value for which to search\r
+   * @param start the position in the <code>BLOB</code> value\r
+   *        at which to begin searching; the first position is 1\r
+   * @return the position at which the pattern begins, else -1\r
+   * @exception SQLException if there is an error accessing the\r
+   * <code>BLOB</code>\r
+   */\r
+    public long position(Blob pattern, long start)\r
+        throws SQLException\r
+    {\r
+        //call checkValidity to exit by throwing a SQLException if\r
+        //the Blob object has been freed by calling free() on it\r
+        checkValidity();\r
+        \r
+        boolean pushStack = false;\r
+        try\r
+        {\r
+            if (start < 1)\r
+                throw StandardException.newException(\r
+                    SQLState.BLOB_BAD_POSITION, new Long(start));\r
+            if (pattern == null)\r
+                throw StandardException.newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);\r
+            synchronized (getConnectionSynchronization())\r
+            {\r
+                pushStack = !getEmbedConnection().isClosed();\r
+                if (pushStack)\r
+                    setupContextStack();\r
+\r
+                setPosition(start-1);\r
+                // look for first character\r
+                byte[] b;\r
+                try\r
+                { // pattern is not necessarily a Derby Blob\r
+                    b = pattern.getBytes(1,1);\r
+                }\r
+                catch (SQLException e)\r
+                {\r
+                    throw StandardException.newException(SQLState.BLOB_UNABLE_TO_READ_PATTERN);\r
+                }\r
+                if (b == null || b.length < 1)  // the 'empty' blob\r
+                    return start; // match DB2's SQL LOCATE function\r
+                int lookFor = b[0];\r
+                int c;\r
+                long curPos;\r
+                while (true)\r
+                {\r
+                    c = read();\r
+                    if (c == -1)  // run out of stream\r
+                        return -1;\r
+                    if (c == lookFor)\r
+                    {\r
+                        curPos = pos;\r
+                        if (checkMatch(pattern))\r
+                            return curPos;\r
+                        else\r
+                            setPosition(curPos);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        catch (StandardException e)\r
+        {  // if this is a setPosition exception then not found\r
+            if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))\r
+                return -1;\r
+            else\r
+                throw handleMyExceptions(e);\r
+        }\r
+        catch (Throwable t)\r
+        {\r
+                       throw handleMyExceptions(t);\r
+        }\r
+        finally\r
+        {\r
+            if (pushStack)\r
+                restoreContextStack();\r
+        }\r
+\r
+    }\r
+\r
+\r
+    /*\r
+     check whether pattern (starting from the second byte) appears inside\r
+     posStream (at the current position)\r
+     @param posStream the stream to search inside\r
+     @param pattern the blob passed in by the user to search with\r
+     @return true if match, false otherwise\r
+     */\r
+    private boolean checkMatch(Blob pattern)\r
+        throws IOException, SQLException\r
+    {\r
+        // check whether rest matches\r
+        // might improve performance by reading buffer at a time\r
+        InputStream pStream;\r
+        try\r
+        {\r
+            pStream = pattern.getBinaryStream();\r
+        }\r
+        catch (SQLException e)\r
+        {\r
+            return false;\r
+        }\r
+        if (pStream == null)\r
+            return false;\r
+        // throw away first character since we already read it in the calling\r
+        // method\r
+        int b1 = pStream.read();\r
+        if (b1 < 0)\r
+            return false;\r
+        while (true)\r
+        {\r
+            b1 = pStream.read();\r
+            if (b1 < 0)  // search blob runs out\r
+                return true;\r
+            int b2 = read();\r
+            if ((b1 != b2) || (b2 < 0))  // mismatch or stream runs out\r
+                return false;\r
+        }\r
+    }\r
+\r
+    /*\r
+      Convert exceptions where needed before calling handleException to convert\r
+      them to SQLExceptions.\r
+    */\r
+       private SQLException handleMyExceptions(Throwable t)\r
+        throws SQLException\r
+    {\r
+        if (t instanceof StandardException)\r
+        {\r
+            // container closed means the blob or clob was accessed after commit\r
+            if (((StandardException) t).getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED))\r
+            {\r
+                t = StandardException.newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);\r
+            }\r
+        }\r
+        return handleException(t);\r
+       }\r
+\r
+\r
+   /*\r
+    If we have a stream, release the resources associated with it.\r
+    */\r
+    protected void finalize()\r
+    {\r
+        if (!materialized)\r
+            ((Resetable)myStream).closeStream();\r
+    }\r
+\r
+       /**\r
+    Following methods are for the new JDBC 3.0 methods in java.sql.Blob\r
+    (see the JDBC 3.0 spec). We have the JDBC 3.0 methods in Local20\r
+    package, so we don't have to have a new class in Local30.\r
+    The new JDBC 3.0 methods don't make use of any new JDBC3.0 classes and\r
+    so this will work fine in jdbc2.0 configuration.\r
+       */\r
+\r
+       /////////////////////////////////////////////////////////////////////////\r
+       //\r
+       //      JDBC 3.0        -       New public methods\r
+       //\r
+       /////////////////////////////////////////////////////////////////////////\r
+\r
+       /**\r
+    * JDBC 3.0\r
+    *\r
+    * Writes the given array of bytes to the BLOB value that this Blob object\r
+    * represents, starting at position pos, and returns the number of bytes written.\r
+    *\r
+    * @param pos - the position in the BLOB object at which to start writing\r
+    * @param bytes - the array of bytes to be written to the BLOB value that this\r
+    * Blob object represents\r
+    * @return the number of bytes written\r
+    * @exception SQLException Feature not implemented for now.\r
+       */\r
+       public int setBytes(long pos, byte[] bytes) throws SQLException {\r
+            return setBytes(pos, bytes, 0, bytes.length);\r
+       }\r
+\r
+   /**\r
+    * JDBC 3.0\r
+    *\r
+    * Writes all or part of the given array of byte array to the BLOB value that\r
+    * this Blob object represents and returns the number of bytes written.\r
+    * Writing starts at position pos in the BLOB value; len bytes from the given\r
+    * byte array are written.\r
+    *\r
+    * @param pos - the position in the BLOB object at which to start writing\r
+    * @param bytes - the array of bytes to be written to the BLOB value that this\r
+    * Blob object represents\r
+    * @param offset - the offset into the array bytes at which to start reading\r
+    * the bytes to be set\r
+    * @param len - the number of bytes to be written to the BLOB value from the\r
+    * array of bytes bytes\r
+    * @return the number of bytes written\r
+    * @exception SQLException Feature not implemented for now.\r
+       */\r
+    public int setBytes(long pos,\r
+            byte[] bytes,\r
+            int offset,\r
+            int len) throws SQLException {\r
+        checkValidity();\r
+        try {\r
+            if (materialized) {\r
+                if (pos - 1 > length())\r
+                    throw Util.generateCsSQLException(\r
+                            SQLState.BLOB_POSITION_TOO_LARGE, new Long(pos));\r
+                if (pos < 1)\r
+                    throw Util.generateCsSQLException(\r
+                        SQLState.BLOB_BAD_POSITION, new Long(pos));\r
+                len = (int) control.write (bytes, offset, len, pos - 1);\r
+            }\r
+            else {\r
+                control = new LOBStreamControl (getEmbedConnection().getDBName());\r
+                control.copyData (myStream, length());\r
+                len = (int) control.write(bytes, offset, len, pos - 1);\r
+                myStream.close();\r
+                materialized = true;\r
+            }\r
+            return len;\r
+        }\r
+        catch (IOException e) {\r
+            throw Util.setStreamFailure (e);\r
+        }\r
+        catch (StandardException se) {\r
+            throw Util.generateCsSQLException (se);\r
+        }\r
+    }\r
+\r
+   /**\r
+    * JDBC 3.0\r
+    *\r
+    * Retrieves a stream that can be used to write to the BLOB value that this\r
+    * Blob object represents. The stream begins at position pos. \r
+    *\r
+    * @param pos - the position in the BLOB object at which to start writing\r
+    * @return a java.io.OutputStream object to which data can be written \r
+    * @exception SQLException Feature not implemented for now.\r
+       */\r
+       public java.io.OutputStream setBinaryStream (long pos)\r
+                                    throws SQLException {\r
+            checkValidity ();\r
+            if (pos - 1 > length())\r
+                throw Util.generateCsSQLException(\r
+                    SQLState.BLOB_POSITION_TOO_LARGE, new Long(pos));\r
+            if (pos < 1)\r
+                throw Util.generateCsSQLException(\r
+                    SQLState.BLOB_BAD_POSITION, new Long(pos));\r
+            try {\r
+                if (materialized) {\r
+                    return control.getOutputStream (pos - 1);\r
+                }\r
+                else {\r
+                    control = new LOBStreamControl (\r
+                                            getEmbedConnection().getDBName());\r
+                    control.copyData (myStream, pos - 1);\r
+                    myStream.close ();\r
+                    materialized = true;\r
+                    return control.getOutputStream(pos - 1);\r
+\r
+                }\r
+            }\r
+            catch (IOException e) {\r
+                throw Util.setStreamFailure (e);\r
+            }\r
+            catch (StandardException se) {\r
+                throw Util.generateCsSQLException (se);\r
+            }\r
+       }\r
+\r
+       /**\r
+    * JDBC 3.0\r
+    *\r
+    * Truncates the BLOB value that this Blob object represents to be len bytes\r
+    * in length.\r
+    *\r
+    * @param len - the length, in bytes, to which the BLOB value that this Blob\r
+    * object represents should be truncated\r
+    * @exception SQLException Feature not implemented for now.\r
+       */\r
+       public void truncate(long len)\r
+                                        throws SQLException\r
+       {\r
+            if (len > length())\r
+                throw Util.generateCsSQLException(\r
+                    SQLState.BLOB_LENGTH_TOO_LONG, new Long(pos));\r
+            try {\r
+                if (materialized) {\r
+                    control.truncate (len);\r
+                }\r
+                else {\r
+                    control = new LOBStreamControl (getEmbedConnection().getDBName());\r
+                    control.copyData (myStream, len);\r
+                    myStream.close();\r
+                    materialized = true;\r
+                }\r
+            }\r
+            catch (IOException e) {\r
+                throw Util.setStreamFailure (e);\r
+            }\r
+            catch (StandardException se) {\r
+                throw Util.generateCsSQLException (se);\r
+            }\r
+       }\r
+\r
+    /////////////////////////////////////////////////////////////////////////\r
+    //\r
+    // JDBC 4.0        -       New public methods\r
+    //\r
+    /////////////////////////////////////////////////////////////////////////\r
+    /**\r
+     * This method frees the <code>Blob</code> object and releases the resources that \r
+     * it holds. The object is invalid once the <code>free</code>\r
+     * method is called. If <code>free</code> is called multiple times, the subsequent\r
+     * calls to <code>free</code> are treated as a no-op.\r
+     * \r
+     * @throws SQLException if an error occurs releasing\r
+     * the Blob's resources\r
+     */\r
+    public void free()\r
+        throws SQLException {\r
+        //calling free() on a already freed object is treated as a no-op\r
+        if (!isValid) return;\r
+        \r
+        //now that free has been called the Blob object is no longer\r
+        //valid\r
+        isValid = false;\r
+        \r
+        //remove entry from connection\r
+        localConn.removeLOBMapping(locator);\r
+        //initialialize length to default value -1\r
+        myLength = -1;\r
+        \r
+        //if it is a stream then close it.\r
+        //if a array of bytes then initialize it to null\r
+        //to free up space\r
+        if (!materialized)\r
+            ((Resetable)myStream).closeStream();\r
+        else {\r
+            try {\r
+                control.free ();\r
+                control = null;\r
+            }\r
+            catch (IOException e) {\r
+                throw Util.setStreamFailure (e);\r
+            }\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Returns an <code>InputStream</code> object that contains a partial \r
+     * <code>Blob</code> value, starting with the byte specified by pos, \r
+     * which is length bytes in length.\r
+     *\r
+     * @param pos the offset to the first byte of the partial value to be \r
+     *      retrieved. The first byte in the <code>Blob</code> is at \r
+     *      position 1\r
+     * @param length the length in bytes of the partial value to be retrieved\r
+     * @return through which the partial <code>Blob</code> value can be read. \r
+     * @throws SQLException if pos is less than 1 or if pos is greater than \r
+     *      the number of bytes in the <code>Blob</code> or if pos + length is\r
+     *      greater than the number of bytes in the <code>Blob</code>\r
+     */\r
+    public InputStream getBinaryStream(long pos, long length)\r
+        throws SQLException {\r
+        //call checkValidity to exit by throwing a SQLException if\r
+        //the Blob object has been freed by calling free() on it\r
+        checkValidity();\r
+        \r
+        if (pos <= 0) {\r
+            throw Util.generateCsSQLException(\r
+                    SQLState.BLOB_BAD_POSITION,\r
+                    new Long(pos));\r
+        }\r
+        if (length < 0) {\r
+            throw Util.generateCsSQLException(\r
+                    SQLState.BLOB_NONPOSITIVE_LENGTH,\r
+                    new Long(length));\r
+        }\r
+        if (length > (this.length() - pos)) {\r
+            throw Util.generateCsSQLException(\r
+                    SQLState.POS_AND_LENGTH_GREATER_THAN_LOB,\r
+                    new Long(pos), new Long(length));\r
+        }\r
+        \r
+        try {\r
+            return new UpdatableBlobStream(this,\r
+                                            getBinaryStream(),\r
+                                            pos-1,\r
+                                            length);\r
+        } catch (IOException ioe) {\r
+            throw Util.setStreamFailure(ioe);\r
+        }\r
+    }\r
+    \r
+    /*\r
+     * Checks is isValid is true. If it is not true throws \r
+     * a SQLException stating that a method has been called on\r
+     * an invalid LOB object\r
+     *\r
+     * throws SQLException if isvalid is not true.\r
+     */\r
+    private void checkValidity() throws SQLException{\r
+        //check for connection to maintain sqlcode for closed\r
+        //connection\r
+        getEmbedConnection().checkIfClosed();\r
+        if(!isValid)\r
+            throw newSQLException(SQLState.LOB_OBJECT_INVALID);\r
+    }\r
+    \r
+    /**\r
+     * Returns if blob data is stored locally (using LOBStreamControl).\r
+     * @return true if materialized else false\r
+     */\r
+    boolean isMaterialized () {\r
+        return materialized;\r
+    }\r
+\r
+    /**\r
+     * Return locator for this lob.\r
+     * \r
+     * @return The locator identifying this blob\r
+     */\r
+    public int getLocator() {\r
+        if (locator == 0) {\r
+            locator = localConn.addLOBMapping(this);\r
+        }\r
+        return locator;\r
+    }\r
+}\r