HHH-15393 - Improve write-paths to use mapping model

This commit is contained in:
Steve Ebersole 2022-11-30 09:01:19 -06:00
parent 3abc8c940a
commit 175fe0e44d
15 changed files with 162 additions and 3 deletions

View File

@ -188,6 +188,8 @@ public class ResultSetReturnImpl implements ResultSetReturn {
@Override
public int executeUpdate(PreparedStatement statement) {
assert statement != null;
long executeStartNanos = 0;
if ( this.sqlStatementLogger.getLogSlowQuery() > 0 ) {
executeStartNanos = System.nanoTime();

View File

@ -75,7 +75,7 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
jdbcServices.getSqlStatementLogger().logStatement( insertStatementDetails.getSqlString() );
jdbcValueBindings.beforeStatement( insertStatementDetails, session );
final PreparedStatement insertStatement = insertStatementDetails.getStatement();
final PreparedStatement insertStatement = insertStatementDetails.resolveStatement();
jdbcCoordinator.getResultSetReturn().executeUpdate( insertStatement );
// the insert is complete, select the generated id...

View File

@ -45,6 +45,11 @@ public abstract class AbstractTableDelete extends AbstractRestrictedTableMutatio
super( mutatingTable, mutationTarget, sqlComment, keyRestrictionBindings, optLockRestrictionBindings, parameters );
}
@Override
protected String getLoggableName() {
return "TableDelete";
}
@Override
public Expectation getExpectation() {
return getMutatingTable().getTableMapping().getDeleteDetails().getExpectation();

View File

@ -45,6 +45,11 @@ public abstract class AbstractTableInsert extends AbstractTableMutation<JdbcInse
this.valueBindings = valueBindings;
}
@Override
protected String getLoggableName() {
return "TableInsert";
}
@Override
public Expectation getExpectation() {
return getMutatingTable().getTableMapping().getInsertDetails().getExpectation();

View File

@ -44,6 +44,18 @@ public abstract class AbstractTableMutation<O extends MutationOperation>
this.parameters = parameters;
}
@Override
public String toString() {
final String type = isCustomSql() ? "custom-sql" : "generated";
return getLoggableName() + "(" + getMutationTarget().getRolePath() + " : " + type + ")";
}
public boolean isCustomSql() {
return this instanceof CustomSqlMutation;
}
protected abstract String getLoggableName();
@Override
public MutatingTableReference getMutatingTable() {
return mutatingTable;

View File

@ -54,6 +54,11 @@ public abstract class AbstractTableUpdate<O extends MutationOperation>
this.valueBindings = valueBindings;
}
@Override
protected String getLoggableName() {
return "TableUpdate";
}
@Override
public Expectation getExpectation() {
return getMutatingTable().getTableMapping().getUpdateDetails().getExpectation();

View File

@ -34,6 +34,11 @@ public class TableDeleteCustomSql extends AbstractTableDelete implements CustomS
super( mutatingTable, mutationTarget, keyRestrictionBindings, optLockRestrictionBindings, parameters );
}
@Override
public boolean isCustomSql() {
return true;
}
@Override
public String getCustomSql() {
return getMutatingTable().getTableMapping().getDeleteDetails().getCustomSql();

View File

@ -28,6 +28,11 @@ public class TableDeleteStandard extends AbstractTableDelete {
super( mutatingTable, mutationTarget, keyRestrictionBindings, optLockRestrictionBindings, parameters );
}
@Override
public boolean isCustomSql() {
return false;
}
@Override
public boolean isCallable() {
return false;

View File

@ -37,6 +37,11 @@ public class TableInsertCustomSql extends AbstractTableInsert implements CustomS
super( mutatingTable, mutationTarget, parameters, valueBindings );
}
@Override
public boolean isCustomSql() {
return true;
}
@Override
public String getCustomSql() {
return getMutatingTable().getTableMapping().getInsertDetails().getCustomSql();

View File

@ -36,6 +36,11 @@ public class TableInsertStandard extends AbstractTableInsert {
this.returningColumns = returningColumns;
}
@Override
public boolean isCustomSql() {
return false;
}
@Override
public List<ColumnReference> getReturningColumns() {
return returningColumns;

View File

@ -37,6 +37,11 @@ public class TableUpdateCustomSql
super( mutatingTable, mutationTarget, parameters, valueBindings, keyRestrictionBindings, optLockRestrictionBindings );
}
@Override
public boolean isCustomSql() {
return true;
}
@Override
public String getCustomSql() {
return getMutatingTable().getTableMapping().getUpdateDetails().getCustomSql();

View File

@ -43,6 +43,16 @@ public class TableUpdateNoSet
);
}
@Override
protected String getLoggableName() {
return "TableUpdateNoSet";
}
@Override
public boolean isCustomSql() {
return false;
}
@Override
public void accept(SqlAstWalker walker) {
}

View File

@ -44,6 +44,11 @@ public class TableUpdateStandard extends AbstractTableUpdate<JdbcMutationOperati
this.whereFragment = whereFragment;
}
@Override
public boolean isCustomSql() {
return true;
}
@Override
public boolean isCallable() {
return false;

View File

@ -65,6 +65,16 @@ public class TableUpsert
this.valueBindings = valueBindings;
}
@Override
protected String getLoggableName() {
return "TableUpsert";
}
@Override
public boolean isCustomSql() {
return false;
}
@Override
public EntityMutationTarget getMutationTarget() {
return (EntityMutationTarget) super.getMutationTarget();

View File

@ -6,20 +6,100 @@
*/
package org.hibernate.orm.test.dialect;
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.HANAColumnStoreDialect;
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.PostInsertIdentityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
import org.hibernate.testing.transaction.TransactionUtil2;
import org.junit.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
public class HANADialectTestCase extends BaseUnitTestCase {
@Test
public void testSqlGeneratedForIdentityInsertNoColumns() {
ServiceRegistryScope.using(
() -> new StandardServiceRegistryBuilder()
.applySetting( AvailableSettings.DIALECT, HANAColumnStoreDialect.class )
.build(),
(registryScope) -> {
final StandardServiceRegistry registry = registryScope.getRegistry();
final MetadataSources metadataSources = new MetadataSources( registry );
metadataSources.addAnnotatedClass( EntityWithIdentity.class );
try ( SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) metadataSources.buildMetadata().buildSessionFactory() ) {
final PostInsertIdentityPersister entityDescriptor = (PostInsertIdentityPersister) sessionFactory.getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( EntityWithIdentity.class );
final MutationOperationGroup staticInsertGroup = ( (SingleTableEntityPersister) entityDescriptor ).getInsertCoordinator().getStaticInsertGroup();
final MutationExecutorService mutationExecutorService = sessionFactory
.getServiceRegistry()
.getService( MutationExecutorService.class );
TransactionUtil2.inTransaction(
sessionFactory,
(session) -> {
final MutationExecutor mutationExecutor = mutationExecutorService.createExecutor(
() -> null,
staticInsertGroup,
session
);
final PreparedStatementDetails statementDetails = mutationExecutor.getPreparedStatementDetails( "EntityWithIdentity" );
assertThat( statementDetails.getSqlString() ).isEqualTo( "insert into EntityWithIdentity values ( )" );
}
);
}
}
);
}
/**
* Intentionally one of those silly cases where a table has only an id column.
* Here especially, since it is an IDENTITY the insert will have no columns at all.
*/
@Entity( name = "EntityWithIdentity" )
@Table( name = "EntityWithIdentity" )
public static class EntityWithIdentity {
@Id @GeneratedValue( strategy = GenerationType.IDENTITY )
private Integer id;
private EntityWithIdentity() {
// for use by Hibernate
}
public EntityWithIdentity(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
}
@Test
@TestForIssue(jiraKey = "HHH-13239")