Author: kristwaa
Date: Mon Jul 6 07:54:43 2009
New Revision: 791403
URL: http://svn.apache.org/viewvc?rev=791403&view=rev
Log:
DERBY-4278: Batch inserts with Clobs fails with the embedded driver.
Merged fix from trunk (revision 790135, patches 1a and 2a).
Patch files: n/a
Modified:
db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/types/SQLClob.java
db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/types/SQLClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/types/SQLClob.java?rev=791403&r1=791402&r2=791403&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/types/SQLClob.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/types/SQLClob.java Mon Jul
6 07:54:43 2009
@@ -102,7 +102,10 @@
// materializing the value if possible?
try
{
- return new SQLClob(getString());
+ SQLClob clone = new SQLClob(getString());
+ // Copy the soft upgrade mode state.
+ clone.inSoftUpgradeMode = inSoftUpgradeMode;
+ return clone;
}
catch (StandardException se)
{
@@ -118,7 +121,10 @@
*/
public DataValueDescriptor getNewNull()
{
- return new SQLClob();
+ SQLClob newClob = new SQLClob();
+ // Copy the soft upgrade mode state.
+ newClob.inSoftUpgradeMode = inSoftUpgradeMode;
+ return newClob;
}
/** @see StringDataValue#getValue(RuleBasedCollator) */
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java?rev=791403&r1=791402&r2=791403&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
(original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
Mon Jul 6 07:54:43 2009
@@ -64,6 +64,7 @@
import org.apache.derby.iapi.jdbc.BrokeredConnectionControl;
import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
import org.apache.derby.iapi.jdbc.EnginePreparedStatement;
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;
import org.apache.derby.iapi.types.StringDataValue;
/**
@@ -91,6 +92,13 @@
protected PreparedStatement preparedStatement;
private Activation activation;
+ /**
+ * Tells if we're accessing a database in soft upgrade mode or not.
+ * <p>
+ * This is lazily set if we need it.
+ * @see #isSoftUpgraded()
+ */
+ private Boolean inSoftUpgradeMode;
private BrokeredConnectionControl bcc=null;
@@ -735,6 +743,7 @@
ReaderToUTF8Stream utfIn;
final StringDataValue dvd = (StringDataValue)
getParms().getParameter(parameterIndex -1);
+ dvd.setSoftUpgradeMode(isSoftUpgraded());
// Need column width to figure out if truncation is needed
DataTypeDescriptor dtd[] = preparedStatement
.getParameterTypes();
@@ -805,6 +814,24 @@
}
/**
+ * Tells if the database being accessed is soft upgraded or not.
+ *
+ * @return {@code true} if database is soft upgraded, {@code false} if not.
+ * @throws StandardException if obtaining the access mode fails
+ */
+ private Boolean isSoftUpgraded()
+ throws StandardException {
+ // Determine if we are accessing a soft upgraded database or not.
+ // This is required to write the correct stream header format for Clobs.
+ if (inSoftUpgradeMode == null) {
+ inSoftUpgradeMode = Boolean.valueOf(
+ lcc.getDataDictionary().checkVersion(
+ DataDictionary.DD_VERSION_CURRENT, null));
+ }
+ return inSoftUpgradeMode;
+ }
+
+ /**
* 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
Modified: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java?rev=791403&r1=791402&r2=791403&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
(original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
Mon Jul 6 07:54:43 2009
@@ -41,6 +41,8 @@
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.Arrays;
+
import junit.framework.Test;
import org.apache.derbyTesting.functionTests.util.streams.CharAlphabet;
@@ -72,6 +74,11 @@
private static final int SET_ASCII_STREAM = 2;
/** Constant for Clob.setCharacterStream method. */
private static final int SET_CHARACTER_STREAM = 4;
+ /**
+ * Next unique id for a Clob. Note that this isn't accessed in a thread-
+ * safe way.
+ */
+ private static int nextUniqueId = 150000;
/** Test data, 18 characters long, containing only Norwegian letters. */
private static final String NORWEGIAN_LETTERS =
@@ -502,6 +509,81 @@
assertEquals(truncateTwiceSize, clob.length());
}
+ /**
+ * Tests that cloning an SQLClob object works when a stream has been set as
+ * the source of the Clob.
+ * <p>
+ * See DERBY-4278
+ *
+ * @throws SQLException if something goes wrong
+ */
+ public void testCloningThroughAddBatchWithStream()
+ throws SQLException {
+ testCloningThroughAddBatch(true, true);
+ testCloningThroughAddBatch(true, false);
+ }
+
+ /**
+ * Tests that cloning an SQLClob object works when a string has been set as
+ * the source of the Clob.
+ *
+ * @throws SQLException if something goes wrong
+ */
+ public void testCloningThroughAddBatchWithString()
+ throws SQLException {
+ testCloningThroughAddBatch(false, true);
+ testCloningThroughAddBatch(false, false);
+ }
+
+ /**
+ * Adds a series of Clobs into the test table using a batch, then deletes
+ * the Clobs inserted.
+ *
+ * @param sourceAsStream whether the source shall be specified as a stream
+ * or a string
+ * @param autoCommit auto commit mode to run with
+ * @throws SQLException if something goes wrong
+ */
+ private void testCloningThroughAddBatch(final boolean sourceAsStream,
+ boolean autoCommit)
+ throws SQLException {
+ final int count = 100;
+ // Adjust auto commit as specified (and reset when done).
+ boolean savedAutoCommitValue = getConnection().getAutoCommit();
+ setAutoCommit(autoCommit);
+ // Expect execution to return an array with ones.
+ int[] expectedResult = new int[count];
+ Arrays.fill(expectedResult, 1);
+ // Insert a series of Clobs using a batch.
+ PreparedStatement insert = prepareStatement(
+ "insert into ClobTestData values (?,?)");
+ int firstId = nextUniqueId;
+ for (int i=0; i < count; i++) {
+ insert.setInt(1, nextUniqueId++);
+ String str = "Clob-" + i;
+ if (sourceAsStream) {
+ insert.setCharacterStream(
+ 2, new StringReader(str), str.length());
+ } else {
+ insert.setString(2, "Clob-" +i);
+ }
+ insert.addBatch();
+ }
+ assertTrue(Arrays.equals(expectedResult, insert.executeBatch()));
+ commit();
+
+ // To avoid keeping the data around, delete it as well.
+ PreparedStatement delete = prepareStatement
+ ("delete from ClobTestData where id = ?");
+ for (int i=0; i < count; i++) {
+ delete.setInt(1, firstId + i);
+ delete.addBatch();
+ }
+ assertTrue(Arrays.equals(expectedResult, delete.executeBatch()));
+ commit();
+ setAutoCommit(savedAutoCommitValue);
+ }
+
/* Test ideas for more tests
*
* truncate:
|