HHH-4635 Oracle ORA-24816 inserting and updating data for entities
containg LOB attributes
This commit is contained in:
parent
563af13c1f
commit
121f495ff8
|
@ -24,10 +24,10 @@
|
|||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import javax.persistence.Lob;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.annotations.Generated;
|
||||
|
@ -57,6 +57,7 @@ import org.hibernate.mapping.RootClass;
|
|||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
|
@ -264,6 +265,7 @@ public class PropertyBinder {
|
|||
prop.setLazy( lazy );
|
||||
prop.setCascade( cascade );
|
||||
prop.setPropertyAccessorName( accessType.getType() );
|
||||
|
||||
Generated ann = property != null ?
|
||||
property.getAnnotation( Generated.class ) :
|
||||
null;
|
||||
|
@ -286,6 +288,7 @@ public class PropertyBinder {
|
|||
prop.setGeneration( PropertyGeneration.parse( generated.toString().toLowerCase() ) );
|
||||
}
|
||||
}
|
||||
|
||||
NaturalId naturalId = property != null ? property.getAnnotation( NaturalId.class ) : null;
|
||||
if ( naturalId != null ) {
|
||||
if ( ! entityBinder.isRootEntity() ) {
|
||||
|
@ -296,6 +299,11 @@ public class PropertyBinder {
|
|||
}
|
||||
prop.setNaturalIdentifier( true );
|
||||
}
|
||||
|
||||
// HHH-4635 -- needed for dialect-specific property ordering
|
||||
Lob lob = property != null ? property.getAnnotation( Lob.class ) : null;
|
||||
prop.setLob( lob != null );
|
||||
|
||||
prop.setInsertable( insertable );
|
||||
prop.setUpdateable( updatable );
|
||||
|
||||
|
|
|
@ -2369,4 +2369,15 @@ public abstract class Dialect implements ConversionContext {
|
|||
public int getInExpressionCountLimit() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* HHH-4635
|
||||
* Oracle expects all Lob values to be last in inserts and updates.
|
||||
*
|
||||
* @return boolean True of Lob values should be last, false if it
|
||||
* does not matter.
|
||||
*/
|
||||
public boolean forceLobAsLastValue() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -576,5 +576,10 @@ public class Oracle8iDialect extends Dialect {
|
|||
public boolean supportsNotNullUnique() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean forceLobAsLastValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ public class Property implements Serializable, MetaAttributable {
|
|||
private java.util.Map metaAttributes;
|
||||
private PersistentClass persistentClass;
|
||||
private boolean naturalIdentifier;
|
||||
private boolean lob;
|
||||
|
||||
public boolean isBackRef() {
|
||||
return false;
|
||||
|
@ -339,4 +340,12 @@ public class Property implements Serializable, MetaAttributable {
|
|||
this.naturalIdentifier = naturalIdentifier;
|
||||
}
|
||||
|
||||
public boolean isLob() {
|
||||
return lob;
|
||||
}
|
||||
|
||||
public void setLob(boolean lob) {
|
||||
this.lob = lob;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -184,6 +184,8 @@ public abstract class AbstractEntityPersister
|
|||
private final boolean[][] propertyColumnInsertable;
|
||||
private final boolean[] propertyUniqueness;
|
||||
private final boolean[] propertySelectable;
|
||||
|
||||
private final List<Integer> lobProperties = new ArrayList<Integer>();
|
||||
|
||||
//information about lazy properties of this class
|
||||
private final String[] lazyPropertyNames;
|
||||
|
@ -630,6 +632,10 @@ public abstract class AbstractEntityPersister
|
|||
propertySelectable[i] = prop.isSelectable();
|
||||
|
||||
propertyUniqueness[i] = prop.getValue().isAlternateUniqueKey();
|
||||
|
||||
if (prop.isLob() && getFactory().getDialect().forceLobAsLastValue() ) {
|
||||
lobProperties.add( i );
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
|
@ -942,6 +948,8 @@ public abstract class AbstractEntityPersister
|
|||
propertySelectable[i] = true;
|
||||
|
||||
propertyUniqueness[i] = singularAttributeBinding.isAlternateUniqueKey();
|
||||
|
||||
// TODO: Does this need AttributeBindings wired into lobProperties? Currently in Property only.
|
||||
|
||||
i++;
|
||||
|
||||
|
@ -2508,12 +2516,26 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
boolean hasColumns = false;
|
||||
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j )
|
||||
&& !lobProperties.contains( i ) ) {
|
||||
// this is a property of the table, which we are updating
|
||||
update.addColumns( getPropertyColumnNames(i), propertyColumnUpdateable[i], propertyColumnWriters[i] );
|
||||
update.addColumns( getPropertyColumnNames(i),
|
||||
propertyColumnUpdateable[i], propertyColumnWriters[i] );
|
||||
hasColumns = hasColumns || getPropertyColumnSpan( i ) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
// HHH-4635
|
||||
// Oracle expects all Lob properties to be last in inserts
|
||||
// and updates. Insert them at the end.
|
||||
for ( int i : lobProperties ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
// this property belongs on the table and is to be inserted
|
||||
update.addColumns( getPropertyColumnNames(i),
|
||||
propertyColumnUpdateable[i], propertyColumnWriters[i] );
|
||||
hasColumns = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION ) {
|
||||
// this is the root (versioned) table, and we are using version-based
|
||||
|
@ -2579,7 +2601,8 @@ public abstract class AbstractEntityPersister
|
|||
/**
|
||||
* Generate the SQL that inserts a row
|
||||
*/
|
||||
protected String generateInsertString(boolean identityInsert, boolean[] includeProperty, int j) {
|
||||
protected String generateInsertString(boolean identityInsert,
|
||||
boolean[] includeProperty, int j) {
|
||||
|
||||
// todo : remove the identityInsert param and variations;
|
||||
// identity-insert strings are now generated from generateIdentityInsertString()
|
||||
|
@ -2589,9 +2612,13 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// add normal properties
|
||||
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j )
|
||||
&& !lobProperties.contains( i ) ) {
|
||||
// this property belongs on the table and is to be inserted
|
||||
insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i], propertyColumnWriters[i] );
|
||||
insert.addColumns( getPropertyColumnNames(i),
|
||||
propertyColumnInsertable[i],
|
||||
propertyColumnWriters[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2611,6 +2638,18 @@ public abstract class AbstractEntityPersister
|
|||
if ( getFactory().getSettings().isCommentsEnabled() ) {
|
||||
insert.setComment( "insert " + getEntityName() );
|
||||
}
|
||||
|
||||
// HHH-4635
|
||||
// Oracle expects all Lob properties to be last in inserts
|
||||
// and updates. Insert them at the end.
|
||||
for ( int i : lobProperties ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
// this property belongs on the table and is to be inserted
|
||||
insert.addColumns( getPropertyColumnNames(i),
|
||||
propertyColumnInsertable[i],
|
||||
propertyColumnWriters[i] );
|
||||
}
|
||||
}
|
||||
|
||||
String result = insert.toStatementString();
|
||||
|
||||
|
@ -2678,8 +2717,9 @@ public abstract class AbstractEntityPersister
|
|||
boolean[][] includeColumns,
|
||||
int j,
|
||||
PreparedStatement st,
|
||||
SessionImplementor session) throws HibernateException, SQLException {
|
||||
return dehydrate( id, fields, null, includeProperty, includeColumns, j, st, session, 1 );
|
||||
SessionImplementor session,
|
||||
boolean isUpdate) throws HibernateException, SQLException {
|
||||
return dehydrate( id, fields, null, includeProperty, includeColumns, j, st, session, 1, isUpdate );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2694,32 +2734,58 @@ public abstract class AbstractEntityPersister
|
|||
final int j,
|
||||
final PreparedStatement ps,
|
||||
final SessionImplementor session,
|
||||
int index) throws SQLException, HibernateException {
|
||||
int index,
|
||||
boolean isUpdate ) throws SQLException, HibernateException {
|
||||
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Dehydrating entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j )
|
||||
&& !lobProperties.contains( i )) {
|
||||
getPropertyTypes()[i].nullSafeSet( ps, fields[i], index, includeColumns[i], session );
|
||||
//index += getPropertyColumnSpan( i );
|
||||
index += ArrayHelper.countTrue( includeColumns[i] ); //TODO: this is kinda slow...
|
||||
}
|
||||
}
|
||||
|
||||
if ( rowId != null ) {
|
||||
ps.setObject( index, rowId );
|
||||
index += 1;
|
||||
|
||||
if ( !isUpdate ) {
|
||||
index += dehydrateId( id, rowId, ps, session, index );
|
||||
}
|
||||
else if ( id != null ) {
|
||||
getIdentifierType().nullSafeSet( ps, id, index, session );
|
||||
index += getIdentifierColumnSpan();
|
||||
|
||||
// HHH-4635
|
||||
// Oracle expects all Lob properties to be last in inserts
|
||||
// and updates. Insert them at the end.
|
||||
for ( int i : lobProperties ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
getPropertyTypes()[i].nullSafeSet( ps, fields[i], index, includeColumns[i], session );
|
||||
index += ArrayHelper.countTrue( includeColumns[i] ); //TODO: this is kinda slow...
|
||||
}
|
||||
}
|
||||
|
||||
if ( isUpdate ) {
|
||||
index += dehydrateId( id, rowId, ps, session, index );
|
||||
}
|
||||
|
||||
return index;
|
||||
|
||||
}
|
||||
|
||||
private int dehydrateId(
|
||||
final Serializable id,
|
||||
final Object rowId,
|
||||
final PreparedStatement ps,
|
||||
final SessionImplementor session,
|
||||
int index ) throws SQLException {
|
||||
if ( rowId != null ) {
|
||||
ps.setObject( index, rowId );
|
||||
return 1;
|
||||
} else if ( id != null ) {
|
||||
getIdentifierType().nullSafeSet( ps, id, index, session );
|
||||
return getIdentifierColumnSpan();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshall the fields of a persistent instance from a result set,
|
||||
|
@ -2860,7 +2926,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
Binder binder = new Binder() {
|
||||
public void bindValues(PreparedStatement ps) throws SQLException {
|
||||
dehydrate( null, fields, notNull, propertyColumnInsertable, 0, ps, session );
|
||||
dehydrate( null, fields, notNull, propertyColumnInsertable, 0, ps, session, false );
|
||||
}
|
||||
public Object getEntity() {
|
||||
return object;
|
||||
|
@ -2956,7 +3022,7 @@ public abstract class AbstractEntityPersister
|
|||
// Write the values of fields onto the prepared statement - we MUST use the state at the time the
|
||||
// insert was issued (cos of foreign key constraints). Not necessarily the object's current state
|
||||
|
||||
dehydrate( id, fields, null, notNull, propertyColumnInsertable, j, insert, session, index );
|
||||
dehydrate( id, fields, null, notNull, propertyColumnInsertable, j, insert, session, index, false );
|
||||
|
||||
if ( useBatch ) {
|
||||
session.getTransactionCoordinator().getJdbcCoordinator().getBatch( inserBatchKey ).addToBatch();
|
||||
|
@ -3083,7 +3149,7 @@ public abstract class AbstractEntityPersister
|
|||
index+= expectation.prepare( update );
|
||||
|
||||
//Now write the values of fields onto the prepared statement
|
||||
index = dehydrate( id, fields, rowId, includeProperty, propertyColumnUpdateable, j, update, session, index );
|
||||
index = dehydrate( id, fields, rowId, includeProperty, propertyColumnUpdateable, j, update, session, index, true );
|
||||
|
||||
// Write any appropriate versioning conditional parameters
|
||||
if ( useVersion && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION ) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.sql.Blob;
|
|||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
|
@ -14,6 +15,7 @@ public class LobTestEntity {
|
|||
@Id
|
||||
private Long id;
|
||||
|
||||
@Lob
|
||||
private Blob lobValue;
|
||||
|
||||
@Column( name = "qwerty", length = 4000 )
|
||||
|
|
Loading…
Reference in New Issue