You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2011/04/11 21:14:39 UTC
svn commit: r1091169 - in /db/derby/code/trunk/java:
engine/org/apache/derby/iapi/types/SQLClob.java
testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DummyReader.java
Author: rhillegas
Date: Mon Apr 11 19:14:39 2011
New Revision: 1091169
URL: http://svn.apache.org/viewvc?rev=1091169&view=rev
Log:
DERBY-4544: Don't use the SQLClob.getLength() optimization on non-resetable streams--this fixes a data corruption.
Added:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DummyReader.java (with props)
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java?rev=1091169&r1=1091168&r2=1091169&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java Mon Apr 11 19:14:39 2011
@@ -268,6 +268,12 @@ public class SQLClob
if (stream == null) {
return super.getLength();
}
+ //
+ // The following check was put in to fix DERBY-4544. We seem to get
+ // confused if we have to re-use non-resetable streams.
+ //
+ if ( !(stream instanceof Resetable) ) { return super.getLength(); }
+
// The Clob is represented as a stream.
// Make sure we have a stream descriptor.
boolean repositionStream = (csd != null);
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java?rev=1091169&r1=1091168&r2=1091169&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java Mon Apr 11 19:14:39 2011
@@ -45,6 +45,8 @@ import java.util.Arrays;
import junit.framework.Test;
+import org.apache.derby.iapi.types.HarmonySerialClob;
+
import org.apache.derbyTesting.functionTests.util.streams.CharAlphabet;
import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader;
import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream;
@@ -686,6 +688,133 @@ public class ClobTest
setAutoCommit(savedAutoCommitValue);
}
+ /**
+ * Verify that generated columns don't interfere with streaming Clobs.
+ * See DERBY-4544.
+ */
+ public void test_4544() throws Exception
+ {
+ int streamLength = 100;
+ String tableName;
+
+ prepareStatement
+ ( "create table t_4544_0 ( myclob clob )" ).execute();
+ insertClob( streamLength, "t_4544_0" );
+ prepareStatement
+ (
+ "create function replace_4544( inclob clob, target varchar( 32672 ), replacement varchar( 32672 ) )\n" +
+ "returns clob\n" +
+ "language java parameter style java no sql deterministic\n" +
+ "external name '" + getClass().getName() + ".replace'"
+ ).execute();
+
+ vetTable
+ (
+ streamLength,
+ "generated always as (length(myclob))",
+ Integer.toString( streamLength )
+ );
+ vetTable
+ (
+ streamLength,
+ "varchar( 3 ) generated always as ( substr(myclob, 1, 3) )",
+ " ab"
+ );
+ vetTable
+ (
+ streamLength,
+ "generated always as (locate( 'def', myclob ))",
+ "5"
+ );
+ vetTable
+ (
+ streamLength,
+ "clob generated always as (upper( myclob ))",
+ (new DummyReader( streamLength )).toString().toUpperCase()
+ );
+ vetTable
+ (
+ streamLength,
+ "clob generated always as (trim( myclob ))",
+ (new DummyReader( streamLength )).toString().trim()
+ );
+ vetTable
+ (
+ streamLength,
+ "clob generated always as (replace_4544( myclob, 'b', 'B' ))",
+ (new DummyReader( streamLength )).toString().replace( 'b', 'B' )
+ );
+
+ dropTable( "t_4544_0" );
+ prepareStatement( "drop function replace_4544" ).execute();
+ }
+ private void vetTable( int streamLength, String gencol, String expectedValue ) throws Exception
+ {
+ String tableName = "t_4544_1";
+
+ prepareStatement
+ ( "create table " + tableName + "( myclob clob, gencol " + gencol + " )" ).execute();
+
+ insertClob( streamLength, tableName );
+ vetTable( tableName, expectedValue );
+ vetClob( streamLength, tableName );
+
+ prepareStatement( "delete from " + tableName ).executeUpdate();
+
+ prepareStatement( "insert into " + tableName + "( myclob ) select myclob from t_4544_0" ).executeUpdate();
+ vetTable( tableName, expectedValue );
+ vetClob( streamLength, tableName );
+
+ dropTable( tableName );
+ }
+ private void vetTable( String tableName, String expectedValue ) throws Exception
+ {
+ ResultSet rs = prepareStatement( "select gencol from " + tableName ).executeQuery();
+ rs.next();
+ assertEquals( expectedValue, rs.getString( 1 ) );
+ rs.close();
+ }
+ private void insertClob( int streamLength, String tableName ) throws Exception
+ {
+ PreparedStatement insert = prepareStatement( "insert into " + tableName + "( myclob ) values ( ? )" );
+ insert.setCharacterStream( 1, new DummyReader( streamLength ), streamLength );
+ insert.executeUpdate();
+ }
+ private void vetClob( int streamLength, String tableName ) throws Exception
+ {
+ PreparedStatement select = prepareStatement( "select myclob from " + tableName );
+ ResultSet rs = select.executeQuery();
+ rs.next();
+ Reader actualReader = rs.getCharacterStream( 1 );
+ Reader expectedReader = new DummyReader( streamLength );
+
+ for ( int i = 0; i < streamLength; i++ )
+ {
+ int actual = actualReader.read();
+ if ( actual < 0 )
+ {
+ fail( " Read stream was only " + i + " characters long." );
+ }
+
+ int expected = expectedReader.read();
+
+ assertEquals( expected, actual );
+ }
+ assertTrue( actualReader.read() < 0 );
+
+ rs.close();
+ }
+ public static Clob replace( Clob clob, String target, String replacement )
+ throws Exception
+ {
+ char targetChar = target.charAt( 0 );
+ char replacementChar = replacement.charAt( 0 );
+ String originalString = clob.getSubString( 1, (int) clob.length() );
+ String resultString = originalString.replace( targetChar, replacementChar );
+
+ return new HarmonySerialClob( resultString );
+ }
+
/* Test ideas for more tests
*
* truncate:
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DummyReader.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DummyReader.java?rev=1091169&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DummyReader.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DummyReader.java Mon Apr 11 19:14:39 2011
@@ -0,0 +1,72 @@
+/*
+
+ Derby - Class org.apache.derbyTesting.functionTests.tests.jdbcapi.DummyReader
+
+ 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.jdbcapi;
+
+import java.io.Reader;
+
+public class DummyReader extends Reader
+{
+ private int _idx = 0;
+ private int _readerLength;
+ private static final String _chars = " abcdefghijklmnopqrstuvwxyz ";
+
+ public DummyReader( int readerLength )
+ {
+ _readerLength = readerLength;
+ }
+
+ public void close() {}
+
+ public int read( char[] buffer, int offset, int length )
+ {
+ if ( _idx >= _readerLength ) { return -1; }
+
+ for ( int i = 0; i < length; i++ )
+ {
+ if ( _idx >= _readerLength )
+ {
+ return i;
+ }
+ else
+ {
+ buffer[ offset + i ] = value( _idx++ );
+ }
+ }
+
+ return length;
+ }
+ private char value( int raw )
+ {
+ return _chars.charAt( raw % _chars.length() );
+ }
+
+ public String toString()
+ {
+ char[] buffer = new char[ _readerLength ];
+
+ for ( int i = 0; i < _readerLength; i++ ) { buffer[ i ] = value( i ); }
+
+ return new String( buffer );
+ }
+}
+
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DummyReader.java
------------------------------------------------------------------------------
svn:eol-style = native