db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r907732 - in /db/derby/code/trunk/java/engine/org/apache/derby: iapi/types/SQLBinary.java iapi/types/SQLBlob.java iapi/types/SQLClob.java impl/sql/execute/BasicSortObserver.java
Date Mon, 08 Feb 2010 17:24:13 GMT
Author: kristwaa
Date: Mon Feb  8 17:24:12 2010
New Revision: 907732

URL: http://svn.apache.org/viewvc?rev=907732&view=rev
Log:
DERBY-4520: Refactor and extend data type cloning facilities 

Changed the cloneValue methods for BLOB and CLOB.
Noteworthy information:
 - made BasicSortObserver force materialization when cloning
   (required because it closes the underlying source result set).
 - java.sql.[BC]lob values are assumed to be "clone-safe"
   (i.e. more than one SQL[BC]lob object can reference them).
 - in some cases invoking cloneValue(false) will result in a stream being
   matieralized, because we don't know how to clone the stream otherwise.
   A better future solution might be to use temporary disk storage instead.
 - there's a TODO for implementing an optimization for small streams, where
   Derby could choose to materialize the streams if the length is known.
   This is only important for a few use-cases, but it avoids decoding the
   stream data more than once.

Patch file: derby-4520-7b-lob_clonevalue_methods.diff

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBinary.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBlob.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBinary.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBinary.java?rev=907732&r1=907731&r2=907732&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBinary.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBinary.java Mon Feb  8
17:24:12 2010
@@ -638,7 +638,7 @@
 	 */
 
 	/** @see DataValueDescriptor#cloneValue */
