db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r427112 - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ client/org/apache/derby/client/net/ testing/org/apache/derbyTesting/functionTests/suites/ testing/org/apache/derbyTesting/functionTests/tests/derbynet/ testing/org/a...
Date Mon, 31 Jul 2006 13:19:09 GMT
Author: rhillegas
Date: Mon Jul 31 06:19:08 2006
New Revision: 427112

URL: http://svn.apache.org/viewvc?rev=427112&view=rev
Log:
DERBY-1417: Commit derby-1417-6d-clientimpl.diff, the network client implementation of lengthless overloads for the streaming api, introduced by JDBC4.

Added:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java   (with props)
    db/derby/code/trunk/java/client/org/apache/derby/client/net/EncodedInputStream.java
      - copied, changed from r426599, db/derby/code/trunk/java/client/org/apache/derby/client/net/UTF32BEEncodedInputStream.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest_app.properties   (with props)
Removed:
    db/derby/code/trunk/java/client/org/apache/derby/client/net/UTF32BEEncodedInputStream.java
Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/CallableStatement40.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/CrossConverters.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/PreparedStatement.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/Request.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbynetclientmats.runall
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/PreparedStatementTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ResultSetTest.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java Mon Jul 31 06:19:08 2006
@@ -23,6 +23,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.sql.SQLException;
+import java.util.ArrayList;
+
 import org.apache.derby.shared.common.reference.SQLState;
 
 public class Blob extends Lob implements java.sql.Blob {
@@ -64,6 +66,34 @@
         lengthObtained_ = true;
     }
 
