db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1488339 - in /db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests: tests/jdbcapi/parameterMapping.java util/streams/ util/streams/CharAlphabet.java util/streams/LoopingAlphabetReader.java
Date Fri, 31 May 2013 17:59:41 GMT
Author: mamta
Date: Fri May 31 17:59:40 2013
New Revision: 1488339

URL: http://svn.apache.org/r1488339
Log:
DERBY-6237(PreparedStatement.execute() fails starting 10.2 when multiple rows are updated
and PreparedStatement.setCharacterStream(int, Reader, int) is used)

In 10.1, setCharacterStream to update CLOB and varchar columns work even when update is going
to update more than one row



Added:
    db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/
    db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java
    db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java
Modified:
    db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/parameterMapping.java

Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/parameterMapping.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/parameterMapping.java?rev=1488339&r1=1488338&r2=1488339&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/parameterMapping.java
(original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/parameterMapping.java
Fri May 31 17:59:40 2013
@@ -21,7 +21,10 @@
 package org.apache.derbyTesting.functionTests.tests.jdbcapi;
 
 import org.apache.derby.tools.ij;
+
 import org.apache.derbyTesting.functionTests.util.TestUtil;
+import org.apache.derbyTesting.functionTests.util.streams.CharAlphabet;
+import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader;
 
 
 import java.sql.*;
@@ -261,7 +264,8 @@ public class parameterMapping {
 			// make the initial connection.
 			 ij.getPropertyArg(args);
 			 Connection conn = ij.startJBMS();
-
+			 testDERBY6237(conn);
+			 
 			 conn.setAutoCommit(false);
 
 			 //create simple a table with BLOB and CLOB thta
@@ -2965,4 +2969,82 @@ public class parameterMapping {
 
 		return "0x" + Integer.toHexString(((int) b1) & 0xff) + "," + "0x" + Integer.toHexString(((int)
b2) & 0xff);
 	}
+	
+	//numberOfRowsToUpdate - value 1 or 2
+	//testVariation - if 1 then update CLOB with short data
+	//                if 2 then update CLOB with large data
+	private static void helperTestDerby6237(int numberOfRowsToUpdate, 
+            int testVariation,
+            Connection conn) throws Exception
+	{
+        CharAlphabet a1 = CharAlphabet.singleChar('a');
+
+        PreparedStatement ps = conn.prepareStatement(
+            "UPDATE TestUpdateCharStream SET c3 = ?, " + 
+            "c2 = c2 + 1 WHERE c1 IN (?, ?)");
+
+        switch (testVariation) {
+        case 1 :
+        	//test short data
+            ps.setCharacterStream(1,
+                    new LoopingAlphabetReader(50, a1), 50);
+            break;
+        case 2 :
+        	//test large data
+            ps.setCharacterStream(1,
+                    new LoopingAlphabetReader(50000, a1), 50000);
+            break;
+        }
+        
+        //First value in IN clause is getting set to 'AAAAA'
+        // Using setCharacterStream on VARCHAR to set the value
+        ps.setCharacterStream(2, new CharArrayReader("AAAAA".toCharArray()), 5);
+        
+        if (numberOfRowsToUpdate == 1 ) {
+            //Second value in IN clause is also getting set to 'AAAAA', which 
+            // means prepared statement will update only one row
+            ps.setObject(3, "AAAAA", Types.VARCHAR);
+        } else {
+            //Second value in IN clause is also getting set to 'EEEEE', which 
+            // means prepared statement will update two rows
+            ps.setObject(3, "EEEEE", Types.VARCHAR);
+        }
+        	
+        ps.execute();
+        ps.close();
+
+    }
+
+    /**
+     * DERBY-6237(PreparedStatement.execute() fails starting 10.2 when 
+     *  multiple rows are updated and 
+     *  PreparedStatement.setCharacterStream(int, Reader, int) is used) 
+     * In 10.1, setCharacterStream to update CLOB and varchar columns
+     *  work even when update is going to update more than one row
+     * @throws Exception
+     */
+	private static void testDERBY6237(Connection conn) throws Exception
+	{
+        Statement s = conn.createStatement();
+        s.executeUpdate("CREATE TABLE TestUpdateCharStream ("+
+                "c1 VARCHAR(64) NOT NULL, " +
+          	    "c2 INTEGER, " +
+                "c3 CLOB)"); 
+        s.executeUpdate("INSERT INTO TestUpdateCharStream (c1, c2) " +
+                "VALUES ('AAAAA', 1)");
+        s.executeUpdate("INSERT INTO TestUpdateCharStream (c1, c2) " +
+                "VALUES ('EEEEE', 1)");
+        
+        //update only one row and use short data
+        helperTestDerby6237(1,1,conn);
+        //update only one row and use large data
+        helperTestDerby6237(1,2,conn);
+        //update two rows and use short data
+        helperTestDerby6237(2,1,conn);
+        //update two rows and use large data
+        helperTestDerby6237(2,2,conn);
+        s.execute("DROP TABLE TestUpdateCharStream");
+        s.close();
+    }
+
 }

Added: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java?rev=1488339&view=auto
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java
(added)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java
Fri May 31 17:59:40 2013
@@ -0,0 +1,200 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.util.streams.CharAlphabet
+
+   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.util.streams;
+
+/**
+ * A looping alphabet, returning characters.
+ *
+ * The alphabet loops over a list of characters. The alphabet-object is used
+ * by looping readers, which in turn is used for testing methods requiring
+ * streaming inputs.
+ *
+ * The following alphabets have been defined:
+ * <ul><li><em>Modern latin, lowercase</em> ; letters a - z (26)
+ *     <li><em>Norwegian/Danish, lowercase</em> ; letters a - z, plus three
+ *         additional letters (29)
+ *     <li><em>Tamil</em> ; 46 Tamil letters from UNICODE U0B80
+ *     <li><em>CJK subset</em> ; 12 letter from UNICODE CJK U4E00 
+ * </ul>
+ */
+public class CharAlphabet {
+    
+    /** Modern latin, lowercase; a - z, 26 letters */
+    public static char[] MODERNLATINLOWER = {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
+        };
+
+    /** Norwegian/Danish alphabet, lowercase; 29 letters */
+    public static char[] NO_DK_LOWER = {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '\u00E6', '\u00F8', '\u00E5'
+        };
+
+    /** Subset of Tamil alphabet; 46 letters, UNICODE U0B80 */
+    public static char[] TAMIL = {
+            '\u0B85', '\u0B86', '\u0B87', '\u0B88', '\u0B89', '\u0B8A',
+            '\u0B8E', '\u0B8F', '\u0B90', '\u0B92', '\u0B93', '\u0B94',
+            '\u0B95', '\u0B99', '\u0B9A', '\u0B9C', '\u0B9E', '\u0B9F',
+            '\u0BA3', '\u0BA4', '\u0BA8', '\u0BA9', '\u0BAA', '\u0BAE',
+            '\u0BAF', '\u0BB0', '\u0BB1', '\u0BB2', '\u0BB3', '\u0BB4',
+            '\u0BB5', '\u0BB6', '\u0BB7', '\u0BB8', '\u0BB9', '\u0BBE',
+            '\u0BBF', '\u0BC0', '\u0BC1', '\u0BC2', '\u0BC6', '\u0BC7',
+            '\u0BC8', '\u0BCA', '\u0BCB', '\u0BCC'
+        };
+
+    /** CJK subset; 12 letters, UNICODE U4E00 */
+    public static char[] CJKSUBSET = {
+            '\u4E00', '\u4E01', '\u4E02', '\u4E03', '\u4E04', '\u4E05',
+            '\u4E06', '\u4E07', '\u4E08', '\u4E09', '\u4E0A', '\u4E0B'
+        };
+
+    /**
+     * Get a modern latin lowercase alphabet.
+     */
+    public static CharAlphabet modernLatinLowercase() {
+        return new CharAlphabet("Modern latin lowercase",
+                                CharAlphabet.MODERNLATINLOWER);
+    }
+
+    /**
+     * Get a CJK subset alphabet.
+     */
+    public static CharAlphabet cjkSubset() {
+        return new CharAlphabet("CJK subset",
+                                CharAlphabet.CJKSUBSET);
+    }
+
+    /**
+     * Get a Tamil alphabet
+     */
+    public static CharAlphabet tamil() {
+        return new CharAlphabet("Tamil", CharAlphabet.TAMIL);
+    }
+
+    /**
+     * Get an alphabet consisting of a single character.
+     */
+    public static CharAlphabet singleChar(char ch) {
+        return new CharAlphabet("Single char: " + ch, new char[] { ch });
+    }
+
+    /** Name of the alphabet. */
+    private final String name;
+    /** Characters in the alphabet. */
+    private final char[] chars;
+    /** Number of characters in the alphabet. */
+    private final int charCount;
+    /** Current offset into the alphabet/character array. */
+    private int off = 0;
+    
+    /**
+     * Create an alphabet with the given name and characters.
+     *
+     * @param name name of the alphabet
+     * @param chars characters in the alphabet.
+     */
+    private CharAlphabet(String name, char[] chars) {
+        this.name = name;
+        this.chars = chars;
+        this.charCount = chars.length;
+    }
+
+    /**
+     * Return the name of the alphabet.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Return the number of characters in the alphabet.
+     */
+    public int charCount() {
+        return this.charCount;
+    }
+
+    /**
+     * Return the next char as an <code>integer</code>.
+     *
+     * @return the next character in the alphabet as an <code>integer</code>
+     */
+    public int nextCharAsInt() {
+        if (off >= charCount) {
+            off = 0;
+        }
+        return (int)chars[off++];
+    }
+
+    /**
+     * Return the next char.
+     *
+     * @return the next character in the alphabet
+     */
+    public char nextChar() {
+        if (off >= charCount) {
+            off = 0;
+        }
+        return chars[off++];
+    }
+
+    /**
+     * Compute the next character to read after reading the specified number
+     * of characters. 
+     *
+     * Besides from returning the index, the internal state of
+     * the alphabet is updated.
+     *
+     * @param charsRead the number of characters read
+     * @return the index of the next character
+     */
+    public int nextCharToRead(int charsRead) {
+        off = (off + (charsRead % charCount)) % charCount;
+        return off;
+    }
+
+    /**
+     * Reset the alphabet, the next character returned will be the first
+     * character in the alphabet.
+     */
+    public void reset() {
+        off = 0;
+    }
+
+    /**
+     * Returns a clone of the alphabet.
+     *
+     * @return A clone.
+     */
+    public CharAlphabet getClone() {
+        return new CharAlphabet(name, chars);
+    }
+
+    /**
+     * Returns a friendlier textual representation of the alphabet.
+     */
+    public String toString() {
+        return (name + "@" + hashCode() + "(charCount=" + charCount + ")");
+    }
+
+} // Enc class CharAlphabet

Added: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java?rev=1488339&view=auto
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java
(added)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java
Fri May 31 17:59:40 2013
@@ -0,0 +1,249 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader
+
+   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.util.streams;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A stream returning characters by looping over an alphabet.
+ */
+public class LoopingAlphabetReader
+    extends Reader {
+
+    /**
+     * Maximum size of buffer.
+     * Balance between size and memory usage.
+     */
+    private static final int MAX_BUF_SIZE = 32*1024;
+    /** The character used for blanks (SPACE). */
+    private static final int SPACE = ' ';
+
+    /** Number of characters in the reader. */
+    private final long length;
+    /** Number of blanks at the end of stream. */
+    private final int trailingBlanks;
+    /** Remaining non-blank characters. */
+    private long remainingNonBlanks;
+    /** Remaining blanks. */
+    private long remainingBlanks;
+    /** 
+     * Internal buffer of characters. 
+     * Used by the read-methods with a char[] argument. 
+     */
+    private char[] buffer = new char[0];
+    /** The alphabet to draw letters from. */
+    private final CharAlphabet alphabet;
+    /** Tell if the reader is closed or not. */
+    private boolean closed = false;
+
+    /**
+     * Create a looping modern latin alphabet reader of the specified length.
+     *
+     * @param length the number of characters
+     */
+    public LoopingAlphabetReader(long length) {
+        this(length, 0);
+    }
+
+    /**
+     * Create a looping modern latin alphabet of the specified length, with
+     * the specified number of trailing blanks.
+     *
+     * The number of non-blank characters is
+     * <code>length - trailingBlanks</code>.
+     *
+     * @param length total number of characters
+     * @param trailingBlanks number of blank characters at the end
+     */
+    public LoopingAlphabetReader(long length, int trailingBlanks) {
+        this.length = length;
+        this.trailingBlanks = trailingBlanks;
+        this.remainingNonBlanks = length - trailingBlanks;
+        this.remainingBlanks = trailingBlanks;
+        this.alphabet = CharAlphabet.modernLatinLowercase();
+        fillBuffer(alphabet.charCount());
+    }
+
+    /**
+     * Create a looping alphabet of the specified type and length.
+     *
+     * @param length the number of chars in the reader
+     * @param alphabet the alphabet to loop over
+     */
+    public LoopingAlphabetReader(long length, CharAlphabet alphabet) {
+        this(length, alphabet, 0);
+    }
+
+    /**
+     * Create a looping alphabet of the specified type and length, with
+     * the specified number of trailing blanks.
+     *
+     * The number of non-blank characters is
+     * <code>length - trailingBlanks</code>.
+     *
+     * @param length total number of characters
+     * @param alphabet the alphabet to draw characters from
+     * @param trailingBlanks number of blank characters at the end
+     */
+    public LoopingAlphabetReader(long length,
+                                 CharAlphabet alphabet,
+                                 int trailingBlanks) {
+        this.length = length;
+        this.trailingBlanks = trailingBlanks;
+        this.remainingNonBlanks = length - trailingBlanks;
+        this.remainingBlanks = trailingBlanks;
+        this.alphabet = alphabet.getClone();
+        fillBuffer(alphabet.charCount());
+    }
+
+    public int read()
+            throws IOException {
+        ensureOpen();
+        if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
+            return -1;
+        }
+        if (remainingNonBlanks <= 0) {
+            remainingBlanks--;
+            return SPACE;
+        }
+        remainingNonBlanks--;
+        return alphabet.nextCharAsInt();
+    }
+
+    public int read(char[] buf, int off, int length)
+            throws IOException {
+        ensureOpen();
+        if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
+            return -1;
+        }
+        // We can only read as many chars as there are in the stream.
+        int nonBlankLength = Math.min((int)remainingNonBlanks, length);
+        fillBuffer(nonBlankLength);
+        int read = 0;
+        // Find position of next char in the buffer.
+        int cOff = alphabet.nextCharToRead(0);
+        if (nonBlankLength <= (buffer.length - cOff)) {
+            System.arraycopy(buffer, cOff, buf, off, nonBlankLength);
+            remainingNonBlanks -= nonBlankLength;
+            read = nonBlankLength;
+            alphabet.nextCharToRead(nonBlankLength);
+        } else {
+            // Must read several times from the buffer.
+            int toRead = 0;
+            while (remainingNonBlanks > 0 && read < nonBlankLength) {
+                cOff = alphabet.nextCharToRead(toRead);
+                toRead = Math.min(buffer.length - cOff, nonBlankLength - read);
+                System.arraycopy(buffer, cOff, buf, off + read, toRead);
+                remainingNonBlanks -= toRead;
+                read += toRead;
+            }
+            cOff = alphabet.nextCharToRead(toRead);
+        }
+        if (read < length && remainingBlanks > 0) {
+            read += fillBlanks(buf, off + read, length - read);
+        }
+        return read;
+    }
+
+    /**
+     * Reset the stream.
+     */
+    public void reset()
+            throws IOException {
+        ensureOpen();
+        remainingNonBlanks = length - trailingBlanks;
+        remainingBlanks = trailingBlanks;
+        alphabet.reset();
+    }
+
+    /**
+     * Return remaining characters in the stream.
+     */
+    public int available() {
+        return (int)(remainingNonBlanks + remainingBlanks);
+    }
+
+    /**
+     * Close the reader.
+     */
+    public void close() {
+        this.closed = true;
+    }
+
+    /**
+     * Fill internal buffer of character sequence.
+     *
+     * @param bufSize the wanted size, might be ignored if too big
+     */
+    private void fillBuffer(int bufSize) {
+        if (bufSize > MAX_BUF_SIZE) {
+            bufSize = MAX_BUF_SIZE;
+        }
+        if (bufSize <= buffer.length) {
+            return;
+        }
+        int curOff = alphabet.nextCharToRead(0);
+        // First letter in buffer is always the first letter in the alphabet.
+        alphabet.reset();
+        buffer = new char[bufSize];
+        for (int i=0; i < bufSize; i++) {
+            buffer[i] = alphabet.nextChar();
+        }
+        // Must reset internal state of the alphabet, as we have not yet
+        // delivered any bytes.
+        alphabet.reset();
+        alphabet.nextCharToRead(curOff);
+    }
+
+    /**
+     * Fill array with blanks (SPACE).
+     *
+     * @param buf array to fill
+     * @param off starting offset
+     * @param length maximum number of blanks to fill in
+     */
+    private int fillBlanks(char[] buf, int off, int length) {
+        int i=0;
+        for (; i < length; i++) {
+            if (remainingBlanks > 0) {
+                buf[off+i] = SPACE;
+                remainingBlanks--;
+            } else {
+                break;
+            }
+        }
+        return i;
+    }
+
+    /**
+     * Ensure reader is open.
+     *
+     * @throws IOException if reader is closed
+     */
+    private final void ensureOpen()
+            throws IOException {
+        if (closed) {
+            throw new IOException("Reader closed");
+        }
+    }
+} // End class LoopingAlphabetReader



Mime
View raw message