db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r734148 - in /db/derby/code/trunk/java/engine/org/apache/derby/iapi: jdbc/CharacterStreamDescriptor.java types/SQLChar.java types/SQLClob.java types/StringDataValue.java
Date Tue, 13 Jan 2009 14:54:16 GMT
Author: kristwaa
Date: Tue Jan 13 06:54:09 2009
New Revision: 734148

URL: http://svn.apache.org/viewvc?rev=734148&view=rev
Log:
DERBY-3907 (partial): Save useful length information for Clobs in store.
Added StringDataValue.getStreamWithDescriptor().
It it intended to be used when getting a stream from a StringDataValue to be
used with a Clob object, or with streaming of string data values in general.
The DVD is responsible for returning a correct descriptor for the raw stream.
The descriptor is in turn used by other classes to correctly configure
themselves with respect to data offsets, buffering, repositioning and so on.

Changes:
 o CharacterStreamDescriptor
   Added a toString method and more verbose assert-messages.

 o StringDataValue
   Added method 'CharacterStreamDescriptor getStreamWithDescriptor()'.

 o SQLChar
   Made setStream non-final so it can be overridden in SQLClob.
   Added default implementation of getStreamWithDescriptor that always returns
   null. This means that all non-Clob string data types will be handled as
   strings instead of streams in situations where a stream is requested through
   getStreamWithDescriptor.  This might be changed.
   Made throwStreamingIOException protected to access it from SQLClob.

 o SQLClob
   Implemented getStreamWithDescriptor, handling the old 2-byte format only.
   Overrid setStream to discard the stream descriptor when a new stream is set
   for the DVD.

Patch file: derby-3907-4a-add_getStreamWithDescriptor.diff


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/CharacterStreamDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/CharacterStreamDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/CharacterStreamDescriptor.java?rev=734148&r1=734147&r2=734148&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/CharacterStreamDescriptor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/CharacterStreamDescriptor.java
Tue Jan 13 06:54:09 2009
@@ -375,13 +375,14 @@
         public CharacterStreamDescriptor build() {
             // Do validation only in sane builds.
             if (SanityManager.DEBUG) {
-                SanityManager.ASSERT(curBytePos >= 0);
+                SanityManager.ASSERT(curBytePos >= 0, "Negative curBytePos");
                 SanityManager.ASSERT(curCharPos >= 1 ||
-                        curCharPos == BEFORE_FIRST);
-                SanityManager.ASSERT(byteLength >= 0);
-                SanityManager.ASSERT(charLength >= 0);
-                SanityManager.ASSERT(dataOffset >= 0);
-                SanityManager.ASSERT(maxCharLength >= 0);
+                        curCharPos == BEFORE_FIRST, "Invalid curCharPos " +
+                        "(BEFORE_FIRST=" + BEFORE_FIRST + "), " + toString());
+                SanityManager.ASSERT(byteLength >= 0, "Negative byteLength");
+                SanityManager.ASSERT(charLength >= 0, "Negative charLength");
+                SanityManager.ASSERT(dataOffset >= 0, "Negative dataOffset");
+                SanityManager.ASSERT(maxCharLength >= 0, "Negative max length");
 
                 // If current byte pos is set, require char pos to be set too.
                 if ((curBytePos != 0 && curCharPos == 0) || 
@@ -395,16 +396,19 @@
                 // If we're in the header section, the character position must
                 // be before the first character.
                 if (curBytePos < dataOffset) {
-                    SanityManager.ASSERT(curCharPos == BEFORE_FIRST);
+                    SanityManager.ASSERT(curCharPos == BEFORE_FIRST,
+                            "curCharPos in header, " + toString());
                 }
                 // Byte length minus data offset must be equal to or greater
                 // then the character length.
                 if (byteLength > 0 && charLength > 0) {
-                    SanityManager.ASSERT(byteLength - dataOffset >= charLength);
+                    SanityManager.ASSERT(byteLength - dataOffset >= charLength,
+                            "Less than one byte per char, " + toString());
                 }
                 SanityManager.ASSERT(stream != null, "Stream cannot be null");
                 if (positionAware) {
-                    SanityManager.ASSERT(stream instanceof PositionedStream);
+                    SanityManager.ASSERT(stream instanceof PositionedStream,
+                            "Stream not a positioned stream, " + toString());
                 }
                 // Note that the character position can be greater than the
                 // maximum character length, because the limit might be imposed
@@ -412,5 +416,21 @@
             }
             return new CharacterStreamDescriptor(this);
         }