+    /**
+     * Create a new <code>Blob</code> from a stream with unknown length.
+     * <em>Important:</em> This constructor is a temporary solution for
+     * implementing lengthless overloads in the JDBC4 API. Before a proper
+     * solution can be implemented, we need to enable streaming without having
+     * to know the stream length in the DRDA protocol. See Jira DERBY-1471 and
+     * DERBY-1417 for more details.
+     *
+     * <em>Shortcomings:</em> This constructor will cause the <em>whole stream
+     * to be materialized</em> to determine its length. If the stream is big
+     * enough, the client will fail with an OutOfMemoryError. Since this is a
+     * temporary solution, state checking is not added to all methods as it
+     * would clutter up the class severely. After using the constructor, the
+     * <code>length</code>-method must be called, which will materialize the
+     * stream and determine the length. <em>Do not pass a Blob object created
+     * with this constructor to the user!</em>
+     *
+     * @param agent
+     * @param binaryStream the stream to get data from
+     */
+    public Blob(Agent agent, java.io.InputStream binaryStream) {
+        super(agent);
+        binaryStream_ = binaryStream;
+        dataType_ |= BINARY_STREAM;
+        sqlLength_ = -1;
+        lengthObtained_ = false;
+    }
+
     // ---------------------------jdbc 2------------------------------------------
 
     public long length() throws SQLException {
@@ -75,6 +105,11 @@
             synchronized (agent_.connection_) {
                 if (agent_.loggingEnabled()) {
                     agent_.logWriter_.traceEntry(this, "length");
+                }
+                // Code to handle the lengthless constructor.
+                if (!lengthObtained_) {
+                    binaryStream_ = super.materializeStream(binaryStream_,
+                                                            "java.sql.Blob");
                 }
                 long retVal = super.sqlLength();
                 if (agent_.loggingEnabled()) {

Added: db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java?rev=427112&view=auto
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java (added)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java Mon Jul 31 06:19:08 2006
@@ -0,0 +1,187 @@
+/*
+    Derby - Class org.apache.derby.client.am.ByteArrayCombinerStream
+
+    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.client.am;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * A stream whose source is a list of byte arrays.
+ *
+ * This class was created when first implementing the JDBC 4 length less
+ * overloads in the client driver. The reason was missing support for
+ * streaming data with unknown length from the client to the server.
+ *
+ * The purpose of the stream is to avoid having to repeatedly copy data to grow
+ * the byte buffer, or doing a single big copy to combine the byte arrays in
+ * the end. This is important for the temporary solution, since we must
+ * materialize the stream to find the length anyway.
+ */
+public class ByteArrayCombinerStream
+    extends InputStream {
+    
+    /** A list of the arrays to combine. */
+    private final ArrayList arrays;
+    /** Length of the stream. */
+    private final long specifiedLength;
+    /** Global offset into the whole stream. */
+    private long gOffset = 0;
+    /** Index of the array we are currently reading from. */
+    private int arrayIndex = 0;
+    /** The array we are currently reading from. */
+    private byte[] curArray;
+    /** The local offset into the current array. */
+    private int off = 0; 
+    
+    /**
+     * Create a stream whose source is a list of byte arrays.
+     *
+     * @param arraysIn an <code>ArrayList</code> with references to the source
+     *      byte arrays. The references are copied to a new
+     *      <code>ArrayList</code> instance.
+     * @param length the length of the stream. Never published outside
+     *      this object
+     */
+    public ByteArrayCombinerStream(ArrayList arraysIn, long length) {
+        this.specifiedLength = length;
+        if (arraysIn != null && arraysIn.size() > 0) {
+            // Copy references to the byte arrays to a new ArrayList.
+            int arrayCount = arraysIn.size();
+            long tmpRemaining = length;
+            byte[] tmpArray;
+            arrays = new ArrayList(arrayCount);
+            // Truncate data if there are more bytes then specified.
+            // Done to simplify boundary checking in the read-methods.
+            for (int i=0; i < arrayCount; i++) {
+                tmpArray = (byte[])arraysIn.get(i);
+                if (tmpRemaining < tmpArray.length) {
+                    // Create a new shrunk array.
+                    byte[] shrunkArray = 
+                        new byte[(int)(tmpRemaining)];
+                    System.arraycopy(tmpArray, 0, 
+                                     shrunkArray, 0, shrunkArray.length);
+                    arrays.add(shrunkArray);
+                    break;
+                } else {
+                    // Add the whole array.
+                    tmpRemaining -= tmpArray.length;
+                    arrays.add(tmpArray);
+                }
+            }
+            // Set the first array as the current one.
+            curArray = nextArray();
+        } else {
+            // Specify gOffset so available returns 0;
+            gOffset = length;
+            arrays = null;
+        }
+    }
+
+    /**
+     * Read a single byte.
+     *
+     * @return a byte, or <code>-1</code> if the end-of-stream is reached
+     */
+    public int read()
+            throws IOException {
+        if (curArray == null) {
+            return -1;
+        }
+        if (off >= curArray.length) {
+            curArray = nextArray();
+            if (curArray == null) {
+                return -1;
+            }
+        }
+        gOffset++;
+        return curArray[off++];
+    }
+
+    /**
+     * Reads up to len 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 buf the array to copy bytes into
+     * @param offset offset into the array
+     * @param length the maximum number of bytes to read
+     * @return the number of bytes read, or <code>-1</code> if end-of-stream
+     *      is reached
+     */
+    public int read(byte[] buf, int offset, int length)
+            throws IOException {
+        int read = 0;
+        if (curArray == null) {
+            return -1;
+        }
+        if (length <= (curArray.length - off)) {
+            System.arraycopy(curArray, off, buf, offset, length);
+            off += length;
+            gOffset += length;
+            read = length;
+        } else {
+            int toRead = 0;
+            while (curArray != null && read < length) {
+                toRead = Math.min(curArray.length, length - read);
+                System.arraycopy(curArray, off, buf, offset + read, toRead);
+                read += toRead;
+                gOffset += toRead;
+                off += toRead;
+                if ( off < curArray.length) {
+                    break;
+                }
+                curArray = nextArray();
+            }
+        }
+        return read;
+    }
+
+    /**
+     * Return the number of available bytes.
+     * The method assumes the specified length of the stream is correct.
+     *
+     * @return number of available bytes
+     */
+    public int available() {
+        return (int)(specifiedLength - gOffset);
+    }
+
+    /**
+     * Fetch the next array to read data from.
+     * The reference in the <code>ArrayList</code> is cleared when the array
+     * is "taken out".
+     *
+     * @return a <code>byte[]</code>-object, or <code>null</code> if there are
+     *      no more arrays
+     */
+    private byte[] nextArray() {
+        if (arrayIndex >= arrays.size()) {
+            return null;
+        }
+        byte[] tmp = (byte[])arrays.get(arrayIndex);
+        arrays.set(arrayIndex++, null);
+        off = 0;
+        return tmp;
+    }
+} // End of class ByteArrayCombinerStream

Propchange: db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/CallableStatement40.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/CallableStatement40.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/CallableStatement40.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/CallableStatement40.java Mon Jul 31 06:19:08 2006
@@ -166,13 +166,22 @@
         throw SQLExceptionFactory.notImplemented ("setRowId (int, RowId)");
     }
     
-    /*********************************************************************************************************
-     * The methods from PreparedStatement for JDBC 4.0
-     *********************************************************************************************************/
+    /**************************************************************************
+     * The methods from PreparedStatement for JDBC 4.0.                       *
+     * These are added here because we can't inherit                          *
+     * PreparedStatement40.java. Instead of moving the non-implemented        *
+     * classes to PreparedStatement.java, we duplicate them here.             *
+     **************************************************************************/
     public void setNString(int index, String value) throws SQLException {
         throw SQLExceptionFactory.notImplemented ("setNString (int, String)");
     }
     
+    public void setNCharacterStream(int parameterIndex, Reader value)
+            throws SQLException {
+        throw SQLExceptionFactory.notImplemented("setNCharacterStream" +
+                "(int,Reader)");
+    }
+
     public void setNCharacterStream(int index, Reader value, long length) throws SQLException {
         throw SQLExceptionFactory.notImplemented ("setNCharacterStream " +
                 "(int,Reader,long)");
@@ -182,6 +191,11 @@
         throw SQLExceptionFactory.notImplemented ("setNClob (int, NClob)");
     }
     
+    public void setNClob(int parameterIndex, Reader reader)
+            throws SQLException {
+        throw SQLExceptionFactory.notImplemented("setNClob(int,Reader)");
+    }
+
     public void setNClob(int parameterIndex, Reader reader, long length)
     throws SQLException {
         throw SQLExceptionFactory.notImplemented ("setNClob (int, " +
@@ -192,9 +206,9 @@
         throw SQLExceptionFactory.notImplemented ("setSQLXML (int, SQLXML)");
     }
 
-    /*********************************************************************************************************
-     * End of methods from PreparedStatement for JDBC 4.0
-     *********************************************************************************************************/
+    /**************************************************************************
+     * End of methods from PreparedStatement for JDBC 4.0.                    *
+     **************************************************************************/
 
     public void setAsciiStream(String parameterName, InputStream x)
             throws SQLException {

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java Mon Jul 31 06:19:08 2006
@@ -20,10 +20,12 @@
 
 package org.apache.derby.client.am;
 
+import java.io.InputStream;
 import java.io.IOException;
 import java.io.Reader;
 import java.sql.SQLException;
 import org.apache.derby.shared.common.reference.SQLState;
+import org.apache.derby.client.net.EncodedInputStream;
 
 public class Clob extends Lob implements java.sql.Clob {
     //---------------------navigational members-----------------------------------
@@ -124,6 +126,35 @@
         }
     }
 
+    /**
+     * Create a <code>Clob</code> of unknown length with the specified
+     * encoding.
+     *
+     * This constructor was added to support the JDBC 4 length less overloads.
+     * Note that a <code>Clob</code> created with this constructor is made for
+     * input to the database only. Do not pass it out to the user!
+     *
+     * @param agent
+     * @param inputStream the data to insert
+     * @param encoding encoding to use for characters. Only "US-ASCII" is
+     *      allowed.
+     */
+    public Clob(Agent agent, java.io.InputStream inputStream, String encoding)
+            throws SqlException {
+        this(agent);
+
+        lengthObtained_ = false;
+
+        if (encoding.equals("US-ASCII")) {
+            asciiStream_ = inputStream;
+            dataType_ |= ASCII_STREAM;
+        } else {
+            throw new SqlException(agent_.logWriter_, 
+                new ClientMessageId(SQLState.UNSUPPORTED_ENCODING),
+                encoding + " InputStream", "String/Clob");
+        }
+    }
+
     // CTOR for character stream input
     // THE ENCODING IS ASSUMED TO BE "UTF-16BE"
     public Clob(Agent agent, java.io.Reader reader, int length) {
@@ -134,6 +165,25 @@
         dataType_ |= CHARACTER_STREAM;
     }
 
+    /**
+     * Create a <code>Clob</code> of unknown length.
+     *
+     * This constructor was added to support the JDBC 4 length less overloads.
+     * Note that a <code>Clob</code> created with this constructor is made for
+     * input to the database only. Do not pass it out to the user!
+     *
+     * @param agent
+     * @param reader the data to insert
+     */
+    public Clob(Agent agent, Reader reader) {
+        this(agent);
+        lengthObtained_ = false;
+        // Wrap reader in stream to share code.
+        unicodeStream_ = EncodedInputStream.createUTF8Stream(reader);
+        // Override type to share logic with the other stream types.
+        dataType_ |= UNICODE_STREAM;
+    }
+
     private Clob(Agent agent) {
         super(agent);
     }
@@ -163,7 +213,7 @@
                 if (lengthObtained_) {
                     return sqlLength_;
                 }
-
+                materializeStream();
                 lengthInBytes_ = super.sqlLength();
 
                 if (agent_.loggingEnabled()) {
@@ -773,5 +823,17 @@
         if(!isValid)
             throw new SqlException(null,new ClientMessageId(SQLState.LOB_OBJECT_INVALID))
                                                   .getSQLException();
+    }
+
+    /**
+     * Materialize the stream used for input to the database.
+     */
+    private void materializeStream()
+        throws SqlException {
+        unicodeStream_ = super.materializeStream(isAsciiStream() ? 
+                                                        asciiStream_ : 
+                                                        unicodeStream_,
+                                                 "java.sql.Clob");
+        dataType_ = UNICODE_STREAM;
     }
 }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/CrossConverters.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/CrossConverters.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/CrossConverters.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/CrossConverters.java Mon Jul 31 06:19:08 2006
@@ -40,6 +40,12 @@
 //
 
 final class CrossConverters {
+
+    /**
+     * Value used to signal unknown length of data.
+     */
+    public static final int UNKNOWN_LENGTH = Integer.MIN_VALUE;
+
     private final static java.math.BigDecimal bdMaxByteValue__ =
             java.math.BigDecimal.valueOf(Byte.MAX_VALUE);
     private final static java.math.BigDecimal bdMinByteValue__ =
@@ -638,6 +644,9 @@
         case Types.LONGVARCHAR:
             return setStringFromReader(source, length);
         case Types.CLOB:
+            if (length == CrossConverters.UNKNOWN_LENGTH) {
+                return new Clob(agent_, source);
+            }
             return new Clob(agent_, source, length);
             // setCharacterStream() against BINARY columns is problematic because w/out metadata, we'll send char encoding bytes.
             // There's no clean solution except to just not support setObject(String/Reader/Stream)
@@ -663,7 +672,8 @@
                 sw.write(read);
                 read = r.read();
             }
-            if (length != totalRead) {
+            if (length != CrossConverters.UNKNOWN_LENGTH &&
+                    length != totalRead) {
                 throw new SqlException(agent_.logWriter_, 
                 		new ClientMessageId (SQLState.READER_UNDER_RUN));
             }
@@ -683,6 +693,9 @@
         case Types.LONGVARCHAR:
             return setStringFromStream(source, encoding, length);
         case Types.CLOB:
+            if (length == CrossConverters.UNKNOWN_LENGTH) {
+                return new Clob(agent_, source, encoding);
+            }
             return new Clob(agent_, source, encoding, length);
         case Types.BINARY:
         case Types.VARBINARY:
@@ -715,7 +728,8 @@
                     e.getClass().getName(), e.getMessage(), e);
             }
 
-            if (length != totalRead) {
+            if (length != CrossConverters.UNKNOWN_LENGTH &&
+                    length != totalRead) {
                 throw new SqlException(agent_.logWriter_, 
                 		new ClientMessageId (SQLState.READER_UNDER_RUN));
             }
@@ -758,6 +772,9 @@
         case Types.LONGVARBINARY:
             return setBytesFromStream(source, length);
         case Types.BLOB:
+            if (length == CrossConverters.UNKNOWN_LENGTH) {
+                return new Blob(agent_, source);
+            }
             return new Blob(agent_, source, length);
         default:
             throw new SqlException(agent_.logWriter_, 
@@ -779,7 +796,8 @@
                 read = is.read();
             }
 
-            if (length != totalRead) {
+            if (length != CrossConverters.UNKNOWN_LENGTH &&
+                    length != totalRead) {
                 throw new SqlException(agent_.logWriter_,
                 		new ClientMessageId (SQLState.READER_UNDER_RUN));
             }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java Mon Jul 31 06:19:08 2006
@@ -20,6 +20,10 @@
 
 package org.apache.derby.client.am;
 
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
 import org.apache.derby.shared.common.reference.SQLState;
 
 public abstract class Lob implements UnitOfWorkListener {
@@ -99,5 +103,68 @@
 
     void completeLocalCommit() {
         ;
+    }
+
+    /**
+     * Materialize the given stream into memory and update the internal
+     * length variable.
+     *
+     * @param is stream to use for input
+     * @param typeDesc description of the data type we are inserting,
+     *      for instance <code>java.sql.Clob</code>
+     * @return a stream whose source is the materialized data
+     * @throws SqlException if the stream exceeds 2 GB, or an error happens
+     *      while reading from the stream
+     */
+    protected InputStream materializeStream(InputStream is, String typeDesc)
+            throws SqlException {
+        final int GROWBY = 32 * 1024; // 32 KB
+        ArrayList byteArrays = new ArrayList();
+        byte[] curBytes = new byte[GROWBY];
+        int totalLength = 0;
+        int partLength = 0;
+        // Read all data from the stream, storing it in a number of arrays.
+        try {
+            do {
+                partLength = is.read(curBytes, 0, curBytes.length);
+                if (partLength == curBytes.length) {
+                    byteArrays.add(curBytes);
+                    // Make sure we don't exceed 2 GB by checking for overflow.
+                    int newLength = totalLength + GROWBY;
+                    if (newLength < 0 || newLength == Integer.MAX_VALUE) {
+                        curBytes = new byte[Integer.MAX_VALUE - totalLength];
+                    } else {
+                        curBytes = new byte[GROWBY];
+                    }
+                }
+                totalLength += partLength;
+            } while (partLength == GROWBY);
+            // Make sure stream is exhausted.
+            if (is.read() != -1) {
+                // We have exceeded 2 GB.
+                throw new SqlException(
+                            null,
+                            new ClientMessageId(
+                                SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE),
+                                typeDesc
+                        );
+            }
+            byteArrays.add(curBytes);
+
+            // Cleanup and set state.
+            curBytes = null;
+            sqlLength_ = totalLength;
+            lengthObtained_ = true;
+            // Return a stream whose source is a list of byte arrays. 
+            // This avoids having to copy all the data into a single big array.
+            return new ByteArrayCombinerStream(byteArrays, totalLength);
+        } catch (IOException ioe) {
+            throw new SqlException(null,
+                        new ClientMessageId(
+                            SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION),
+                        typeDesc,
+                        ioe
+                    );
+        }
     }
 }

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/PreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/PreparedStatement.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/PreparedStatement.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/PreparedStatement.java Mon Jul 31 06:19:08 2006
@@ -887,7 +887,16 @@
             setNullX(parameterIndex, java.sql.Types.BLOB);
             return;
         }
-        setInput(parameterIndex, new Blob(agent_, x, length));
+        Blob blob;
+        if (length == -1) {
+            // Create a blob of unknown length. This might cause an
+            // OutOfMemoryError due to the temporary implementation in Blob.
+            // The whole stream will be materialzied. See comments in Blob.
+            blob = new Blob(agent_, x);
+        } else {
+            blob = new Blob(agent_, x, length);
+        }
+        setInput(parameterIndex, blob);
     }
 
     /**
@@ -967,6 +976,42 @@
         throw SQLExceptionFactory.notImplemented ("setUnicodeStream");
     }
 
+    /**
+     * Sets the designated parameter to the given <code>Reader</code> object.
+     * When a very large UNICODE value is input to a LONGVARCHAR parameter, it
+     * may be more practical to send it via a <code>java.io.Reader</code>
+     * object. The data will be read from the stream as needed until
+     * end-of-file is reached. The JDBC driver will do any necessary conversion
+     * from UNICODE to the database char format.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the <code>java.io.Reader</code> object that contains the
+     *      Unicode data
+     * @throws SQLException if a database access error occurs or this method is
+     *      called on a closed <code>PreparedStatement</code>
+     */
+    public void setCharacterStream(int parameterIndex, Reader x)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "setCharacterStream",
+                        parameterIndex, x);
+            }
+            try {
+                parameterIndex = checkSetterPreconditions(parameterIndex);
+                parameterMetaData_.clientParamtertype_[parameterIndex -1] =
+                    java.sql.Types.CLOB;
+                if (x == null) {
+                    setNull(parameterIndex, java.sql.Types.CLOB);
+                    return;
+                }
+                setInput(parameterIndex, new Clob(agent_, x));
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
+
      /**
      * Sets the designated parameter to the given Reader, which will have
      * the specified number of bytes.
@@ -2271,6 +2316,97 @@
     }
     
     //jdbc 4.0 methods
+
+    /**
+     * Sets the designated parameter to the given input stream.
+     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code>. Data will be read from the stream as
+     * needed until end-of-file is reached. The JDBC driver will do any
+     * necessary conversion from ASCII to the database char format.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the Java input stream that contains the ASCII parameter value
+     * @throws SQLException if a database access error occurs or this method is
+     *      called on a closed <code>PreparedStatement</code>
+     */
+    public void setAsciiStream(int parameterIndex, InputStream x)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "setAsciiStream",
+                        parameterIndex, x);
+            }
+            try {
+                parameterIndex = checkSetterPreconditions(parameterIndex);
+                parameterMetaData_.clientParamtertype_[parameterIndex - 1] = java.sql.Types.CLOB;
+                if (x == null) {
+                    setNull(parameterIndex, java.sql.Types.CLOB);
+                    return;
+                }
+                setInput(parameterIndex, new Clob(agent_, x, "US-ASCII"));
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
+
+    /**
+     * Sets the designated parameter to the given input stream.
+     * When a very large binary value is input to a <code>LONGVARBINARY</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the
+     * stream as needed until end-of-file is reached.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the java input stream which contains the binary parameter value
+     * @throws SQLException if a database access error occurs or this method is
+     *      called on a closed <code>PreparedStatement</code>
+     */
+    public void setBinaryStream(int parameterIndex, InputStream x)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "setBinaryStream",
+                        parameterIndex, x);
+            }
+            try {
+                setBinaryStreamX(parameterIndex, x, -1);
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
+
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.
+     *
+     * @param parameterIndex index of the first parameter is 1, the second is 
+     *      2, ...
+     * @param reader an object that contains the data to set the parameter
+     *      value to. 
+     * @throws SQLException if parameterIndex does not correspond to a 
+     *      parameter marker in the SQL statement; if a database access error
+     *      occurs; this method is called on a closed PreparedStatementor if
+     *      parameterIndex does not correspond to a parameter marker in the SQL
+     *      statement
+     */
+    public void setClob(int parameterIndex, Reader reader)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "setClob",
+                        parameterIndex, reader);
+            }
+            try {
+                checkForClosedStatement();
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+            setInput(parameterIndex, new Clob(agent_, reader));
+        }
+    }
+
    /**
      * Sets the designated parameter to a Reader object.
      *
@@ -2300,6 +2436,39 @@
                     new Long(length), new Integer(Integer.MAX_VALUE)).getSQLException();
             else
                 setInput(parameterIndex, new Clob(agent_, reader, (int)length));
+        }
+    }
+
+    /**
+     * Sets the designated parameter to a <code>InputStream</code> object.
+     * This method differs from the <code>setBinaryStream(int, InputStream)
+     * </code>  method because it informs the driver that the parameter value
+     * should be sent to the server as a <code>BLOB</code>. When the
+     * <code>setBinaryStream</code> method is used, the driver may have to do
+     * extra work to determine whether the parameter data should be sent to the
+     * server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
+     *
+     * @param parameterIndex index of the first parameter is 1, the second is
+     *      2, ...
+     * @param inputStream an object that contains the data to set the parameter
+     *      value to.
+     * @throws SQLException if a database access error occurs, this method is
+     *      called on a closed <code>PreparedStatement</code> or if
+     *      <code>parameterIndex</code> does not correspond to a parameter
+     *      marker in the SQL statement
+     */
+    public void setBlob(int parameterIndex, InputStream inputStream)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "setBlob", parameterIndex,
+                        inputStream);
+            }
+            try {
+                setBinaryStreamX(parameterIndex, inputStream, -1);
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
         }
     }
 

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java Mon Jul 31 06:19:08 2006
@@ -5413,6 +5413,43 @@
         return isClosed;
     }
 
+    /**
+     * Updates the designated column with an ascii stream value.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @throws SQLException if the columnIndex is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateAsciiStream(int columnIndex, InputStream x)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "updateAsciiStream",
+                        columnIndex, x);
+            }
+            try {
+                checkUpdatePreconditions(columnIndex, "updateAsciiStream");
+                updateColumn(columnIndex,
+                        agent_.crossConverters_.setObjectFromCharacterStream(
+                            resultSetMetaData_.types_[columnIndex -1],
+                            x,
+                            "US-ASCII",
+                            CrossConverters.UNKNOWN_LENGTH));
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
 
     /**
      * Update a column with an ascii stream value.
@@ -5442,6 +5479,43 @@
     }
 
     /**
+     * Updates the designated column with a binary stream value.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value 
+     * @throws SQLException if the columnIndex is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateBinaryStream(int columnIndex, InputStream x)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "updateBinaryStream",
+                        columnIndex, x);
+            }
+            try {
+                checkUpdatePreconditions(columnIndex, "updateBinaryStream");
+                updateColumn(columnIndex,
+                             agent_.crossConverters_.setObjectFromBinaryStream(
+                                    resultSetMetaData_.types_[columnIndex -1],
+                                    x,
+                                    CrossConverters.UNKNOWN_LENGTH));
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
+
+    /**
      * Update a column with a binary stream value.
      *
      * The updateXXX() methods are used to update column values in the current
@@ -5470,6 +5544,79 @@
      }
 
     /**
+     * Updates the designated column using the given input stream.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @throws SQLException if the columnIndex is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateBlob(int columnIndex, InputStream x)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "updateBlob",
+                        columnIndex, x);
+            }
+            try {
+                checkUpdatePreconditions(columnIndex, "updateBlob");
+                updateColumn(columnIndex,
+                             agent_.crossConverters_.setObject(
+                                    resultSetMetaData_.types_[columnIndex -1],
+                                    new Blob(agent_, x)));
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param reader the new column value
+     * @throws SQLException if the columnLabel is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateCharacterStream(int columnIndex, Reader reader)
+            throws SQLException {
+        synchronized (connection_) {
+            try {
+                if (agent_.loggingEnabled()) {
+                    agent_.logWriter_.traceEntry(this, "updateCharacterStream",
+                            columnIndex, reader);
+                }
+                checkUpdatePreconditions(columnIndex, "updateCharacterStream");
+                updateColumn(columnIndex,
+                             agent_.crossConverters_.setObject(
+                                    resultSetMetaData_.types_[columnIndex -1],
+                                    reader,
+                                    CrossConverters.UNKNOWN_LENGTH));
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
+
+    /**
      * Update a column with a character stream value.
      *
      * The updateXXX() methods are used to update column values in the current
@@ -5497,6 +5644,73 @@
     }
 
     /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object. 
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached. The JDBC driver will do any necessary conversion from UNICODE
+     * to the database char format.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param reader an object that contains the data to set the parameter
+     *      value to. 
+     * @throws SQLException if the columnIndex is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateClob(int columnIndex, Reader reader)
+            throws SQLException {
+        synchronized (connection_) {
+            if (agent_.loggingEnabled()) {
+                agent_.logWriter_.traceEntry(this, "updateClob",
+                        columnIndex, reader);
+            }
+            try {
+                checkUpdatePreconditions(columnIndex, "updateClob");
+                updateColumn(columnIndex,
+                             agent_.crossConverters_.setObject(
+                                 resultSetMetaData_.types_[columnIndex -1], 
+                                 new Clob(agent_, reader)));
+            } catch (SqlException se) {
+                throw se.getSQLException();
+            }
+        }
+    }
+
+    /**
+     * Updates the designated column with an ascii stream value.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnName the label for the column specified with the SQL AS
+     *      clause. If the SQL AS clause was not specified, then the label is
+     *      the name of the column
+     * @param x the new column value
+     * @throws SQLException if the columnLabel is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateAsciiStream(String columnName, InputStream x)
+            throws SQLException {
+        try {
+            updateAsciiStream(findColumnX(columnName), x);
+        } catch (SqlException se) {
+            throw se.getSQLException();
+        }
+    }
+
+    /**
      * Update a column with an ascii stream value.
      *
      * The updateXXX() methods are used to update column values in the current
@@ -5524,6 +5738,34 @@
     }
 
     /**
+     * Updates the designated column with a binary stream value.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS
+     *      clause. If the SQL AS clause was not specified, then the label is
+     *      the name of the column
+     * @param x the new column value 
+     * @throws SQLException if the columnLabel is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateBinaryStream(String columnLabel, InputStream x)
+            throws SQLException {
+        try {
+            updateBinaryStream(findColumnX(columnLabel), x);
+        } catch (SqlException se) {
+            throw se.getSQLException();
+        }
+    }
+
+    /**
      * Update a column with a binary stream value.
      *
      * The updateXXX() methods are used to update column values in the current
@@ -5551,6 +5793,62 @@
     }
 
     /**
+     * Updates the designated column using the given input stream.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS
+     *      clause. If the SQL AS clause was not specified, then the label is
+     *      the name of the column
+     * @param x the new column value
+     * @throws SQLException if the columnLabel is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateBlob(String columnLabel, InputStream x)
+            throws SQLException {
+        try {
+            updateBlob(findColumnX(columnLabel), x);
+        } catch (SqlException se) {
+            throw se.getSQLException();
+        }
+    }
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS
+     *      clause. If the SQL AS clause was not specified, then the label is
+     *      the name of the column
+     * @param reader the new column value
+     * @throws SQLException if the columnLabel is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateCharacterStream(String columnLabel, Reader reader)
+            throws SQLException {
+        try {
+            updateCharacterStream(findColumnX(columnLabel), reader);
+        } catch (SqlException se) {
+            throw se.getSQLException();
+        }
+    }
+
+    /**
      * Update a column with a character stream value.
      *
      * The updateXXX() methods are used to update column values in the current
@@ -5576,4 +5874,35 @@
              throw sqle.getSQLException();
          }
      }
+
+    /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object. 
+     * The data will be read from the stream as needed until end-of-stream is
+     * reached. The JDBC driver will do any necessary conversion from UNICODE
+     * to the database char format.
+     *
+     * The updater methods are used to update column values in the current row
+     * or the insert row. The updater methods do not update the underlying
+     * database; instead the <code>updateRow</code> or <code>insertRow</code>
+     * methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS
+     *      clause. If the SQL AS clause was not specified, then the label is
+     *      the name of the column
+     * @param reader an object that contains the data to set the parameter
+     *      value to. 
+     * @throws SQLException if the columnIndex is not valid; if a database
+     *      access error occurs; the result set concurrency is
+     *      <code>CONCUR_READ_ONLY</code> or this method is called on a closed
+     *      result set
+     */
+    public void updateClob(String columnLabel, Reader reader)
+            throws SQLException {
+        try {
+            updateClob(findColumnX(columnLabel), reader);
+        } catch (SqlException se) {
+            throw se.getSQLException();
+        }
+    }
 }

Copied: db/derby/code/trunk/java/client/org/apache/derby/client/net/EncodedInputStream.java (from r426599, db/derby/code/trunk/java/client/org/apache/derby/client/net/UTF32BEEncodedInputStream.java)
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/EncodedInputStream.java?p2=db/derby/code/trunk/java/client/org/apache/derby/client/net/EncodedInputStream.java&p1=db/derby/code/trunk/java/client/org/apache/derby/client/net/UTF32BEEncodedInputStream.java&r1=426599&r2=427112&rev=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/UTF32BEEncodedInputStream.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/EncodedInputStream.java Mon Jul 31 06:19:08 2006
@@ -1,21 +1,22 @@
 /*
- 
-Derby - Class org.apache.derby.client.net.UTF32BEEncodedInputStream
-
-Copyright 2002, 2004 The Apache Software Foundation or its licensors, as applicable.
-
-Licensed 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.
+    Derby - Class org.apache.derby.client.net.EncodedInputStream
 
+    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.client.net;
 
@@ -31,42 +32,89 @@
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
 /**
+ * Create an encoded stream from a <code>Reader</code>.
  *
- * UTF32BEEncodedInputStream passes
- * stream from Reader, which is stream of decoded style, 
- * to user of this subclass of InputStream, which is stream of encoded style.
- *
- * The encoding of stream passed to user is limited to UTF32BE.
- *
- * This class will be used to pass stream, which is served as a Reader,
- * as a InputStream of a UTF32BE encoding.
+ * This is an internal class, used to pass readers of characters as streams of
+ * bytes. The characters will be represented according to the specified
+ * encoding. It is up to the caller to ensure the specified encoding is
+ * available, and in general only encodings available as default from Java 1.3
+ * and up should be used.
  *
+ * Currently, the encodings 'UTF8' and 'UTF-16BE' are used.
+ * Streams are obtained by calling the static methods of this class,
+ * for instance <code>createUTF8Stream</code>.
  */
-public class UTF32BEEncodedInputStream extends InputStream {
+public final class EncodedInputStream extends InputStream {
 
+    /**
+     * Create a UTF-8 encoded stream from the given <code>Reader</code>.
+     *
+     * @param reader the <code>Reader</code> to read characters from.
+     * @return a byte-stream with UTF-8 encoded characters
+     */
+    public static EncodedInputStream createUTF8Stream(Reader reader) {
+        return new EncodedInputStream(reader, 
+                                      "UTF8",
+                                      BUFFERED_CHAR_LEN,
+                                      BUFFERED_CHAR_LEN*3);
+    }
+
+    /**
+     * Create a UTF-16BE encoded stream from the given <code>Reader</code>.
+     *
+     * @param reader the <code>Reader</code> to read characters from.
+     * @return a byte-stream with UTF-16BE encoded characters
+     */
+    static EncodedInputStream createUTF16BEStream(Reader reader) {
+        return new EncodedInputStream(reader,
+                                      "UTF-16BE",
+                                      BUFFERED_CHAR_LEN,
+                                      BUFFERED_CHAR_LEN*2);
+    }
+    
     private static final int BUFFERED_CHAR_LEN = 1024;
 	private static final ByteArrayInputStream suspendMarker = new ByteArrayInputStream( new byte[ 0 ] );
 
     private Reader reader_;
-    private char[] decodedBuffer_;
+    private final char[] decodedBuffer_;
     
     private OutputStreamWriter encodedStreamWriter_;
     private PublicBufferOutputStream encodedOutputStream_;
     
     private ByteArrayInputStream encodedInputStream_;
     
-    public UTF32BEEncodedInputStream(Reader reader) {
+    /**
+     * Create an encoded stream for the specified <code>Reader</code>.
+     * 
+     * @param reader the <code>Reader</code> to read characters from
+     * @param encoding the encoding to use in the encoded stream
+     * @param charBufferSize the size of the char buffer. This is the number
+     *      of characters read at once from the <code>Reader</code>.
+     * @param initialByteBufferSize the initial size of the byte buffer.
+     *      holding the encoded bytes
+     */
+    private EncodedInputStream(Reader reader,
+                               String encoding,
+                               int charBufferSize,
+                               int initialByteBufferSize) {
 	
 		reader_ = reader;
-		decodedBuffer_ = new char[BUFFERED_CHAR_LEN];
+		decodedBuffer_ = new char[charBufferSize];
 
-		encodedOutputStream_ = new PublicBufferOutputStream( BUFFERED_CHAR_LEN * 2 );
+		encodedOutputStream_ = new PublicBufferOutputStream(
+				initialByteBufferSize);
 		
 		try{
-			encodedStreamWriter_ = new OutputStreamWriter(encodedOutputStream_,"UnicodeBigUnmarked");
+			encodedStreamWriter_ = new OutputStreamWriter(encodedOutputStream_,
+                                                          encoding);
 			
 		}catch(UnsupportedEncodingException e){
-			//never happens ...
+			// Should never happen. It is up to the caller to ensure the
+            // specified encoding is available.
+            if (SanityManager.DEBUG) {
+                SanityManager.THROWASSERT("Unavailable encoding specified: " +
+                        encoding, e);
+            }
 		}
 	
 		encodedInputStream_ = suspendMarker;
@@ -80,7 +128,7 @@
 	
 		int count;
 		do{
-			count = reader.read(decodedBuffer_, 0, BUFFERED_CHAR_LEN);
+			count = reader.read(decodedBuffer_, 0, decodedBuffer_.length);
 			
 		}while(count == 0);
 			
@@ -180,7 +228,4 @@
 		}
 	
     }
-
 }
-
-

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/Request.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/Request.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/Request.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/Request.java Mon Jul 31 06:19:08 2006
@@ -507,15 +507,15 @@
                                  java.io.Reader r,
                                  boolean writeNullByte,
                                  int parameterIndex) throws DisconnectException, 
