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 km...@apache.org on 2010/07/12 18:07:20 UTC
svn commit: r963326 - in /db/derby/code/branches/10.5: ./
java/engine/org/apache/derby/iapi/sql/execute/
java/engine/org/apache/derby/impl/sql/compile/
java/engine/org/apache/derby/impl/sql/execute/
java/testing/org/apache/derbyTesting/functionTests/te...
Author: kmarsden
Date: Mon Jul 12 16:07:19 2010
New Revision: 963326
URL: http://svn.apache.org/viewvc?rev=963326&view=rev
Log:
DERBY-3646 Embedded returns wrong results when selecting a blob column twice and using getBinaryStream()
merged svn 902857 with manual merge of BLOBTest.java
Contributed by Kristian Waagan
Modified:
db/derby/code/branches/10.5/ (props changed)
db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/HashTableNode.java
db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java
db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/ProjectRestrictResultSet.java
db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
Propchange: db/derby/code/branches/10.5/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Jul 12 16:07:19 2010
@@ -1,2 +1,2 @@
/db/derby/code/branches/10.6:957000,962738
-/db/derby/code/trunk:757811,769596,769602,769606,769962,772090,772337,772449,772534,774281,777105,779681,782991,785131,785139,785163,785570,785662,788369,788670,788674,788968,789264,790218,791027,792434,793089,793588,794106,794303,794955,795166,795459,796020,796027,796316,796372,797147,798347,798742,800523,803548,803948,805696,808494,808850,809643,810860,812669,816531,816536,819006,822289,823659,824694,829022,829410,831304,831319,832379,833430,835286,881074,881444,882732,884163,885421,885659,887246,888311,892912,897161,898635,901165,901648,901760,903108,905224,908418,908586,909176,911315,915733,916075,916897,918359,921028,927430,928065,936215,942286,942476,942480,942587,946794,948045,948069,951346,951366,952138,952581,954748,955001,955634,956075,956445,956659,958163,959550,962716
+/db/derby/code/trunk:757811,769596,769602,769606,769962,772090,772337,772449,772534,774281,777105,779681,782991,785131,785139,785163,785570,785662,788369,788670,788674,788968,789264,790218,791027,792434,793089,793588,794106,794303,794955,795166,795459,796020,796027,796316,796372,797147,798347,798742,800523,803548,803948,805696,808494,808850,809643,810860,812669,816531,816536,819006,822289,823659,824694,829022,829410,831304,831319,832379,833430,835286,881074,881444,882732,884163,885421,885659,887246,888311,892912,897161,898635,901165,901648,901760,902857,903108,905224,908418,908586,909176,911315,915733,916075,916897,918359,921028,927430,928065,936215,942286,942476,942480,942587,946794,948045,948069,951346,951366,952138,952581,954748,955001,955634,956075,956445,956659,958163,959550,962716
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java?rev=963326&r1=963325&r2=963326&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java Mon Jul 12 16:07:19 2010
@@ -293,7 +293,8 @@ public interface ResultSetFactory {
Boolean restriction() throws StandardException;
</verbatim>
@param mapArrayItem Item # for mapping of source to target columns
- @param reuseResult Whether or not to reuse the result row.
+ @param cloneMapItem Item # for columns that need cloning
+ @param reuseResult Whether or not to reuse the result row.
@param doesProjection Whether or not this PRN does a projection
@param optimizerEstimatedRowCount Estimated total # of rows by
optimizer
@@ -307,6 +308,7 @@ public interface ResultSetFactory {
GeneratedMethod projection, int resultSetNumber,
GeneratedMethod constantRestriction,
int mapArrayItem,
+ int cloneMapItem,
boolean reuseResult,
boolean doesProjection,
double optimizerEstimatedRowCount,
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/HashTableNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/HashTableNode.java?rev=963326&r1=963325&r2=963326&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/HashTableNode.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/HashTableNode.java Mon Jul 12 16:07:19 2010
@@ -256,7 +256,11 @@ public class HashTableNode extends Singl
// Map the result columns to the source columns
- int[] mapArray = resultColumns.mapSourceColumns();
+ ResultColumnList.ColumnMapping mappingArrays =
+ resultColumns.mapSourceColumns();
+
+ int[] mapArray = mappingArrays.mapArray;
+
int mapArrayItem = acb.addItem(new ReferencedColumnsDescriptorImpl(mapArray));
// Save the hash key columns
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java?rev=963326&r1=963325&r2=963326&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java Mon Jul 12 16:07:19 2010
@@ -1423,8 +1423,15 @@ public class ProjectRestrictNode extends
// Map the result columns to the source columns
- int[] mapArray = resultColumns.mapSourceColumns();
+
+ ResultColumnList.ColumnMapping mappingArrays =
+ resultColumns.mapSourceColumns();
+
+ int[] mapArray = mappingArrays.mapArray;
+ boolean[] cloneMap = mappingArrays.cloneMap;
+
int mapArrayItem = acb.addItem(new ReferencedColumnsDescriptorImpl(mapArray));
+ int cloneMapItem = acb.addItem(cloneMap);
/* Will this node do a projection? */
boolean doesProjection = true;
@@ -1462,13 +1469,14 @@ public class ProjectRestrictNode extends
* arg6: constantExpress - Expression for constant restriction
* (for example, where 1 = 2)
* arg7: mapArrayItem - item # for mapping of source columns
- * arg8: reuseResult - whether or not the result row can be reused
- * (ie, will it always be the same)
- * arg9: doesProjection - does this node do a projection
- * arg10: estimated row count
- * arg11: estimated cost
- * arg12: close method
- */
+ * arg8: cloneMapItem - item # for mapping of columns that need cloning
+ * arg9: reuseResult - whether or not the result row can be reused
+ * (ie, will it always be the same)
+ * arg10: doesProjection - does this node do a projection
+ * arg11: estimated row count
+ * arg12: estimated cost
+ * arg13: close method
+ */
acb.pushGetResultSetFactoryExpression(mb);
if (genChildResultSet)
@@ -1597,13 +1605,14 @@ public class ProjectRestrictNode extends
}
mb.push(mapArrayItem);
+ mb.push(cloneMapItem);
mb.push(resultColumns.reusableResult());
mb.push(doesProjection);
mb.push(costEstimate.rowCount());
mb.push(costEstimate.getEstimatedCost());
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getProjectRestrictResultSet",
- ClassName.NoPutResultSet, 10);
+ ClassName.NoPutResultSet, 11);
}
/**
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java?rev=963326&r1=963325&r2=963326&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java Mon Jul 12 16:07:19 2010
@@ -26,6 +26,8 @@ import java.sql.ResultSetMetaData;
import java.sql.Types;
import java.util.Hashtable;
import java.util.Vector;
+import java.util.Map;
+import java.util.HashMap;
import org.apache.derby.catalog.types.DefaultInfoImpl;
import org.apache.derby.iapi.error.StandardException;
@@ -3504,14 +3506,23 @@ public class ResultColumnList extends Qu
* -1.
* This is useful for determining if we need to do reflection
* at execution time.
+ * <p/>
+ * Also build an array of boolean for columns that point to the same virtual
+ * column and have types that are streamable to be able to determine if
+ * cloning is needed at execution time.
*
* @return Array representiong mapping of RCs to source RCs.
*/
- int[] mapSourceColumns()
+ ColumnMapping mapSourceColumns()
{
- int[] mapArray = new int[size()];
+ int[] mapArray = new int[size()];
+ boolean[] cloneMap = new boolean[size()];
+
ResultColumn resultColumn;
+ // key: virtual column number, value: index
+ Map seenMap = new HashMap();
+
int size = size();
for (int index = 0; index < size; index++)
@@ -3529,7 +3540,9 @@ public class ResultColumnList extends Qu
else
{
// Virtual column #s are 1-based
- mapArray[index] = vcn.getSourceColumn().getVirtualColumnId();
+ ResultColumn rc = vcn.getSourceColumn();
+ updateArrays(mapArray, cloneMap, seenMap, rc, index);
+
}
}
else if (resultColumn.getExpression() instanceof ColumnReference)
@@ -3544,7 +3557,9 @@ public class ResultColumnList extends Qu
else
{
// Virtual column #s are 1-based
- mapArray[index] = cr.getSource().getVirtualColumnId();
+ ResultColumn rc = cr.getSource();
+
+ updateArrays(mapArray, cloneMap, seenMap, rc, index);
}
}
else
@@ -3553,7 +3568,8 @@ public class ResultColumnList extends Qu
}
}
- return mapArray;
+ ColumnMapping result = new ColumnMapping(mapArray, cloneMap);
+ return result;
}
/** Set the nullability of every ResultColumn in this list
@@ -4231,6 +4247,7 @@ public class ResultColumnList extends Qu
return false;
}
+
/*
* Remove all window functions columns from this list
*/
@@ -4250,4 +4267,52 @@ public class ResultColumnList extends Qu
resetVirtualColumnIds();
}
+
+ private static boolean streamableType(ResultColumn rc) {
+ DataTypeDescriptor dtd = rc.getType();
+ TypeId s = TypeId.getBuiltInTypeId(dtd.getTypeName());
+
+ if (s != null) {
+ return s.streamStorable();
+ } else {
+ return false;
+ }
+ }
+
+
+ private static void updateArrays(int[] mapArray,
+ boolean[] cloneMap,
+ Map seenMap,
+ ResultColumn rc,
+ int index) {
+
+ int vcId = rc.getVirtualColumnId();
+
+ mapArray[index] = vcId;
+
+ if (streamableType(rc)) {
+ Integer seenIndex =
+ (Integer)seenMap.get(new Integer(vcId));
+
+ if (seenIndex != null) {
+ // We have already mapped this column at index
+ // seenIndex, so mark occurence 2..n for cloning.
+ cloneMap[index] = true;
+ } else {
+ seenMap.put(new Integer(vcId), new Integer(index));
+ }
+ }
+ }
+
+
+ public class ColumnMapping {
+
+ public final int[] mapArray;
+ public final boolean[] cloneMap;
+
+ public ColumnMapping(int[] mapArray, boolean[] cloneMap) {
+ this.mapArray = mapArray;
+ this.cloneMap = cloneMap;
+ }
+ }
}
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java?rev=963326&r1=963325&r2=963326&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java Mon Jul 12 16:07:19 2010
@@ -212,6 +212,7 @@ public class GenericResultSetFactory imp
GeneratedMethod projection, int resultSetNumber,
GeneratedMethod constantRestriction,
int mapRefItem,
+ int cloneMapItem,
boolean reuseResult,
boolean doesProjection,
double optimizerEstimatedRowCount,
@@ -220,7 +221,7 @@ public class GenericResultSetFactory imp
{
return new ProjectRestrictResultSet(source, source.getActivation(),
restriction, projection, resultSetNumber,
- constantRestriction, mapRefItem,
+ constantRestriction, mapRefItem, cloneMapItem,
reuseResult,
doesProjection,
optimizerEstimatedRowCount,
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/ProjectRestrictResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/ProjectRestrictResultSet.java?rev=963326&r1=963325&r2=963326&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/ProjectRestrictResultSet.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/execute/ProjectRestrictResultSet.java Mon Jul 12 16:07:19 2010
@@ -24,6 +24,7 @@ package org.apache.derby.impl.sql.execut
import org.apache.derby.iapi.services.monitor.Monitor;
import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.services.io.StreamStorable;
import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
import org.apache.derby.iapi.services.stream.InfoStreams;
@@ -69,6 +70,13 @@ class ProjectRestrictResultSet extends N
public boolean doesProjection;
private GeneratedMethod projection;
private int[] projectMapping;
+
+ /**
+ * Holds columns present more than once in the result set and which may be
+ * represented by a stream, since such columns need to be cloned.
+ */
+ private boolean[] cloneMap;
+
private boolean runTimeStatsOn;
private ExecRow mappedResultRow;
public boolean reuseResult;
@@ -87,6 +95,7 @@ class ProjectRestrictResultSet extends N
int resultSetNumber,
GeneratedMethod cr,
int mapRefItem,
+ int cloneMapItem,
boolean reuseResult,
boolean doesProjection,
double optimizerEstimatedRowCount,
@@ -115,6 +124,9 @@ class ProjectRestrictResultSet extends N
mappedResultRow = activation.getExecutionFactory().getValueRow(projectMapping.length);
}
+ cloneMap =
+ ((boolean[])a.getPreparedStatement().getSavedObject(cloneMapItem));
+
/* Remember whether or not RunTimeStatistics is on */
runTimeStatsOn = getLanguageConnectionContext().getRunTimeStatisticsMode();
recordConstructorTime();
@@ -507,7 +519,28 @@ class ProjectRestrictResultSet extends N
{
if (projectMapping[index] != -1)
{
- result.setColumn(index + 1, sourceRow.getColumn(projectMapping[index]));
+ DataValueDescriptor dvd =
+ sourceRow.getColumn(projectMapping[index]);
+
+ // See if the column has been marked for cloning.
+ // If the value isn't a stream, don't bother cloning it.
+ if (cloneMap[index] && dvd.getStream() != null) {
+
+ // Enable this code after DERBY-3650 is in: FIXME
+ //
+ // long length = dvd.getLengthIfKnown();
+ //
+ // If the stream isn't clonable, we have to load the stream.
+ // if ((length > 32*1024 || length == -1) &&
+ // dvd.getStream() instanceof CloneableStream) {
+ // // Copy the stream, the value may be large.
+ // dvd = dvd.copyForRead();
+ // } else {
+ // // Load the stream, then we don't have to clone.
+ ((StreamStorable)dvd).loadStream();
+ // }
+ }
+ result.setColumn(index + 1, dvd);
}
}
Modified: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java?rev=963326&r1=963325&r2=963326&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java (original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java Mon Jul 12 16:07:19 2010
@@ -40,8 +40,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
-import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream;
-
/**
* Tests reading and updating binary large objects (BLOBs).
*/
@@ -388,11 +386,14 @@ final public class BLOBTest extends Base
rs.close();
}
+
/**
* Tests that a lob can be safely occur multiple times in a SQL select.
* <p/>
* See DERBY-4477.
* <p/>
+ * @see org.apache.derbyTesting.functionTests.tests.memory.BlobMemTest#testDerby4477_3645_3646_Repro_lowmem
+ * @see org.apache.derbyTesting.functionTests.tests.memory.ClobMemTest#testDerby4477_3645_3646_Repro_lowmem_clob
*/
public void testDerby4477_3645_3646_Repro() throws SQLException, IOException {
setAutoCommit(false);
@@ -693,34 +694,35 @@ final public class BLOBTest extends Base
throws IOException, SQLException
{
println("Verify new value in table: " + newVal);
-
- final Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
+
+ final Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
-
- final ResultSet rs =
- stmt.executeQuery("SELECT * FROM " +
+
+ final ResultSet rs =
+ stmt.executeQuery("SELECT * FROM " +
BLOBDataModelSetup.getBlobTableName() +
" WHERE val = " + newVal);
-
+
println("Query executed, calling next");
-
+
boolean foundVal = false;
-
+
while (rs.next()) {
println("Next called, verifying row");
-
- assertEquals("Unexpected value in val column",
+
+ assertEquals("Unexpected value in val column",
newVal, rs.getInt(1));
-
+
verifyBlob(newVal, newSize, rs.getBlob(3));
foundVal = true;
}
assertTrue("No column with value= " + newVal + " found ", foundVal);
-
+
rs.close();
stmt.close();
}
-
+
+
/**
* Verifies that the blob is consistent
* @param expectedVal the InputStream for the Blob should return this value
@@ -730,19 +732,19 @@ final public class BLOBTest extends Base
* @exception SQLException causes test to fail with error
* @exception IOException causes test to fail with error
*/
- private void verifyBlob(final int expectedVal,
- final int expectedSize,
- final Blob blob)
+ private void verifyBlob(final int expectedVal,
+ final int expectedSize,
+ final Blob blob)
throws IOException, SQLException
{
final InputStream stream = blob.getBinaryStream();
int blobSize = 0;
for (int val = stream.read(); val!=-1; val = stream.read()) {
blobSize++;
-
+
// avoid doing a string-concat for every byte in blob
if (expectedVal!=val) {
- assertEquals("Unexpected value in stream at position " +
+ assertEquals("Unexpected value in stream at position " +
blobSize,
expectedVal, val);
}
@@ -768,7 +770,6 @@ final public class BLOBTest extends Base
public final void setUp()
throws Exception
{
- println("Setup of: " + getName());
getConnection().setAutoCommit(false);
}
}