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

This commit is contained in:
Steve Ebersole 2022-11-30 15:36:28 -06:00
parent c04caa18de
commit 1c083a5863
22 changed files with 280 additions and 109 deletions

View File

@ -38,7 +38,6 @@ public class TableInsertReturningBuilder extends AbstractTableInsertBuilder {
getMutatingTable(), getMutatingTable(),
getMutationTarget(), getMutationTarget(),
combine( getValueBindingList(), getKeyBindingList(), getLobValueBindingList() ), combine( getValueBindingList(), getKeyBindingList(), getLobValueBindingList() ),
true,
Collections.singletonList( new ColumnReference( getMutatingTable(), identifierMapping ) ), Collections.singletonList( new ColumnReference( getMutatingTable(), identifierMapping ) ),
getParameters() getParameters()
); );

View File

@ -1785,6 +1785,7 @@ public abstract class AbstractCollectionPersister
return (RestrictedTableMutation) new TableDeleteStandard( return (RestrictedTableMutation) new TableDeleteStandard(
tableReference, tableReference,
this, this,
"one-shot delete for " + getRolePath(),
keyRestrictionBindings, keyRestrictionBindings,
Collections.emptyList(), Collections.emptyList(),
parameters parameters

View File

@ -389,6 +389,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
return new TableUpdateStandard( return new TableUpdateStandard(
tableReference, tableReference,
this, this,
"one-shot delete for " + getRolePath(),
valueBindings, valueBindings,
keyRestrictionBindings, keyRestrictionBindings,
null, null,

View File

@ -256,10 +256,10 @@ import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl; import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.NonIdentifierAttribute; import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute; import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.AnyType; import org.hibernate.type.AnyType;
@ -1934,6 +1934,10 @@ public abstract class AbstractEntityPersister
@Override @Override
public Object forceVersionIncrement(Object id, Object currentVersion, SharedSessionContractImplementor session) { public Object forceVersionIncrement(Object id, Object currentVersion, SharedSessionContractImplementor session) {
if ( superMappingType != null ) {
return superMappingType.getEntityPersister().forceVersionIncrement( id, currentVersion, session );
}
if ( !isVersioned() ) { if ( !isVersioned() ) {
throw new AssertionFailure( "cannot force version increment on non-versioned entity" ); throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
} }
@ -1944,6 +1948,7 @@ public abstract class AbstractEntityPersister
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" ); throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
} }
final EntityVersionMapping versionMapping = getVersionMapping(); final EntityVersionMapping versionMapping = getVersionMapping();
final Object nextVersion = getVersionJavaType().next( final Object nextVersion = getVersionJavaType().next(
currentVersion, currentVersion,
@ -1960,36 +1965,38 @@ public abstract class AbstractEntityPersister
); );
} }
// todo : cache this sql... updateCoordinator.forceVersionIncrement( id, currentVersion, nextVersion, session );
String versionIncrementString = generateVersionIncrementUpdateString();
PreparedStatement st; // // todo : cache this sql...
try { // String versionIncrementString = generateVersionIncrementUpdateString();
st = session // PreparedStatement st;
.getJdbcCoordinator() // try {
.getStatementPreparer() // st = session
.prepareStatement( versionIncrementString, false ); // .getJdbcCoordinator()
try { // .getStatementPreparer()
getVersionType().nullSafeSet( st, nextVersion, 1, session ); // .prepareStatement( versionIncrementString, false );
getIdentifierType().nullSafeSet( st, id, 2, session ); // try {
getVersionType().nullSafeSet( st, currentVersion, 2 + getIdentifierColumnSpan(), session ); // getVersionType().nullSafeSet( st, nextVersion, 1, session );
int rows = session.getJdbcCoordinator().getResultSetReturn().executeUpdate( st ); // getIdentifierType().nullSafeSet( st, id, 2, session );
if ( rows != 1 ) { // getVersionType().nullSafeSet( st, currentVersion, 2 + getIdentifierColumnSpan(), session );
throw new StaleObjectStateException( getEntityName(), id ); // int rows = session.getJdbcCoordinator().getResultSetReturn().executeUpdate( st );
} // if ( rows != 1 ) {
} // throw new StaleObjectStateException( getEntityName(), id );
finally { // }
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st ); // }
session.getJdbcCoordinator().afterStatementExecution(); // finally {
} // session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
} // session.getJdbcCoordinator().afterStatementExecution();
catch (SQLException sqle) { // }
throw session.getJdbcServices().getSqlExceptionHelper().convert( // }
sqle, // catch (SQLException sqle) {
"could not retrieve version: " + // throw session.getJdbcServices().getSqlExceptionHelper().convert(
MessageHelper.infoString( this, id, getFactory() ), // sqle,
getVersionSelectString() // "could not retrieve version: " +
); // MessageHelper.infoString( this, id, getFactory() ),
} // getVersionSelectString()
// );
// }
return nextVersion; return nextVersion;
} }

