HHH-10422 - Add test for issue (from HHH-9983)
(cherry picked from commit1f3048e572
) HHH-10422 - Fix Error saving entity with identity id on Oracle 12c (from HHH-9983) (cherry picked from commit33458ab6f8
) Conflicts: hibernate-core/src/main/java/org/hibernate/dialect/Oracle12cDialect.java hibernate-core/src/main/java/org/hibernate/dialect/identity/Oracle12cIdentityColumnSupport.java HHH-10422 : Backport HHH-9983 to fix identity IDs using Oracle12cDialect in 5.0 HHH-10422 : Custom identity support test HHH-10422 : Custom identity support test
This commit is contained in:
parent
de3ce125bc
commit
659157a45c
|
@ -40,6 +40,8 @@ import org.hibernate.dialect.function.SQLFunction;
|
||||||
import org.hibernate.dialect.function.SQLFunctionTemplate;
|
import org.hibernate.dialect.function.SQLFunctionTemplate;
|
||||||
import org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions;
|
import org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions;
|
||||||
import org.hibernate.dialect.function.StandardSQLFunction;
|
import org.hibernate.dialect.function.StandardSQLFunction;
|
||||||
|
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||||
|
import org.hibernate.dialect.identity.IdentityColumnSupportImpl;
|
||||||
import org.hibernate.dialect.lock.LockingStrategy;
|
import org.hibernate.dialect.lock.LockingStrategy;
|
||||||
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
|
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
|
||||||
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
|
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
|
||||||
|
@ -728,7 +730,7 @@ public abstract class Dialect implements ConversionContext {
|
||||||
* @return The native generator class.
|
* @return The native generator class.
|
||||||
*/
|
*/
|
||||||
public Class getNativeIdentifierGeneratorClass() {
|
public Class getNativeIdentifierGeneratorClass() {
|
||||||
if ( supportsIdentityColumns() ) {
|
if ( getIdentityColumnSupport().supportsIdentityColumns() ) {
|
||||||
return IdentityGenerator.class;
|
return IdentityGenerator.class;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -739,11 +741,25 @@ public abstract class Dialect implements ConversionContext {
|
||||||
|
|
||||||
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the appropriate {@link IdentityColumnSupport}
|
||||||
|
*
|
||||||
|
* @return the IdentityColumnSupport
|
||||||
|
*/
|
||||||
|
public IdentityColumnSupport getIdentityColumnSupport(){
|
||||||
|
return new IdentityColumnSupportImpl( this );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this dialect support identity column key generation?
|
* Does this dialect support identity column key generation?
|
||||||
*
|
*
|
||||||
* @return True if IDENTITY columns are supported; false otherwise.
|
* @return True if IDENTITY columns are supported; false otherwise.
|
||||||
|
*
|
||||||
|
* @deprecated {@link #getIdentityColumnSupport()} should be overridden instead;
|
||||||
|
* if {@code getIdentityColumnSupport().supportsIdentityColumns()} does not delegate
|
||||||
|
* to this method, then this method is ignored.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean supportsIdentityColumns() {
|
public boolean supportsIdentityColumns() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -754,7 +770,12 @@ public abstract class Dialect implements ConversionContext {
|
||||||
*
|
*
|
||||||
* @return True if the dialect supports selecting the just
|
* @return True if the dialect supports selecting the just
|
||||||
* generated IDENTITY in the insert statement.
|
* generated IDENTITY in the insert statement.
|
||||||
|
*
|
||||||
|
* @deprecated {@link #getIdentityColumnSupport()} should be overridden instead;
|
||||||
|
* if {@code getIdentityColumnSupport().supportsInsertSelectIdentity()} does not delegate
|
||||||
|
* to this method, then this method is ignored.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean supportsInsertSelectIdentity() {
|
public boolean supportsInsertSelectIdentity() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -764,7 +785,12 @@ public abstract class Dialect implements ConversionContext {
|
||||||
* completely separate identity data type
|
* completely separate identity data type
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
|
*
|
||||||
|
* @deprecated {@link #getIdentityColumnSupport()} should be overridden instead;
|
||||||
|
* if {@code getIdentityColumnSupport().hasDataTypeInIdentityColumn()} does not delegate
|
||||||
|
* to this method, then this method is ignored.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean hasDataTypeInIdentityColumn() {
|
public boolean hasDataTypeInIdentityColumn() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -779,7 +805,12 @@ public abstract class Dialect implements ConversionContext {
|
||||||
* @param insertString The insert command
|
* @param insertString The insert command
|
||||||
* @return The insert command with any necessary identity select
|
* @return The insert command with any necessary identity select
|
||||||
* clause attached.
|
* clause attached.
|
||||||
|
*
|
||||||
|
* @deprecated {@link #getIdentityColumnSupport()} should be overridden instead;
|
||||||
|
* if {@code getIdentityColumnSupport().appendIdentitySelectToInsert(String)} does not delegate
|
||||||
|
* to this method, then this method is ignored.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String appendIdentitySelectToInsert(String insertString) {
|
public String appendIdentitySelectToInsert(String insertString) {
|
||||||
return insertString;
|
return insertString;
|
||||||
}
|
}
|
||||||
|
@ -793,7 +824,12 @@ public abstract class Dialect implements ConversionContext {
|
||||||
* @param type The {@link java.sql.Types} type code.
|
* @param type The {@link java.sql.Types} type code.
|
||||||
* @return The appropriate select command
|
* @return The appropriate select command
|
||||||
* @throws MappingException If IDENTITY generation is not supported.
|
* @throws MappingException If IDENTITY generation is not supported.
|
||||||
|
*
|
||||||
|
* @deprecated {@link #getIdentityColumnSupport()} should be overridden instead;
|
||||||
|
* if {@code getIdentityColumnSupport().getIdentitySelectString(String,String,int)} does not delegate
|
||||||
|
* to this method, then this method is ignored.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getIdentitySelectString(String table, String column, int type) throws MappingException {
|
public String getIdentitySelectString(String table, String column, int type) throws MappingException {
|
||||||
return getIdentitySelectString();
|
return getIdentitySelectString();
|
||||||
}
|
}
|
||||||
|
@ -819,7 +855,12 @@ public abstract class Dialect implements ConversionContext {
|
||||||
* @param type The {@link java.sql.Types} type code.
|
* @param type The {@link java.sql.Types} type code.
|
||||||
* @return The appropriate DDL fragment.
|
* @return The appropriate DDL fragment.
|
||||||
* @throws MappingException If IDENTITY generation is not supported.
|
* @throws MappingException If IDENTITY generation is not supported.
|
||||||
|
*
|
||||||
|
* @deprecated {@link #getIdentityColumnSupport()} should be overridden instead;
|
||||||
|
* if {@code getIdentityColumnSupport().getIdentityColumnString(int)} does not delegate
|
||||||
|
* to this method, then this method is ignored.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getIdentityColumnString(int type) throws MappingException {
|
public String getIdentityColumnString(int type) throws MappingException {
|
||||||
return getIdentityColumnString();
|
return getIdentityColumnString();
|
||||||
}
|
}
|
||||||
|
@ -842,7 +883,12 @@ public abstract class Dialect implements ConversionContext {
|
||||||
* Need if the dialect does not support inserts that specify no column values.
|
* Need if the dialect does not support inserts that specify no column values.
|
||||||
*
|
*
|
||||||
* @return The appropriate keyword.
|
* @return The appropriate keyword.
|
||||||
|
*
|
||||||
|
* @deprecated {@link #getIdentityColumnSupport()} should be overridden instead;
|
||||||
|
* if {@code getIdentityColumnSupport().getIdentityInsertString()} does not delegate
|
||||||
|
* to this method, then this method is ignored.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getIdentityInsertString() {
|
public String getIdentityInsertString() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
package org.hibernate.dialect;
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||||
|
import org.hibernate.dialect.identity.Oracle12cIdentityColumnSupport;
|
||||||
import org.hibernate.dialect.pagination.LimitHandler;
|
import org.hibernate.dialect.pagination.LimitHandler;
|
||||||
import org.hibernate.dialect.pagination.SQL2008StandardLimitHandler;
|
import org.hibernate.dialect.pagination.SQL2008StandardLimitHandler;
|
||||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||||
|
@ -38,6 +40,7 @@ public class Oracle12cDialect extends Oracle10gDialect {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Class getNativeIdentifierGeneratorClass() {
|
public Class getNativeIdentifierGeneratorClass() {
|
||||||
return SequenceStyleGenerator.class;
|
return SequenceStyleGenerator.class;
|
||||||
}
|
}
|
||||||
|
@ -52,4 +55,8 @@ public class Oracle12cDialect extends Oracle10gDialect {
|
||||||
return SQL2008StandardLimitHandler.INSTANCE;
|
return SQL2008StandardLimitHandler.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdentityColumnSupport getIdentityColumnSupport() {
|
||||||
|
return new Oracle12cIdentityColumnSupport( this );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.identity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
import org.hibernate.id.insert.AbstractReturningDelegate;
|
||||||
|
import org.hibernate.id.insert.IdentifierGeneratingInsert;
|
||||||
|
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate for dealing with IDENTITY columns using JDBC3 getGeneratedKeys
|
||||||
|
*
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class GetGeneratedKeysDelegate
|
||||||
|
extends AbstractReturningDelegate
|
||||||
|
implements InsertGeneratedIdentifierDelegate {
|
||||||
|
private final PostInsertIdentityPersister persister;
|
||||||
|
private final Dialect dialect;
|
||||||
|
|
||||||
|
public GetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
|
||||||
|
super( persister );
|
||||||
|
this.persister = persister;
|
||||||
|
this.dialect = dialect;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
|
||||||
|
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
|
||||||
|
insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
|
||||||
|
return insert;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
||||||
|
return session
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getStatementPreparer()
|
||||||
|
.prepareStatement( insertSQL, PreparedStatement.RETURN_GENERATED_KEYS );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable executeAndExtract(PreparedStatement insert, SessionImplementor session)
|
||||||
|
throws SQLException {
|
||||||
|
session.getJdbcCoordinator().getResultSetReturn().executeUpdate( insert );
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
rs = insert.getGeneratedKeys();
|
||||||
|
return IdentifierGeneratorHelper.getGeneratedIdentity(
|
||||||
|
rs,
|
||||||
|
persister.getRootTableKeyColumnNames()[0],
|
||||||
|
persister.getIdentifierType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( rs != null ) {
|
||||||
|
session.getJdbcCoordinator().getResourceRegistry().release( rs, insert );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.identity;
|
||||||
|
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a support for the Dialect identity key generation
|
||||||
|
*
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public interface IdentityColumnSupport {
|
||||||
|
/**
|
||||||
|
* Does this dialect support identity column key generation?
|
||||||
|
*
|
||||||
|
* @return True if IDENTITY columns are supported; false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean supportsIdentityColumns();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the dialect support some form of inserting and selecting
|
||||||
|
* the generated IDENTITY value all in the same statement.
|
||||||
|
*
|
||||||
|
* @return True if the dialect supports selecting the just
|
||||||
|
* generated IDENTITY in the insert statement.
|
||||||
|
*/
|
||||||
|
public boolean supportsInsertSelectIdentity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this dialect have an Identity clause added to the data type or a
|
||||||
|
* completely separate identity data type
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean hasDataTypeInIdentityColumn();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provided we {@link #supportsInsertSelectIdentity}, then attach the
|
||||||
|
* "select identity" clause to the insert statement.
|
||||||
|
* <p/>
|
||||||
|
* Note, if {@link #supportsInsertSelectIdentity} == false then
|
||||||
|
* the insert-string should be returned without modification.
|
||||||
|
*
|
||||||
|
* @param insertString The insert command
|
||||||
|
*
|
||||||
|
* @return The insert command with any necessary identity select
|
||||||
|
* clause attached.
|
||||||
|
*/
|
||||||
|
public String appendIdentitySelectToInsert(String insertString);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the select command to use to retrieve the last generated IDENTITY
|
||||||
|
* value for a particular table
|
||||||
|
*
|
||||||
|
* @param table The table into which the insert was done
|
||||||
|
* @param column The PK column.
|
||||||
|
* @param type The {@link java.sql.Types} type code.
|
||||||
|
*
|
||||||
|
* @return The appropriate select command
|
||||||
|
*
|
||||||
|
* @throws MappingException If IDENTITY generation is not supported.
|
||||||
|
*/
|
||||||
|
public String getIdentitySelectString(String table, String column, int type) throws MappingException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The syntax used during DDL to define a column as being an IDENTITY of
|
||||||
|
* a particular type.
|
||||||
|
*
|
||||||
|
* @param type The {@link java.sql.Types} type code.
|
||||||
|
*
|
||||||
|
* @return The appropriate DDL fragment.
|
||||||
|
*
|
||||||
|
* @throws MappingException If IDENTITY generation is not supported.
|
||||||
|
*/
|
||||||
|
public String getIdentityColumnString(int type) throws MappingException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The keyword used to insert a generated value into an identity column (or null).
|
||||||
|
* Need if the dialect does not support inserts that specify no column values.
|
||||||
|
*
|
||||||
|
* @return The appropriate keyword.
|
||||||
|
*/
|
||||||
|
public String getIdentityInsertString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Delegate for dealing with IDENTITY columns using JDBC3 getGeneratedKeys
|
||||||
|
*
|
||||||
|
* @param persister The persister
|
||||||
|
* @param dialect The dialect against which to generate the delegate
|
||||||
|
*
|
||||||
|
* @return the dialect specific GetGeneratedKeys delegate
|
||||||
|
*/
|
||||||
|
public GetGeneratedKeysDelegate buildGetGeneratedKeysDelegate(
|
||||||
|
PostInsertIdentityPersister persister,
|
||||||
|
Dialect dialect);
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.identity;
|
||||||
|
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class IdentityColumnSupportImpl implements IdentityColumnSupport {
|
||||||
|
private final Dialect dialect;
|
||||||
|
|
||||||
|
public IdentityColumnSupportImpl(Dialect dialect) {
|
||||||
|
this.dialect = dialect;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsIdentityColumns() {
|
||||||
|
return dialect.supportsIdentityColumns();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInsertSelectIdentity() {
|
||||||
|
return dialect.supportsInsertSelectIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDataTypeInIdentityColumn() {
|
||||||
|
return dialect.hasDataTypeInIdentityColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String appendIdentitySelectToInsert(String insertString) {
|
||||||
|
return dialect.appendIdentitySelectToInsert( insertString );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentitySelectString(String table, String column, int type) throws MappingException {
|
||||||
|
return dialect.getIdentitySelectString( table, column, type );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityColumnString(int type) throws MappingException {
|
||||||
|
return dialect.getIdentityColumnString( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityInsertString() {
|
||||||
|
return dialect.getIdentityInsertString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GetGeneratedKeysDelegate buildGetGeneratedKeysDelegate(
|
||||||
|
PostInsertIdentityPersister persister,
|
||||||
|
Dialect dialect) {
|
||||||
|
return new GetGeneratedKeysDelegate( persister, dialect );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.identity;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.dialect.identity.GetGeneratedKeysDelegate;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class Oracle12cGetGeneratedKeysDelegate extends GetGeneratedKeysDelegate {
|
||||||
|
private String[] keyColumns;
|
||||||
|
|
||||||
|
public Oracle12cGetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
|
||||||
|
super( persister, dialect );
|
||||||
|
this.keyColumns = getPersister().getRootTableKeyColumnNames();
|
||||||
|
if ( keyColumns.length > 1 ) {
|
||||||
|
throw new HibernateException( "Identity generator cannot be used with multi-column keys" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
||||||
|
return session
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getStatementPreparer()
|
||||||
|
.prepareStatement( insertSQL, keyColumns );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.identity;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class Oracle12cIdentityColumnSupport extends IdentityColumnSupportImpl {
|
||||||
|
|
||||||
|
public Oracle12cIdentityColumnSupport(Dialect dialect) {
|
||||||
|
super( dialect );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GetGeneratedKeysDelegate buildGetGeneratedKeysDelegate(
|
||||||
|
PostInsertIdentityPersister persister, Dialect dialect) {
|
||||||
|
return new Oracle12cGetGeneratedKeysDelegate( persister, dialect );
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,9 +38,9 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
|
||||||
Dialect dialect,
|
Dialect dialect,
|
||||||
boolean isGetGeneratedKeysEnabled) throws HibernateException {
|
boolean isGetGeneratedKeysEnabled) throws HibernateException {
|
||||||
if ( isGetGeneratedKeysEnabled ) {
|
if ( isGetGeneratedKeysEnabled ) {
|
||||||
return new GetGeneratedKeysDelegate( persister, dialect );
|
return dialect.getIdentityColumnSupport().buildGetGeneratedKeysDelegate( persister, dialect );
|
||||||
}
|
}
|
||||||
else if ( dialect.supportsInsertSelectIdentity() ) {
|
else if ( dialect.getIdentityColumnSupport().supportsInsertSelectIdentity() ) {
|
||||||
return new InsertSelectDelegate( persister, dialect );
|
return new InsertSelectDelegate( persister, dialect );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -48,56 +48,7 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegate for dealing with IDENTITY columns using JDBC3 getGeneratedKeys
|
|
||||||
*/
|
|
||||||
public static class GetGeneratedKeysDelegate
|
|
||||||
extends AbstractReturningDelegate
|
|
||||||
implements InsertGeneratedIdentifierDelegate {
|
|
||||||
private final PostInsertIdentityPersister persister;
|
|
||||||
private final Dialect dialect;
|
|
||||||
|
|
||||||
public GetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
|
|
||||||
super( persister );
|
|
||||||
this.persister = persister;
|
|
||||||
this.dialect = dialect;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
|
|
||||||
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
|
|
||||||
insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
|
|
||||||
return insert;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
|
||||||
return session
|
|
||||||
.getJdbcCoordinator()
|
|
||||||
.getStatementPreparer()
|
|
||||||
.prepareStatement( insertSQL, PreparedStatement.RETURN_GENERATED_KEYS );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable executeAndExtract(PreparedStatement insert, SessionImplementor session)
|
|
||||||
throws SQLException {
|
|
||||||
session.getJdbcCoordinator().getResultSetReturn().executeUpdate( insert );
|
|
||||||
ResultSet rs = null;
|
|
||||||
try {
|
|
||||||
rs = insert.getGeneratedKeys();
|
|
||||||
return IdentifierGeneratorHelper.getGeneratedIdentity(
|
|
||||||
rs,
|
|
||||||
persister.getRootTableKeyColumnNames()[0],
|
|
||||||
persister.getIdentifierType()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if ( rs != null ) {
|
|
||||||
session.getJdbcCoordinator().getResourceRegistry().release( rs, insert );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate for dealing with IDENTITY columns where the dialect supports returning
|
* Delegate for dealing with IDENTITY columns where the dialect supports returning
|
||||||
|
|
|
@ -20,6 +20,6 @@ public class InsertSelectIdentityInsert extends IdentifierGeneratingInsert {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toStatementString() {
|
public String toStatementString() {
|
||||||
return getDialect().appendIdentitySelectToInsert( super.toStatementString() );
|
return getDialect().getIdentityColumnSupport().appendIdentitySelectToInsert( super.toStatementString() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -535,11 +535,11 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
||||||
|
|
||||||
if ( identityColumn && col.getQuotedName( dialect ).equals( pkname ) ) {
|
if ( identityColumn && col.getQuotedName( dialect ).equals( pkname ) ) {
|
||||||
// to support dialects that have their own identity data type
|
// to support dialects that have their own identity data type
|
||||||
if ( dialect.hasDataTypeInIdentityColumn() ) {
|
if ( dialect.getIdentityColumnSupport().hasDataTypeInIdentityColumn() ) {
|
||||||
buf.append( col.getSqlType( dialect, p ) );
|
buf.append( col.getSqlType( dialect, p ) );
|
||||||
}
|
}
|
||||||
buf.append( ' ' )
|
buf.append( ' ' )
|
||||||
.append( dialect.getIdentityColumnString( col.getSqlTypeCode( p ) ) );
|
.append( dialect.getIdentityColumnSupport().getIdentityColumnString( col.getSqlTypeCode( p ) ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
|
|
@ -2496,7 +2496,7 @@ public abstract class AbstractEntityPersister
|
||||||
|
|
||||||
// append the SQL to return the generated identifier
|
// append the SQL to return the generated identifier
|
||||||
if ( j == 0 && identityInsert && useInsertSelectIdentity() ) { //TODO: suck into Insert
|
if ( j == 0 && identityInsert && useInsertSelectIdentity() ) { //TODO: suck into Insert
|
||||||
result = getFactory().getDialect().appendIdentitySelectToInsert( result );
|
result = getFactory().getDialect().getIdentityColumnSupport().appendIdentitySelectToInsert( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -2748,7 +2748,7 @@ public abstract class AbstractEntityPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean useInsertSelectIdentity() {
|
protected boolean useInsertSelectIdentity() {
|
||||||
return !useGetGeneratedKeys() && getFactory().getDialect().supportsInsertSelectIdentity();
|
return !useGetGeneratedKeys() && getFactory().getDialect().getIdentityColumnSupport().supportsInsertSelectIdentity();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean useGetGeneratedKeys() {
|
protected boolean useGetGeneratedKeys() {
|
||||||
|
@ -2794,11 +2794,12 @@ public abstract class AbstractEntityPersister
|
||||||
|
|
||||||
public String getIdentitySelectString() {
|
public String getIdentitySelectString() {
|
||||||
//TODO: cache this in an instvar
|
//TODO: cache this in an instvar
|
||||||
return getFactory().getDialect().getIdentitySelectString(
|
return getFactory().getDialect().getIdentityColumnSupport()
|
||||||
getTableName( 0 ),
|
.getIdentitySelectString(
|
||||||
getKeyColumns( 0 )[0],
|
getTableName( 0 ),
|
||||||
getIdentifierType().sqlTypes( getFactory() )[0]
|
getKeyColumns( 0 )[0],
|
||||||
);
|
getIdentifierType().sqlTypes( getFactory() )[0]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSelectByUniqueKeyString(String propertyName) {
|
public String getSelectByUniqueKeyString(String propertyName) {
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class Insert {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Insert addIdentityColumn(String columnName) {
|
public Insert addIdentityColumn(String columnName) {
|
||||||
String value = dialect.getIdentityInsertString();
|
String value = dialect.getIdentityColumnSupport().getIdentityInsertString();
|
||||||
if ( value != null ) {
|
if ( value != null ) {
|
||||||
addColumn( columnName, value );
|
addColumn( columnName, value );
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,11 +86,11 @@ public class StandardTableExporter implements Exporter<Table> {
|
||||||
|
|
||||||
if ( isPrimaryKeyIdentity && colName.equals( pkColName ) ) {
|
if ( isPrimaryKeyIdentity && colName.equals( pkColName ) ) {
|
||||||
// to support dialects that have their own identity data type
|
// to support dialects that have their own identity data type
|
||||||
if ( dialect.hasDataTypeInIdentityColumn() ) {
|
if ( dialect.getIdentityColumnSupport().hasDataTypeInIdentityColumn() ) {
|
||||||
buf.append( col.getSqlType( dialect, metadata ) );
|
buf.append( col.getSqlType( dialect, metadata ) );
|
||||||
}
|
}
|
||||||
buf.append( ' ' )
|
buf.append( ' ' )
|
||||||
.append( dialect.getIdentityColumnString( col.getSqlTypeCode( metadata ) ) );
|
.append( dialect.getIdentityColumnSupport().getIdentityColumnString( col.getSqlTypeCode( metadata ) ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
buf.append( col.getSqlType( dialect, metadata ) );
|
buf.append( col.getSqlType( dialect, metadata ) );
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: Apache License, Version 2.0
|
||||||
|
* See the LICENSE file in the root directory or visit http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.idgen.identity;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.dialect.identity.GetGeneratedKeysDelegate;
|
||||||
|
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-10422")
|
||||||
|
public class CustomIdentityColumnSupportTest extends BaseUnitTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLegacyIdentityColumnSupport() {
|
||||||
|
testIdentityColumnSupport( new LegacyIdentityColumnSupportDialect().getIdentityColumnSupport() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCustomIdentityColumnSupport() {
|
||||||
|
testIdentityColumnSupport( new IdentityColumnSupportDialect().getIdentityColumnSupport() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testIdentityColumnSupport(IdentityColumnSupport support) {
|
||||||
|
assertEquals( true, support.supportsIdentityColumns() );
|
||||||
|
assertEquals( true, support.supportsInsertSelectIdentity() );
|
||||||
|
assertEquals( false, support.hasDataTypeInIdentityColumn() );
|
||||||
|
assertEquals( "abcInsertString", support.appendIdentitySelectToInsert( "InsertString" ) );
|
||||||
|
try {
|
||||||
|
support.getIdentitySelectString( "a", "b", 1 );
|
||||||
|
fail( "should have thrown MappingException" );
|
||||||
|
}
|
||||||
|
catch( MappingException ex ) {
|
||||||
|
assertEquals( "blah", ex.getMessage() );
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
support.getIdentityColumnString( 1 );
|
||||||
|
fail( "should have thrown MappingException" );
|
||||||
|
}
|
||||||
|
catch( MappingException ex ) {
|
||||||
|
assertEquals( "blah, blah", ex.getMessage() );
|
||||||
|
}
|
||||||
|
assertEquals( "insert string", support.getIdentityInsertString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class LegacyIdentityColumnSupportDialect extends Dialect {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsIdentityColumns() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInsertSelectIdentity() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDataTypeInIdentityColumn() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String appendIdentitySelectToInsert(String insertString) {
|
||||||
|
return "abc" + insertString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentitySelectString(String table, String column, int type) throws MappingException {
|
||||||
|
throw new MappingException( "blah" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityColumnString(int type) throws MappingException {
|
||||||
|
throw new MappingException( "blah, blah" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityInsertString() {
|
||||||
|
return "insert string";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class IdentityColumnSupportDialect extends Dialect {
|
||||||
|
|
||||||
|
public IdentityColumnSupport getIdentityColumnSupport(){
|
||||||
|
return new IdentityColumnSupport() {
|
||||||
|
@Override
|
||||||
|
public boolean supportsIdentityColumns() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInsertSelectIdentity() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDataTypeInIdentityColumn() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String appendIdentitySelectToInsert(String insertString) {
|
||||||
|
return "abc" + insertString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentitySelectString(String table, String column, int type) throws MappingException {
|
||||||
|
throw new MappingException( "blah" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityColumnString(int type) throws MappingException {
|
||||||
|
throw new MappingException( "blah, blah" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityInsertString() {
|
||||||
|
return "insert string";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GetGeneratedKeysDelegate buildGetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
|
||||||
|
return new GetGeneratedKeysDelegate( persister, dialect );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: Apache License, Version 2.0
|
||||||
|
* See the LICENSE file in the root directory or visit http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.idgen.identity.hhh9983;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.dialect.Oracle12cDialect;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-9983")
|
||||||
|
@RequiresDialect(Oracle12cDialect.class)
|
||||||
|
public class SaveEntityTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {Company.class};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSave() {
|
||||||
|
Session s = openSession();
|
||||||
|
Transaction transaction = s.beginTransaction();
|
||||||
|
try {
|
||||||
|
s.save( new Company() );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "Company")
|
||||||
|
public class Company {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Company() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ abstract public class DialectChecks {
|
||||||
|
|
||||||
public static class SupportsIdentityColumns implements DialectCheck {
|
public static class SupportsIdentityColumns implements DialectCheck {
|
||||||
public boolean isMatch(Dialect dialect) {
|
public boolean isMatch(Dialect dialect) {
|
||||||
return dialect.supportsIdentityColumns();
|
return dialect.getIdentityColumnSupport().supportsIdentityColumns();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue