Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / jdbc / StoreStreamClob.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java
new file mode 100644 (file)
index 0000000..9047afd
--- /dev/null
@@ -0,0 +1,322 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.jdbc.StoreStreamClob\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one\r
+   or more contributor license agreements.  See the NOTICE file\r
+   distributed with this work for additional information\r
+   regarding copyright ownership.  The ASF licenses this file\r
+   to you under the Apache License, Version 2.0 (the\r
+   "License"); you may not use this file except in compliance\r
+   with 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,\r
+   software distributed under the License is distributed on an\r
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
+   KIND, either express or implied.  See the License for the\r
+   specific language governing permissions and limitations\r
+   under the License.\r
+\r
+ */\r
+package org.apache.derby.impl.jdbc;\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.EOFException;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.Reader;\r
+import java.io.Writer;\r
+\r
+import java.sql.SQLException;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.types.Resetable;\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.util.UTF8Util;\r
+\r
+/**\r
+ * A read-only Clob representation operating on streams out of the Derby store\r
+ * module.\r
+ * <p>\r
+ * Note that the streams from the store are expected to have the following\r
+ * properties:\r
+ * <ol> <li>The first two bytes are used for length encoding. Note that due to\r
+ *          the inadequate max number of this format, it is always ignored. This\r
+ *          is also true if there actually is a length encoded there. The two\r
+ *          bytes are excluded from the length of the stream.\r
+ *      <li>A Derby-specific end-of-stream marker at the end of the stream can\r
+ *          be present. The marker is expected to be <code>0xe0 0x00 0x00</code>\r
+ * </ol>\r
+ */\r
+final class StoreStreamClob\r
+    implements InternalClob {\r
+\r
+    /** Maximum value used when requesting bytes/chars to be skipped. */\r
+    private static final long SKIP_BUFFER_SIZE = 8*1024; // 8 KB\r
+\r
+    /** Tells whether this Clob has been released or not. */\r
+    private volatile boolean released = false;\r
+\r
+    /**\r
+     * The stream from store, used to read bytes from the database.\r
+     * <p>\r
+     * To be able to support the requirements, the stream must implement\r
+     * {@link Resetable}.\r
+     */\r
+    //@GuardedBy("synchronizationObject")\r
+    private final PositionedStoreStream positionedStoreStream;\r
+    /** The connection (child) this Clob belongs to. */\r
+    private final ConnectionChild conChild;\r
+    /** Object used for synchronizing access to the store stream. */\r
+    private final Object synchronizationObject;\r
+\r
+\r
+    /**\r
+     * Creates a new Clob based on a stream from store.\r
+     * <p>\r
+     * Note that the stream passed in have to fulfill certain requirements,\r
+     * which are not currently totally enforced by Java (the language).\r
+     *\r
+     * @param stream the stream containing the Clob value. This stream is\r
+     *      expected to implement {@link Resetable} and to be a\r
+     *      {@link org.apache.derby.iapi.services.io.FormatIdInputStream} with\r
+     *      an ${link org.apache.derby.impl.store.raw.data.OverflowInputStream}\r
+     *      inside. However, the available interfaces does not guarantee this.\r
+     *      See the class JavaDoc for more information about this stream.\r
+     * @param conChild the connection (child) this Clob belongs to\r
+     * @throws StandardException if initializing the store stream fails\r
+     * @throws NullPointerException if <code>stream</code> or\r
+     *      <code>conChild</code> is null\r
+     * @throws ClassCastException if <code>stream</code> is not an instance\r
+     *      of <code>Resetable</code>\r
+     * @see org.apache.derby.iapi.services.io.FormatIdInputStream\r
+     * @see org.apache.derby.impl.store.raw.data.OverflowInputStream\r
+     */\r
+    public StoreStreamClob(InputStream stream, ConnectionChild conChild)\r
+            throws StandardException {\r
+        this.positionedStoreStream = new PositionedStoreStream(stream);\r
+        this.conChild = conChild;\r
+        this.synchronizationObject = conChild.getConnectionSynchronization();\r
+        this.positionedStoreStream.initStream();\r
+    }\r
+\r
+    /**\r
+     * Releases resources associated with this Clob.\r
+     */\r
+    public void release() {\r
+        if (!released) {\r
+            this.positionedStoreStream.closeStream();\r
+            this.released = true;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns the number of bytes in the Clob.\r
+     *\r
+     * @return The number of bytes in the Clob.\r
+     * @throws IOException if accessing the I/O resources fail\r
+     * @throws SQLException if accessing the store resources fail\r
+     */\r
+    public long getByteLength()\r
+            throws IOException, SQLException {\r
+        checkIfValid();\r
+        // Read through the whole stream to get the length.\r
+        long byteLength = 0;\r
+        try {\r
+            this.conChild.setupContextStack();\r
+            this.positionedStoreStream.reposition(0L);\r
+            // See if length is encoded in the stream.\r
+            int us1 = this.positionedStoreStream.read();\r
+            int us2 = this.positionedStoreStream.read();\r
+            byteLength = (us1 << 8) + (us2 << 0);\r
+            if (byteLength == 0) {\r
+                while (true) {\r
+                    long skipped =\r
+                        this.positionedStoreStream.skip(SKIP_BUFFER_SIZE);\r
+                    if (skipped <= 0) {\r
+                        break;\r
+                    }\r
+                    byteLength += skipped;\r
+                }\r
+                // Subtract 3 bytes for the end-of-stream marker.\r
+                byteLength -= 3;\r
+            }\r
+            return byteLength;\r
+        } catch (StandardException se) {\r
+            throw Util.generateCsSQLException(se);\r
+        } finally {\r
+            this.conChild.restoreContextStack();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns the number of characters in the Clob.\r
+     *\r
+     * @return Number of characters in the Clob.\r
+     * @throws SQLException if any kind of error is encountered, be it related\r
+     *      to I/O or something else\r
+     */\r
+    public long getCharLength()\r
+            throws SQLException {\r
+        checkIfValid();\r
+        synchronized (this.synchronizationObject) {\r
+            this.conChild.setupContextStack();\r
+            try {\r
+                return UTF8Util.skipUntilEOF(\r
+                                new BufferedInputStream(getRawByteStream()));\r
+            } catch (Throwable t) {\r
+                throw noStateChangeLOB(t);\r
+            } finally {\r
+                this.conChild.restoreContextStack();\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns a stream serving the raw bytes of this Clob.\r
+     * <p>\r
+     * Note that the stream returned is an internal stream, and it should not be\r
+     * pulished to end users.\r
+     *\r
+     * @return A stream serving the bytes of this Clob, initialized at byte 0 of\r
+     *      the data. The buffer must be assumed to be unbuffered, but no such\r
+     *      guarantee is made.\r
+     * @throws IOException if accessing the I/O resources fail\r
+     * @throws SQLException if accessing the store resources fail\r
+     */\r
+    public InputStream getRawByteStream()\r
+            throws IOException, SQLException {\r
+        checkIfValid();\r
+        try {\r
+            // Skip the encoded length.\r
+            this.positionedStoreStream.reposition(2L);\r
+        } catch (StandardException se) {\r
+            throw Util.generateCsSQLException(se);\r
+        }\r
+        return this.positionedStoreStream;\r
+    }\r
+\r
+    /**\r
+     * Returns a reader for the Clob, initialized at the specified character\r
+     * position.\r
+     *\r
+     * @param pos character position. The first character is at position 1.\r
+     * @return A reader initialized at the specified position.\r
+     * @throws EOFException if the positions is larger than the Clob\r
+     * @throws IOException if accessing the I/O resources fail\r
+     * @throws SQLException if accessing the store resources fail\r
+     */\r
+    public Reader getReader(long pos)\r
+            throws IOException, SQLException  {\r
+        checkIfValid();\r
+        try {\r
+            this.positionedStoreStream.reposition(0L);\r
+        } catch (StandardException se) {\r
+            throw Util.generateCsSQLException(se);\r
+        }\r
+        Reader reader = new UTF8Reader(this.positionedStoreStream,\r
+                                TypeId.CLOB_MAXWIDTH, this.conChild,\r
+                                this.synchronizationObject);\r
+        long leftToSkip = pos -1;\r
+        long skipped;\r
+        while (leftToSkip > 0) {\r
+            skipped = reader.skip(leftToSkip);\r
+            // Since Reader.skip block until some characters are available,\r
+            // a return value of 0 must mean EOF.\r
+            if (skipped <= 0) {\r
+                throw new EOFException("Reached end-of-stream prematurely");\r
+            }\r
+            leftToSkip -= skipped;\r
+        }\r
+        return reader;\r
+    }\r
+\r
+    /**\r
+     * Returns the byte position for the specified character position.\r
+     *\r
+     * @param charPos character position. First character is at position 1.\r
+     * @return Corresponding byte position. First byte is at position 0.\r
+     * @throws EOFException if the position is bigger then the Clob\r
+     * @throws IOException if accessing the underlying I/O resources fail\r
+     * @throws SQLException if accessing the underlying store resources fail\r
+     */\r
+    public long getBytePosition(long charPos)\r
+            throws IOException, SQLException {\r
+        return UTF8Util.skipFully(getRawByteStream(), charPos -1);\r
+    }\r
+\r
+    /**\r
+     * Not supported.\r
+     *\r
+     * @see InternalClob#getWriter\r
+     */\r
+    public Writer getWriter(long pos) {\r
+        throw new UnsupportedOperationException(\r
+            "A StoreStreamClob object is not updatable");\r
+    }\r
+\r
+    /**\r
+     * Not supported.\r
+     *\r
+     * @see InternalClob#insertString\r
+     */\r
+    public long insertString(String str, long pos) {\r
+        throw new UnsupportedOperationException(\r
+            "A StoreStreamClob object is not updatable");\r
+    }\r
+\r
+    /**\r
+     * Tells if this Clob can be modified.\r
+     *\r
+     * @return <code>false</code>, this Clob is read-only.\r
+     */\r
+    public boolean isWritable() {\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Not supported.\r
+     *\r
+     * @see InternalClob#truncate\r
+     */\r
+    public void truncate(long newLength) {\r
+        throw new UnsupportedOperationException(\r
+            "A StoreStreamClob object is not updatable");\r
+    }\r
+\r
+    /**\r
+     * Wrap real exception in a {@link SQLException} to avoid changing the state\r
+     * of the connection child by cleaning it up.\r
+     *\r
+     * @param t real cause of error that we want to "ignore" with respect to\r
+     *      transaction context cleanup\r
+     * @return A {@link SQLException} wrapped around the real cause of the error\r
+     */\r
+    private static SQLException noStateChangeLOB(Throwable t) {\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 org.apache.derby.impl.jdbc.EmbedResultSet.noStateChangeException(t);\r
+    }\r
+\r
+    /**\r
+     * Makes sure the Clob has not been released.\r
+     * <p>\r
+     * All operations are invalid on a released Clob.\r
+     *\r
+     * @throws IllegalStateException if the Clob has been released\r
+     */\r
+    private void checkIfValid() {\r
+        if (this.released) {\r
+            throw new IllegalStateException(\r
+                "The Clob has been released and is not valid");\r
+        }\r
+    }\r
+} // End class StoreStreamClob\r