Since version 2.2.2, the insert operation fails with clobs and Oracle:
java.lang.ClassCastException: java.lang.String cannot be cast to oracle.sql.CLOB
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:9229)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8843)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:9316)
at org.dbunit.dataset.datatype.ClobDataType.setSqlValue(ClobDataType.java:67)
at org.dbunit.database.statement.SimplePreparedStatement.addValue(SimplePreparedStatement.java:73)
at org.dbunit.database.statement.AutomaticPreparedBatchStatement.addValue(AutomaticPreparedBatchStatement.java:63)
at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:201)
at org.dbunit.ant.Operation.execute(Operation.java:212)
The change that triggers this problem seems to come from this:
ClobDataType.getSqlValue(int column, ResultSet resultSet) contains
statement.setObject(column, typeCast(value), getSqlType());
where getSqlType() returns Types.CLOB -> 2005
In version 2.2.1, where it works, it was:
statement.setObject(column, typeCast(value), DataType.LONGVARCHAR.getSqlType());
where DataType.LONGVARCHAR.getSqlType() -> -1
the same as Types.LONGVARCHAR
Oracle driver: 10.2.0.2.0 and 10.2.0.4.0
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
Logged In: YES
user_id=1232035
Originator: NO
Hi there,
Would you have a simple test case reproducing the issue? If you use an OracleConnection, OracleClobDataType should be used instead of the "normal" ClobDataType.
Regards,
Sébastien
Logged In: YES
user_id=711602
Originator: YES
I've tried using OracleDataTypeFactory(with driver class oracle.jdbc.OracleDriver and oracle.jdbc.driver.OracleDriver), but it doesn't work:
java.lang.ClassCastException: oracle.jdbc.driver.T4CConnection cannot be cast to oracle.jdbc.OracleConnection
at oracle.sql.CLOB.createTemporary(CLOB.java:754)
at oracle.sql.CLOB.createTemporary(CLOB.java:716)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.dbunit.ext.oracle.OracleClobDataType.getClob(OracleClobDataType.java:70)
at org.dbunit.ext.oracle.OracleClobDataType.setSqlValue(OracleClobDataType.java:56)
at org.dbunit.database.statement.SimplePreparedStatement.addValue(SimplePreparedStatement.java:62)
at org.dbunit.database.statement.AutomaticPreparedBatchStatement.addValue(AutomaticPreparedBatchStatement.java:52)
at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:177)
at org.dbunit.ant.Operation.execute(Operation.java:183)
I'll try and create a simple test case.
Logged In: YES
user_id=57511
Originator: NO
Oviously the problem is OracleDataTypeFactory is not aware of the pure JDBC oracle driver and recognizes only the previous classes12.jar driver
I suggest to introduce a new factory or patch the actual one to work with both (the latter seems a little bit harder to me)
Logged In: YES
user_id=711602
Originator: YES
The thing I don't understand is why was the change that broke 2.2 was required...
It worked perfectly fine.
I've searched Hibernate sources for oracle.sql.CLOB and they don't seem to used it, so maybe it's not required at all.
Logged In: YES
user_id=711602
Originator: YES
It seems it's because of the fix for 1806363
Logged In: YES
user_id=1232035
Originator: NO
This fix was introduced because LONGVARCHAR was causing issues with other RSBMSes. Cf. https://sourceforge.net/tracker/?func=detail&atid=449491&aid=1806363&group_id=47439
Given that we have an Oracle-specific data type, I think that fix is legitimate since the target is everything but Oracle. Now as Roberto indicated, the problem seems to be caused because the OracleDataTypeFactory should probably support T4CConnection along with OracleConnection.
Regards,
Sébastien.
Logged In: YES
user_id=57511
Originator: NO
I suggest rollback your dbunit version until we find out a solution or, in
case you need some of the patches applied after the 2.2.1 release, you can
rollback the commit relative to the #1806363 issue.
Sorry for the inconvenience, we already know we should set up a multi
rdbms integration test platform, but time and money are needed for such
activities and we actually have none of them :\
Logged In: YES
user_id=711602
Originator: YES
No problem... If I find the time, I'll try to fix it using your sugestions and provide a patch.
Logged In: YES
user_id=1232035
Originator: NO
If you could still provide us with a test case reproducing the issue, that would help us investigate the problem, as I haven't been able to reproduce the issue so far.
Thanks,
Sébastien.
test project
Logged In: YES
user_id=711602
Originator: YES
I've attached a project that demonstrates the problem.
File Added: 1984596.zip
Logged In: YES
user_id=711602
Originator: YES
Btw, you would have to use the instructions at http://maven.apache.org/guides/development/guide-plugin-snapshot-repositories.html to be able to use the required plugin
Logged In: YES
user_id=711602
Originator: YES
Maybe you can get pointers from here:
http://springframework.cvs.sourceforge.net/springframework/spring/src/org/springframework/jdbc/support/lob/OracleLobHandler.java?revision=1.25&view=markup
Logged In: YES
user_id=1803108
Originator: NO
Hi all,
I tried to reproduce the problem using your testcase and I got the same exception as you mentioned initially. I added the dataTypeFactory to the pom.xml and the test was green afterwards.
...
<configuration>
<driver>${driver}</driver>
<url>${url}</url>
<username>${username}</username>
<password>${password}</password>
<skip>${maven.test.skip}</skip>
<dataTypeFactoryName>org.dbunit.ext.oracle.OracleDataTypeFactory</dataTypeFactoryName>
</configuration>
...
Note that if you want to set it in the java code you can do it as follows:
...
DatabaseConnection dbConnection = new DatabaseConnection(jdbcConnection);
dbConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new OracleDataTypeFactory());
...
I also found that you might get into this problem when you work inside a Container (Tomcat or J2EE) while having the ojdbc.jar in your deployment artifact AND in the server lib dir. The cause are the ClassLoader strategies used by the container. See http://forums.oracle.com/forums/thread.jspa?threadID=554480&tstart=0 for further information.
If this would be true (just speculating a bit) the cause could be that dbunit's OracleClobDataType uses "Class.forName("oracle.sql.CLOB")" instead of "connection.getClass().getClassLoader().loadClass("oracle.sql.CLOB")"
Regards,
mat
Logged In: YES
user_id=1232035
Originator: NO
Hi Bustuila,
Thanks a mil for that project, that really helps! If only all the bug reports were coming with these packages test cases, life would be so much easier!
Also, apologies, I hadn't realised you were using dbunit through the maven plugin. As mat mentioned below, adding:
<dataTypeFactoryName>org.dbunit.ext.oracle.OracleDataTypeFactory</dataTypeFactoryName>
solves the problem for me too. Is that the case for you too, or is it what caused your second problem?:
java.lang.ClassCastException: oracle.jdbc.driver.T4CConnection cannot be
cast to oracle.jdbc.OracleConnection
I haven't been able to reproduce that second issue, though (on Oracle Database 10g Express Edition Release 10.2.0.1.0 - Product). Did you get this my tweaking your maven config?
Regards,
Sébastien.
Logged In: YES
user_id=711602
Originator: YES
I'm glad the test project was useful, especially since I forgot to put the schema.sql in it...
I don't run dbunit with the maven plugin in my work project, we're still using ant.
I just used maven for this example, which indeed works after using the oracle datatype factory...
I think the problem with the "oracle.jdbc.driver.T4CConnection cannot be cast to oracle.jdbc.OracleConnection" comes from the ant classloader, because I see before that another error:
[taskdef] log4j:ERROR A "org.apache.log4j.xml.DOMConfigurator" object is not assignable to a "org.apache.log4j.spi.Configurator" variable.
[taskdef] log4j:ERROR The class "org.apache.log4j.spi.Configurator" was loaded by
[taskdef] log4j:ERROR [AntClassLoader[...]].
[taskdef] log4j:ERROR Could not instantiate configurator [org.apache.log4j.xml.DOMConfigurator].
Another thing... it seems that these newer Oracle drivers are using the standard way of working with lobs:
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14249/adlob_api_overview.htm
"You can make changes to an entire persistent LOB, or to pieces of the beginning, middle, or end of a persistent LOB in Java by means of the JDBC API using the classes:
oracle.sql.BLOB
oracle.sql.CLOB
These classes implement java.sql.Blob and java.sql.Clob interfaces according to the JDBC 3.0 specification, which has methods for LOB modification. They also include legacy Oracle proprietary methods for LOB modification. These legacy methods are marked as deprecated and may be removed in a future release.
If you use JDK 1.4 or higher, then you can use variables typed java.sql.Blob and java.sql.Clob.
The JDBC 3.0 methods are included in classes12.jar, so that they can be used in JDK 1.2 or 1.3, but since they are not part of the java.sql.Blob and java.sql.Clob interfaces in those JDK versions, you must use variables typed or cast to oracle.sql.BLOB or oracle.sql.CLOB."
When using the application with the spring framework and hibernate, it has no problem in inserting and updating lobs with org.springframework.jdbc.support.lob.DefaultLobHandler, so I guess this is another hint that the new drivers are much improved and they can be used with the standard jdbc interfaces.
I've tried using org.springframework.jdbc.support.lob.OracleLobHandler, but it needs another dependency(NativeJdbcExtractor), so, I was very hapy the default handler worked.
So, I guess something could be improved in dbunit in detecting in some way that the standard interfaces can be used... spring framework seems to use java.sql.PreparedStatement.setClob(int i, Clob x) and maybe dbunit could do it too...
And then, I will try to see what I workaround I can find to make ant not screw up things..
Thanks for your help.
Logged In: YES
user_id=1803108
Originator: NO
Hi Bustuila,
Thanks a lot for the hints. I think chances are good that your second exception is a classloader issue since the dbunit ant task uses the AntClassLoader to load the db driver class.
If you have a couple of minutes you could test this as follows:
- Get dbunit trunk sources from repository
- Replace one line in the file org.dbunit.ext.oracle.OracleClobDataType#getClob():
<<<OLD line: Class aClobClass = Class.forName("oracle.sql.CLOB");
>>>NEW line: Class aClobClass = connection.getClass().getClassLoader().loadClass("oracle.sql.CLOB");
- Invoke "mvn install" in the dbunit trunk directory
Then try using the newly created 2.3.0-SNAPSHOT version of dbunit.
I think you are right in terms of checking and updating the oracle support in dbunit. It would be nice to start a discussion on how to do that (perhaps dbunit could introduce a new Oracle10DataTypeFactory that uses the newer JDBC API with java.sql.CLOB)
Hope this helps.
Regards,
mat
Logged In: YES
user_id=711602
Originator: YES
Hello,
sorry for the long pause.
It works with this change :-)
I also had to modify org.dbunit.ant.Operation, to fix a NPE, in toString():
replace result.append(", src=" + _src == null ? null : _src.getAbsolutePath());
with result.append(", src=" + _src == null ? "null" : _src.getAbsolutePath());
Thank you
Logged In: YES
user_id=1803108
Originator: NO
Hi there,
I committed the change on rev. 773/trunk for the upcoming 2.3.0 release. The change affects OracleNClobDataType/OracleClobDataType/OracleBlobDataType which now load the classes via the JDBC connection's classloader.
Thanks again and regards,
mat
Logged In: YES
user_id=2169370
Originator: NO
i tried the latest build from today
the clob problem still occures
I am using the latest version of DBUnit (2.4.7), on Oracle 11GR2. I'm using Java 6 (1.6.0_15) and the latest version of Oracle's client jar (jdbc6.jar)
I've been unable to successfully load any data referenced by a CLOB Oracle field from an XML file into the database.
I've used all sorts of versions of the Oracle JDBC library / Hibernate library etc...I think the problem lies in DBUnit.
I've tried: both FlatXmlDataSet and XmlDataset,
I've tried both OracleDataTypeFactory , Oracle10DataTypeFactory and Oracle11DataTypeFactory found here: https://sourceforge.net/tracker/index.php?func=detail&aid=2010567&group_id=47439&atid=449494
I'm fairly convinced that its a DBunit problem as reverting all the way down to DBunit 2.2.1 seems to fix the problem. Please let me know if you want any additional info.
The exception being reported is: * Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to oracle.sql.CLOB
Hi,
I also was hitting the same problem with v2.4.7 and latest Oracle JDBC driver. I took the easy way out and built 2.4.7 myself with the one line change shown in this bug, in the org.dbunit.dataset.datatype.ClobDataType.setSqlValue(...) method.
Works fine now for Oracle CLOBs, but not sure it would work across other databases.
In the comments there is a mention of the fix being applied to the v3 branch, but that does not seem to have appeared.
John