When qualifying Java DB on JDK 7u4-ea-b06, we saw intermittent errors (manifested as SQLExceptions) on the 64-bit VM on SPARC, and initially filed a bug in the Apache Derby bug tracker, including a repro: https://issues.apache.org/jira/browse/DERBY-5569 This problem is also reproducible on 7u4-ea-b05, but not on 7u4-ea-b04, and it is only seen with the 64-bit VM for SPARC. By instrumenting the code, we narrowed down the problem to the following method in the org.apache.derby.impl.jdbc.EmbedResultSet class (the println() call has been added by us for debugging): public final Object getObject(int columnIndex) throws SQLException { checkIfClosed("getObject"); // need special handling for some types. int colType = getColumnType(columnIndex); switch (colType) { case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: // handles maxfield size correctly return getString(columnIndex); case Types.CLOB: return getClob(columnIndex); case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: System.out.println(colType); // handles maxfield size correctly return getBytes(columnIndex); case Types.BLOB: return getBlob(columnIndex); default: break; } try { DataValueDescriptor dvd = getColumn(columnIndex); if (wasNull = dvd.isNull()) return null; return dvd.getObject(); } catch (StandardException t) { throw noStateChangeException(t); } } If the above code ever calls println(), it should print a value equal to one of the constants Types.BINARY, Types.VARBINARY or Types.LONGVARBINARY. These constants are defined in java.sql.Types as -2, -3 and -4, respectively. However, when we see the error, the number -5 is printed (which corresponds to Types.BIGINT). That should be impossible, since there's no way the colType variable could have changed between the switch and the println(), so we suspect that the wrong code is produced for the above switch statement under some conditions. Unfortunately, we haven't been able to come up with a simple, standalone test case that demonstrates the problem. The test case we do have, runs quite a lot of Java DB code. So, for now, in order to reproduce the bug you will have to download and compile the D5569 class from https://issues.apache.org/jira/browse/DERBY-5569 and run it on JDK 7u4-ea on a SPARC machine: java -d64 -Xmx512M -Xms30M -cp $JAVA_HOME/db/lib/derby.jar:. D5569 (the memory settings are not necessary, but seem to make the test case fail more frequently on the machines where we've tested it) Then observe that the repro typically fails after 1700 to 3000 iterations because it takes the wrong code path in the above mentioned getObject() method: 0 100 200 300 (...) 1500 1600 1700 Exception in thread "main" java.sql.SQLException: The exception 'java.sql.SQLException: An attempt was made to get a data value of type 'byte[]' from a data value of type 'BIGINT'.' was thrown while evaluating an expression. at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source) (...) at org.apache.derby.impl.jdbc.EmbedResultSet.getBytes(Unknown Source) at org.apache.derby.impl.jdbc.EmbedResultSet.getObject(Unknown Source) at org.apache.derby.exe.ac9e300ac8x0134xf0dfx8da0x00000165e5883.e0(Unknown Source) (...) It reproduces fairly consistently on the two SPARC machines where we've run the repro, but not always. If it haven't reproduced after 3000 iterations (the number printed to the console is the iteration count), kill the repro and restart it. Running with -XX:+PrintCompilation shows that the getObject() method is compiled a long time before the error (it's compiled somewhere between the 100th and 200th iteration in the test case), so the compiled version appears to have been executed quite a number of times successfully before it starts failing. What's somewhat suspicious, though, is that the error always happens almost immediately after the getColumnType() method in the same class is recompiled, assuming that's what the following output means: 416520 7406 4 org.apache.derby.impl.jdbc.EmbedResultSet::getColumnType (63 bytes) 416530 5658 3 org.apache.derby.impl.jdbc.EmbedResultSet::getColumnType (63 bytes) made not entrant getColumnType() is the method that returns the value that's passed to the problematic switch statement in getObject(): int colType = getColumnType(columnIndex); switch (colType) { ...
|