generalize the InsertReturningDelegates to handle arbitrary InDatabaseGenerators
the bit limitation is that an InDatabaseGenerator can be multi-column, but all the InsertReturningDelegates assume that they map exactly one IDENTITY column
This commit is contained in:
parent
7b0ca427dd
commit
4195772c15
|
@ -13,6 +13,7 @@ import org.hibernate.metamodel.mapping.NonTransientException;
|
|||
*
|
||||
* todo (6.0) : prior going final, we need to find all usages of this and implement all methods (or throw a different exception)
|
||||
*/
|
||||
@Internal
|
||||
public class NotYetImplementedFor6Exception extends RuntimeException implements NonTransientException,
|
||||
NotImplementedYetException {
|
||||
public NotYetImplementedFor6Exception(String message) {
|
||||
|
|
|
@ -12,7 +12,6 @@ import java.math.BigInteger;
|
|||
import java.math.RoundingMode;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
@ -36,8 +35,8 @@ public final class IdentifierGeneratorHelper {
|
|||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( IdentifierGeneratorHelper.class );
|
||||
|
||||
/**
|
||||
* Marker object returned from {@link IdentifierGenerator#generate} to indicate that we should short-circuit any
|
||||
* continued generated id checking. Currently this is only used in the case of the
|
||||
* Marker object returned from {@link IdentifierGenerator#generate} to indicate that we should
|
||||
* short-circuit any continued generated id checking. Currently, this is only used in the case of the
|
||||
* {@linkplain ForeignGenerator foreign} generator as a way to signal that we should use the associated
|
||||
* entity's id value.
|
||||
*/
|
||||
|
@ -49,8 +48,8 @@ public final class IdentifierGeneratorHelper {
|
|||
};
|
||||
|
||||
/**
|
||||
* Marker object returned from {@link IdentifierGenerator#generate} to indicate that the entity's identifier will
|
||||
* be generated as part of the database insertion.
|
||||
* Marker object returned from {@link IdentifierGenerator#generate} to indicate that the entity's
|
||||
* identifier will be generated as part of the database insertion.
|
||||
*/
|
||||
public static final Serializable POST_INSERT_INDICATOR = new Serializable() {
|
||||
@Override
|
||||
|
@ -63,7 +62,7 @@ public final class IdentifierGeneratorHelper {
|
|||
/**
|
||||
* Get the generated identifier when using identity columns
|
||||
*
|
||||
* @param rs The result set from which to extract the generated identity.
|
||||
* @param resultSet The result set from which to extract the generated identity.
|
||||
* @param identityColumn The name of the identifier column
|
||||
* @param type The expected type mapping for the identity value.
|
||||
* @param dialect The current database dialect.
|
||||
|
@ -74,16 +73,16 @@ public final class IdentifierGeneratorHelper {
|
|||
* @throws HibernateException Indicates a problem reading back a generated identity value.
|
||||
*/
|
||||
public static Object getGeneratedIdentity(
|
||||
ResultSet rs,
|
||||
ResultSet resultSet,
|
||||
NavigableRole insertionTargetRole,
|
||||
String identityColumn,
|
||||
Type type,
|
||||
Dialect dialect) throws SQLException {
|
||||
if ( !rs.next() ) {
|
||||
if ( !resultSet.next() ) {
|
||||
throw new HibernateException( "The database returned no natively generated identity value : " + insertionTargetRole.getFullPath() );
|
||||
}
|
||||
|
||||
final Object id = get( rs, insertionTargetRole, identityColumn, type, dialect );
|
||||
final Object id = get( resultSet, insertionTargetRole, identityColumn, type, dialect );
|
||||
LOG.debugf( "Natively generated identity (%s) : %s", insertionTargetRole.getFullPath(), id );
|
||||
return id;
|
||||
}
|
||||
|
@ -92,7 +91,7 @@ public final class IdentifierGeneratorHelper {
|
|||
* Extract the value from the result set (which is assumed to already have been positioned to the appropriate row)
|
||||
* and wrp it in the appropriate Java numeric type.
|
||||
*
|
||||
* @param rs The result set from which to extract the value.
|
||||
* @param resultSet The result set from which to extract the value.
|
||||
* @param identifier The name of the identifier column
|
||||
* @param type The expected type of the value.
|
||||
* @param dialect The current database dialect.
|
||||
|
@ -103,52 +102,44 @@ public final class IdentifierGeneratorHelper {
|
|||
* @throws IdentifierGenerationException Indicates an unknown type.
|
||||
*/
|
||||
public static Object get(
|
||||
ResultSet rs,
|
||||
ResultSet resultSet,
|
||||
NavigableRole insertionTargetRole,
|
||||
String identifier,
|
||||
Type type,
|
||||
Dialect dialect)
|
||||
throws SQLException, IdentifierGenerationException {
|
||||
if ( type instanceof ResultSetIdentifierConsumer ) {
|
||||
return ( (ResultSetIdentifierConsumer) type ).consumeIdentifier( rs );
|
||||
return ( (ResultSetIdentifierConsumer) type ).consumeIdentifier( resultSet );
|
||||
}
|
||||
if ( type instanceof CustomType ) {
|
||||
final CustomType<?> customType = (CustomType<?>) type;
|
||||
if (customType.getUserType() instanceof ResultSetIdentifierConsumer) {
|
||||
return ( (ResultSetIdentifierConsumer) customType.getUserType() ).consumeIdentifier( rs );
|
||||
if ( customType.getUserType() instanceof ResultSetIdentifierConsumer ) {
|
||||
return ( (ResultSetIdentifierConsumer) customType.getUserType() ).consumeIdentifier( resultSet );
|
||||
}
|
||||
}
|
||||
ResultSetMetaData resultSetMetaData;
|
||||
int columnCount = 1;
|
||||
try {
|
||||
resultSetMetaData = rs.getMetaData();
|
||||
columnCount = resultSetMetaData.getColumnCount();
|
||||
}
|
||||
catch (Exception e) {
|
||||
//Oracle driver will throw NPE
|
||||
}
|
||||
|
||||
int columnCount = getColumnCount( resultSet );
|
||||
final Class<?> clazz = type.getReturnedClass();
|
||||
if ( columnCount == 1 ) {
|
||||
if ( clazz == Long.class ) {
|
||||
return rs.getLong( 1 );
|
||||
return resultSet.getLong( 1 );
|
||||
}
|
||||
else if ( clazz == Integer.class ) {
|
||||
return rs.getInt( 1 );
|
||||
return resultSet.getInt( 1 );
|
||||
}
|
||||
else if ( clazz == Short.class ) {
|
||||
return rs.getShort( 1 );
|
||||
return resultSet.getShort( 1 );
|
||||
}
|
||||
else if ( clazz == String.class ) {
|
||||
return rs.getString( 1 );
|
||||
return resultSet.getString( 1 );
|
||||
}
|
||||
else if ( clazz == BigInteger.class ) {
|
||||
return rs.getBigDecimal( 1 )
|
||||
return resultSet.getBigDecimal( 1 )
|
||||
.setScale( 0, RoundingMode.UNNECESSARY )
|
||||
.toBigInteger();
|
||||
}
|
||||
else if ( clazz == BigDecimal.class ) {
|
||||
return rs.getBigDecimal( 1 )
|
||||
return resultSet.getBigDecimal( 1 )
|
||||
.setScale( 0, RoundingMode.UNNECESSARY );
|
||||
}
|
||||
else {
|
||||
|
@ -165,21 +156,20 @@ public final class IdentifierGeneratorHelper {
|
|||
}
|
||||
else {
|
||||
try {
|
||||
return extractIdentifier( rs, identifier, type, clazz );
|
||||
return extractIdentifier( resultSet, identifier, type, clazz );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
if ( StringHelper.isQuoted( identifier, dialect ) ) {
|
||||
return extractIdentifier( rs, StringHelper.unquote( identifier, dialect ), type, clazz );
|
||||
return extractIdentifier( resultSet, StringHelper.unquote( identifier, dialect ), type, clazz );
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getColumnCount(ResultSet rs) {
|
||||
private static int getColumnCount(ResultSet resultSet) {
|
||||
try {
|
||||
final ResultSetMetaData resultSetMetaData = rs.getMetaData();
|
||||
return resultSetMetaData.getColumnCount();
|
||||
return resultSet.getMetaData().getColumnCount();
|
||||
}
|
||||
catch (Exception e) {
|
||||
//Oracle driver will throw NPE
|
||||
|
@ -724,6 +714,8 @@ public final class IdentifierGeneratorHelper {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disallow instantiation of IdentifierGeneratorHelper.
|
||||
*/
|
||||
|
|
|
@ -12,16 +12,15 @@ import java.sql.SQLException;
|
|||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
|
||||
/**
|
||||
* Abstract InsertGeneratedIdentifierDelegate implementation where the
|
||||
* underlying strategy causes the generated identifier to be returned as an
|
||||
* effect of performing the insert statement. Thus, there is no need for an
|
||||
* additional sql statement to determine the generated identifier.
|
||||
* Abstract {@link InsertGeneratedIdentifierDelegate} implementation where
|
||||
* the underlying strategy causes the generated identifier to be returned as
|
||||
* an effect of performing the insert statement. Thus, there is no need for
|
||||
* an additional sql statement to determine the generated identifier.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -38,16 +37,9 @@ public abstract class AbstractReturningDelegate implements InsertGeneratedIdenti
|
|||
JdbcValueBindings valueBindings,
|
||||
Object entity,
|
||||
SharedSessionContractImplementor session) {
|
||||
final SqlStatementLogger sqlStatementLogger = session.getJdbcServices().getSqlStatementLogger();
|
||||
|
||||
sqlStatementLogger.logStatement( insertStatementDetails.getSqlString() );
|
||||
session.getJdbcServices().getSqlStatementLogger().logStatement( insertStatementDetails.getSqlString() );
|
||||
valueBindings.beforeStatement( insertStatementDetails, session );
|
||||
|
||||
return executeAndExtract(
|
||||
insertStatementDetails.getSqlString(),
|
||||
insertStatementDetails.getStatement(),
|
||||
session
|
||||
);
|
||||
return executeAndExtract( insertStatementDetails.getSqlString(), insertStatementDetails.getStatement(), session );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
|||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
||||
import org.hibernate.engine.jdbc.spi.StatementPreparer;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
|
@ -23,9 +22,9 @@ import org.hibernate.pretty.MessageHelper;
|
|||
import static java.sql.Statement.NO_GENERATED_KEYS;
|
||||
|
||||
/**
|
||||
* Abstract InsertGeneratedIdentifierDelegate implementation where the
|
||||
* underlying strategy requires a subsequent select after the insert
|
||||
* to determine the generated identifier.
|
||||
* Abstract {@link InsertGeneratedIdentifierDelegate} implementation where
|
||||
* the underlying strategy requires a subsequent {@code select} after the
|
||||
* {@code insert} to determine the generated identifier.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -81,9 +80,9 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
|
|||
try {
|
||||
bindParameters( entity, idSelect, session );
|
||||
|
||||
final ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( idSelect );
|
||||
final ResultSet resultSet = session.getJdbcCoordinator().getResultSetReturn().extract( idSelect );
|
||||
try {
|
||||
return extractGeneratedValue( entity, rs, session );
|
||||
return extractGeneratedValue( entity, resultSet, session );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw jdbcServices.getSqlExceptionHelper().convert(
|
||||
|
|
|
@ -9,23 +9,23 @@ package org.hibernate.id.insert;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
|
||||
import static org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity;
|
||||
|
||||
/**
|
||||
* Delegate for dealing with IDENTITY columns where the dialect requires an
|
||||
* additional command execution to retrieve the generated IDENTITY value
|
||||
* Delegate for dealing with {@code IDENTITY} columns where the dialect requires an
|
||||
* additional command execution to retrieve the generated {@code IDENTITY} value
|
||||
*/
|
||||
public class BasicSelectingDelegate extends AbstractSelectingDelegate {
|
||||
private final PostInsertIdentityPersister persister;
|
||||
|
@ -40,7 +40,7 @@ public class BasicSelectingDelegate extends AbstractSelectingDelegate {
|
|||
@Override
|
||||
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
|
||||
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
|
||||
insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
|
||||
insert.addGeneratedColumns( persister.getRootTableKeyColumnNames(), (InDatabaseGenerator) persister.getGenerator() );
|
||||
return insert;
|
||||
}
|
||||
|
||||
|
@ -52,13 +52,16 @@ public class BasicSelectingDelegate extends AbstractSelectingDelegate {
|
|||
final TableInsertBuilder builder =
|
||||
new TableInsertBuilderStandard( persister, persister.getIdentifierTableMapping(), factory );
|
||||
|
||||
IdentityColumnSupport identityColumnSupport = dialect.getIdentityColumnSupport();
|
||||
if ( identityColumnSupport.hasIdentityInsertKeyword() ) {
|
||||
builder.addKeyColumn(
|
||||
identifierMapping.getSelectionExpression(),
|
||||
identityColumnSupport.getIdentityInsertString(),
|
||||
identifierMapping.getJdbcMapping()
|
||||
);
|
||||
final InDatabaseGenerator generator = (InDatabaseGenerator) persister.getGenerator();
|
||||
if ( generator.referenceColumnsInSql( dialect ) ) {
|
||||
final String[] columnNames = persister.getRootTableKeyColumnNames();
|
||||
final String[] columnValues = generator.getReferencedColumnValues( dialect );
|
||||
if ( columnValues.length != columnNames.length ) {
|
||||
throw new MappingException("wrong number of generated columns");
|
||||
}
|
||||
for ( int i = 0; i < columnValues.length; i++ ) {
|
||||
builder.addKeyColumn( columnNames[i], columnValues[i], identifierMapping.getJdbcMapping() );
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
|
@ -70,12 +73,12 @@ public class BasicSelectingDelegate extends AbstractSelectingDelegate {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Object extractGeneratedValue(Object entity, ResultSet rs, SharedSessionContractImplementor session)
|
||||
protected Object extractGeneratedValue(Object entity, ResultSet resultSet, SharedSessionContractImplementor session)
|
||||
throws SQLException {
|
||||
return getGeneratedIdentity(
|
||||
rs,
|
||||
resultSet,
|
||||
persister.getNavigableRole(),
|
||||
persister.getRootTableKeyColumnNames()[0],
|
||||
DelegateHelper.getKeyColumnName( persister ),
|
||||
persister.getIdentifierType(),
|
||||
session.getJdbcServices().getJdbcEnvironment().getDialect()
|
||||
);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.id.insert;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
|
||||
class DelegateHelper {
|
||||
static String getKeyColumnName(PostInsertIdentityPersister persister) {
|
||||
String[] columnNames = persister.getRootTableKeyColumnNames();
|
||||
if ( columnNames.length != 1 ) {
|
||||
//TODO: remove this limitation
|
||||
throw new NotYetImplementedFor6Exception("GetGeneratedKeysDelegate does not yet support multi-column Generators");
|
||||
}
|
||||
return columnNames[0];
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -11,24 +11,28 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
|
||||
import static java.sql.Statement.RETURN_GENERATED_KEYS;
|
||||
import static org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity;
|
||||
|
||||
/**
|
||||
* Delegate for dealing with IDENTITY columns using JDBC3 getGeneratedKeys
|
||||
* Delegate for dealing with {@code IDENTITY} columns using the JDBC3 method
|
||||
* {@link PreparedStatement#getGeneratedKeys()}.
|
||||
*
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
|
@ -45,7 +49,7 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
|
|||
@Override
|
||||
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
|
||||
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
|
||||
insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
|
||||
insert.addGeneratedColumns( persister.getRootTableKeyColumnNames(), (InDatabaseGenerator) persister.getGenerator() );
|
||||
return insert;
|
||||
}
|
||||
|
||||
|
@ -53,16 +57,20 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
|
|||
public TableInsertBuilder createTableInsertBuilder(
|
||||
BasicEntityIdentifierMapping identifierMapping,
|
||||
Expectation expectation,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final TableInsertBuilder builder = new TableInsertBuilderStandard(
|
||||
persister,
|
||||
persister.getIdentifierTableMapping(),
|
||||
sessionFactory
|
||||
);
|
||||
SessionFactoryImplementor factory) {
|
||||
final TableInsertBuilder builder =
|
||||
new TableInsertBuilderStandard( persister, persister.getIdentifierTableMapping(), factory );
|
||||
|
||||
final String value = dialect.getIdentityColumnSupport().getIdentityInsertString();
|
||||
if ( value != null ) {
|
||||
builder.addKeyColumn( persister.getRootTableKeyColumnNames()[0], value, identifierMapping.getJdbcMapping() );
|
||||
final InDatabaseGenerator generator = (InDatabaseGenerator) persister.getGenerator();
|
||||
if ( generator.referenceColumnsInSql( dialect ) ) {
|
||||
final String[] columnNames = persister.getRootTableKeyColumnNames();
|
||||
final String[] columnValues = generator.getReferencedColumnValues( dialect );
|
||||
if ( columnValues.length != columnNames.length ) {
|
||||
throw new MappingException("wrong number of generated columns");
|
||||
}
|
||||
for ( int i = 0; i < columnValues.length; i++ ) {
|
||||
builder.addKeyColumn( columnNames[i], columnValues[i], identifierMapping.getJdbcMapping() );
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
|
@ -70,15 +78,10 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
|
|||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String insertSql, SharedSessionContractImplementor session) {
|
||||
final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
|
||||
final MutationStatementPreparer statementPreparer = jdbcCoordinator.getMutationStatementPreparer();
|
||||
return statementPreparer.prepareStatement(
|
||||
insertSql,
|
||||
PreparedStatement.RETURN_GENERATED_KEYS
|
||||
);
|
||||
return session.getJdbcCoordinator().getMutationStatementPreparer()
|
||||
.prepareStatement( insertSql, RETURN_GENERATED_KEYS );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object performInsert(
|
||||
PreparedStatementDetails insertStatementDetails,
|
||||
|
@ -99,12 +102,12 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
|
|||
jdbcCoordinator.getResultSetReturn().executeUpdate( insertStatement );
|
||||
|
||||
try {
|
||||
final ResultSet rs = insertStatement.getGeneratedKeys();
|
||||
final ResultSet resultSet = insertStatement.getGeneratedKeys();
|
||||
try {
|
||||
return IdentifierGeneratorHelper.getGeneratedIdentity(
|
||||
rs,
|
||||
return getGeneratedIdentity(
|
||||
resultSet,
|
||||
persister.getNavigableRole(),
|
||||
persister.getRootTableKeyColumnNames()[ 0 ],
|
||||
DelegateHelper.getKeyColumnName( persister ),
|
||||
persister.getIdentifierType(),
|
||||
jdbcServices.getJdbcEnvironment().getDialect()
|
||||
);
|
||||
|
@ -121,11 +124,11 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
|
|||
);
|
||||
}
|
||||
finally {
|
||||
if ( rs != null ) {
|
||||
if ( resultSet != null ) {
|
||||
jdbcCoordinator
|
||||
.getLogicalConnection()
|
||||
.getResourceRegistry()
|
||||
.release( rs, insertStatement );
|
||||
.release( resultSet, insertStatement );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,12 +156,12 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
|
|||
jdbcCoordinator.getResultSetReturn().executeUpdate( insertStatement );
|
||||
|
||||
try {
|
||||
final ResultSet rs = insertStatement.getGeneratedKeys();
|
||||
final ResultSet resultSet = insertStatement.getGeneratedKeys();
|
||||
try {
|
||||
return IdentifierGeneratorHelper.getGeneratedIdentity(
|
||||
rs,
|
||||
return getGeneratedIdentity(
|
||||
resultSet,
|
||||
persister.getNavigableRole(),
|
||||
persister.getRootTableKeyColumnNames()[0],
|
||||
DelegateHelper.getKeyColumnName( persister ),
|
||||
persister.getIdentifierType(),
|
||||
jdbcServices.getJdbcEnvironment().getDialect()
|
||||
);
|
||||
|
@ -171,11 +174,8 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
|
|||
);
|
||||
}
|
||||
finally {
|
||||
if ( rs != null ) {
|
||||
jdbcCoordinator
|
||||
.getLogicalConnection()
|
||||
.getResourceRegistry()
|
||||
.release( rs, insertStatement );
|
||||
if ( resultSet != null ) {
|
||||
jdbcCoordinator.getLogicalConnection().getResourceRegistry().release( resultSet, insertStatement );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.sql.Insert;
|
||||
|
||||
/**
|
||||
* Nothing more than a distinguishing subclass of Insert used to indicate
|
||||
* intent. Some subclasses of this also provided some additional
|
||||
* Nothing more than a distinguishing subclass of {@link Insert} used to
|
||||
* indicate intent. Some subclasses of this also provided some additional
|
||||
* functionality or semantic to the generated SQL statement string.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
|
|
|
@ -17,17 +17,18 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
|||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
|
||||
import static java.sql.Statement.NO_GENERATED_KEYS;
|
||||
import static org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity;
|
||||
|
||||
/**
|
||||
* Delegate for dealing with IDENTITY columns where the dialect supports returning
|
||||
* the generated IDENTITY value directly from the insert statement.
|
||||
* Delegate for dealing with {@code IDENTITY} columns where the dialect supports
|
||||
* returning the generated {@code IDENTITY} value directly from the insert statement.
|
||||
*
|
||||
* @see org.hibernate.id.IdentityGenerator
|
||||
* @see IdentityColumnSupport#supportsInsertSelectIdentity()
|
||||
|
@ -45,7 +46,7 @@ public class InsertReturningDelegate extends AbstractReturningDelegate {
|
|||
@Override
|
||||
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
|
||||
InsertSelectIdentityInsert insert = new InsertSelectIdentityInsert( dialect );
|
||||
insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[ 0 ] );
|
||||
insert.addGeneratedColumns( persister.getRootTableKeyColumnNames(), (InDatabaseGenerator) persister.getGenerator() );
|
||||
return insert;
|
||||
}
|
||||
|
||||
|
@ -65,13 +66,13 @@ public class InsertReturningDelegate extends AbstractReturningDelegate {
|
|||
final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
|
||||
final JdbcServices jdbcServices = session.getJdbcServices();
|
||||
|
||||
final ResultSet rs = jdbcCoordinator.getResultSetReturn().execute( insertStatement );
|
||||
final ResultSet resultSet = jdbcCoordinator.getResultSetReturn().execute( insertStatement );
|
||||
|
||||
try {
|
||||
return IdentifierGeneratorHelper.getGeneratedIdentity(
|
||||
rs,
|
||||
return getGeneratedIdentity(
|
||||
resultSet,
|
||||
persister.getNavigableRole(),
|
||||
persister.getRootTableKeyColumnNames()[ 0 ],
|
||||
DelegateHelper.getKeyColumnName( persister ),
|
||||
persister.getIdentifierType(),
|
||||
jdbcServices.getJdbcEnvironment().getDialect()
|
||||
);
|
||||
|
@ -84,10 +85,7 @@ public class InsertReturningDelegate extends AbstractReturningDelegate {
|
|||
);
|
||||
}
|
||||
finally {
|
||||
jdbcCoordinator
|
||||
.getLogicalConnection()
|
||||
.getResourceRegistry()
|
||||
.release( rs, insertStatement );
|
||||
jdbcCoordinator.getLogicalConnection().getResourceRegistry().release( resultSet, insertStatement );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.id.insert;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.sql.Insert;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
|
||||
/**
|
||||
* Specialized IdentifierGeneratingInsert which appends the database
|
||||
* specific clause which signifies to return generated IDENTITY values
|
||||
* Specialized {@link IdentifierGeneratingInsert} which appends the database
|
||||
* specific clause which signifies to return generated {@code IDENTITY} values
|
||||
* to the end of the insert statement.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
|
@ -23,6 +25,17 @@ public class InsertSelectIdentityInsert extends IdentifierGeneratingInsert {
|
|||
return super.addIdentityColumn( columnName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insert addGeneratedColumns(String[] columnNames, InDatabaseGenerator generator) {
|
||||
if ( columnNames.length != 1 ) {
|
||||
//TODO: Should this allow multiple columns? Would require changing
|
||||
// IdentityColumnSupport.appendIdentitySelectToInsert()
|
||||
throw new MappingException("wrong number of generated columns");
|
||||
}
|
||||
identityColumnName = columnNames[0];
|
||||
return super.addGeneratedColumns( columnNames, generator );
|
||||
}
|
||||
|
||||
public InsertSelectIdentityInsert(Dialect dialect) {
|
||||
super( dialect );
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ public class TableInsertReturningBuilder extends AbstractTableInsertBuilder {
|
|||
|
||||
@Override
|
||||
public TableInsert buildMutation() {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) getMutationTarget().getIdentifierMapping();
|
||||
final BasicEntityIdentifierMapping identifierMapping =
|
||||
(BasicEntityIdentifierMapping) getMutationTarget().getIdentifierMapping();
|
||||
return new TableInsertStandard(
|
||||
getMutatingTable(),
|
||||
getMutationTarget(),
|
||||
|
|
|
@ -23,7 +23,10 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class SelectGeneratorDelegate extends AbstractSelectingDelegate {
|
||||
/**
|
||||
* Uses a unique key of the inserted entity to locate the newly inserted row.
|
||||
*/
|
||||
public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
|
||||
private final PostInsertIdentityPersister persister;
|
||||
private final Dialect dialect;
|
||||
|
||||
|
@ -33,15 +36,15 @@ public class SelectGeneratorDelegate extends AbstractSelectingDelegate {
|
|||
|
||||
private final String idSelectString;
|
||||
|
||||
public SelectGeneratorDelegate(PostInsertIdentityPersister persister, Dialect dialect, String uniqueKeyPropertyName) {
|
||||
public UniqueKeySelectingDelegate(PostInsertIdentityPersister persister, Dialect dialect, String uniqueKeyPropertyName) {
|
||||
super( persister );
|
||||
|
||||
this.persister = persister;
|
||||
this.dialect = dialect;
|
||||
this.uniqueKeyPropertyName = uniqueKeyPropertyName;
|
||||
|
||||
idSelectString = persister.getSelectByUniqueKeyString(this.uniqueKeyPropertyName);
|
||||
uniqueKeyType = persister.getPropertyType(this.uniqueKeyPropertyName);
|
||||
idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyName );
|
||||
uniqueKeyType = persister.getPropertyType( uniqueKeyPropertyName );
|
||||
idType = (BasicType<?>) persister.getIdentifierType();
|
||||
}
|
||||
|
||||
|
@ -68,12 +71,12 @@ public class SelectGeneratorDelegate extends AbstractSelectingDelegate {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Object extractGeneratedValue(Object entity, ResultSet rs, SharedSessionContractImplementor session)
|
||||
protected Object extractGeneratedValue(Object entity, ResultSet resultSet, SharedSessionContractImplementor session)
|
||||
throws SQLException {
|
||||
if ( !rs.next() ) {
|
||||
if ( !resultSet.next() ) {
|
||||
throw new IdentifierGenerationException("the inserted row could not be located by the unique key: "
|
||||
+ uniqueKeyPropertyName);
|
||||
}
|
||||
return idType.getJdbcValueExtractor().extract( rs, 1, session );
|
||||
return idType.getJdbcValueExtractor().extract( resultSet, 1, session );
|
||||
}
|
||||
}
|
|
@ -97,9 +97,8 @@ import org.hibernate.id.Assigned;
|
|||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.SelectGeneratorDelegate;
|
||||
import org.hibernate.id.insert.UniqueKeySelectingDelegate;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
import org.hibernate.id.insert.BasicSelectingDelegate;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
|
@ -2886,7 +2885,7 @@ public abstract class AbstractEntityPersister
|
|||
@Override
|
||||
public InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegateForProperty(String uniqueKeyPropertyName) {
|
||||
Dialect dialect = getFactory().getJdbcServices().getDialect();
|
||||
return new SelectGeneratorDelegate( this, dialect, uniqueKeyPropertyName );
|
||||
return new UniqueKeySelectingDelegate( this, dialect, uniqueKeyPropertyName );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,8 @@ import java.util.Map;
|
|||
import org.hibernate.Internal;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
|
||||
/**
|
||||
* An SQL {@code INSERT} statement
|
||||
|
@ -89,9 +91,22 @@ public class Insert {
|
|||
}
|
||||
|
||||
public Insert addIdentityColumn(String columnName) {
|
||||
String value = dialect.getIdentityColumnSupport().getIdentityInsertString();
|
||||
if ( value != null ) {
|
||||
addColumn( columnName, value );
|
||||
final IdentityColumnSupport identityColumnSupport = dialect.getIdentityColumnSupport();
|
||||
if ( identityColumnSupport.hasIdentityInsertKeyword() ) {
|
||||
addColumn( columnName, identityColumnSupport.getIdentityInsertString() );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Insert addGeneratedColumns(String[] columnNames, InDatabaseGenerator generator) {
|
||||
if ( generator.referenceColumnsInSql( dialect ) ) {
|
||||
String[] columnValues = generator.getReferencedColumnValues( dialect );
|
||||
if ( columnNames.length != columnValues.length ) {
|
||||
throw new MappingException("wrong number of generated columns"); //TODO!
|
||||
}
|
||||
for ( int i = 0; i < columnNames.length; i++ ) {
|
||||
addColumn( columnNames[i], columnValues[i] );
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -76,10 +76,7 @@ public abstract class AbstractTableInsertBuilder
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addValueColumn(
|
||||
String columnName,
|
||||
String columnWriteFragment,
|
||||
JdbcMapping jdbcMapping) {
|
||||
public void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) {
|
||||
final ColumnValueBinding valueBinding = createValueBinding( columnName, columnWriteFragment, jdbcMapping );
|
||||
|
||||
if ( jdbcMapping.getJdbcType().isLob() && getJdbcServices().getDialect().forceLobAsLastValue() ) {
|
||||
|
@ -94,10 +91,7 @@ public abstract class AbstractTableInsertBuilder
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addKeyColumn(
|
||||
String columnName,
|
||||
String columnWriteFragment,
|
||||
JdbcMapping jdbcMapping) {
|
||||
public void addKeyColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) {
|
||||
addColumn( columnName, columnWriteFragment, jdbcMapping, keyBindingList );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue