Bug 462860 - Storing large Strings (> 4000 Characters) as CLOB in Oracle Data
Summary: Storing large Strings (> 4000 Characters) as CLOB in Oracle Data
Status: NEW
Alias: None
Product: EMF
Classification: Modeling
Component: cdo.net4j (show other bugs)
Version: 4.13   Edit
Hardware: PC Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-03-23 11:39 EDT by Robert Blust CLA
Modified: 2020-12-11 10:43 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Blust CLA 2015-03-23 11:39:05 EDT
I'm using CDO 4.3 (Luna) with the Oracle DB Adapter.
In our models (xcore) we define a class (FLElement) having a String member (description). The description can be more then 4000 Characters so we need to store it as oracle clob. To do this, we use the DBStore annotation columnType="CLOB"


annotation "http://www.eclipse.org/CDO/DBStore" as DBStore

class FLElement {

 @DBStore(columnType="CLOB")
 String description

}

The column is created as expected as clob. Reading the value works, while writing the value produces a ClassCastException in the plugin org.eclipse.net4j.db.jdbc.DelegatingPreparedStatement 4.3.0.v20140114-0640. 

org.eclipse.emf.cdo.util.CommitException: Rollback in DBStore: java.lang.ClassCastException: java.lang.String cannot be cast to oracle.sql.CLOB
	at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8717)
	at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8259)
	at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8820)
	at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:238)
	at org.eclipse.net4j.db.jdbc.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:259)
	at org.eclipse.emf.cdo.server.db.mapping.AbstractTypeMapping.doSetValue(AbstractTypeMapping.java:254)
	at org.eclipse.emf.cdo.server.db.mapping.AbstractTypeMapping.setValue(AbstractTypeMapping.java:148)
	at org.eclipse.emf.cdo.server.db.mapping.AbstractTypeMapping.setValueFromRevision(AbstractTypeMapping.java:106)
	at org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditClassMapping.writeValues(HorizontalAuditClassMapping.java:408)
	at org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalClassMapping.writeRevision(AbstractHorizontalClassMapping.java:515)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.writeRevision(DBStoreAccessor.java:590)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.writeRevisions(DBStoreAccessor.java:570)
	at org.eclipse.emf.cdo.spi.server.StoreAccessor.doWrite(StoreAccessor.java:109)
	at org.eclipse.emf.cdo.spi.server.StoreAccessorBase.write(StoreAccessorBase.java:152)
	at org.eclipse.emf.cdo.internal.server.TransactionCommitContext.write(TransactionCommitContext.java:651)
	at org.eclipse.emf.cdo.spi.server.InternalCommitContext$1.runLoop(InternalCommitContext.java:47)

On the internet a found the following http://www.onjava.com/pub/a/onjava/2001/12/19/oraclejdbc.html?page=2
"7. Use the Oracle locator methods to insert and update large objects (LOBs).

Oracle's implementation of PreparedStatement does not fully support the manipulation of large objects like BLOBs and CLOBs. Specifically, the Thin driver does not support the use of the PreparedStatement object's setObject() and setBinaryStream() methods to set a BLOB's value, nor does it support the use of setCharacterStream() to set a CLOB's value. In addition, only methods in the locator itself, represented by a java.sql.Blob or a java.sql.Clob, can retrieve a LOB's value from the database. The fact that you can use a PreparedStatement to insert or update a LOB, but need to use a locator to retrieve a LOB's value, is inconsistent. Because of these two issues, I recommend you consistently use the locator's methods to insert, update, and retrieve LOB data."

This explains, why the setObject(int parameterIndex, Object x, int targetSqlType) throws the ClasCastException

I patch the class org.eclipse.net4j.db.jdbc.DelegatingPreparedStatement with the following code.

 public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException
  {
	 try {
		 delegate.setObject(parameterIndex, x, targetSqlType);
	 } catch (ClassCastException e) {
		if (targetSqlType == Types.CLOB) {
			Clob clob = delegate.getConnection().createClob();
		    clob.setString(1, x.toString());
		    setClob(parameterIndex, clob);
		} else {
			throw e;
		}	
	 } 
  }

which works but maybee there are cleaner solutions for solving this problem.
Does anyone have better solution to handle large Strings together with Oracle?

Thanks for your advice.
Comment 1 Eike Stepper CLA 2015-07-14 02:15:16 EDT
Moving all open bugzillas to 4.5.
Comment 2 Eike Stepper CLA 2016-07-31 00:58:20 EDT
Moving all unaddressed bugzillas to 4.6.
Comment 3 Eike Stepper CLA 2017-12-28 01:11:19 EST
Moving all open bugs to 4.7
Comment 4 Eike Stepper CLA 2019-11-08 02:13:02 EST
Moving all unresolved issues to version 4.8-
Comment 5 Eike Stepper CLA 2019-12-13 12:52:10 EST
Moving all unresolved issues to version 4.9
Comment 6 Eike Stepper CLA 2020-12-11 10:43:48 EST
Moving to 4.13.