-															SqlException{
+                                                            SqlException{
         
-		writeScalarStream(chained,
-						  chainedWithSameCorrelator,
-						  codePoint,
-						  length * 2,
-						  new UTF32BEEncodedInputStream( r ),
-						  writeNullByte,
-						  parameterIndex);
+        writeScalarStream(chained,
+                          chainedWithSameCorrelator,
+                          codePoint,
+                          length * 2,
+                          EncodedInputStream.createUTF16BEStream(r),
+                          writeNullByte,
+                          parameterIndex);
     }
 
 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbynetclientmats.runall
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbynetclientmats.runall?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbynetclientmats.runall (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbynetclientmats.runall Mon Jul 31 06:19:08 2006
@@ -4,4 +4,5 @@
 jdbcapi/lobStreams.java
 jdbcapi/XATest.java
 jdbcapi/checkDataSource.java
+derbynet/ByteArrayCombinerStreamTest.junit
 derbynet/SqlExceptionTest.junit

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java?rev=427112&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java Mon Jul 31 06:19:08 2006
@@ -0,0 +1,143 @@
+/*
+    Derby - Class org.apache.derbyTesting.functionTests.tests.derbynet.ByteArrayCombinerStreamTest
+
+    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.derbynet;
+
+import org.apache.derbyTesting.functionTests.util.BaseTestCase;
+
+import org.apache.derby.client.am.ByteArrayCombinerStream;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Test functionality of <code>ByteArrayCombinerStream</code>.
+ */
+public class ByteArrayCombinerStreamTest
+    extends BaseTestCase {
+
+    private static final byte[] defaultArray = {
+            65,66,67,68,69,70,71,72,73,74,75,76,
+            77,78,79,80,81,82,83,84,85,86,87,88};
+
+    private ByteArrayCombinerStream combiner;
+    
+    public ByteArrayCombinerStreamTest(String name) {
+        super(name);
+    }
+
+    public void testCombineNullRead()
+            throws IOException {
+        combiner = new ByteArrayCombinerStream(null, 10);
+        assertEquals(-1, combiner.read());
+    }
+
+    public void testCombineNullReadArray()
+            throws IOException {
+        combiner = new ByteArrayCombinerStream(null, 10);
+        assertEquals(-1, combiner.read(new byte[10], 0, 10));
+    }
+
+    public void testCombineAvailableNull()
+            throws IOException {
+        combiner = new ByteArrayCombinerStream(null, -34);
+        assertEquals(0, combiner.available()); 
+    }
+
+    public void testCombineAvailable4bytes()
+            throws IOException {
+        byte[] array = {65,66,77,79};
+        ArrayList list = new ArrayList(1);
+        list.add(array);
+        combiner = new ByteArrayCombinerStream(list, 4);
+        assertEquals(4, combiner.available()); 
+    }
+    
+    public void testCombineOneArray()
+            throws IOException {
+        ArrayList list = new ArrayList(1);
+        list.add(defaultArray);
+        combiner = new ByteArrayCombinerStream(list, defaultArray.length);
+        byte[] resArray = new byte[defaultArray.length];
+        assertEquals(defaultArray.length, 
+                     combiner.read(resArray,0, resArray.length));
+        assertTrue(combiner.read() == -1);
+        assertTrue(Arrays.equals(defaultArray, resArray));
+    }
+
+    public void testCominbe100SmallArrays()
+            throws IOException {
+        int arrays = 100;
+        byte[] array = {65,66,77,79};
+        ArrayList list = new ArrayList(arrays);
+        long length = 0;
+        for (int i=0; i < arrays; i++) {
+            list.add(array);
+            length += array.length;
+        }
+        byte[] targetArray = new byte[(int)length];
+        int offset = 0;
+        for (int i=0; i < arrays; i++) {
+            System.arraycopy(array, 0, targetArray, offset, array.length);
+            offset += array.length;
+        }
+        combiner = new ByteArrayCombinerStream(list, length);
+        byte[] resArray = new byte[(int)length];
+        assertEquals(length, combiner.read(resArray, 0, resArray.length));
+        assertTrue(combiner.read() == -1);
+        assertTrue(combiner.read() == -1);
+        assertTrue(Arrays.equals(targetArray, resArray));
+    }
+    
+    public void testTruncateDataFromOneArray()
+            throws IOException {
+        int length = defaultArray.length -5;
+        ArrayList list = new ArrayList(1);
+        list.add(defaultArray);
+        byte[] targetArray = new byte[length];
+        System.arraycopy(defaultArray, 0,
+                         targetArray, 0, length);
+        byte[] resArray = new byte[length];
+        combiner = new ByteArrayCombinerStream(list, length);
+        assertEquals(length, combiner.read(resArray, 0, length));
+        assertTrue(combiner.read() == -1);
+        assertTrue(Arrays.equals(targetArray, resArray));
+    }
+    
+    public void testTruncateDataFromTwoArrays()
+            throws IOException {
+        int length = (defaultArray.length *2) -7;
+        ArrayList list = new ArrayList(2);
+        list.add(defaultArray);
+        list.add(defaultArray);
+        byte[] targetArray = new byte[length];
+        System.arraycopy(defaultArray, 0,
+                         targetArray, 0, defaultArray.length);
+        System.arraycopy(defaultArray, 0,
+                         targetArray, defaultArray.length, 
+                         length - defaultArray.length);
+        byte[] resArray = new byte[length];
+        combiner = new ByteArrayCombinerStream(list, length);
+        assertEquals(length, combiner.read(resArray, 0, length));
+        assertTrue(combiner.read() == -1);
+        assertTrue(Arrays.equals(targetArray, resArray));
+    }
+} // End class ByteArrayCombinerStreamTest 

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

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest_app.properties
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest_app.properties?rev=427112&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest_app.properties (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest_app.properties Mon Jul 31 06:19:08 2006
@@ -0,0 +1,2 @@
+# This is actually a unit test. We don't need Derby at all.
+startServer=false

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

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/PreparedStatementTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/PreparedStatementTest.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/PreparedStatementTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/PreparedStatementTest.java Mon Jul 31 06:19:08 2006
@@ -112,19 +112,6 @@
     public static Test suite() {
         TestSuite suite = new TestSuite();
         suite.addTestSuite(PreparedStatementTest.class);
-        if (usingEmbedded()) {
-            // Add methods temporarily disabled for DerbyNetClient
-            suite.addTest(new PreparedStatementTest(
-                        "embonlytmptestSetClobLengthless"));
-            suite.addTest(new PreparedStatementTest(
-                        "embonlytmptestSetBlobLengthless"));
-            suite.addTest(new PreparedStatementTest(
-                        "embonlytmptestSetCharacterStreamLengthless"));
-            suite.addTest(new PreparedStatementTest(
-                        "embonlytmptestSetAsciiStreamLengthless"));
-            suite.addTest(new PreparedStatementTest(
-                        "embonlytmptestSetBinaryStreamLengthless"));
-        }
         suite.addTest(SetObjectUnsupportedTest.suite(false));
         return suite;
     }
@@ -376,7 +363,7 @@
      * a <code>Clob</code> object. This object is then inserted into the
      * database again.
      */
-    public void embonlytmptestSetClobLengthless()
+    public void testSetClobLengthless()
             throws IOException, SQLException {
         // Insert test data.
         String testString = "Test string for setCharacterStream\u1A00";
@@ -458,7 +445,7 @@
      * a <code>Blob</code> object. This object is then inserted into the
      * database again.
      */
-    public void embonlytmptestSetBlobLengthless()
+    public void testSetBlobLengthless()
             throws IOException, SQLException {
         // Insert test data.
         InputStream is = new ByteArrayInputStream(BYTES);
@@ -584,7 +571,7 @@
         ps_sc.close();
     }
 
-    public void embonlytmptestSetCharacterStreamLengthless()
+    public void testSetCharacterStreamLengthless()
             throws IOException, SQLException {
         // Insert test data.
         String testString = "Test string for setCharacterStream\u1A00";
@@ -649,7 +636,7 @@
         ps_sb.close();
     }
 
-    public void embonlytmptestSetAsciiStreamLengthless()
+    public void testSetAsciiStreamLengthless()
             throws IOException, SQLException {
         // Insert test data.
         InputStream is = new ByteArrayInputStream(BYTES);
@@ -724,7 +711,7 @@
         ps_sb.close();
     }
 
-    public void embonlytmptestSetBinaryStreamLengthless()
+    public void testSetBinaryStreamLengthless()
             throws IOException, SQLException {
         // Insert test data.
         InputStream is = new ByteArrayInputStream(BYTES);

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ResultSetTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ResultSetTest.java?rev=427112&r1=427111&r2=427112&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ResultSetTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ResultSetTest.java Mon Jul 31 06:19:08 2006
@@ -200,7 +200,7 @@
         }
     }
 
-    public void embonlytmpUpdateNCharacterStreamIntLengthLessNotImplemented()
+    public void testUpdateNCharacterStreamIntLengthLessNotImplemented()
         throws SQLException {
         try {
             rs.updateNCharacterStream(1, null);
@@ -221,7 +221,7 @@
         }
     }
 
-    public void embonlytmpUpdateNCharacterStreamStringLengthlessNotImplemented()
+    public void testUpdateNCharacterStreamStringLengthlessNotImplemented()
         throws SQLException {
         try {
             rs.updateNCharacterStream("some-column-name", null);
@@ -558,7 +558,11 @@
         rs1.close();
     }
 
-    public void embonlytmpUpdateBinaryStreamLengthless()
+    /**
+     * Test <code>updateBinaryStream</code> on a BINARY column, without
+     * specifying length of inputstream.
+     */
+    public void testUpdateBinaryStreamLengthless()
             throws IOException, SQLException {
         InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
         // InputStream used for update.
@@ -588,7 +592,41 @@
         rs1.close();
     }
 
-    public void embonlytmpUpdateBinaryStreamLengthlessParameterName()
+    /**
+     * Test <code>updateBinaryStream</code> on a BLOB column, without
+     * specifying length of inputstream.
+     */
+    public void testUpdateBinaryStreamLengthlessBlob()
+            throws IOException, SQLException {
+        InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
+        // InputStream used for update.
+        InputStream is2 = new java.io.ByteArrayInputStream(BYTES2);
+
+        //Prepared Statement used to insert the data
+        PreparedStatement ps_sb = prep(con, "dBlob");
+        ps_sb.setInt(1, key);
+        ps_sb.setBinaryStream(2, is1);
+        ps_sb.executeUpdate();
+        ps_sb.close();
+
+        //Update operation
+        ResultSet rs1 = fetchUpd(con, "dBlob", key);
+        rs1.next();
+        rs1.updateBinaryStream(1, is2);
+        rs1.updateRow();
+        rs1.close();
+
+        //Query to see whether the data that has been updated
+        //using the updateBinaryStream method is the same
+        //data that we expected
+
+        rs1 = fetch(con, "dBlob", key);
+        rs1.next();
+        assertEquals(new ByteArrayInputStream(BYTES2), rs1.getBinaryStream(1));
+        rs1.close();
+    }
+
+    public void testUpdateBinaryStreamLengthlessParameterName()
             throws IOException, SQLException {
         InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
         // InputStream used for update.
@@ -676,7 +714,7 @@
         rs1.close();
     }
 
-    public void embonlytmpUpdateAsciiStreamLengthless()
+    public void testUpdateAsciiStreamLengthless()
             throws IOException, SQLException {
         // Array to keep updated data fetched from the database.
         byte[] bytesRet = new byte[10];
@@ -715,7 +753,7 @@
         rs1.close();
     }
 
-    public void embonlytmpUpdateAsciiStreamLengthlessParameterName()
+    public void testUpdateAsciiStreamLengthlessParameterName()
             throws IOException, SQLException {
         // Array to keep updated data fetched from the database.
         byte[] bytesRet = new byte[10];
@@ -809,7 +847,7 @@
         rs1.close();
     }
 
-    public void embonlytmpUpdateCharacterStreamLengthless()
+    public void testUpdateCharacterStreamLengthless()
             throws IOException, SQLException {
         String str = "This is the (\u0FFF\u1234) test string";
         String strUpdated = "An updated (\u0FEF\u9876) test string";
@@ -841,7 +879,7 @@
         updatedStr.close();
     }
 
-    public void embonlytmpUpdateCharacterStreamLengthlessParameterName()
+    public void testUpdateCharacterStreamLengthlessParameterName()
             throws IOException, SQLException {
         String str = "This is the (\u0FFF\u1234) test string";
         String strUpdated = "An updated (\u0FEF\u9876) test string";
@@ -940,7 +978,7 @@
         rs1.close();
     }
 
-    public void embeddedUpdateClobLengthless()
+    public void testUpdateClobLengthless()
             throws Exception {
         Reader r1 = new java.io.StringReader(new String(BYTES1));
         // InputStream for insertion.
@@ -1035,7 +1073,7 @@
         rs1.close();
     }
 
-    public void embeddedUpdateBlobLengthless()
+    public void testUpdateBlobLengthless()
             throws Exception {
         InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
         // InputStream for insertion.
@@ -1129,7 +1167,7 @@
         rs1.close();
     }
 
-    public void embeddedUpdateClobLengthlessParameterName()
+    public void testUpdateClobLengthlessParameterName()
             throws Exception {
         Reader r1 = new java.io.StringReader(new String(BYTES1));
         // InputStream for insertion.
@@ -1224,7 +1262,7 @@
         rs1.close();
     }
 
-    public void embeddedUpdateBlobLengthlessParameterName()
+    public void testUpdateBlobWithStreamLengthlessParameterName()
             throws Exception {
         InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
         // InputStream for insertion.
@@ -1273,36 +1311,7 @@
         embeddedSuite.addTest(new ResultSetTest(
                     "embeddedUpdateClob"));
         embeddedSuite.addTest(new ResultSetTest(
-                    "embeddedUpdateBlobStringParameterName"));
-        embeddedSuite.addTest(new ResultSetTest(
                     "embeddedUpdateClobStringParameterName"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embeddedUpdateBlobLengthless"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embeddedUpdateBlobLengthlessParameterName"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embeddedUpdateClobLengthless"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embeddedUpdateClobLengthlessParameterName"));
-        // A bunch of tests disabled temporarily for DerbyNetClient.
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateAsciiStreamLengthless"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateAsciiStreamLengthlessParameterName"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateBinaryStreamLengthless"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateBinaryStreamLengthlessParameterName"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateCharacterStreamLengthless"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateCharacterStreamLengthlessParameterName"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateNCharacterStreamIntLengthLessNotImplemented"));
-        embeddedSuite.addTest(new ResultSetTest(
-                    "embonlytmpUpdateNCharacterStreamStringLengthlessNotImplemented"));
-        //embeddedSuite.addTest(new ResultSetTest(
-        //            ""));
         return embeddedSuite;
     }
 



Mime
View raw message