HHH-15561 - Fixed and added test for issue

Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
Jan Schatteman 2022-10-11 14:58:33 +02:00 committed by Jan Schatteman
parent f13230803d
commit 0baefce734
7 changed files with 177 additions and 3 deletions

View File

@ -28,6 +28,7 @@ import org.hibernate.dialect.SimpleDatabaseVersion;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.dialect.identity.H2FinalTableIdentityColumnSupport;
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
@ -774,7 +775,7 @@ public class H2LegacyDialect extends Dialect {
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new H2IdentityColumnSupport();
return getVersion().isSameOrAfter( 2 ) ? H2FinalTableIdentityColumnSupport.INSTANCE : H2IdentityColumnSupport.INSTANCE;
}
@Override

View File

@ -20,6 +20,7 @@ import org.hibernate.PessimisticLockException;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.dialect.identity.H2FinalTableIdentityColumnSupport;
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
@ -741,7 +742,7 @@ public class H2Dialect extends Dialect {
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new H2IdentityColumnSupport();
return getVersion().isSameOrAfter( 2 ) ? H2FinalTableIdentityColumnSupport.INSTANCE : H2IdentityColumnSupport.INSTANCE;
}
@Override

View File

@ -0,0 +1,29 @@
/*
* 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;
/**
* Identity column support for H2 2+ versions
* @author Jan Schatteman
*/
public class H2FinalTableIdentityColumnSupport extends H2IdentityColumnSupport {
public static final H2FinalTableIdentityColumnSupport INSTANCE = new H2FinalTableIdentityColumnSupport();
private H2FinalTableIdentityColumnSupport() {
}
@Override
public boolean supportsInsertSelectIdentity() {
return true;
}
@Override
public String appendIdentitySelectToInsert(String identityColumnName, String insertString) {
return "select " + identityColumnName + " from final table ( " + insertString + " )";
}
}

View File

@ -10,6 +10,12 @@ package org.hibernate.dialect.identity;
* @author Andrea Boriero
*/
public class H2IdentityColumnSupport extends IdentityColumnSupportImpl {
public static final H2IdentityColumnSupport INSTANCE = new H2IdentityColumnSupport();
protected H2IdentityColumnSupport() {
}
@Override
public boolean supportsIdentityColumns() {
return true;

View File

@ -57,6 +57,23 @@ public interface IdentityColumnSupport {
*/
String appendIdentitySelectToInsert(String insertString);
/**
* 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 identityColumnName The name of the identity column
* @param insertString The insert command
*
* @return The insert command with any necessary identity select
* clause attached.
*/
default String appendIdentitySelectToInsert(String identityColumnName, String insertString) {
return appendIdentitySelectToInsert( insertString );
}
/**
* Get the select command to use to retrieve the last generated IDENTITY
* value for a particular table

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.id.insert;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.Insert;
/**
* Specialized IdentifierGeneratingInsert which appends the database
@ -15,11 +16,18 @@ import org.hibernate.dialect.Dialect;
* @author Steve Ebersole
*/
public class InsertSelectIdentityInsert extends IdentifierGeneratingInsert {
protected String identityColumnName;
public Insert addIdentityColumn(String columnName) {
identityColumnName = columnName;
return super.addIdentityColumn( columnName );
}
public InsertSelectIdentityInsert(Dialect dialect) {
super( dialect );
}
public String toStatementString() {
return getDialect().getIdentityColumnSupport().appendIdentitySelectToInsert( super.toStatementString() );
return getDialect().getIdentityColumnSupport().appendIdentitySelectToInsert( identityColumnName, super.toStatementString() );
}
}

View File

@ -0,0 +1,112 @@
/*
* 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.orm.test.id;
import java.util.Date;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Jan Schatteman
*/
@TestForIssue(jiraKey = "HHH-15561")
@RequiresDialect( value = H2Dialect.class )
public class IdentityIdEntityTest {
@AfterEach
public void cleanup(SessionFactoryScope scope) {
scope.inTransaction(
session -> session.createMutationQuery( "delete from id_entity" ).executeUpdate()
);
}
@Test
@ServiceRegistry(
settings = { @Setting( name = AvailableSettings.USE_GET_GENERATED_KEYS, value = "false") }
)
@DomainModel( annotatedClasses = { IdentityEntity.class } )
@SessionFactory
public void testIdentityEntityWithDisabledGetGeneratedKeys(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
try {
IdentityEntity ie = new IdentityEntity();
ie.setTimestamp( new Date() );
session.persist( ie );
}
catch (Exception e) {
fail( "Creation of an IDENTITY-id-based entity failed when \"hibernate.jdbc.use_get_generated_keys\" was set to false (" + e.getMessage() + ")" );
}
}
);
}
@Test
@ServiceRegistry(
settings = { @Setting( name = "use_jdbc_metadata_defaults", value = "false") }
)
@DomainModel( annotatedClasses = { IdentityEntity.class } )
@SessionFactory
public void testIdentityEntityWithDisabledJdbcMetadataDefaults(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
try {
IdentityEntity ie = new IdentityEntity();
ie.setTimestamp( new Date() );
session.persist( ie );
}
catch (Exception e) {
fail( "Creation of an IDENTITY-id-based entity failed when \"use_jdbc_metadata_defaults\" was set to false (" + e.getMessage() + ")" );
}
}
);
}
@Entity(name = "id_entity")
public static class IdentityEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private Date timestamp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
}
}