View File

@ -31,4 +31,10 @@ public interface UpdateCoordinator {
int[] dirtyAttributeIndexes, int[] dirtyAttributeIndexes,
boolean hasDirtyCollection, boolean hasDirtyCollection,
SharedSessionContractImplementor session); SharedSessionContractImplementor session);
void forceVersionIncrement(
Object id,
Object currentVersion,
Object nextVersion,
SharedSessionContractImplementor session);
} }

View File

@ -31,4 +31,9 @@ public class UpdateCoordinatorNoOp implements UpdateCoordinator {
public void coordinateUpdate(Object entity, Object id, Object rowId, Object[] values, Object oldVersion, Object[] incomingOldValues, int[] dirtyAttributeIndexes, boolean hasDirtyCollection, SharedSessionContractImplementor session) { public void coordinateUpdate(Object entity, Object id, Object rowId, Object[] values, Object oldVersion, Object[] incomingOldValues, int[] dirtyAttributeIndexes, boolean hasDirtyCollection, SharedSessionContractImplementor session) {
// nothing to do // nothing to do
} }
@Override
public void forceVersionIncrement(Object id, Object currentVersion, Object nextVersion, SharedSessionContractImplementor session) {
// nothing to do
}
} }

View File

@ -12,6 +12,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.OptimisticLockStyle;
@ -49,9 +50,9 @@ import org.hibernate.sql.model.ast.builder.TableUpdateBuilderSkipped;
import org.hibernate.sql.model.ast.builder.TableUpdateBuilderStandard; import org.hibernate.sql.model.ast.builder.TableUpdateBuilderStandard;
import org.hibernate.sql.model.internal.MutationOperationGroupSingle; import org.hibernate.sql.model.internal.MutationOperationGroupSingle;
import org.hibernate.sql.model.jdbc.JdbcMutationOperation; import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy; import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.InMemoryValueGenerationStrategy; import org.hibernate.tuple.InMemoryValueGenerationStrategy;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityMetamodel;
import static org.hibernate.engine.OptimisticLockStyle.ALL; import static org.hibernate.engine.OptimisticLockStyle.ALL;
@ -102,6 +103,18 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
return ( entry == null ? entityPersister().isMutable() : entry.isModifiableEntity() ); return ( entry == null ? entityPersister().isMutable() : entry.isModifiableEntity() );
} }
@Override
public void forceVersionIncrement(
Object id,
Object currentVersion,
Object nextVersion,
SharedSessionContractImplementor session) {
if ( versionUpdateGroup == null ) {
throw new HibernateException( "Cannot force version increment relative to sub-type; use the root type" );
}
doVersionUpdate( null, id, nextVersion, currentVersion, session );
}
@Override @Override
public void coordinateUpdate( public void coordinateUpdate(
Object entity, Object entity,
@ -606,6 +619,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
); );
try { try {
//noinspection SuspiciousMethodCalls
mutationExecutor.execute( mutationExecutor.execute(
entity, entity,
valuesAnalysis, valuesAnalysis,
@ -799,6 +813,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
entity, entity,
valuesAnalysis, valuesAnalysis,
(tableMapping) -> { (tableMapping) -> {
//noinspection SuspiciousMethodCalls
if ( tableMapping.isOptional() if ( tableMapping.isOptional()
&& !valuesAnalysis.tablesWithNonNullValues.contains( tableMapping ) ) { && !valuesAnalysis.tablesWithNonNullValues.contains( tableMapping ) ) {
// the table is optional, and we have null values for all of its columns // the table is optional, and we have null values for all of its columns
@ -806,7 +821,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
return false; return false;
} }
//noinspection RedundantIfStatement //noinspection SuspiciousMethodCalls,RedundantIfStatement
if ( !valuesAnalysis.tablesNeedingUpdate.contains( tableMapping ) ) { if ( !valuesAnalysis.tablesNeedingUpdate.contains( tableMapping ) ) {
// nothing changed // nothing changed
return false; return false;
@ -842,6 +857,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
final RestrictedTableMutationBuilder<?,?> tableUpdateBuilder; final RestrictedTableMutationBuilder<?,?> tableUpdateBuilder;
final MutatingTableReference tableReference = new MutatingTableReference( tableMapping ); final MutatingTableReference tableReference = new MutatingTableReference( tableMapping );
//noinspection SuspiciousMethodCalls
if ( ! valuesAnalysis.tablesNeedingUpdate.contains( tableReference.getTableMapping() ) ) { if ( ! valuesAnalysis.tablesNeedingUpdate.contains( tableReference.getTableMapping() ) ) {
// this table does not need updating // this table does not need updating
tableUpdateBuilder = new TableUpdateBuilderSkipped( tableReference ); tableUpdateBuilder = new TableUpdateBuilderSkipped( tableReference );
@ -1371,26 +1387,6 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
null, null,
valuesAnalysis, valuesAnalysis,
(position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).isDirty(), (position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).isDirty(),
// // optimistic locking (restriction) checker
// (position, attribute) -> {
// final OptimisticLockStyle optimisticLockStyle = entityPersister()
// .getEntityMetamodel()
// .getOptimisticLockStyle();
//
// if ( optimisticLockStyle == ALL ) {
// return true;
// }
//
// if ( optimisticLockStyle == VERSION ) {
// final EntityVersionMapping versionMapping = entityPersister().getVersionMapping();
// if ( versionMapping == null ) {
// return false;
// }
// return attribute == versionMapping.getVersionAttribute();
// }
//
// return false;
// },
// session // session
null null
); );
@ -1406,12 +1402,18 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
return null; return null;
} }
if ( entityPersister().getSuperMappingType() != null ) {
return null;
}
final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard( final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard(
entityPersister(), entityPersister(),
entityPersister().getIdentifierTableMapping(), entityPersister().getIdentifierTableMapping(),
factory() factory()
); );
updateBuilder.setSqlComment( "forced version increment for " + entityPersister().getRolePath() );
updateBuilder.addValueColumn( versionMapping ); updateBuilder.addValueColumn( versionMapping );
entityPersister().getIdentifierMapping().forEachSelectable( (selectionIndex, selectableMapping) -> { entityPersister().getIdentifierMapping().forEachSelectable( (selectionIndex, selectableMapping) -> {
@ -1439,10 +1441,6 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
@FunctionalInterface @FunctionalInterface
private interface InclusionChecker { private interface InclusionChecker {
boolean include(int position, SingularAttributeMapping attribute); boolean include(int position, SingularAttributeMapping attribute);
default boolean reject(int position, SingularAttributeMapping attribute) {
return !include( position, attribute );
}
} }
@FunctionalInterface @FunctionalInterface

View File

@ -7643,6 +7643,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
} }
private void renderInsertInto(TableInsertStandard tableInsert) { private void renderInsertInto(TableInsertStandard tableInsert) {
applySqlComment( tableInsert.getMutationComment() );
if ( tableInsert.getNumberOfValueBindings() == 0 ) { if ( tableInsert.getNumberOfValueBindings() == 0 ) {
renderInsertIntoNoColumns( tableInsert ); renderInsertIntoNoColumns( tableInsert );
return; return;
@ -7710,6 +7712,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
public void visitStandardTableUpdate(TableUpdateStandard tableUpdate) { public void visitStandardTableUpdate(TableUpdateStandard tableUpdate) {
getCurrentClauseStack().push( Clause.UPDATE ); getCurrentClauseStack().push( Clause.UPDATE );
try { try {
applySqlComment( tableUpdate.getMutationComment() );
sqlBuffer.append( "update " ); sqlBuffer.append( "update " );
appendSql( tableUpdate.getMutatingTable().getTableName() ); appendSql( tableUpdate.getMutatingTable().getTableName() );
registerAffectedTable( tableUpdate.getMutatingTable().getTableName() ); registerAffectedTable( tableUpdate.getMutatingTable().getTableName() );
@ -7775,6 +7779,16 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
} }
} }
private void applySqlComment(String comment) {
if ( sessionFactory.getSessionFactoryOptions().isCommentsEnabled() ) {
if ( comment != null ) {
appendSql( "/* " );
appendSql( Dialect.escapeComment( comment ) );
appendSql( " */" );
}
}
}
@Override @Override
public void visitCustomTableUpdate(TableUpdateCustomSql tableUpdate) { public void visitCustomTableUpdate(TableUpdateCustomSql tableUpdate) {
assert sqlBuffer.toString().isEmpty(); assert sqlBuffer.toString().isEmpty();
@ -7787,6 +7801,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
public void visitStandardTableDelete(TableDeleteStandard tableDelete) { public void visitStandardTableDelete(TableDeleteStandard tableDelete) {
getCurrentClauseStack().push( Clause.DELETE ); getCurrentClauseStack().push( Clause.DELETE );
try { try {
applySqlComment( tableDelete.getMutationComment() );
sqlBuffer.append( "delete from " ); sqlBuffer.append( "delete from " );
appendSql( tableDelete.getMutatingTable().getTableName() ); appendSql( tableDelete.getMutatingTable().getTableName() );
registerAffectedTable( tableDelete.getMutatingTable().getTableName() ); registerAffectedTable( tableDelete.getMutatingTable().getTableName() );

View File

@ -31,13 +31,14 @@ public abstract class AbstractTableUpdate<O extends MutationOperation>
public AbstractTableUpdate( public AbstractTableUpdate(
MutatingTableReference mutatingTable, MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings) { List<ColumnValueBinding> optLockRestrictionBindings) {
super( super(
mutatingTable, mutatingTable,
mutationTarget, mutationTarget,
"update for " + mutationTarget.getNavigableRole(), sqlComment,
keyRestrictionBindings, keyRestrictionBindings,
optLockRestrictionBindings, optLockRestrictionBindings,
collectParameters( valueBindings, keyRestrictionBindings, optLockRestrictionBindings ) collectParameters( valueBindings, keyRestrictionBindings, optLockRestrictionBindings )
@ -49,6 +50,7 @@ public abstract class AbstractTableUpdate<O extends MutationOperation>
public <T> AbstractTableUpdate( public <T> AbstractTableUpdate(
MutatingTableReference tableReference, MutatingTableReference tableReference,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings, List<ColumnValueBinding> optLockRestrictionBindings,
@ -56,7 +58,7 @@ public abstract class AbstractTableUpdate<O extends MutationOperation>
super( super(
tableReference, tableReference,
mutationTarget, mutationTarget,
"update for " + mutationTarget.getNavigableRole(), sqlComment,
keyRestrictionBindings, keyRestrictionBindings,
optLockRestrictionBindings, optLockRestrictionBindings,
parameters parameters

View File

@ -33,11 +33,14 @@ public abstract class AbstractTableInsertBuilder
private final List<ColumnValueParameter> parameters = new ArrayList<>(); private final List<ColumnValueParameter> parameters = new ArrayList<>();
private String sqlComment;
public AbstractTableInsertBuilder( public AbstractTableInsertBuilder(
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
TableMapping table, TableMapping table,
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
super( MutationType.INSERT, mutationTarget, table, sessionFactory ); super( MutationType.INSERT, mutationTarget, table, sessionFactory );
this.sqlComment = "insert for " + mutationTarget.getRolePath();
} }
public AbstractTableInsertBuilder( public AbstractTableInsertBuilder(
@ -45,6 +48,15 @@ public abstract class AbstractTableInsertBuilder
MutatingTableReference tableReference, MutatingTableReference tableReference,
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
super( MutationType.INSERT, mutationTarget, tableReference, sessionFactory ); super( MutationType.INSERT, mutationTarget, tableReference, sessionFactory );
this.sqlComment = "insert for " + mutationTarget.getRolePath();
}
public String getSqlComment() {
return sqlComment;
}
public void setSqlComment(String sqlComment) {
this.sqlComment = sqlComment;
} }
protected List<ColumnValueBinding> getKeyBindingList() { protected List<ColumnValueBinding> getKeyBindingList() {

View File

@ -32,11 +32,14 @@ public abstract class AbstractTableUpdateBuilder<O extends MutationOperation>
private final List<ColumnValueBinding> valueBindings = new ArrayList<>(); private final List<ColumnValueBinding> valueBindings = new ArrayList<>();
private List<ColumnValueBinding> lobValueBindings; private List<ColumnValueBinding> lobValueBindings;
private String sqlComment;
public AbstractTableUpdateBuilder( public AbstractTableUpdateBuilder(
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
TableMapping tableMapping, TableMapping tableMapping,
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
super( MutationType.UPDATE, mutationTarget, tableMapping, sessionFactory ); super( MutationType.UPDATE, mutationTarget, tableMapping, sessionFactory );
this.sqlComment = "update for " + mutationTarget.getRolePath();
} }
public AbstractTableUpdateBuilder( public AbstractTableUpdateBuilder(
@ -46,6 +49,14 @@ public abstract class AbstractTableUpdateBuilder<O extends MutationOperation>
super( MutationType.UPDATE, mutationTarget, tableReference, sessionFactory ); super( MutationType.UPDATE, mutationTarget, tableReference, sessionFactory );
} }
public String getSqlComment() {
return sqlComment;
}
public void setSqlComment(String sqlComment) {
this.sqlComment = sqlComment;
}
/** /**
* The bindings for each key restriction (WHERE clause). * The bindings for each key restriction (WHERE clause).
* *

View File

@ -34,6 +34,8 @@ public class TableDeleteBuilderStandard
private final List<ColumnValueParameter> parameters = new ArrayList<>(); private final List<ColumnValueParameter> parameters = new ArrayList<>();
private String sqlComment;
public TableDeleteBuilderStandard( public TableDeleteBuilderStandard(
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
TableMapping table, TableMapping table,
@ -48,6 +50,15 @@ public class TableDeleteBuilderStandard
super( MutationType.DELETE, mutationTarget, tableReference, sessionFactory ); super( MutationType.DELETE, mutationTarget, tableReference, sessionFactory );
this.isCustomSql = tableReference.getTableMapping().getDeleteDetails().getCustomSql() != null; this.isCustomSql = tableReference.getTableMapping().getDeleteDetails().getCustomSql() != null;
this.sqlComment = "delete for " + mutationTarget.getRolePath();
}
public String getSqlComment() {
return sqlComment;
}
public void setSqlComment(String sqlComment) {
this.sqlComment = sqlComment;
} }
@Override @Override
@ -76,6 +87,7 @@ public class TableDeleteBuilderStandard
return new TableDeleteCustomSql( return new TableDeleteCustomSql(
getMutatingTable(), getMutatingTable(),
getMutationTarget(), getMutationTarget(),
sqlComment,
getKeyRestrictionBindings(), getKeyRestrictionBindings(),
getOptimisticLockBindings(), getOptimisticLockBindings(),
getParameters() getParameters()
@ -85,6 +97,7 @@ public class TableDeleteBuilderStandard
return new TableDeleteStandard( return new TableDeleteStandard(
getMutatingTable(), getMutatingTable(),
getMutationTarget(), getMutationTarget(),
sqlComment,
getKeyRestrictionBindings(), getKeyRestrictionBindings(),
getOptimisticLockBindings(), getOptimisticLockBindings(),
getParameters() getParameters()

View File

@ -6,14 +6,9 @@
*/ */
package org.hibernate.sql.model.ast.builder; package org.hibernate.sql.model.ast.builder;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.model.MutationTarget; import org.hibernate.sql.model.MutationTarget;
import org.hibernate.sql.model.TableMapping; import org.hibernate.sql.model.TableMapping;
import org.hibernate.sql.model.ast.MutatingTableReference; import org.hibernate.sql.model.ast.MutatingTableReference;
@ -27,51 +22,24 @@ import org.hibernate.sql.model.internal.TableInsertStandard;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class TableInsertBuilderStandard extends AbstractTableInsertBuilder { public class TableInsertBuilderStandard extends AbstractTableInsertBuilder {
private final boolean returningGeneratedKeys;
private final boolean isCustomSql; private final boolean isCustomSql;
private List<ColumnReference> returningColumnsList;
public TableInsertBuilderStandard( public TableInsertBuilderStandard(
MutationTarget mutationTarget, MutationTarget<?> mutationTarget,
TableMapping table, TableMapping table,
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
super( mutationTarget, table, sessionFactory ); super( mutationTarget, table, sessionFactory );
final Dialect dialect = getJdbcServices().getDialect();
this.returningGeneratedKeys = dialect.getDefaultUseGetGeneratedKeys();
this.isCustomSql = table.getInsertDetails().getCustomSql() != null; this.isCustomSql = table.getInsertDetails().getCustomSql() != null;
} }
public TableInsertBuilderStandard( public TableInsertBuilderStandard(
MutationTarget mutationTarget, MutationTarget<?> mutationTarget,
MutatingTableReference tableReference, MutatingTableReference tableReference,
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
super( mutationTarget, tableReference, sessionFactory ); super( mutationTarget, tableReference, sessionFactory );
final Dialect dialect = getJdbcServices().getDialect();
this.returningGeneratedKeys = dialect.getDefaultUseGetGeneratedKeys();
this.isCustomSql = tableReference.getTableMapping().getInsertDetails().getCustomSql() != null; this.isCustomSql = tableReference.getTableMapping().getInsertDetails().getCustomSql() != null;
} }
public boolean isReturningGeneratedKeys() {
return returningGeneratedKeys;
}
public List<ColumnReference> getReturningColumns() {
return returningColumnsList == null ? Collections.emptyList() : returningColumnsList;
}
public ColumnReference addReturningColumn(SelectableMapping selectableMapping) {
final ColumnReference columnReference = new ColumnReference( (String) null, selectableMapping, null );
if ( returningColumnsList == null ) {
returningColumnsList = new ArrayList<>();
}
returningColumnsList.add( columnReference );
return columnReference;
}
@Override @Override
public TableInsert buildMutation() { public TableInsert buildMutation() {
if ( isCustomSql ) { if ( isCustomSql ) {
@ -87,8 +55,7 @@ public class TableInsertBuilderStandard extends AbstractTableInsertBuilder {
getMutatingTable(), getMutatingTable(),
getMutationTarget(), getMutationTarget(),
combine( getValueBindingList(), getKeyBindingList(), getLobValueBindingList() ), combine( getValueBindingList(), getKeyBindingList(), getLobValueBindingList() ),
returningGeneratedKeys, Collections.emptyList(),
returningColumnsList,
getParameters() getParameters()
); );
} }

View File

@ -27,6 +27,7 @@ import org.hibernate.sql.model.internal.TableUpsert;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class TableUpdateBuilderStandard<O extends MutationOperation> extends AbstractTableUpdateBuilder<O> { public class TableUpdateBuilderStandard<O extends MutationOperation> extends AbstractTableUpdateBuilder<O> {
public TableUpdateBuilderStandard( public TableUpdateBuilderStandard(
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
TableMapping tableMapping, TableMapping tableMapping,
@ -53,6 +54,7 @@ public class TableUpdateBuilderStandard<O extends MutationOperation> extends Abs
return (RestrictedTableMutation<O>) new TableUpdateCustomSql( return (RestrictedTableMutation<O>) new TableUpdateCustomSql(
getMutatingTable(), getMutatingTable(),
getMutationTarget(), getMutationTarget(),
getSqlComment(),
valueBindings, valueBindings,
getKeyRestrictionBindings(), getKeyRestrictionBindings(),
getOptimisticLockBindings() getOptimisticLockBindings()
@ -72,6 +74,7 @@ public class TableUpdateBuilderStandard<O extends MutationOperation> extends Abs
return (RestrictedTableMutation<O>) new TableUpdateStandard( return (RestrictedTableMutation<O>) new TableUpdateStandard(
getMutatingTable(), getMutatingTable(),
getMutationTarget(), getMutationTarget(),
getSqlComment(),
valueBindings, valueBindings,
getKeyRestrictionBindings(), getKeyRestrictionBindings(),
getOptimisticLockBindings() getOptimisticLockBindings()

View File

@ -28,10 +28,11 @@ public class TableDeleteCustomSql extends AbstractTableDelete implements CustomS
public TableDeleteCustomSql( public TableDeleteCustomSql(
MutatingTableReference mutatingTable, MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings, List<ColumnValueBinding> optLockRestrictionBindings,
List<ColumnValueParameter> parameters) { List<ColumnValueParameter> parameters) {
super( mutatingTable, mutationTarget, keyRestrictionBindings, optLockRestrictionBindings, parameters ); super( mutatingTable, mutationTarget, sqlComment, keyRestrictionBindings, optLockRestrictionBindings, parameters );
} }
@Override @Override

View File

@ -22,10 +22,11 @@ public class TableDeleteStandard extends AbstractTableDelete {
public TableDeleteStandard( public TableDeleteStandard(
MutatingTableReference mutatingTable, MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings, List<ColumnValueBinding> optLockRestrictionBindings,
List<ColumnValueParameter> parameters) { List<ColumnValueParameter> parameters) {
super( mutatingTable, mutationTarget, keyRestrictionBindings, optLockRestrictionBindings, parameters ); super( mutatingTable, mutationTarget, sqlComment, keyRestrictionBindings, optLockRestrictionBindings, parameters );
} }
@Override @Override

View File

@ -21,18 +21,15 @@ import org.hibernate.sql.model.ast.MutatingTableReference;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class TableInsertStandard extends AbstractTableInsert { public class TableInsertStandard extends AbstractTableInsert {
private final boolean returnGeneratedKeys;
private final List<ColumnReference> returningColumns; private final List<ColumnReference> returningColumns;
public TableInsertStandard( public TableInsertStandard(
MutatingTableReference mutatingTable, MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
boolean returnGeneratedKeys,
List<ColumnReference> returningColumns, List<ColumnReference> returningColumns,
List<ColumnValueParameter> parameters) { List<ColumnValueParameter> parameters) {
super( mutatingTable, mutationTarget, parameters, valueBindings ); super( mutatingTable, mutationTarget, parameters, valueBindings );
this.returnGeneratedKeys = returnGeneratedKeys;
this.returningColumns = returningColumns; this.returningColumns = returningColumns;
} }

View File

@ -30,20 +30,22 @@ public class TableUpdateCustomSql
public TableUpdateCustomSql( public TableUpdateCustomSql(
MutatingTableReference mutatingTable, MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings) { List<ColumnValueBinding> optLockRestrictionBindings) {
super( mutatingTable, mutationTarget, valueBindings, keyRestrictionBindings, optLockRestrictionBindings ); super( mutatingTable, mutationTarget, sqlComment, valueBindings, keyRestrictionBindings, optLockRestrictionBindings );
} }
public TableUpdateCustomSql( public TableUpdateCustomSql(
MutatingTableReference mutatingTable, MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings, List<ColumnValueBinding> optLockRestrictionBindings,
List<ColumnValueParameter> parameters) { List<ColumnValueParameter> parameters) {
super( mutatingTable, mutationTarget, valueBindings, keyRestrictionBindings, optLockRestrictionBindings, parameters ); super( mutatingTable, mutationTarget, sqlComment, valueBindings, keyRestrictionBindings, optLockRestrictionBindings, parameters );
} }
@Override @Override

View File

@ -25,38 +25,41 @@ public class TableUpdateStandard extends AbstractTableUpdate<JdbcMutationOperati
public TableUpdateStandard( public TableUpdateStandard(
MutatingTableReference mutatingTable, MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings) { List<ColumnValueBinding> optLockRestrictionBindings) {
super( mutatingTable, mutationTarget, valueBindings, keyRestrictionBindings, optLockRestrictionBindings ); super( mutatingTable, mutationTarget, sqlComment, valueBindings, keyRestrictionBindings, optLockRestrictionBindings );
this.whereFragment = null; this.whereFragment = null;
} }
public TableUpdateStandard( public TableUpdateStandard(
MutatingTableReference tableReference, MutatingTableReference tableReference,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings, List<ColumnValueBinding> optLockRestrictionBindings,
List<ColumnValueParameter> parameters) { List<ColumnValueParameter> parameters) {
this( tableReference, mutationTarget, valueBindings, keyRestrictionBindings, optLockRestrictionBindings, parameters, null ); this( tableReference, mutationTarget, sqlComment, valueBindings, keyRestrictionBindings, optLockRestrictionBindings, parameters, null );
} }
public TableUpdateStandard( public TableUpdateStandard(
MutatingTableReference tableReference, MutatingTableReference tableReference,
MutationTarget<?> mutationTarget, MutationTarget<?> mutationTarget,
String sqlComment,
List<ColumnValueBinding> valueBindings, List<ColumnValueBinding> valueBindings,
List<ColumnValueBinding> keyRestrictionBindings, List<ColumnValueBinding> keyRestrictionBindings,
List<ColumnValueBinding> optLockRestrictionBindings, List<ColumnValueBinding> optLockRestrictionBindings,
List<ColumnValueParameter> parameters, List<ColumnValueParameter> parameters,
String whereFragment) { String whereFragment) {
super( tableReference, mutationTarget, valueBindings, keyRestrictionBindings, optLockRestrictionBindings, parameters ); super( tableReference, mutationTarget, sqlComment, valueBindings, keyRestrictionBindings, optLockRestrictionBindings, parameters );
this.whereFragment = whereFragment; this.whereFragment = whereFragment;
} }
@Override @Override
public boolean isCustomSql() { public boolean isCustomSql() {
return true; return false;
} }
@Override @Override

View File

@ -271,6 +271,7 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
tableDelete = new TableDeleteCustomSql( tableDelete = new TableDeleteCustomSql(
new MutatingTableReference( tableMapping ), new MutatingTableReference( tableMapping ),
getMutationTarget(), getMutationTarget(),
"upsert delete for " + mutationTarget.getRolePath(),
keyBindings, keyBindings,
optimisticLockBindings, optimisticLockBindings,
parameters parameters
@ -280,6 +281,7 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
tableDelete = new TableDeleteStandard( tableDelete = new TableDeleteStandard(
new MutatingTableReference( tableMapping ), new MutatingTableReference( tableMapping ),
getMutationTarget(), getMutationTarget(),
"upsert delete for " + mutationTarget.getRolePath(),
keyBindings, keyBindings,
optimisticLockBindings, optimisticLockBindings,
parameters parameters
@ -311,6 +313,7 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
tableUpdate = new TableUpdateCustomSql( tableUpdate = new TableUpdateCustomSql(
new MutatingTableReference( tableMapping ), new MutatingTableReference( tableMapping ),
mutationTarget, mutationTarget,
"upsert update for " + mutationTarget.getRolePath(),
valueBindings, valueBindings,
keyBindings, keyBindings,
optimisticLockBindings, optimisticLockBindings,
@ -321,6 +324,7 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
tableUpdate = new TableUpdateStandard( tableUpdate = new TableUpdateStandard(
new MutatingTableReference( tableMapping ), new MutatingTableReference( tableMapping ),
mutationTarget, mutationTarget,
"upsert update for " + mutationTarget.getRolePath(),
valueBindings, valueBindings,
keyBindings, keyBindings,
optimisticLockBindings, optimisticLockBindings,
@ -427,7 +431,6 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
new MutatingTableReference( tableMapping ), new MutatingTableReference( tableMapping ),
getMutationTarget(), getMutationTarget(),
CollectionHelper.combine( valueBindings, keyBindings ), CollectionHelper.combine( valueBindings, keyBindings ),
false,
Collections.emptyList(), Collections.emptyList(),
parameters parameters
); );

View File

@ -0,0 +1,121 @@
/*
* 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.sql;
import org.hibernate.LockMode;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
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 jakarta.persistence.Basic;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Steve Ebersole
*/
@ServiceRegistry(
settings = @Setting( name = AvailableSettings.USE_SQL_COMMENTS, value = "true" )
)
@DomainModel( annotatedClasses = StatementCommentTests.VersionedEntity.class )
@SessionFactory( useCollectingStatementInspector = true )
public class StatementCommentTests {
@Test
public void testEntityMutationComments(SessionFactoryScope scope) {
final SQLStatementInspector inspector = scope.getCollectingStatementInspector();
inspector.clear();
// insert
scope.inTransaction( (session) -> {
session.persist( new VersionedEntity( 1, "tbd" ) );
} );
checkEntityComments( inspector );
// update
scope.inTransaction( (session) -> {
final VersionedEntity entity = session.find( VersionedEntity.class, 1 );
inspector.clear();
entity.setName( "The One" );
} );
checkEntityComments( inspector );
// forced version increment
scope.inTransaction( (session) -> {
final VersionedEntity entity = session.find( VersionedEntity.class, 1 );
inspector.clear();
session.lock( entity, LockMode.OPTIMISTIC_FORCE_INCREMENT );
} );
checkEntityComments( inspector );
// delete
scope.inTransaction( (session) -> {
final VersionedEntity entity = session.find( VersionedEntity.class, 1 );
inspector.clear();
session.remove( entity );
} );
checkEntityComments( inspector );
}
private void checkEntityComments(SQLStatementInspector inspector) {
assertThat( inspector.getSqlQueries() ).hasSize( 1 );
assertThat( inspector.getSqlQueries().get( 0 ) ).contains( "VersionedEntity */" );
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
session.createMutationQuery( "delete VersionedEntity" ).executeUpdate();
} );
}
@Entity( name = "VersionedEntity" )
@Table( name = "entity_table" )
public static class VersionedEntity {
@Id
private Integer id;
@Version
private Integer version;
@Basic
private String name;
protected VersionedEntity() {
// for use by Hibernate
}
public VersionedEntity(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVersion() {
return version;
}
}
}

View File

@ -13,11 +13,13 @@ import jakarta.persistence.Entity;
import jakarta.persistence.EnumType; import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated; import jakarta.persistence.Enumerated;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Table;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Entity @Entity
@Table( name = "user_accounts" )
public class Account { public class Account {
private Integer id; private Integer id;