From derby-commits-return-8522-apmail-db-derby-commits-archive=db.apache.org@db.apache.org Mon Oct 01 18:27:37 2007 Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 11505 invoked from network); 1 Oct 2007 18:27:36 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 1 Oct 2007 18:27:36 -0000 Received: (qmail 86122 invoked by uid 500); 1 Oct 2007 18:27:26 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 86093 invoked by uid 500); 1 Oct 2007 18:27:26 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 86082 invoked by uid 99); 1 Oct 2007 18:27:25 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 Oct 2007 11:27:25 -0700 X-ASF-Spam-Status: No, hits=-98.8 required=10.0 tests=ALL_TRUSTED,DNS_FROM_DOB,RCVD_IN_DOB X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 Oct 2007 18:27:35 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 42FC61A9832; Mon, 1 Oct 2007 11:27:15 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r581031 - in /db/derby/code/branches/10.3/java: drda/org/apache/derby/impl/drda/DRDAConnThread.java drda/org/apache/derby/impl/drda/DRDAStatement.java testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java Date: Mon, 01 Oct 2007 18:27:14 -0000 To: derby-commits@db.apache.org From: kmarsden@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20071001182715.42FC61A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: kmarsden Date: Mon Oct 1 11:27:09 2007 New Revision: 581031 URL: http://svn.apache.org/viewvc?rev=581031&view=rev Log: DERBY-3085 Fails to handle BLOB fields with a PreparedStatement with size >32750 bytes port from trunk Modified: db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAStatement.java db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java Modified: db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=581031&r1=581030&r2=581031&view=diff ============================================================================== --- db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original) +++ db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Mon Oct 1 11:27:09 2007 @@ -4527,6 +4527,10 @@ for (int i = 0; i < numExt; i++) { int paramPos = stmt.getExtPosition(i); + // Only the last EXTDTA is streamed. This is because all of + // the parameters have to be set before execution and are + // consecutive in the network server stream, so only the last + // one can be streamed. final boolean doStreamLOB = (streamLOB && i == numExt -1); readAndSetExtParam(paramPos, stmt, @@ -4580,12 +4584,13 @@ paramBytes = null; final EXTDTAReaderInputStream stream = reader.getEXTDTAReaderInputStream(checkNullability); - + // Save the streamed parameter so we can drain it if it does not get used + // by embedded when the statement is executed. DERBY-3085 + stmt.setStreamedParameter(stream); if( stream instanceof StandardEXTDTAReaderInputStream ){ final StandardEXTDTAReaderInputStream stdeis = (StandardEXTDTAReaderInputStream) stream ; - ps.setBinaryStream( i + 1, stdeis, (int) stdeis.getLength() ); @@ -4643,7 +4648,7 @@ case DRDAConstants.DRDA_TYPE_LOBCSBCS: case DRDAConstants.DRDA_TYPE_NLOBCSBCS: - setAsCharacterStream(ps, + setAsCharacterStream(stmt, i, checkNullability, reader, @@ -4654,7 +4659,7 @@ case DRDAConstants.DRDA_TYPE_LOBCDBCS: case DRDAConstants.DRDA_TYPE_NLOBCDBCS: - setAsCharacterStream(ps, + setAsCharacterStream(stmt, i, checkNullability, reader, @@ -4665,7 +4670,7 @@ case DRDAConstants.DRDA_TYPE_LOBCMIXED: case DRDAConstants.DRDA_TYPE_NLOBCMIXED: - setAsCharacterStream(ps, + setAsCharacterStream(stmt, i, checkNullability, reader, @@ -8259,7 +8264,7 @@ } - private static void setAsCharacterStream(PreparedStatement ps, + private static void setAsCharacterStream(DRDAStatement stmt, int i, boolean checkNullability, DDMReader reader, @@ -8268,12 +8273,16 @@ throws DRDAProtocolException , SQLException , IOException { - + PreparedStatement ps = stmt.getPreparedStatement(); EnginePreparedStatement engnps = ( EnginePreparedStatement ) ps; final EXTDTAReaderInputStream extdtastream = reader.getEXTDTAReaderInputStream(checkNullability); + // DERBY-3085. Save the stream so it can be drained later + // if not used. + if (streamLOB) + stmt.setStreamedParameter(extdtastream); final InputStream is = streamLOB ? Modified: db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAStatement.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAStatement.java?rev=581031&r1=581030&r2=581031&view=diff ============================================================================== --- db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAStatement.java (original) +++ db/derby/code/branches/10.3/java/drda/org/apache/derby/impl/drda/DRDAStatement.java Mon Oct 1 11:27:09 2007 @@ -21,6 +21,7 @@ package org.apache.derby.impl.drda; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -108,6 +109,12 @@ * of Integer/Byte in order to re-use the same storage each time * the statement is executed. */ private static class DrdaParamState { + // The last parameter may be streamed. + // We need to keep a record of it so we can drain it if it is not + // used. + // Only the last parameter with an EXTDTA will be streamed. + //(See DRDAConnThread.readAndSetAllExtParams()). + private EXTDTAReaderInputStream streamedParameter = null; private int typeLstEnd_ = 0; private byte[] typeLst_ = new byte[10]; private int[] lenLst_ = new int[10]; @@ -132,6 +139,7 @@ * @param trim - if true; release excess storage */ protected void clear(boolean trim) { + streamedParameter = null; typeLstEnd_ = 0; extLstEnd_ = 0; if (trim && typeLst_.length > 10) { @@ -223,6 +231,33 @@ * of the ith external parameter (zero-based) */ protected int getExtPos(int i) { return extLst_[i]; } + + /** + * Read the rest of the streamed parameter if not consumed + * by the executing statement. DERBY-3085 + * @throws IOException + */ + protected void drainStreamedParameter() throws IOException + { + if (streamedParameter != null) + { + // we drain the buffer 1000 bytes at a time. + // 1000 is just a random selection that doesn't take + // too much memory. Perhaps something else would be + // more efficient? + byte[] buffer = new byte[1000]; + int i; + do { + i= streamedParameter.read(buffer,0,1000); + } while (i != -1); + } + } + + + public void setStreamedParameter(EXTDTAReaderInputStream eis) { + streamedParameter = eis; + } + } private DrdaParamState drdaParamState_ = new DrdaParamState(); @@ -664,7 +699,16 @@ protected boolean execute() throws SQLException { boolean hasResultSet = ps.execute(); - + // DERBY-3085 - We need to make sure we drain the streamed parameter + // if not used by the server, for example if an update statement does not + // update any rows, the parameter won't be used. Network Server will + // stream only the last parameter with an EXTDTA. This is stored when the + // parameter is set and drained now after statement execution if needed. + try { + drdaParamState_.drainStreamedParameter(); + } catch (IOException e) { + Util.javaException(e); + } // java.sql.Statement says any result sets that are opened // when the statement is re-executed must be closed; this // is handled by the call to "ps.execute()" above--but we @@ -1260,6 +1304,11 @@ drdaParamState_.addDrdaParam(t, l); } + protected void setStreamedParameter(EXTDTAReaderInputStream eis) + { + drdaParamState_.setStreamedParameter(eis); + } + /** * get parameter DRDAType * Modified: db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java?rev=581031&r1=581030&r2=581031&view=diff ============================================================================== --- db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java (original) +++ db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java Mon Oct 1 11:27:09 2007 @@ -20,6 +20,7 @@ package org.apache.derbyTesting.functionTests.tests.jdbcapi; import java.io.ByteArrayInputStream; +import java.io.CharArrayReader; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; @@ -87,6 +88,101 @@ /*** TESTS ***/ /** + * DERBY-3085. Test update where streamed parameter is not + * consumed by the server. Network Server needs to clean-up + * after execution. + * + */ + public void testUnconsumedParameter() throws SQLException + { + Connection conn = getConnection(); + conn.setAutoCommit(false); + Statement s = conn.createStatement(); + // Test table with no rows. + s.executeUpdate("create table testing(num int, addr varchar(40), contents blob(16M))"); + // no rows inserted so there is no match. + byte[] data = new byte[ 38000]; + for (int i = 0; i < data.length; i++) + data[i] = 'a'; + ByteArrayInputStream is = new ByteArrayInputStream( data); + String sql = "UPDATE testing SET Contents=? WHERE num=1"; + + PreparedStatement ps = prepareStatement( sql); + ps.setBinaryStream( 1, is,data.length); + ps.executeUpdate(); + // Make sure things still work ok when we have a parameter that does get consumed. + // insert a matching row. + s.executeUpdate("insert into testing values (1,null,null)"); + is = new ByteArrayInputStream(data); + ps.setBinaryStream( 1, is,data.length); + ps.executeUpdate(); + // Check update occurred + ResultSet rs = s.executeQuery("select length(contents) from testing where num = 1"); + JDBC.assertSingleValueResultSet(rs, "38000"); + ps.close(); + conn.commit(); + // Check the case where there are rows inserted but there is no match. + is = new ByteArrayInputStream( data); + sql = "UPDATE testing SET Contents=? WHERE num=2"; + ps = prepareStatement( sql); + ps.setBinaryStream( 1, is,data.length); + ps.executeUpdate(); + ps.close(); + s.executeUpdate("drop table testing"); + conn.commit(); + + // Test with multiple parameters + s.executeUpdate("create table testing(num int, addr varchar(40), contents blob(16M),contents2 blob(16M))"); + + is = new ByteArrayInputStream( data); + ByteArrayInputStream is2 = new ByteArrayInputStream(data); + sql = "UPDATE testing SET Contents=?, contents2=? WHERE num=1"; + + ps = prepareStatement( sql); + ps.setBinaryStream( 1, is,data.length); + ps.setBinaryStream(2, is2,data.length); + ps.executeUpdate(); + + + // multiple parameters and matching row + s.executeUpdate("insert into testing values (1,'addr',NULL,NULL)"); + is = new ByteArrayInputStream( data); + is2 = new ByteArrayInputStream(data); + ps.setBinaryStream( 1, is,data.length); + ps.setBinaryStream(2, is2,data.length); + ps.executeUpdate(); + rs = s.executeQuery("select length(contents), length(contents2) from testing where num = 1"); + JDBC.assertFullResultSet(rs, new String[][] {{"38000","38000"}}); + rs.close(); + s.executeUpdate("drop table testing"); + + // With Clob + s.executeUpdate("create table testing(num int, addr varchar(40), contents Clob(16M))"); + char[] charData = new char[ 38000]; + for (int i = 0; i < data.length; i++) + data[i] = 'a'; + CharArrayReader reader = new CharArrayReader( charData); + sql = "UPDATE testing SET Contents=? WHERE num=1"; + + ps = prepareStatement( sql); + ps.setCharacterStream( 1, reader,charData.length); + ps.executeUpdate(); + // with a matching row + s.executeUpdate("insert into testing values (1,null,null)"); + reader = new CharArrayReader(charData); + ps.setCharacterStream( 1, reader,data.length); + ps.executeUpdate(); + // Check update occurred + rs = s.executeQuery("select length(contents) from testing where num = 1"); + JDBC.assertSingleValueResultSet(rs, "38000"); + s.executeUpdate("drop table testing"); + ps.close(); + + conn.commit(); + + } + + /** * Tests PreparedStatement.setCharacterStream */ public void testSetCharacterStream() throws Exception { @@ -3189,6 +3285,7 @@ s.execute("drop table blobCheck"); } + private void checkException(String SQLState, SQLException se) throws Exception {