-	public final DataValueDescriptor cloneValue(boolean forceMaterialization)
+	public DataValueDescriptor cloneValue(boolean forceMaterialization)
 	{
 		try
 		{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBlob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBlob.java?rev=907732&r1=907731&r2=907732&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBlob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLBlob.java Mon Feb  8 17:24:12
2010
@@ -24,8 +24,11 @@
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.reference.Limits;
 import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.services.io.CloneableStream;
 import org.apache.derby.iapi.services.io.StoredFormatIds;
 
+import org.apache.derby.shared.common.sanity.SanityManager;
+
 import java.sql.Blob;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -77,6 +80,61 @@
 	}
 
     /**
+     * Returns a clone of this BLOB value.
+     * <p>
+     * Unlike the other binary types, BLOBs can be very large. We try to clone
+     * the underlying stream when possible to avoid having to materialize the
+     * value into memory.
+     *
+     * @param forceMaterialization any streams representing the data value will
+     *      be materialized if {@code true}, the data value will be kept as a
+     *      stream if possible if {@code false}
+     * @return A clone of this BLOB value.
+     */
+    public DataValueDescriptor cloneValue(boolean forceMaterialization) {
+        // TODO: Add optimization for materializing "smallish" streams. This
+        //       may be more effective because the data doesn't have to be
+        //       decoded multiple times.
+        final SQLBlob clone = new SQLBlob();
+
+        // Shortcut cases where value is NULL.
+        if (isNull()) {
+            return clone;
+        }
+
+        if (!forceMaterialization && dataValue == null) {
+            if (stream != null && stream instanceof CloneableStream) {
+                clone.setStream( ((CloneableStream)stream).cloneStream());
+                if (streamValueLength != -1) {
+                    clone.streamValueLength = streamValueLength;
+                }
+            } else if (_blobValue != null) {
+                // Assumes the Blob object can be shared between value holders.
+                clone.setValue(_blobValue);
+            }
+            // At this point we may still not have cloned the value because we
+            // have a stream that isn't cloneable.
+            // TODO: Add functionality to materialize to temporary disk storage
+            //       to avoid OOME for large BLOBs.
+        }
+
+        // See if we are forced to materialize the value, either because
+        // requested by the user or because we don't know how to clone it.
+        if (clone.isNull() || forceMaterialization) {
+            try {
+                // NOTE: The byte array holding the value is shared.
+                clone.setValue(getBytes());
+            } catch (StandardException se) {
+                if (SanityManager.DEBUG) {
+                    SanityManager.THROWASSERT("Unexpected exception", se);
+                }
+                return null;
+            }
+        }
+        return clone;
+    }
+
+    /**
      * @see DataValueDescriptor#getNewNull
      */
 	public DataValueDescriptor getNewNull()

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java?rev=907732&r1=907731&r2=907732&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java Mon Feb  8 17:24:12
2010
@@ -26,6 +26,7 @@
 import org.apache.derby.iapi.jdbc.CharacterStreamDescriptor;
 
 import org.apache.derby.iapi.services.io.ArrayInputStream;
+import org.apache.derby.iapi.services.io.CloneableStream;
 import org.apache.derby.iapi.services.io.FormatIdInputStream;
 import org.apache.derby.iapi.services.io.InputStreamUtil;
 import org.apache.derby.iapi.services.io.StoredFormatIds;
@@ -97,25 +98,63 @@
 	 * DataValueDescriptor interface
 	 */
 
-	/** @see DataValueDescriptor#cloneValue */
-	public DataValueDescriptor cloneValue(boolean forceMaterialization)
-	{
-        // TODO: Should this be rewritten to clone the stream instead of
-        //       materializing the value if possible?
-		try
-		{
-            SQLClob clone = new SQLClob(getString());
-            // Copy the soft upgrade mode state.
-            clone.inSoftUpgradeMode = inSoftUpgradeMode;
+    /**
+     * Returns a clone of this CLOB value.
+     * <p>
+     * Unlike the other binary types, CLOBs can be very large. We try to clone
+     * the underlying stream when possible to avoid having to materialize the
+     * value into memory.
+     *
+     * @param forceMaterialization any streams representing the data value will
+     *      be materialized if {@code true}, the data value will be kept as a
+     *      stream if possible if {@code false}
+     * @return A clone of this CLOB value.
+     * @see DataValueDescriptor#cloneValue
+     */
+    public DataValueDescriptor cloneValue(boolean forceMaterialization) {
+        // TODO: Add optimization for materializing "smallish" streams. This
+        //       may be more effective because the data doesn't have to be
+        //       decoded multiple times.
+        final SQLClob clone = new SQLClob();
+        // Copy the soft upgrade mode state.
+        clone.inSoftUpgradeMode = inSoftUpgradeMode;
+        
+        // Shortcut cases where the value is NULL.
+        if (isNull()) {
             return clone;
-		}
-		catch (StandardException se)
-		{
-			if (SanityManager.DEBUG)
-				SanityManager.THROWASSERT("Unexpected exception", se);
-			return null;
-		}
-	}
+        }
+
+        if (!forceMaterialization) {
+            if (stream != null && stream instanceof CloneableStream) {
+                int length = UNKNOWN_LOGICAL_LENGTH;
+                if (csd != null && csd.getCharLength() > 0) {
+                    length = (int)csd.getCharLength();
+                }
+                clone.setValue(((CloneableStream)stream).cloneStream(), length);
+            } else if (_clobValue != null) {
+                // Assumes the Clob object can be shared between value holders.
+                clone.setValue(_clobValue);
+            }
+            // At this point we may still not have cloned the value because we
+            // have a stream that isn't cloneable.
+            // TODO: Add functionality to materialize to temporary disk storage
+            //       to avoid OOME for large CLOBs.
+        }
+
+        // See if we are forced to materialize the value, either because
+        // requested by the user or because we don't know how to clone it.
+        if (clone.isNull() || forceMaterialization) {
+            try {
+                clone.setValue(getString());
+            } catch (StandardException se) {
+                if (SanityManager.DEBUG) {
+                    SanityManager.THROWASSERT("Unexpected exception", se);
+                }
+                return null;
+            }
+        }
+        return clone;
+    }
 
 	/**
 	 * @see DataValueDescriptor#getNewNull

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java?rev=907732&r1=907731&r2=907732&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java
Mon Feb  8 17:24:12 2010
@@ -162,11 +162,12 @@
 		for (int i = 0; i < origArray.length; i++)
 		{
             // History: We used to materialize streams when getting a clone
-            //          here (i.e. used cloneValue, not cloneObject). We still
-            //          do.
-            //          TODO: change to 'true' below and add comment.
+            //          here (i.e. used getClone, not cloneObject). We still
+            //          do, as the sorter closes the underlying source result
+            //          set very early, which causes store streams to fail
+            //          because the container handle is closed.
             // Beetle 4896.
-			newArray[i] = origArray[i].cloneValue(false);
+            newArray[i] = origArray[i].cloneValue(true);
 		}
 
 		return newArray;



Mime
View raw message