+
+        /**
+         * Returns a textual representation of the builder.
+         *
+         * @return The textual representation of the builder.
+         */
+        public String toString() {
+            String str = "CharacterStreamBuiler@"  + hashCode() +
+                    ":bufferable=" + bufferable + ", isPositionAware=" +
+                    positionAware + ", curBytePos=" + curBytePos +
+                    ", curCharPos=" + curCharPos + ", dataOffset=" +
+                    dataOffset + ", byteLength=" + byteLength +
+                    ", charLength=" + charLength + ", maxCharLength=" +
+                    maxCharLength + ", stream=" + stream.getClass();
+            return str;
+        }
     }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java?rev=734148&r1=734147&r2=734148&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java Tue Jan 13 06:54:09
2009
@@ -40,6 +40,7 @@
 import org.apache.derby.iapi.reference.SQLState;
 
 import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.jdbc.CharacterStreamDescriptor;
 
 import org.apache.derby.iapi.services.cache.ClassSize;
 import org.apache.derby.iapi.services.io.ArrayInputStream;
@@ -66,7 +67,6 @@
 import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
-import java.text.CollationElementIterator;
 import java.text.RuleBasedCollator;
 import java.text.CollationKey;
 import java.text.DateFormat;
@@ -531,8 +531,7 @@
     /**
      * Set this value to the on-disk format stream.
      */
