[
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5704?page=c...
]
Alebastrov commented on HHH-5704:
---------------------------------
and (BlobProxy)
{code}
else if ( argCount == 2 ) {
long start = (Long) args[0];
if ( start < 1 ) {
throw new SQLException( "Start position 1-based; must be 1 or more." );
}
if ( start-1 > getLength() ) {
throw new SQLException( "Start position [" + start + "] cannot exceed
overall CLOB length [" + getLength() + "]" );
}
int length = (Integer) args[1];
if ( length < 0 ) {
// java docs specifically say for getBinaryStream(long,int) that the start+length
must not exceed the
// total length, however that is at odds with the getBytes(long,int) behavior.
throw new SQLException( "Length must be great-than-or-equal to zero." );
}
else if (length==0) return new BinaryStreamImpl(new byte[]{});
return DataHelper.subStream( getStream(), start-1, length );
}
{code}
New getSubString() handling in ClobProxy is incompatible with MySQL
JDBC PS.setClob(int, Clob) for empty CLOB
-------------------------------------------------------------------------------------------------------------
Key: HHH-5704
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5704
Project: Hibernate Core
Issue Type: Bug
Affects Versions: 3.6.0
Environment: MySQL JDBC 5.1.12 / 5.1.13
Reporter: Sergey Vladimirov
Assignee: Gail Badner
Fix For: 3.6.1, 4.0.0.Alpha1
Attachments: hibernate-3.6.0-HHH-5704.patch
For all empty but not-null CLOBs MySQL drivers do the following
(com.mysql.jdbc.PreparedStatement):
String forcedEncoding = this.connection.getClobCharacterEncoding();
if (forcedEncoding == null) {
setString(i, x.getSubString(1L, (int) x.length()));
} else {
try {
setBytes(i, x.getSubString(1L,
(int)x.length()).getBytes(forcedEncoding));
} catch (UnsupportedEncodingException uee) {
throw SQLError.createSQLException("Unsupported character encoding " +
forcedEncoding, SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
}
As you can see, getSubString is called with first argument (start) equal to 1, even if
length of CLOB is 0. Of course, it's not very good, but it worked for previous
versions of Hibernate. But in 3.6.0 getSubString() handling in ClobProxy introduces
additional checks that prevents the code above from working:
if ( start > getLength() ) {
throw new SQLException( "Start position [" + start + "] cannot exceed
overall CLOB length [" + getLength() + "]" );
}
Thus this code will now thrown an exception if content is empty (but not null!) CLOB.
Here the part of stack trace:
31.10 16:46:03 .AbstractFlushingEventListener ERROR Could not synchronize database state
with session
org.hibernate.exception.GenericJDBCException: could not insert:
[ru.arptek.classes.dummy.Article$Content]
at
org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128)
at
org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2436)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2856)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at
org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at
org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at
org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795)
at ru.arptek.arpsite.content.WebObjectHome.create(WebObjectHome.java:122)
(...)
Caused by: java.sql.SQLException: Start position [1] cannot exceed overall CLOB length
[0]
at org.hibernate.engine.jdbc.ClobProxy.invoke(ClobProxy.java:146)
at $Proxy52.getSubString(Unknown Source)
at com.mysql.jdbc.PreparedStatement.setClob(PreparedStatement.java:3542)
at
com.mysql.jdbc.jdbc2.optional.PreparedStatementWrapper.setClob(PreparedStatementWrapper.java:299)
at
org.apache.commons.dbcp.DelegatingPreparedStatement.setClob(DelegatingPreparedStatement.java:187)
at
org.apache.commons.dbcp.DelegatingPreparedStatement.setClob(DelegatingPreparedStatement.java:187)
at
org.hibernate.type.descriptor.sql.ClobTypeDescriptor$1.doBind(ClobTypeDescriptor.java:60)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:89)
at
org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:282)
at
org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:277)
at
org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:85)
at
org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2166)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2412)
... 70 more
I believe there should be additional check like:
long start = (Long) args[0];
if ( start < 1 ) {
throw new SQLException( "Start position 1-based; must be 1 or more."
);
}
int length = (Integer) args[1];
if ( length < 0 ) {
throw new SQLException( "Length must be great-than-or-equal to zero."
);
}
// workaround for MySQL incompatibility
if ( start == 1 && length == 0) {
return "";
} else if ( start > getLength() ) {
throw new SQLException( "Start position [" + start + "] cannot exceed
overall CLOB length [" + getLength() + "]" );
}
return getSubString( start-1, length );
--
This message is automatically generated by JIRA.
For more information on JIRA, see:
http://www.atlassian.com/software/jira