-    public final void setStream(InputStream newStream)
-    {
+    public void setStream(InputStream newStream) {
         this.value = null;
         this.rawLength = -1;
         this.stream = newStream;
@@ -560,6 +559,22 @@
     {
         return stream;
     }
+
+    /**
+     * Returns a descriptor for the input stream for this character data value.
+     *
+     * @return Unless the method is overridden, {@code null} is returned.
+     * @throws StandardException if obtaining the descriptor fails
+     * @see SQLClob#getStreamWithDescriptor()
+     */
+    public CharacterStreamDescriptor getStreamWithDescriptor()
+            throws StandardException {
+        // For now return null for all non-Clob types.
+        // TODO: Is this what we want, or do we want to treat some of the other
+        //       string types as streams as well?
+        return null;
+    }
+
     /**
      * CHAR/VARCHAR/LONG VARCHAR implementation. 
      * Convert to a BigDecimal using getString.
@@ -615,7 +630,15 @@
         return utflen;
     }
 
-    private void throwStreamingIOException(IOException ioe) throws StandardException {
+    /**
+     * Wraps an {@code IOException} in a {@code StandardException} then throws
+     * the wrapping exception.
+     *
+     * @param ioe the {@code IOException} to wrap
+     * @throws StandardException the wrapping exception
+     */
+    protected void throwStreamingIOException(IOException ioe)
+            throws StandardException {
 		throw StandardException.
 			newException(SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION,
 						 ioe, getTypeName());

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=734148&r1=734147&r2=734148&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 Tue Jan 13 06:54:09
2009
@@ -21,16 +21,16 @@
 
 package org.apache.derby.iapi.types;
 
-import org.apache.derby.iapi.types.DataValueDescriptor;
-import org.apache.derby.iapi.types.TypeId;
 import org.apache.derby.iapi.error.StandardException;
 
-import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.jdbc.CharacterStreamDescriptor;
+
 import org.apache.derby.iapi.services.io.StoredFormatIds;
 
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
-import java.sql.Blob;
+import java.io.IOException;
+import java.io.InputStream;
 import java.sql.Clob;
 import java.sql.Date;
 import java.sql.SQLException;
@@ -58,6 +58,13 @@
                     new byte[] {0x00, 0x00, (byte)0xF0, 0x00, 0x00},
                     new byte[] {24, 16, -1, 8, 0}, true, true);
 
+    /**
+     * The descriptor for the stream. If there is no stream this should be
+     * {@code null}, which is also true if the descriptor hasen't been
+     * constructed yet.
+     */
+    private CharacterStreamDescriptor csd;
+
 	/*
 	 * DataValueDescriptor interface.
 	 *
@@ -209,6 +216,80 @@
 		throw dataTypeConversion("java.sql.Date");
 	}
 
+    /**
+     * Returns a descriptor for the input stream for this CLOB value.
+     * <p>
+     * The descriptor contains information about header data, current positions,
+     * length, whether the stream should be buffered or not, and if the stream
+     * is capable of repositioning itself.
+     *
+     * @return A descriptor for the stream, which includes a reference to the
+     *      stream itself. If the value cannot be represented as a stream,
+     *      {@code null} is returned instead of a decsriptor.
+     * @throws StandardException if obtaining the descriptor fails
+     */
+    public CharacterStreamDescriptor getStreamWithDescriptor()
+            throws StandardException {
+        if (stream == null) {
+            // Lazily reset the descriptor here, to avoid further changes in
+            // {@code SQLChar}.
+            csd = null;
+            return null;
+        }
+        // NOTE: Getting down here several times is potentially dangerous.
+        // When the stream is published, we can't assume we know the position
+        // any more. The best we can do, which may hurt performance to some
+        // degree in some non-recommended use-cases, is to reset the stream if
+        // possible.
+        if (csd != null) {
+            if (stream instanceof Resetable) {
+                try {
+                    ((Resetable)stream).resetStream();
+                    } catch (IOException ioe) {
+                        throwStreamingIOException(ioe);
+                    }
+            } else {
+                if (SanityManager.DEBUG) {
+                    SanityManager.THROWASSERT("Unable to reset stream when " +
+                            "fetched the second time: " + stream.getClass());
+                }
+            }
+        }
+
+        if (csd == null) {
+            // First time, read the header format of the stream.
+            // NOTE: For now, just read the old header format.
+            try {
+                final int dataOffset = 2;
+                byte[] header = new byte[dataOffset];
+                int read = stream.read(header);
+                if (read != dataOffset) {
+                    String hdr = "[";
+                    for (int i=0; i < read; i++) {
+                        hdr += Integer.toHexString(header[i] & 0xff);
+                    }
+                    throw new IOException("Invalid stream header length " +
+                            read + ", got " + hdr + "]");
+                }
+
+                // Note that we add the two bytes holding the header *ONLY* if
+                // we know how long the user data is.
+                long utflen = ((header[0] & 0xff) << 8) | ((header[1] & 0xff));
+                if (utflen > 0) {
+                    utflen += dataOffset;
+                }
+
+                csd = new CharacterStreamDescriptor.Builder().stream(stream).
+                    bufferable(false).positionAware(false).
+                    curCharPos(1).curBytePos(dataOffset).
+                    dataOffset(dataOffset).byteLength(utflen).build();
+            } catch (IOException ioe) {
+                throwStreamingIOException(ioe);
+            }
+        }
+        return this.csd;
+    }
+
 	public Time	getTime(java.util.Calendar cal) throws StandardException
 	{
 		throw dataTypeConversion("java.sql.Time");
@@ -300,6 +381,17 @@
 		throwLangSetMismatch("java.math.BigDecimal");
 	}
 
+    /**
+     * Sets a new stream for this CLOB.
+     *
+     * @param stream the new stream
+     */
+    public final void setStream(InputStream stream) {
+        super.setStream(stream);
+        // Discard the old stream descriptor.
+        this.csd = null;
+    }
+
 	public void setValue(int theValue) throws StandardException
 	{
 		throwLangSetMismatch("int");

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java?rev=734148&r1=734147&r2=734148&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java Tue Jan
13 06:54:09 2009
@@ -24,6 +24,7 @@
 import org.apache.derby.iapi.error.StandardException;
 
 import java.text.RuleBasedCollator;
+import org.apache.derby.iapi.jdbc.CharacterStreamDescriptor;
 
 public interface StringDataValue extends ConcatableDataValue
 {
@@ -207,4 +208,19 @@
      *      specific end-of-stream marker.
      */
     public StreamHeaderHolder generateStreamHeader(long charLength);
+
+    /**
+     * Returns a descriptor for the input stream for this data value.
+     * <p>
+     * The descriptor contains information about header data, current positions,
+     * length, whether the stream should be buffered or not, and if the stream
+     * is capable of repositioning itself.
+     *
+     * @return A descriptor for the stream, which includes a reference to the
+     *      stream itself, or {@code null} if the value cannot be represented
+     *      as a stream.
+     * @throws StandardException if obtaining the descriptor fails
+     */
+    public CharacterStreamDescriptor getStreamWithDescriptor()
+            throws StandardException;
 }



Mime
View raw message