diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java index e3650537cdbd..5cf369059d4b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java @@ -475,13 +475,11 @@ default String getImportedName() { return getEntityPersister().getImportedName(); } - default RootGraphImplementor createRootGraph(SharedSessionContractImplementor session) { - if ( getRepresentationStrategy() instanceof EntityRepresentationStrategyMap mapRep ) { - return session.getSessionFactory().createGraphForDynamicEntity( getEntityName() ); - } - else { - return session.getSessionFactory().createEntityGraph( getMappedJavaType().getJavaTypeClass() ); - } + default RootGraphImplementor createRootGraph(SharedSessionContractImplementor session) { + final var factory = session.getSessionFactory(); + return getRepresentationStrategy() instanceof EntityRepresentationStrategyMap strategyMap + ? factory.createGraphForDynamicEntity( getEntityName() ) + : factory.createEntityGraph( getMappedJavaType().getJavaTypeClass() ); } interface ConstraintOrderedTableConsumer { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/SqlExecLogger.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/SqlExecLogger.java index 2a6e5790eb73..a6da9c00c368 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/SqlExecLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/SqlExecLogger.java @@ -9,10 +9,16 @@ import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; +import org.jboss.logging.annotations.LogMessage; +import org.jboss.logging.annotations.Message; import org.jboss.logging.annotations.MessageLogger; import org.jboss.logging.annotations.ValidIdRange; import java.lang.invoke.MethodHandles; +import java.util.Set; + +import static org.jboss.logging.Logger.Level.DEBUG; +import static org.jboss.logging.Logger.Level.TRACE; /** * @author Steve Ebersole @@ -28,4 +34,45 @@ public interface SqlExecLogger extends BasicLogger { String LOGGER_NAME = SubSystemLogging.BASE + ".sql.exec"; SqlExecLogger SQL_EXEC_LOGGER = Logger.getMessageLogger( MethodHandles.lookup(), SqlExecLogger.class, LOGGER_NAME ); + + @LogMessage(level = DEBUG) + @Message(id = 90004001, value = "Collection locking for collection table '%s' - %s") + void collectionLockingForCollectionTable(String keyTableName, String rootPathName); + + @LogMessage(level = DEBUG) + @Message(id = 90004002, value = "Follow-on locking for collection table '%s' - %s") + void followOnLockingForCollectionTable(String keyTableName, String rootPathName); + + @LogMessage(level = DEBUG) + @Message(id = 90004003, value = "Follow-on locking collected loaded values:\n%s") + void followOnLockingCollectedLoadedValues(String summary); + + @LogMessage(level = DEBUG) + @Message(id = 90004010, value = "Starting include-collections locking process - %s") + void startingIncludeCollectionsLockingProcess(String entityName); + + @LogMessage(level = DEBUG) + @Message(id = 90004011, value = "Starting follow-on locking process - %s") + void startingFollowOnLockingProcess(String entityName); + + @LogMessage(level = DEBUG) + @Message(id = 90004012, value = "Adding table '%s' for follow-on locking - %s") + void addingTableForFollowOnLocking(String tableName, String entityName); + + // Trace messages (typesafe) + @LogMessage(level = TRACE) + @Message(id = 90004013, value = "Reading query result cache data [%s]") + void readingQueryResultCacheData(String cacheModeName); + + @LogMessage(level = TRACE) + @Message(id = 90004014, value = "Affected query spaces unexpectedly empty") + void affectedQuerySpacesUnexpectedlyEmpty(); + + @LogMessage(level = TRACE) + @Message(id = 90004015, value = "Affected query spaces %s") + void affectedQuerySpaces(Set querySpaces); + + @LogMessage(level = TRACE) + @Message(id = 90004016, value = "Skipping reading query result cache data (query cache %s, cache mode %s)") + void skippingReadingQueryResultCacheData(String queryCacheStatus, String cacheModeName); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/AbstractJdbcParameter.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/AbstractJdbcParameter.java index 68a1c5bd35c3..145307528ddf 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/AbstractJdbcParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/AbstractJdbcParameter.java @@ -17,7 +17,6 @@ import org.hibernate.metamodel.mapping.MappingModelExpressible; import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.SqlExpressible; -import org.hibernate.type.BindableType; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.exec.ExecutionException; @@ -27,8 +26,6 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.EnumJavaType; -import org.hibernate.type.descriptor.jdbc.JdbcType; -import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; /** * @author Steve Ebersole @@ -85,12 +82,12 @@ public void bindParameterValue( int startPosition, JdbcParameterBindings jdbcParamBindings, ExecutionContext executionContext) throws SQLException { - final JdbcParameterBinding binding = jdbcParamBindings.getBinding( AbstractJdbcParameter.this ); + final var binding = jdbcParamBindings.getBinding( AbstractJdbcParameter.this ); if ( binding == null ) { throw new ExecutionException( "JDBC parameter value not bound - " + this ); } - final JdbcMapping jdbcMapping = jdbcMapping( executionContext, binding ); + final var jdbcMapping = jdbcMapping( executionContext, binding ); bindParameterValue( jdbcMapping, statement, binding.getBindValue(), startPosition, executionContext ); } @@ -118,14 +115,11 @@ protected void bindParameterValue( PreparedStatement statement, Object bindValue, int startPosition, - ExecutionContext executionContext) throws SQLException { + ExecutionContext executionContext) + throws SQLException { //noinspection unchecked - jdbcMapping.getJdbcValueBinder().bind( - statement, - bindValue, - startPosition, - executionContext.getSession() - ); + jdbcMapping.getJdbcValueBinder() + .bind( statement, bindValue, startPosition, executionContext.getSession() ); } private JdbcMapping guessBindType(ExecutionContext executionContext, Object bindValue, JdbcMapping jdbcMapping) { @@ -133,32 +127,29 @@ private JdbcMapping guessBindType(ExecutionContext executionContext, Object bind return jdbcMapping; } else { - final BindableType parameterType = + final var parameterType = executionContext.getSession().getFactory().getMappingMetamodel() .resolveParameterBindType( bindValue ); - if ( parameterType == null && bindValue instanceof Enum ) { - return createEnumType( executionContext, (Class) bindValue.getClass() ); - } - else { - return parameterType instanceof JdbcMapping ? (JdbcMapping) parameterType : null; - } + return parameterType == null && bindValue instanceof Enum enumValue + ? createEnumType( executionContext, enumValue.getClass() ) + : parameterType instanceof JdbcMapping ? (JdbcMapping) parameterType : null; } } private static > BasicType createEnumType(ExecutionContext executionContext, Class enumClass) { - final EnumJavaType enumJavaType = new EnumJavaType<>( enumClass ); - final JdbcTypeIndicators indicators = - executionContext.getSession().getTypeConfiguration().getCurrentBaseSqlTypeIndicators(); - final JdbcType jdbcType = + final var enumJavaType = new EnumJavaType<>( enumClass ); + final var typeConfiguration = executionContext.getSession().getTypeConfiguration(); + final var indicators = typeConfiguration.getCurrentBaseSqlTypeIndicators(); + final var jdbcType = // we don't know whether to map the enum as ORDINAL or STRING, // so just accept the default from the TypeConfiguration, which // is usually ORDINAL (the default according to JPA) - enumJavaType.getRecommendedJdbcType(indicators); - return indicators.getTypeConfiguration().getBasicTypeRegistry().resolve( enumJavaType, jdbcType ); + enumJavaType.getRecommendedJdbcType( indicators ); + return typeConfiguration.getBasicTypeRegistry().resolve( enumJavaType, jdbcType ); } @Override - public MappingModelExpressible getExpressionType() { + public MappingModelExpressible getExpressionType() { return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallImpl.java index 265a55166593..ec5bd690ba54 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallImpl.java @@ -37,7 +37,7 @@ public class JdbcCallImpl implements JdbcOperationQueryCall { private final JdbcCallFunctionReturn functionReturn; private final List parameterRegistrations; private final List parameterBinders; - private final List parameterExtractors; + private final List> parameterExtractors; private final List refCursorExtractors; public JdbcCallImpl(Builder builder) { @@ -64,7 +64,7 @@ protected JdbcCallImpl( JdbcCallFunctionReturn functionReturn, List parameterRegistrations, List parameterBinders, - List parameterExtractors, + List> parameterExtractors, List refCursorExtractors) { this.callableName = callableName; this.functionReturn = functionReturn; @@ -74,22 +74,6 @@ protected JdbcCallImpl( this.refCursorExtractors = refCursorExtractors; } - protected JdbcCallImpl( - String callableName, - JdbcCallFunctionReturn functionReturn, - List parameterRegistrations, - List parameterBinders, - List parameterExtractors) { - this( - callableName, - functionReturn, - parameterRegistrations, - parameterBinders, - parameterExtractors, - null - ); - } - @Override public String getSqlString() { return callableName; @@ -132,7 +116,7 @@ public boolean isCompatibleWith( } @Override - public List getParameterExtractors() { + public List> getParameterExtractors() { return parameterExtractors == null ? emptyList() : parameterExtractors; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallParameterRegistrationImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallParameterRegistrationImpl.java index 860bc18f5ebf..01fcd24a2549 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallParameterRegistrationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallParameterRegistrationImpl.java @@ -13,7 +13,6 @@ import org.hibernate.sql.exec.spi.JdbcCallParameterExtractor; import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration; import org.hibernate.sql.exec.spi.JdbcParameterBinder; -import org.hibernate.type.descriptor.jdbc.JdbcType; import jakarta.persistence.ParameterMode; @@ -108,7 +107,7 @@ private void registerRefCursorParameter( private void registerOutputParameter( CallableStatement callableStatement, SharedSessionContractImplementor session) { - final JdbcType sqlTypeDescriptor = ormType.getJdbcType(); + final var sqlTypeDescriptor = ormType.getJdbcType(); try { sqlTypeDescriptor.registerOutParameter( callableStatement, jdbcParameterPositionStart ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallRefCursorExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallRefCursorExtractorImpl.java index 8fe5a350f358..d5a7092a0447 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallRefCursorExtractorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcCallRefCursorExtractorImpl.java @@ -34,8 +34,7 @@ public ResultSet extractResultSet( // .getJdbcEnvironment() // .getExtractedDatabaseMetaData() // .supportsNamedParameters(); - return session.getFactory() - .getServiceRegistry() + return session.getFactory().getServiceRegistry() .requireService( RefCursorSupport.class ) .getResultSet( callableStatement, jdbcParameterPosition ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcOperationQuerySelect.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcOperationQuerySelect.java index 97b256fe1ed3..9339d0a6ffec 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcOperationQuerySelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcOperationQuerySelect.java @@ -5,7 +5,6 @@ package org.hibernate.sql.exec.internal; import org.checkerframework.checker.nullness.qual.Nullable; -import org.hibernate.query.spi.Limit; import org.hibernate.query.spi.QueryOptions; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.exec.spi.ExecutionContext; @@ -127,13 +126,14 @@ public JdbcLockStrategy getLockStrategy() { @Override public boolean isCompatibleWith(JdbcParameterBindings jdbcParameterBindings, QueryOptions queryOptions) { + final var limit = queryOptions.getLimit(); if ( !appliedParameters.isEmpty() ) { if ( jdbcParameterBindings == null ) { return false; } for ( var entry : appliedParameters.entrySet() ) { - final JdbcParameter parameter = entry.getKey(); - final JdbcParameterBinding appliedBinding = entry.getValue(); + final var parameter = entry.getKey(); + final var appliedBinding = entry.getValue(); // This is a special case where the rendered SQL depends on the presence of the parameter, // but not specifically on the value. In this case we have to re-generate the SQL if we can't find a binding // The need for this can be tested with the OracleFollowOnLockingTest#testPessimisticLockWithMaxResultsThenNoFollowOnLocking @@ -141,12 +141,12 @@ public boolean isCompatibleWith(JdbcParameterBindings jdbcParameterBindings, Que // we must treat the absence of Limit parameters, when they were considered for locking, as incompatible if ( appliedBinding == null ) { if ( parameter == offsetParameter ) { - if ( queryOptions.getLimit() == null || queryOptions.getLimit().getFirstRowJpa() == 0 ) { + if ( limit == null || limit.getFirstRowJpa() == 0 ) { return false; } } else if ( parameter == limitParameter ) { - if ( queryOptions.getLimit() == null || queryOptions.getLimit().getMaxRowsJpa() == Integer.MAX_VALUE ) { + if ( limit == null || limit.getMaxRowsJpa() == Integer.MAX_VALUE ) { return false; } } @@ -156,7 +156,7 @@ else if ( jdbcParameterBindings.getBinding( parameter ) == null ) { } // We handle limit and offset parameters below if ( parameter != offsetParameter && parameter != limitParameter ) { - final JdbcParameterBinding binding = jdbcParameterBindings.getBinding( parameter ); + final var binding = jdbcParameterBindings.getBinding( parameter ); // TODO: appliedBinding can be null here, resulting in NPE if ( binding == null || !equal( appliedBinding, binding, appliedBinding.getBindType().getJavaTypeDescriptor() ) ) { @@ -165,7 +165,6 @@ else if ( jdbcParameterBindings.getBinding( parameter ) == null ) { } } } - final Limit limit = queryOptions.getLimit(); return ( offsetParameter != null || limitParameter != null || limit == null || limit.isEmpty() ) && isCompatible( offsetParameter, limit == null ? null : limit.getFirstRow(), 0 ) && isCompatible( limitParameter, limit == null ? null : limit.getMaxRows(), Integer.MAX_VALUE ); @@ -176,7 +175,7 @@ private boolean isCompatible(JdbcParameter parameter, Integer requestedValue, in return requestedValue == null; } else { - final JdbcParameterBinding jdbcParameterBinding = appliedParameters.get( parameter ); + final var jdbcParameterBinding = appliedParameters.get( parameter ); if ( jdbcParameterBinding == null ) { // If this query includes the parameter this is only compatible when a requested value is given through the query options // If not, this query string contains limit/offset but the query options don't request that diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java index ef1bad2b161d..d9cdedb04e1c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java @@ -53,66 +53,54 @@ public JdbcParameterBindingsImpl( final boolean paddingEnabled = factory.getSessionFactoryOptions().inClauseParameterPaddingEnabled(); final int inExprLimit = factory.getJdbcServices().getDialect().getParameterCountLimit(); - for ( ParameterOccurrence occurrence : parameterOccurrences ) { - final QueryParameterImplementor param = occurrence.parameter(); - final QueryParameterBinding binding = queryParameterBindings.getBinding( param ); + for ( var occurrence : parameterOccurrences ) { + final var parameter = occurrence.parameter(); + final var binding = queryParameterBindings.getBinding( parameter ); - final JdbcMapping jdbcMapping = jdbcMapping( factory, param, binding ); + final var jdbcMapping = jdbcMapping( factory, parameter, binding ); final BasicValueConverter valueConverter = jdbcMapping == null ? null : jdbcMapping.getValueConverter(); if ( binding.isMultiValued() ) { - final Collection bindValues = binding.getBindValues(); + final var bindValues = binding.getBindValues(); final int bindValueCount = bindValues.size(); final int bindValueMaxCount = determineBindValueMaxCount( paddingEnabled, inExprLimit, bindValueCount ); Object lastBindValue = null; - if ( valueConverter != null ) { - for ( Object bindValue : bindValues ) { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); - jdbcParameterBinders.add( jdbcParameter ); - lastBindValue = valueConverter.toRelationalValue( bindValue ); - addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) ); - } - if ( bindValueMaxCount != bindValueCount ) { - for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); - jdbcParameterBinders.add( jdbcParameter ); - addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) ); - } - } + for ( Object bindValue : bindValues ) { + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); + jdbcParameterBinders.add( jdbcParameter ); + lastBindValue = + valueConverter == null + ? bindValue + : valueConverter.toRelationalValue( bindValue ); + addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) ); } - else { - for ( Object bindValue : bindValues ) { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); + if ( bindValueMaxCount != bindValueCount ) { + for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) { + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); jdbcParameterBinders.add( jdbcParameter ); - addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, bindValue ) ); - lastBindValue = bindValue; - } - if ( bindValueMaxCount != bindValueCount ) { - for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); - jdbcParameterBinders.add( jdbcParameter ); - addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) ); - } + addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) ); } } + } else { - final Object bindValue = - valueConverter != null && binding.getBindValue() != null - ? valueConverter.toRelationalValue( binding.getBindValue() ) - : binding.getBindValue(); - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); + final Object bindValue = binding.getBindValue(); + final Object convertedBindValue = + valueConverter != null && bindValue != null + ? valueConverter.toRelationalValue( bindValue ) + : bindValue; + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); jdbcParameterBinders.add( jdbcParameter ); - addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, bindValue ) ); + addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, convertedBindValue ) ); } } } } private JdbcMapping jdbcMapping(SessionFactoryImplementor factory, QueryParameterImplementor param, QueryParameterBinding binding) { - final BindableType type = determineParamType( param, binding ); + final var type = determineParamType( param, binding ); if ( type == null ) { return factory.getTypeConfiguration().getBasicTypeForJavaType( Object.class ); } @@ -129,7 +117,7 @@ else if ( type instanceof BasicValuedMapping basicValuedMapping ) { } private BindableType determineParamType(QueryParameterImplementor param, QueryParameterBinding binding) { - final BindableType type = binding.getBindType(); + final var type = binding.getBindType(); return type == null ? param.getHibernateType() : type; } @@ -165,11 +153,4 @@ public void clear() { bindingMap.clear(); } } - - /** - * For testing. - */ - public Map getBindingMap() { - return bindingMap; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParametersImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParametersImpl.java index 567dda479288..9af477c6e77b 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParametersImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParametersImpl.java @@ -18,10 +18,6 @@ * @author Steve Ebersole */ public class JdbcParametersImpl implements JdbcParameters { - /** - * Singleton access - */ - public static final JdbcParametersImpl NO_PARAMETERS = new JdbcParametersImpl(); private Set jdbcParameters; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java index 51bcde658445..39f9adcd5927 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java @@ -287,13 +287,13 @@ protected JdbcValues resolveJdbcValuesSource( final QueryKey queryResultsCacheKey; final List cachedResults; if ( cacheable && cacheMode.isGetEnabled() ) { - SQL_EXEC_LOGGER.tracef( "Reading query result cache data [%s]", cacheMode.name() ); + SQL_EXEC_LOGGER.readingQueryResultCacheData( cacheMode.name() ); final Set querySpaces = jdbcSelect.getAffectedTableNames(); if ( querySpaces == null || querySpaces.isEmpty() ) { - SQL_EXEC_LOGGER.tracef( "Affected query spaces unexpectedly empty" ); + SQL_EXEC_LOGGER.affectedQuerySpacesUnexpectedlyEmpty(); } else { - SQL_EXEC_LOGGER.tracef( "Affected query spaces %s", querySpaces ); + SQL_EXEC_LOGGER.affectedQuerySpaces( querySpaces ); } final var queryCache = factory.getCache() @@ -333,7 +333,7 @@ protected JdbcValues resolveJdbcValuesSource( } } else { - SQL_EXEC_LOGGER.tracef( "Skipping reading query result cache data (query cache %s, cache mode %s)", + SQL_EXEC_LOGGER.skippingReadingQueryResultCacheData( queryCacheEnabled ? "enabled" : "disabled", cacheMode.name() ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/LockTimeoutHandler.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/LockTimeoutHandler.java index f3e38b738a14..6a17cd64dd50 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/LockTimeoutHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/LockTimeoutHandler.java @@ -39,7 +39,7 @@ public Timeout getBaseline() { @Override public void performPreAction(StatementAccess jdbcStatementAccess, Connection jdbcConnection, ExecutionContext executionContext) { - final SessionFactoryImplementor factory = executionContext.getSession().getFactory(); + final var factory = executionContext.getSession().getFactory(); // first, get the baseline (for post-action) baseline = lockTimeoutStrategy.getLockTimeout( jdbcConnection, factory ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java index e90924258694..fd77dc72b41f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java @@ -9,19 +9,12 @@ import java.util.function.BiConsumer; import java.util.function.Function; -import org.hibernate.JDBCException; import org.hibernate.engine.jdbc.spi.JdbcServices; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.monitor.spi.EventMonitor; -import org.hibernate.event.monitor.spi.DiagnosticEvent; import org.hibernate.exception.ConstraintViolationException; -import org.hibernate.query.spi.QueryOptions; -import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.JdbcMutationExecutor; import org.hibernate.sql.exec.spi.JdbcOperationQueryInsert; import org.hibernate.sql.exec.spi.JdbcOperationQueryMutation; -import org.hibernate.sql.exec.spi.JdbcParameterBinder; import org.hibernate.sql.exec.spi.JdbcParameterBindings; /** @@ -40,27 +33,28 @@ public int execute( Function statementCreator, BiConsumer expectationCheck, ExecutionContext executionContext) { - final SharedSessionContractImplementor session = executionContext.getSession(); + final var session = executionContext.getSession(); session.autoFlushIfRequired( jdbcMutation.getAffectedTableNames() ); - final LogicalConnectionImplementor logicalConnection = + final var logicalConnection = session.getJdbcCoordinator().getLogicalConnection(); - final JdbcServices jdbcServices = session.getJdbcServices(); + final var jdbcServices = session.getJdbcServices(); final String finalSql = applyOptions( jdbcMutation, executionContext, jdbcServices ); + final var queryOptions = executionContext.getQueryOptions(); try { // prepare the query - final PreparedStatement preparedStatement = statementCreator.apply( finalSql ); - + final var preparedStatement = statementCreator.apply( finalSql ); try { - if ( executionContext.getQueryOptions().getTimeout() != null ) { - preparedStatement.setQueryTimeout( executionContext.getQueryOptions().getTimeout() ); + final Integer timeout = queryOptions.getTimeout(); + if ( timeout != null ) { + preparedStatement.setQueryTimeout( timeout ); } // bind parameters // todo : validate that all query parameters were bound? int paramBindingPosition = 1; - for ( JdbcParameterBinder parameterBinder : jdbcMutation.getParameterBinders() ) { + for ( var parameterBinder : jdbcMutation.getParameterBinders() ) { parameterBinder.bindParameterValue( preparedStatement, paramBindingPosition++, @@ -70,16 +64,15 @@ public int execute( } session.getEventListenerManager().jdbcExecuteStatementStart(); - final EventMonitor eventMonitor = session.getEventMonitor(); - final DiagnosticEvent jdbcPreparedStatementExecutionEvent = - eventMonitor.beginJdbcPreparedStatementExecutionEvent(); + final var eventMonitor = session.getEventMonitor(); + final var executionEvent = eventMonitor.beginJdbcPreparedStatementExecutionEvent(); try { final int rows = preparedStatement.executeUpdate(); expectationCheck.accept( rows, preparedStatement ); return rows; } finally { - eventMonitor.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, finalSql ); + eventMonitor.completeJdbcPreparedStatementExecutionEvent( executionEvent, finalSql ); session.getEventListenerManager().jdbcExecuteStatementEnd(); } } @@ -97,11 +90,11 @@ public int execute( private static int handleException( JdbcOperationQueryMutation jdbcMutation, SQLException sqle, JdbcServices jdbcServices, String finalSql) { - final JDBCException exception = + final var exception = jdbcServices.getSqlExceptionHelper() .convert( sqle, "JDBC exception executing SQL", finalSql ); if ( exception instanceof ConstraintViolationException constraintViolationException - && jdbcMutation instanceof JdbcOperationQueryInsert jdbcInsert ) { + && jdbcMutation instanceof JdbcOperationQueryInsert jdbcInsert ) { if ( constraintViolationException.getKind() == ConstraintViolationException.ConstraintKind.UNIQUE ) { final String uniqueConstraintNameThatMayFail = jdbcInsert.getUniqueConstraintNameThatMayFail(); if ( uniqueConstraintNameThatMayFail != null ) { @@ -117,7 +110,7 @@ private static int handleException( private static String applyOptions( JdbcOperationQueryMutation jdbcMutation, ExecutionContext executionContext, JdbcServices jdbcServices) { - final QueryOptions queryOptions = executionContext.getQueryOptions(); + final var queryOptions = executionContext.getQueryOptions(); return queryOptions == null ? jdbcMutation.getSqlString() : jdbcServices.getDialect().addSqlHintOrComment( diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardStatementCreator.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardStatementCreator.java index cb038d319760..aefe14443c80 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardStatementCreator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardStatementCreator.java @@ -18,12 +18,12 @@ public class StandardStatementCreator implements JdbcSelectExecutor.StatementCre static final StandardStatementCreator[] INSTANCES; static { - final ScrollMode[] values = ScrollMode.values(); - final StandardStatementCreator[] instances = new StandardStatementCreator[values.length + 1]; - for ( int i = 0; i < values.length; i++ ) { - instances[i] = new StandardStatementCreator( values[i] ); + final var scrollModes = ScrollMode.values(); + final var instances = new StandardStatementCreator[scrollModes.length + 1]; + for ( int i = 0; i < scrollModes.length; i++ ) { + instances[i] = new StandardStatementCreator( scrollModes[i] ); } - instances[values.length] = new StandardStatementCreator( null ); + instances[scrollModes.length] = new StandardStatementCreator( null ); INSTANCES = instances; } @@ -40,10 +40,9 @@ private StandardStatementCreator(@Nullable ScrollMode scrollMode) { } @Override - public PreparedStatement createStatement(ExecutionContext executionContext, String sql) throws SQLException { - return executionContext.getSession() - .getJdbcCoordinator() - .getStatementPreparer() + public PreparedStatement createStatement(ExecutionContext executionContext, String sql) + throws SQLException { + return executionContext.getSession().getJdbcCoordinator().getStatementPreparer() .prepareQueryStatement( sql, false, scrollMode ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/CollectionLockingAction.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/CollectionLockingAction.java index f9f69385aded..56457df3fa98 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/CollectionLockingAction.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/CollectionLockingAction.java @@ -9,11 +9,8 @@ import org.hibernate.LockOptions; import org.hibernate.Locking; import org.hibernate.engine.spi.CollectionKey; -import org.hibernate.engine.spi.EffectiveEntityGraph; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.query.sqm.mutation.internal.SqmMutationStrategyHelper; @@ -34,7 +31,6 @@ import java.util.Map; import static org.hibernate.sql.exec.SqlExecLogger.SQL_EXEC_LOGGER; -import static org.hibernate.sql.exec.internal.lock.LockingHelper.segmentLoadedValues; /** * PostAction intended to perform collection locking with @@ -84,15 +80,15 @@ public void performPostAction( ExecutionContext executionContext) { LockingHelper.logLoadedValues( loadedValuesCollector ); - final SharedSessionContractImplementor session = executionContext.getSession(); + final var session = executionContext.getSession(); // NOTE: we deal with effective graphs here to make sure embedded associations are treated as lazy - final EffectiveEntityGraph effectiveEntityGraph = session.getLoadQueryInfluencers().getEffectiveEntityGraph(); - final RootGraphImplementor initialGraph = effectiveEntityGraph.getGraph(); - final GraphSemantic initialSemantic = effectiveEntityGraph.getSemantic(); + final var effectiveEntityGraph = session.getLoadQueryInfluencers().getEffectiveEntityGraph(); + final var initialGraph = effectiveEntityGraph.getGraph(); + final var initialSemantic = effectiveEntityGraph.getSemantic(); // collect registrations by entity type - final Map> entitySegments = segmentLoadedValues( loadedValuesCollector ); + final var entitySegments = segmentLoadedValues( loadedValuesCollector ); try { // for each entity-type, prepare a locking select statement per table. @@ -101,19 +97,18 @@ public void performPostAction( // the select-list for that table-segment. entitySegments.forEach( (entityMappingType, entityKeys) -> { if ( SQL_EXEC_LOGGER.isDebugEnabled() ) { - SQL_EXEC_LOGGER.debugf( "Starting include-collections locking process - %s", - entityMappingType.getEntityName() ); + SQL_EXEC_LOGGER.startingIncludeCollectionsLockingProcess( entityMappingType.getEntityName() ); } // apply an empty "fetch graph" to make sure any embedded associations reachable from // any of the DomainResults we will create are treated as lazy - final RootGraphImplementor graph = entityMappingType.createRootGraph( session ); + final var graph = entityMappingType.createRootGraph( session ); effectiveEntityGraph.clear(); effectiveEntityGraph.applyGraph( graph, GraphSemantic.FETCH ); // create a cross-reference of information related to an entity based on its identifier. // we use this as the collection owners whose collections need to be locked - final Map entityDetailsMap = LockingHelper.resolveEntityKeys( entityKeys, executionContext ); + final var entityDetailsMap = LockingHelper.resolveEntityKeys( entityKeys, executionContext ); SqmMutationStrategyHelper.visitCollectionTables( entityMappingType, (attribute) -> { // we may need to lock the "collection table". @@ -136,15 +131,15 @@ public void performPostAction( } private static LoadedValuesCollectorImpl resolveLoadedValuesCollector(FromClause fromClause) { - final List roots = fromClause.getRoots(); - if ( roots.size() == 1 ) { + final var fromClauseRoots = fromClause.getRoots(); + if ( fromClauseRoots.size() == 1 ) { return new LoadedValuesCollectorImpl( - List.of( roots.get( 0 ).getNavigablePath() ) + List.of( fromClauseRoots.get( 0 ).getNavigablePath() ) ); } else { return new LoadedValuesCollectorImpl( - roots.stream().map( TableGroup::getNavigablePath ).toList() + fromClauseRoots.stream().map( TableGroup::getNavigablePath ).toList() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/FollowOnLockingAction.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/FollowOnLockingAction.java index dc53a769da63..c22b76214459 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/FollowOnLockingAction.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/FollowOnLockingAction.java @@ -10,11 +10,9 @@ import org.hibernate.LockOptions; import org.hibernate.Locking; import org.hibernate.engine.spi.CollectionKey; -import org.hibernate.engine.spi.EffectiveEntityGraph; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.PluralAttributeMapping; @@ -37,13 +35,13 @@ import java.sql.Connection; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import static java.util.Collections.emptyMap; import static org.hibernate.sql.exec.SqlExecLogger.SQL_EXEC_LOGGER; /** @@ -77,7 +75,7 @@ public static void apply( QuerySpec lockingTarget, LockingClauseStrategy lockingClauseStrategy, JdbcSelectWithActions.Builder jdbcSelectBuilder) { - final FromClause fromClause = lockingTarget.getFromClause(); + final var fromClause = lockingTarget.getFromClause(); final var loadedValuesCollector = resolveLoadedValuesCollector( fromClause, lockingClauseStrategy ); // NOTE: we need to set this separately so that it can get incorporated into @@ -100,18 +98,20 @@ public void performPostAction( ExecutionContext executionContext) { LockingHelper.logLoadedValues( loadedValuesCollector ); - final SharedSessionContractImplementor session = executionContext.getSession(); + final var session = executionContext.getSession(); // NOTE: we deal with effective graphs here to make sure embedded associations are treated as lazy - final EffectiveEntityGraph effectiveEntityGraph = session.getLoadQueryInfluencers().getEffectiveEntityGraph(); - final RootGraphImplementor initialGraph = effectiveEntityGraph.getGraph(); - final GraphSemantic initialSemantic = effectiveEntityGraph.getSemantic(); + final var effectiveEntityGraph = session.getLoadQueryInfluencers().getEffectiveEntityGraph(); + final var initialGraph = effectiveEntityGraph.getGraph(); + final var initialSemantic = effectiveEntityGraph.getSemantic(); try { // collect registrations by entity type - final Map> entitySegments = segmentLoadedValues(); + final var entitySegments = segmentLoadedValues(); final Map>> collectionSegments = - lockScope == Locking.Scope.INCLUDE_FETCHES ? segmentLoadedCollections() : Collections.emptyMap(); + lockScope == Locking.Scope.INCLUDE_FETCHES + ? segmentLoadedCollections() + : emptyMap(); // for each entity-type, prepare a locking select statement per table. // this is based on the attributes for "state array" ordering purposes - @@ -119,40 +119,37 @@ public void performPostAction( // the select-list for that table-segment. entitySegments.forEach( (entityMappingType, entityKeys) -> { if ( SQL_EXEC_LOGGER.isDebugEnabled() ) { - SQL_EXEC_LOGGER.debugf( "Starting follow-on locking process - %s", entityMappingType.getEntityName() ); + SQL_EXEC_LOGGER.startingFollowOnLockingProcess( entityMappingType.getEntityName() ); } // apply an empty "fetch graph" to make sure any embedded associations reachable from // any of the DomainResults we will create are treated as lazy - final RootGraphImplementor graph = entityMappingType.createRootGraph( session ); + final var graph = entityMappingType.createRootGraph( session ); effectiveEntityGraph.clear(); effectiveEntityGraph.applyGraph( graph, GraphSemantic.FETCH ); // create a table-lock reference for each table for the entity (keyed by name) - final Map tableLocks = prepareTableLocks( entityMappingType, entityKeys, session ); + final var tableLocks = prepareTableLocks( entityMappingType, entityKeys, session ); // create a cross-reference of information related to an entity based on its identifier, // we'll use this later when we adjust the state array and inject state into the entity instance. - final Map entityDetailsMap = LockingHelper.resolveEntityKeys( entityKeys, executionContext ); + final var entityDetailsMap = LockingHelper.resolveEntityKeys( entityKeys, executionContext ); entityMappingType.forEachAttributeMapping( (index, attributeMapping) -> { - if ( attributeMapping instanceof PluralAttributeMapping pluralAttributeMapping ) { - // we need to handle collections specially (which we do below, so skip them here) - return; - } - - final TableLock tableLock = resolveTableLock( attributeMapping, tableLocks, entityMappingType ); + // we need to handle collections specially (which we do below, so skip them here) + if ( !(attributeMapping instanceof PluralAttributeMapping) ) { + final var tableLock = resolveTableLock( attributeMapping, tableLocks, entityMappingType ); + if ( tableLock == null ) { + throw new AssertionFailure( String.format( + Locale.ROOT, + "Unable to locate table for attribute `%s`", + attributeMapping.getNavigableRole().getFullPath() + ) ); + } - if ( tableLock == null ) { - throw new AssertionFailure( String.format( - Locale.ROOT, - "Unable to locate table for attribute `%s`", - attributeMapping.getNavigableRole().getFullPath() - ) ); + // here we apply the selection for the attribute to the corresponding table-lock ref + tableLock.applyAttribute( index, attributeMapping ); } - - // here we apply the selection for the attribute to the corresponding table-lock ref - tableLock.applyAttribute( index, attributeMapping ); } ); // now we do process any collections, if asked @@ -172,8 +169,7 @@ public void performPostAction( else if ( lockScope == Locking.Scope.INCLUDE_FETCHES && loadedValuesCollector.getCollectedCollections() != null && !loadedValuesCollector.getCollectedCollections().isEmpty() ) { - final Map> attributeKeys = - collectionSegments.get( entityMappingType ); + final var attributeKeys = collectionSegments.get( entityMappingType ); if ( attributeKeys != null ) { for ( var entry : attributeKeys.entrySet() ) { LockingHelper.lockCollectionTable( @@ -189,10 +185,9 @@ else if ( lockScope == Locking.Scope.INCLUDE_FETCHES // at this point, we have all the individual locking selects ready to go - execute them - final QueryOptions lockingOptions = buildLockingOptions( executionContext ); - tableLocks.forEach( (s, tableLock) -> { - tableLock.performActions( entityDetailsMap, lockingOptions, session ); - } ); + final var lockingOptions = buildLockingOptions( executionContext ); + tableLocks.forEach( (s, tableLock) -> + tableLock.performActions( entityDetailsMap, lockingOptions, session ) ); } ); } finally { @@ -206,20 +201,19 @@ private TableLock resolveTableLock( AttributeMapping attributeMapping, Map tableSegments, EntityMappingType entityMappingType) { - if ( entityMappingType.getEntityPersister() instanceof UnionSubclassEntityPersister usp ) { - // in the union-subclass strategy, attributes defined on the super are reported as - // contained by the logical super table. See also the hacks in TableSegment - // to deal with this - // todo (JdbcOperation) : need to allow for secondary-tables - return tableSegments.get( usp.getMappedTableDetails().getTableName() ); - } - else { - return tableSegments.get( attributeMapping.getContainingTableExpression() ); - } + final Object key = + entityMappingType.getEntityPersister() instanceof UnionSubclassEntityPersister usp + // In the union-subclass strategy, attributes defined on the + // super are reported as contained by the logical super table. + // See also the hacks in TableSegment to deal with this. + // todo (JdbcOperation) : need to allow for secondary-tables + ? usp.getMappedTableDetails().getTableName() + : attributeMapping.getContainingTableExpression(); + return tableSegments.get( key ); } private QueryOptions buildLockingOptions(ExecutionContext executionContext) { - final QueryOptionsImpl lockingQueryOptions = new QueryOptionsImpl(); + final var lockingQueryOptions = new QueryOptionsImpl(); lockingQueryOptions.getLockOptions().setLockMode( lockMode ); lockingQueryOptions.getLockOptions().setTimeout( lockTimeout ); lockingQueryOptions.getLockOptions().setFollowOnStrategy( Locking.FollowOn.DISALLOW ); @@ -264,16 +258,16 @@ private TableLock createTableLock(TableDetails tableDetails, EntityMappingType e private static LoadedValuesCollectorImpl resolveLoadedValuesCollector( FromClause fromClause, LockingClauseStrategy lockingClauseStrategy) { - final List roots = fromClause.getRoots(); - if ( roots.size() == 1 ) { + final var fromClauseRoots = fromClause.getRoots(); + if ( fromClauseRoots.size() == 1 ) { return new LoadedValuesCollectorImpl( - List.of( roots.get( 0 ).getNavigablePath() ), + List.of( fromClauseRoots.get( 0 ).getNavigablePath() ), lockingClauseStrategy ); } else { return new LoadedValuesCollectorImpl( - roots.stream().map( TableGroup::getNavigablePath ).toList(), + fromClauseRoots.stream().map( TableGroup::getNavigablePath ).toList(), lockingClauseStrategy ); } @@ -294,34 +288,33 @@ public LoadedValuesCollectorImpl(List rootPaths, LockingClauseStr @Override public void registerEntity(NavigablePath navigablePath, EntityMappingType entityDescriptor, EntityKey entityKey) { - if ( !pathsToLock.contains( navigablePath ) ) { - return; - } - - if ( rootPaths.contains( navigablePath ) ) { - if ( rootEntitiesToLock == null ) { - rootEntitiesToLock = new ArrayList<>(); + if ( pathsToLock.contains( navigablePath ) ) { + if ( rootPaths.contains( navigablePath ) ) { + if ( rootEntitiesToLock == null ) { + rootEntitiesToLock = new ArrayList<>(); + } + rootEntitiesToLock.add( + new LoadedEntityRegistration( navigablePath, entityDescriptor, entityKey ) ); } - rootEntitiesToLock.add( new LoadedEntityRegistration( navigablePath, entityDescriptor, entityKey ) ); - } - else { - if ( nonRootEntitiesToLock == null ) { - nonRootEntitiesToLock = new ArrayList<>(); + else { + if ( nonRootEntitiesToLock == null ) { + nonRootEntitiesToLock = new ArrayList<>(); + } + nonRootEntitiesToLock.add( + new LoadedEntityRegistration( navigablePath, entityDescriptor, entityKey ) ); } - nonRootEntitiesToLock.add( new LoadedEntityRegistration( navigablePath, entityDescriptor, entityKey ) ); } } @Override public void registerCollection(NavigablePath navigablePath, PluralAttributeMapping collectionDescriptor, CollectionKey collectionKey) { - if ( !pathsToLock.contains( navigablePath ) ) { - return; - } - - if ( collectionsToLock == null ) { - collectionsToLock = new ArrayList<>(); + if ( pathsToLock.contains( navigablePath ) ) { + if ( collectionsToLock == null ) { + collectionsToLock = new ArrayList<>(); + } + collectionsToLock.add( + new LoadedCollectionRegistration( navigablePath, collectionDescriptor, collectionKey ) ); } - collectionsToLock.add( new LoadedCollectionRegistration( navigablePath, collectionDescriptor, collectionKey ) ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingCreationStates.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingCreationStates.java index ace41c64b389..211cabbfb658 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingCreationStates.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingCreationStates.java @@ -24,10 +24,8 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; -import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.spi.TypeConfiguration; @@ -160,10 +158,11 @@ public SqlSelection resolveSqlSelection( } if ( expression instanceof ColumnReference columnReference ) { - final SqlSelectionImpl created = new SqlSelectionImpl( columnReference, querySpec.getSelectClause().getSqlSelections().size() ); - sqlSelectionMap.put( expression, created ); - querySpec.getSelectClause().addSqlSelection( created ); - return created; + final var selection = + new SqlSelectionImpl( columnReference, querySpec.getSelectClause().getSqlSelections().size() ); + sqlSelectionMap.put( expression, selection ); + querySpec.getSelectClause().addSqlSelection( selection ); + return selection; } throw new UnsupportedOperationException( "Unsupported Expression type (expected ColumnReference) : " + expression ); @@ -176,37 +175,27 @@ public ModelPart resolveModelPart(NavigablePath navigablePath) { @Override public ImmutableFetchList visitFetches(FetchParent fetchParent) { - final ImmutableFetchList.Builder fetches = - new ImmutableFetchList.Builder( fetchParent.getReferencedMappingContainer() ); - - final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer(); - + final var fetches = new ImmutableFetchList.Builder( fetchParent.getReferencedMappingContainer() ); + final var referencedMappingContainer = fetchParent.getReferencedMappingContainer(); final int size = referencedMappingContainer.getNumberOfFetchables(); for ( int i = 0; i < size; i++ ) { final Fetchable fetchable = referencedMappingContainer.getFetchable( i ); processFetchable( fetchParent, fetchable, fetches ); } return fetches.build(); - } private void processFetchable(FetchParent fetchParent, Fetchable fetchable, ImmutableFetchList.Builder fetches) { - if ( !fetchable.isSelectable() ) { - return; + if ( fetchable.isSelectable() ) { + fetches.add( fetchParent.generateFetchableFetch( + fetchable, + fetchParent.resolveNavigablePath( fetchable ), + FetchTiming.DELAYED, + false, + null, + this + ) ); } - - final NavigablePath fetchablePath = fetchParent.resolveNavigablePath( fetchable ); - - final Fetch fetch = fetchParent.generateFetchableFetch( - fetchable, - fetchablePath, - FetchTiming.DELAYED, - false, - null, - this - ); - - fetches.add( fetch ); } @Override @@ -221,7 +210,6 @@ public boolean isResolvingCircularFetch() { @Override public void setResolvingCircularFetch(boolean resolvingCircularFetch) { - } @Override @@ -231,6 +219,5 @@ public ForeignKeyDescriptor.Nature getCurrentlyResolvingForeignKeyPart() { @Override public void setCurrentlyResolvingForeignKeyPart(ForeignKeyDescriptor.Nature currentlyResolvingForeignKeySide) { - } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingHelper.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingHelper.java index 5bf0799c11b6..d483c0245eb7 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingHelper.java @@ -9,31 +9,22 @@ import org.hibernate.ScrollMode; import org.hibernate.Session; import org.hibernate.collection.spi.PersistentCollection; -import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.CollectionKey; -import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; -import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.metamodel.mapping.ValuedModelPart; import org.hibernate.query.internal.QueryOptionsImpl; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.sqm.ComparisonOperator; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.LockingClauseStrategy; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.from.NamedTableReference; -import org.hibernate.sql.ast.tree.from.TableGroup; -import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.InListPredicate; @@ -45,9 +36,7 @@ import org.hibernate.sql.exec.internal.JdbcParameterImpl; import org.hibernate.sql.exec.internal.StandardStatementCreator; import org.hibernate.sql.exec.spi.ExecutionContext; -import org.hibernate.sql.exec.internal.JdbcOperationQuerySelect; import org.hibernate.sql.exec.spi.JdbcParameterBindings; -import org.hibernate.sql.exec.spi.JdbcSelectExecutor; import org.hibernate.sql.exec.spi.LoadedValuesCollector; import org.hibernate.sql.results.spi.ListResultsConsumer; @@ -84,86 +73,75 @@ public static void lockCollectionTable( ExecutionContext executionContext) { final SharedSessionContractImplementor session = executionContext.getSession(); - final ForeignKeyDescriptor keyDescriptor = attributeMapping.getKeyDescriptor(); + final var keyDescriptor = attributeMapping.getKeyDescriptor(); final String keyTableName = keyDescriptor.getKeyTable(); if ( SQL_EXEC_LOGGER.isDebugEnabled() ) { - SQL_EXEC_LOGGER.debugf( "Collection locking for collection table `%s` - %s", keyTableName, attributeMapping.getRootPathName() ); + SQL_EXEC_LOGGER.collectionLockingForCollectionTable( keyTableName, attributeMapping.getRootPathName() ); } - final QuerySpec querySpec = new QuerySpec( true ); + final var querySpec = new QuerySpec( true ); - final NamedTableReference tableReference = new NamedTableReference( keyTableName, "tbl" ); - final LockingTableGroup tableGroup = new LockingTableGroup( - tableReference, - keyTableName, - attributeMapping, - keyDescriptor.getKeySide().getModelPart() - ); + final var tableReference = new NamedTableReference( keyTableName, "tbl" ); - querySpec.getFromClause().addRoot( tableGroup ); + querySpec.getFromClause() + .addRoot( new LockingTableGroup( + tableReference, + keyTableName, + attributeMapping, + keyDescriptor.getKeySide().getModelPart() + ) ); - final ValuedModelPart keyPart = keyDescriptor.getKeyPart(); - final ColumnReference columnReference = new ColumnReference( tableReference, keyPart.getSelectable( 0 ) ); + final var keyPart = keyDescriptor.getKeyPart(); + final var columnReference = new ColumnReference( tableReference, keyPart.getSelectable( 0 ) ); // NOTE: We add the key column to the selection list, but never create a DomainResult // as we won't read the value back. Ideally, we would read the "value column(s)" and // update the collection state accordingly much like is done for entity state - // however, the concern is minor, so for simplicity we do not. - final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( columnReference, 0 ); - querySpec.getSelectClause().addSqlSelection( sqlSelection ); + querySpec.getSelectClause() + .addSqlSelection( new SqlSelectionImpl( columnReference, 0 ) ); - final JdbcParameterBindingsImpl parameterBindings = new JdbcParameterBindingsImpl( keyDescriptor.getJdbcTypeCount() ); + final int jdbcTypeCount = keyDescriptor.getJdbcTypeCount(); + final var parameterBindings = new JdbcParameterBindingsImpl( jdbcTypeCount ); final ComparisonPredicate restriction; - if ( keyDescriptor.getJdbcTypeCount() == 1 ) { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( keyPart.getSelectable( 0 ).getJdbcMapping() ); + if ( jdbcTypeCount == 1 ) { + final var jdbcParameter = + new JdbcParameterImpl( keyPart.getSelectable( 0 ).getJdbcMapping() ); keyDescriptor.breakDownJdbcValues( collectionToLock.getKey(), (valueIndex, value, jdbcValueMapping) -> { - parameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + parameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) ); }, session ); restriction = new ComparisonPredicate( columnReference, ComparisonOperator.EQUAL, jdbcParameter ); } else { - final List columnReferences = new ArrayList<>( keyDescriptor.getJdbcTypeCount() ); - final List jdbcParameters = new ArrayList<>( keyDescriptor.getJdbcTypeCount() ); + final List columnReferences = new ArrayList<>( jdbcTypeCount ); + final List jdbcParameters = new ArrayList<>( jdbcTypeCount ); keyDescriptor.breakDownJdbcValues( collectionToLock.getKey(), (valueIndex, value, jdbcValueMapping) -> { columnReferences.add( new ColumnReference( tableReference, jdbcValueMapping ) ); - - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcValueMapping.getJdbcMapping() ); + final var jdbcMapping = jdbcValueMapping.getJdbcMapping(); + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); jdbcParameters.add( jdbcParameter ); - parameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + parameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, value ) ); }, session ); - final SqlTuple columns = new SqlTuple( columnReferences, keyDescriptor ); - final SqlTuple parameters = new SqlTuple( jdbcParameters, keyDescriptor ); + final var columns = new SqlTuple( columnReferences, keyDescriptor ); + final var parameters = new SqlTuple( jdbcParameters, keyDescriptor ); restriction = new ComparisonPredicate( columns, ComparisonOperator.EQUAL, parameters ); } querySpec.applyPredicate( restriction ); - final QueryOptionsImpl lockingQueryOptions = new QueryOptionsImpl(); - lockingQueryOptions.getLockOptions().setLockMode( lockMode ); - lockingQueryOptions.getLockOptions().setTimeout( lockTimeout ); - final ExecutionContext lockingExecutionContext = new BaseExecutionContext( executionContext.getSession() ) { - @Override - public QueryOptions getQueryOptions() { - return lockingQueryOptions; - } - }; - - performLocking( querySpec, parameterBindings, lockingExecutionContext ); + performLocking( querySpec, parameterBindings, + lockingExecutionContext( lockMode, lockTimeout, executionContext ) ); } /** @@ -174,46 +152,47 @@ public QueryOptions getQueryOptions() { * @param lockTimeout A lock timeout to apply, if one. * @param ownerDetailsMap Details for each owner, whose collection-table rows should be locked. */ - public static void lockCollectionTable( +public static void lockCollectionTable( PluralAttributeMapping attributeMapping, LockMode lockMode, Timeout lockTimeout, Map ownerDetailsMap, ExecutionContext executionContext) { - final ForeignKeyDescriptor keyDescriptor = attributeMapping.getKeyDescriptor(); + final var keyDescriptor = attributeMapping.getKeyDescriptor(); final String keyTableName = keyDescriptor.getKeyTable(); if ( SQL_EXEC_LOGGER.isDebugEnabled() ) { - SQL_EXEC_LOGGER.debugf( "Follow-on locking for collection table `%s` - %s", keyTableName, attributeMapping.getRootPathName() ); + SQL_EXEC_LOGGER.followOnLockingForCollectionTable( keyTableName, attributeMapping.getRootPathName() ); } - final QuerySpec querySpec = new QuerySpec( true ); + final var querySpec = new QuerySpec( true ); - final NamedTableReference tableReference = new NamedTableReference( keyTableName, "tbl" ); - final LockingTableGroup tableGroup = new LockingTableGroup( - tableReference, - keyTableName, - attributeMapping, - keyDescriptor.getKeySide().getModelPart() - ); + final var tableReference = new NamedTableReference( keyTableName, "tbl" ); - querySpec.getFromClause().addRoot( tableGroup ); + querySpec.getFromClause() + .addRoot( new LockingTableGroup( + tableReference, + keyTableName, + attributeMapping, + keyDescriptor.getKeySide().getModelPart() + ) ); - final ValuedModelPart keyPart = keyDescriptor.getKeyPart(); - final ColumnReference columnReference = new ColumnReference( tableReference, keyPart.getSelectable( 0 ) ); + final var keyPart = keyDescriptor.getKeyPart(); + final var columnReference = new ColumnReference( tableReference, keyPart.getSelectable( 0 ) ); // NOTE: We add the key column to the selection list, but never create a DomainResult // as we won't read the value back. Ideally, we would read the "value column(s)" and // update the collection state accordingly much like is done for entity state - // however, the concern is minor, so for simplicity we do not. - final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( columnReference, 0 ); - querySpec.getSelectClause().addSqlSelection( sqlSelection ); + querySpec.getSelectClause() + .addSqlSelection( new SqlSelectionImpl( columnReference, 0 ) ); - final int expectedParamCount = ownerDetailsMap.size() * keyDescriptor.getJdbcTypeCount(); - final JdbcParameterBindingsImpl parameterBindings = new JdbcParameterBindingsImpl( expectedParamCount ); + final int jdbcTypeCount = keyDescriptor.getJdbcTypeCount(); + final int expectedParamCount = ownerDetailsMap.size() * jdbcTypeCount; + final var parameterBindings = new JdbcParameterBindingsImpl( expectedParamCount ); final InListPredicate restriction; - if ( keyDescriptor.getJdbcTypeCount() == 1 ) { + if ( jdbcTypeCount == 1 ) { restriction = new InListPredicate( columnReference ); applySimpleCollectionKeyTableLockRestrictions( attributeMapping, @@ -236,17 +215,21 @@ public static void lockCollectionTable( } querySpec.applyPredicate( restriction ); - final QueryOptionsImpl lockingQueryOptions = new QueryOptionsImpl(); - lockingQueryOptions.getLockOptions().setLockMode( lockMode ); - lockingQueryOptions.getLockOptions().setTimeout( lockTimeout ); - final ExecutionContext lockingExecutionContext = new BaseExecutionContext( executionContext.getSession() ) { + performLocking( querySpec, parameterBindings, + lockingExecutionContext( lockMode, lockTimeout, executionContext ) ); + } + + private static ExecutionContext lockingExecutionContext(LockMode lockMode, Timeout lockTimeout, ExecutionContext executionContext) { + final var lockingQueryOptions = new QueryOptionsImpl(); + final var lockOptions = lockingQueryOptions.getLockOptions(); + lockOptions.setLockMode( lockMode ); + lockOptions.setTimeout( lockTimeout ); + return new BaseExecutionContext( executionContext.getSession() ) { @Override public QueryOptions getQueryOptions() { return lockingQueryOptions; } }; - - performLocking( querySpec, parameterBindings, lockingExecutionContext ); } private static void applySimpleCollectionKeyTableLockRestrictions( @@ -258,19 +241,17 @@ private static void applySimpleCollectionKeyTableLockRestrictions( SharedSessionContractImplementor session) { ownerDetailsMap.forEach( (o, entityDetails) -> { - final PersistentCollection collectionInstance = (PersistentCollection) entityDetails.entry().getLoadedState()[attributeMapping.getStateArrayPosition()]; - final Object collectionKeyValue = collectionInstance.getKey(); + final var collectionInstance = + (PersistentCollection) + entityDetails.entry().getLoadedState()[attributeMapping.getStateArrayPosition()]; keyDescriptor.breakDownJdbcValues( - collectionKeyValue, + collectionInstance.getKey(), (valueIndex, value, jdbcValueMapping) -> { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( - jdbcValueMapping.getJdbcMapping() ); + final var jdbcMapping = jdbcValueMapping.getJdbcMapping(); + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); restriction.addExpression( jdbcParameter ); - - parameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + parameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, value ) ); }, session ); @@ -292,26 +273,28 @@ private static InListPredicate applyCompositeCollectionKeyTableLockRestrictions( ); } - final List columnReferences = new ArrayList<>( keyDescriptor.getJdbcTypeCount() ); + final int jdbcTypeCount = keyDescriptor.getJdbcTypeCount(); + final List columnReferences = new ArrayList<>( jdbcTypeCount ); keyDescriptor.forEachSelectable( (selectionIndex, selectableMapping) -> { columnReferences.add( new ColumnReference( tableReference, selectableMapping ) ); } ); final InListPredicate inListPredicate = new InListPredicate( new SqlTuple( columnReferences, keyDescriptor ) ); ownerDetailsMap.forEach( (o, entityDetails) -> { - final PersistentCollection collectionInstance = (PersistentCollection) entityDetails.entry().getLoadedState()[attributeMapping.getStateArrayPosition()]; + final var collectionInstance = + (PersistentCollection) + entityDetails.entry().getLoadedState()[attributeMapping.getStateArrayPosition()]; final Object collectionKeyValue = collectionInstance.getKey(); - final List jdbcParameters = new ArrayList<>( keyDescriptor.getJdbcTypeCount() ); + final List jdbcParameters = new ArrayList<>( jdbcTypeCount ); keyDescriptor.breakDownJdbcValues( collectionKeyValue, (valueIndex, value, jdbcValueMapping) -> { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcValueMapping.getJdbcMapping() ); + final var jdbcMapping = jdbcValueMapping.getJdbcMapping(); + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); jdbcParameters.add( jdbcParameter ); - parameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + parameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, value ) ); }, session ); @@ -335,17 +318,17 @@ public static void lockCollectionTable( Timeout lockTimeout, List collectionKeys, ExecutionContext executionContext) { - final ForeignKeyDescriptor keyDescriptor = attributeMapping.getKeyDescriptor(); + final var keyDescriptor = attributeMapping.getKeyDescriptor(); final String keyTableName = keyDescriptor.getKeyTable(); if ( SQL_EXEC_LOGGER.isDebugEnabled() ) { - SQL_EXEC_LOGGER.debugf( "Follow-on locking for collection table `%s` - %s", keyTableName, attributeMapping.getRootPathName() ); + SQL_EXEC_LOGGER.followOnLockingForCollectionTable( keyTableName, attributeMapping.getRootPathName() ); } - final QuerySpec querySpec = new QuerySpec( true ); + final var querySpec = new QuerySpec( true ); - final NamedTableReference tableReference = new NamedTableReference( keyTableName, "tbl" ); - final LockingTableGroup tableGroup = new LockingTableGroup( + final var tableReference = new NamedTableReference( keyTableName, "tbl" ); + final var tableGroup = new LockingTableGroup( tableReference, keyTableName, attributeMapping, @@ -354,24 +337,24 @@ public static void lockCollectionTable( querySpec.getFromClause().addRoot( tableGroup ); - final ValuedModelPart keyPart = keyDescriptor.getKeyPart(); - final ColumnReference columnReference = new ColumnReference( tableReference, keyPart.getSelectable( 0 ) ); + final var keyPart = keyDescriptor.getKeyPart(); + final var columnReference = new ColumnReference( tableReference, keyPart.getSelectable( 0 ) ); // NOTE: We add the key column to the selection list, but never create a DomainResult // as we won't read the value back. Ideally, we would read the "value column(s)" and // update the collection state accordingly much like is done for entity state - // however, the concern is minor, so for simplicity we do not. - final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( columnReference, 0 ); + final var sqlSelection = new SqlSelectionImpl( columnReference, 0 ); querySpec.getSelectClause().addSqlSelection( sqlSelection ); - final int expectedParamCount = collectionKeys.size() * keyDescriptor.getJdbcTypeCount(); - final JdbcParameterBindingsImpl parameterBindings = new JdbcParameterBindingsImpl( expectedParamCount ); + final int jdbcTypeCount = keyDescriptor.getJdbcTypeCount(); + final int expectedParamCount = collectionKeys.size() * jdbcTypeCount; + final var parameterBindings = new JdbcParameterBindingsImpl( expectedParamCount ); final InListPredicate restriction; - if ( keyDescriptor.getJdbcTypeCount() == 1 ) { + if ( jdbcTypeCount == 1 ) { restriction = new InListPredicate( columnReference ); applySimpleCollectionKeyTableLockRestrictions( - attributeMapping, keyDescriptor, restriction, parameterBindings, @@ -391,39 +374,25 @@ public static void lockCollectionTable( } querySpec.applyPredicate( restriction ); - final QueryOptionsImpl lockingQueryOptions = new QueryOptionsImpl(); - lockingQueryOptions.getLockOptions().setLockMode( lockMode ); - lockingQueryOptions.getLockOptions().setTimeout( lockTimeout ); - final ExecutionContext lockingExecutionContext = new BaseExecutionContext( executionContext.getSession() ) { - @Override - public QueryOptions getQueryOptions() { - return lockingQueryOptions; - } - }; - - performLocking( querySpec, parameterBindings, lockingExecutionContext ); + performLocking( querySpec, parameterBindings, + lockingExecutionContext( lockMode, lockTimeout, executionContext ) ); } private static void applySimpleCollectionKeyTableLockRestrictions( - PluralAttributeMapping attributeMapping, ForeignKeyDescriptor keyDescriptor, InListPredicate restriction, JdbcParameterBindingsImpl parameterBindings, List collectionKeys, SharedSessionContractImplementor session) { - for ( CollectionKey collectionKey : collectionKeys ) { - final Object collectionKeyValue = collectionKey.getKey(); + for ( var collectionKey : collectionKeys ) { keyDescriptor.breakDownJdbcValues( - collectionKeyValue, + collectionKey.getKey(), (valueIndex, value, jdbcValueMapping) -> { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( - jdbcValueMapping.getJdbcMapping() ); + final var jdbcMapping = jdbcValueMapping.getJdbcMapping(); + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); restriction.addExpression( jdbcParameter ); - - parameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + parameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, value ) ); }, session ); @@ -445,25 +414,23 @@ private static InListPredicate applyCompositeCollectionKeyTableLockRestrictions( ); } - final List columnReferences = new ArrayList<>( keyDescriptor.getJdbcTypeCount() ); + final int jdbcTypeCount = keyDescriptor.getJdbcTypeCount(); + final List columnReferences = new ArrayList<>( jdbcTypeCount ); keyDescriptor.forEachSelectable( (selectionIndex, selectableMapping) -> { columnReferences.add( new ColumnReference( tableReference, selectableMapping ) ); } ); - final InListPredicate inListPredicate = new InListPredicate( new SqlTuple( columnReferences, keyDescriptor ) ); + final var inListPredicate = new InListPredicate( new SqlTuple( columnReferences, keyDescriptor ) ); - for ( CollectionKey collectionKey : collectionKeys ) { - final Object collectionKeyValue = collectionKey.getKey(); - - final List jdbcParameters = new ArrayList<>( keyDescriptor.getJdbcTypeCount() ); + for ( var collectionKey : collectionKeys ) { + final List jdbcParameters = new ArrayList<>( jdbcTypeCount ); keyDescriptor.breakDownJdbcValues( - collectionKeyValue, + collectionKey.getKey(), (valueIndex, value, jdbcValueMapping) -> { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcValueMapping.getJdbcMapping() ); + final var jdbcMapping = jdbcValueMapping.getJdbcMapping(); + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); jdbcParameters.add( jdbcParameter ); - parameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + parameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, value ) ); }, session ); @@ -477,17 +444,12 @@ private static void performLocking( QuerySpec querySpec, JdbcParameterBindings jdbcParameterBindings, ExecutionContext lockingExecutionContext) { - final SessionFactoryImplementor sessionFactory = lockingExecutionContext.getSession().getSessionFactory(); - final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); - - final SelectStatement selectStatement = new SelectStatement( querySpec ); - final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcServices.getDialect().getSqlAstTranslatorFactory(); - final SqlAstTranslator translator = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, selectStatement ); - final JdbcOperationQuerySelect jdbcOperation = translator.translate( jdbcParameterBindings, lockingExecutionContext.getQueryOptions() ); - - final JdbcSelectExecutor jdbcSelectExecutor = jdbcServices.getJdbcSelectExecutor(); - jdbcSelectExecutor.executeQuery( - jdbcOperation, + final var sessionFactory = lockingExecutionContext.getSession().getSessionFactory(); + final var jdbcServices = sessionFactory.getJdbcServices(); + jdbcServices.getJdbcSelectExecutor().executeQuery( + jdbcServices.getDialect().getSqlAstTranslatorFactory() + .buildSelectTranslator( sessionFactory, new SelectStatement( querySpec ) ) + .translate( jdbcParameterBindings, lockingExecutionContext.getQueryOptions() ), jdbcParameterBindings, lockingExecutionContext, row -> row, @@ -502,22 +464,28 @@ private static void performLocking( */ public static void logLoadedValues(LoadedValuesCollector collector) { if ( SQL_EXEC_LOGGER.isDebugEnabled() ) { - SQL_EXEC_LOGGER.debug( "Follow-on locking collected loaded values..." ); - - SQL_EXEC_LOGGER.debug( " Loaded root entities:" ); + var summary = new StringBuilder(); + summary.append( " Loaded root entities:\n" ); collector.getCollectedRootEntities().forEach( (reg) -> { - SQL_EXEC_LOGGER.debugf( " - %s#%s", reg.entityDescriptor().getEntityName(), reg.entityKey().getIdentifier() ); + summary.append( String.format( " - %s#%s\n", + reg.entityDescriptor().getEntityName(), + reg.entityKey().getIdentifier() ) ); } ); - SQL_EXEC_LOGGER.debug( " Loaded non-root entities:" ); + summary.append( " Loaded non-root entities:\n" ); collector.getCollectedNonRootEntities().forEach( (reg) -> { - SQL_EXEC_LOGGER.debugf( " - %s#%s", reg.entityDescriptor().getEntityName(), reg.entityKey().getIdentifier() ); + summary.append( String.format( " - %s#%s\n", + reg.entityDescriptor().getEntityName() + , reg.entityKey().getIdentifier() ) ); } ); - SQL_EXEC_LOGGER.debug( " Loaded collections:" ); + summary.append( " Loaded collections:\n" ); collector.getCollectedCollections().forEach( (reg) -> { - SQL_EXEC_LOGGER.debugf( " - %s#%s", reg.collectionDescriptor().getRootPathName(), reg.collectionKey().getKey() ); + summary.append( String.format( " - %s#%s\n", + reg.collectionDescriptor().getRootPathName(), + reg.collectionKey().getKey() ) ); } ); + SQL_EXEC_LOGGER.followOnLockingCollectedLoadedValues( summary.toString() ); } } @@ -528,24 +496,22 @@ public static void logLoadedValues(LoadedValuesCollector collector) { public static Collection extractPathsToLock(LockingClauseStrategy lockingClauseStrategy) { final LinkedHashSet paths = new LinkedHashSet<>(); - final Collection rootsToLock = lockingClauseStrategy.getRootsToLock(); + final var rootsToLock = lockingClauseStrategy.getRootsToLock(); if ( rootsToLock != null ) { rootsToLock.forEach( (tableGroup) -> paths.add( tableGroup.getNavigablePath() ) ); } - final Collection joinsToLock = lockingClauseStrategy.getJoinsToLock(); + final var joinsToLock = lockingClauseStrategy.getJoinsToLock(); if ( joinsToLock != null ) { joinsToLock.forEach( (tableGroupJoin) -> { - paths.add( tableGroupJoin.getNavigablePath() ); - - final ModelPartContainer modelPart = tableGroupJoin.getJoinedGroup().getModelPart(); + final var navigablePath = tableGroupJoin.getNavigablePath(); + paths.add( navigablePath ); + final var modelPart = tableGroupJoin.getJoinedGroup().getModelPart(); if ( modelPart instanceof PluralAttributeMapping pluralAttributeMapping ) { - final NavigablePath elementPath = tableGroupJoin.getNavigablePath().append( pluralAttributeMapping.getElementDescriptor().getPartName() ); - paths.add( elementPath ); - - if ( pluralAttributeMapping.getIndexDescriptor() != null ) { - final NavigablePath indexPath = tableGroupJoin.getNavigablePath().append( pluralAttributeMapping.getIndexDescriptor().getPartName() ); - paths.add( indexPath ); + paths.add( navigablePath.append( pluralAttributeMapping.getElementDescriptor().getPartName() ) ); + final var indexDescriptor = pluralAttributeMapping.getIndexDescriptor(); + if ( indexDescriptor != null ) { + paths.add( navigablePath.append( indexDescriptor.getPartName() ) ); } } } ); @@ -554,47 +520,40 @@ public static Collection extractPathsToLock(LockingClauseStrategy } public static void segmentLoadedValues(List registrations, Map> map) { - if ( registrations == null ) { - return; + if ( registrations != null ) { + registrations.forEach( (registration) -> { + final var entityKeys = + map.computeIfAbsent( registration.entityDescriptor(), + entityMappingType -> new ArrayList<>() ); + entityKeys.add( registration.entityKey() ); + } ); } - - registrations.forEach( (registration) -> { - final List entityKeys = map.computeIfAbsent( - registration.entityDescriptor(), - entityMappingType -> new ArrayList<>() - ); - entityKeys.add( registration.entityKey() ); - } ); } public static void segmentLoadedCollections(List registrations, Map>> map) { - if ( registrations == null ) { - return; + if ( registrations != null ) { + registrations.forEach( (registration) -> { + final var pluralAttributeMapping = registration.collectionDescriptor(); + if ( pluralAttributeMapping.getSeparateCollectionTable() != null ) { + final var attributeKeys = + map.computeIfAbsent( pluralAttributeMapping.findContainingEntityMapping(), + entityMappingType -> new HashMap<>() ); + final var collectionKeys = + attributeKeys.computeIfAbsent( pluralAttributeMapping, + entityMappingType -> new ArrayList<>() ); + collectionKeys.add( registration.collectionKey() ); + } + } ); } - - registrations.forEach( (registration) -> { - final PluralAttributeMapping pluralAttributeMapping = registration.collectionDescriptor(); - if ( pluralAttributeMapping.getSeparateCollectionTable() != null ) { - final Map> attributeKeys = map.computeIfAbsent( - pluralAttributeMapping.findContainingEntityMapping(), - entityMappingType -> new HashMap<>() - ); - final List collectionKeys = attributeKeys.computeIfAbsent( - pluralAttributeMapping, - entityMappingType -> new ArrayList<>() - ); - collectionKeys.add( registration.collectionKey() ); - } - } ); } public static Map resolveEntityKeys(List entityKeys, ExecutionContext executionContext) { final Map map = new HashMap<>(); - final PersistenceContext persistenceContext = executionContext.getSession().getPersistenceContext(); + final var persistenceContext = executionContext.getSession().getPersistenceContext(); entityKeys.forEach( (entityKey) -> { final Object instance = persistenceContext.getEntity( entityKey ); - final EntityEntry entry = persistenceContext.getEntry( instance ); - map.put( entityKey.getIdentifierValue(), new EntityDetails( entityKey, entry, instance ) ); + final var entityEntry = persistenceContext.getEntry( instance ); + map.put( entityKey.getIdentifierValue(), new EntityDetails( entityKey, entityEntry, instance ) ); } ); return map; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingTableGroup.java index 60d64c7c16e8..0ecdb4ce8ee4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingTableGroup.java @@ -14,10 +14,11 @@ import org.hibernate.sql.ast.tree.from.TableReferenceJoin; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import static java.util.Collections.emptyList; + /** * TableGroup wrapping a {@linkplain TableLock table to be locked}. * @@ -71,7 +72,7 @@ public String getSourceAlias() { @Override public List getTableGroupJoins() { return tableGroupJoins == null - ? Collections.emptyList() + ? emptyList() : tableGroupJoins; } @@ -140,9 +141,6 @@ public ModelPart getExpressionType() { @Override public TableReference getTableReference(NavigablePath navigablePath, String tableExpression, boolean resolve) { - if ( tableName.equals( tableExpression ) ) { - return tableReference; - } - return null; + return tableName.equals( tableExpression ) ? tableReference : null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/TableLock.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/TableLock.java index 374a18eab487..c7291f806b13 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/TableLock.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/TableLock.java @@ -6,12 +6,9 @@ import org.hibernate.AssertionFailure; import org.hibernate.ScrollMode; -import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.TableDetails; @@ -19,8 +16,6 @@ import org.hibernate.persister.entity.UnionSubclassEntityPersister; import org.hibernate.query.spi.QueryOptions; import org.hibernate.spi.NavigablePath; -import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.from.NamedTableReference; @@ -36,11 +31,7 @@ import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; import org.hibernate.sql.exec.internal.JdbcParameterImpl; import org.hibernate.sql.exec.internal.StandardStatementCreator; -import org.hibernate.sql.exec.spi.ExecutionContext; -import org.hibernate.sql.exec.internal.JdbcOperationQuerySelect; import org.hibernate.sql.exec.spi.JdbcParameterBindings; -import org.hibernate.sql.exec.spi.JdbcSelect; -import org.hibernate.sql.exec.spi.JdbcSelectExecutor; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.spi.ListResultsConsumer; @@ -85,18 +76,25 @@ public TableLock( List entityKeys, SharedSessionContractImplementor session) { if ( SQL_EXEC_LOGGER.isDebugEnabled() ) { - SQL_EXEC_LOGGER.debugf( "Adding table `%s` for follow-on locking - %s", tableDetails.getTableName(), entityMappingType.getEntityName() ); + SQL_EXEC_LOGGER.addingTableForFollowOnLocking( tableDetails.getTableName(), entityMappingType.getEntityName() ); } this.tableDetails = tableDetails; this.entityMappingType = entityMappingType; - this.rootPath = new NavigablePath( tableDetails.getTableName() ); - this.physicalTableReference = new NamedTableReference( tableDetails.getTableName(), "tbl" ); - this.physicalTableGroup = new LockingTableGroup( physicalTableReference, tableDetails.getTableName(), entityMappingType, tableDetails.getKeyDetails() ); + rootPath = new NavigablePath( tableDetails.getTableName() ); + physicalTableReference = + new NamedTableReference( tableDetails.getTableName(), "tbl" ); + physicalTableGroup = + new LockingTableGroup( + physicalTableReference, + tableDetails.getTableName(), + entityMappingType, + tableDetails.getKeyDetails() + ); if ( entityMappingType.getEntityPersister() instanceof UnionSubclassEntityPersister usp ) { - final UnionTableReference unionTableReference = new UnionTableReference( + final var unionTableReference = new UnionTableReference( tableDetails.getTableName(), usp.getSynchronizedQuerySpaces(), "tbl", @@ -132,32 +130,36 @@ public TableLock( creationStates ) ); - final int expectedParamCount = entityKeys.size() * entityMappingType.getIdentifierMapping().getJdbcTypeCount(); + final int expectedParamCount = + entityKeys.size() * entityMappingType.getIdentifierMapping().getJdbcTypeCount(); jdbcParameterBindings = new JdbcParameterBindingsImpl( expectedParamCount ); applyKeyRestrictions( entityKeys, session ); } public void applyAttribute(int index, AttributeMapping attributeMapping) { - final NavigablePath attributePath = rootPath.append( attributeMapping.getPartName() ); + final var attributePath = rootPath.append( attributeMapping.getPartName() ); final DomainResult domainResult; final ResultHandler resultHandler; if ( attributeMapping instanceof ToOneAttributeMapping toOne ) { - domainResult = toOne.getForeignKeyDescriptor().getKeyPart().createDomainResult( - attributePath, - logicalTableGroup, - ForeignKeyDescriptor.PART_NAME, - creationStates - ); + domainResult = + toOne.getForeignKeyDescriptor().getKeyPart() + .createDomainResult( + attributePath, + logicalTableGroup, + ForeignKeyDescriptor.PART_NAME, + creationStates + ); resultHandler = new ToOneResultHandler( index, toOne ); } else { - domainResult = attributeMapping.createDomainResult( - attributePath, - logicalTableGroup, - null, - creationStates - ); + domainResult = + attributeMapping.createDomainResult( + attributePath, + logicalTableGroup, + null, + creationStates + ); resultHandler = new NonToOneResultHandler( index ); } domainResults.add( domainResult ); @@ -175,40 +177,37 @@ public void applyKeyRestrictions(List entityKeys, SharedSessionContra } private void applySimpleKeyRestriction(List entityKeys, SharedSessionContractImplementor session) { - final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping(); + final var identifierMapping = entityMappingType.getIdentifierMapping(); - final TableDetails.KeyColumn keyColumn = tableDetails.getKeyDetails().getKeyColumn( 0 ); - final ColumnReference columnReference = new ColumnReference( physicalTableReference, keyColumn ); + final var keyColumn = tableDetails.getKeyDetails().getKeyColumn( 0 ); + final var columnReference = new ColumnReference( physicalTableReference, keyColumn ); - final InListPredicate restriction = new InListPredicate( columnReference ); + final var restriction = new InListPredicate( columnReference ); querySpec.applyPredicate( restriction ); entityKeys.forEach( (entityKey) -> identifierMapping.breakDownJdbcValues( entityKey.getIdentifierValue(), (valueIndex, value, jdbcValueMapping) -> { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( - jdbcValueMapping.getJdbcMapping() ); + final var jdbcMapping = jdbcValueMapping.getJdbcMapping(); + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); restriction.addExpression( jdbcParameter ); - - jdbcParameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + jdbcParameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, value ) ); }, session ) ); } private void applyCompositeKeyRestriction(List entityKeys, SharedSessionContractImplementor session) { - final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping(); + final var identifierMapping = entityMappingType.getIdentifierMapping(); final ArrayList columnRefs = arrayList( tableDetails.getKeyDetails().getColumnCount() ); tableDetails.getKeyDetails().forEachKeyColumn( (position, keyColumn) -> { columnRefs.add( new ColumnReference( physicalTableReference, keyColumn ) ); } ); - final SqlTuple keyRef = new SqlTuple( columnRefs, identifierMapping ); + final var keyRef = new SqlTuple( columnRefs, identifierMapping ); - final InListPredicate restriction = new InListPredicate( keyRef ); + final var restriction = new InListPredicate( keyRef ); querySpec.applyPredicate( restriction ); entityKeys.forEach( (entityKey) -> { @@ -216,41 +215,37 @@ private void applyCompositeKeyRestriction(List entityKeys, SharedSess identifierMapping.breakDownJdbcValues( entityKey.getIdentifierValue(), (valueIndex, value, jdbcValueMapping) -> { - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcValueMapping.getJdbcMapping() ); + final var jdbcMapping = jdbcValueMapping.getJdbcMapping(); + final var jdbcParameter = new JdbcParameterImpl( jdbcMapping ); valueParams.add( jdbcParameter ); - jdbcParameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcValueMapping.getJdbcMapping(), value ) - ); + jdbcParameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, value ) ); }, session ); - final SqlTuple valueTuple = new SqlTuple( valueParams, identifierMapping ); + final var valueTuple = new SqlTuple( valueParams, identifierMapping ); restriction.addExpression( valueTuple ); } ); } public void performActions(Map entityDetailsMap, QueryOptions lockingQueryOptions, SharedSessionContractImplementor session) { - final SessionFactoryImplementor sessionFactory = session.getSessionFactory(); - final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); - - final SelectStatement selectStatement = new SelectStatement( querySpec, domainResults ); - final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcServices.getDialect().getSqlAstTranslatorFactory(); - final SqlAstTranslator translator = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, selectStatement ); - final JdbcSelect jdbcOperation = translator.translate( jdbcParameterBindings, lockingQueryOptions ); - - // IMPORTANT: we need a "clean" ExecutionContext to not further apply locking - final ExecutionContext executionContext = new BaseExecutionContext( session ); - final JdbcSelectExecutor jdbcSelectExecutor = jdbcServices.getJdbcSelectExecutor(); - final List results = jdbcSelectExecutor.executeQuery( - jdbcOperation, - jdbcParameterBindings, - executionContext, - row -> row, - Object[].class, - StandardStatementCreator.getStatementCreator( ScrollMode.FORWARD_ONLY ), - ListResultsConsumer.instance( ListResultsConsumer.UniqueSemantic.ALLOW ) - ); + final var sessionFactory = session.getSessionFactory(); + final var jdbcServices = sessionFactory.getJdbcServices(); + final var selectStatement = new SelectStatement( querySpec, domainResults ); + final List results = + jdbcServices.getJdbcSelectExecutor() + .executeQuery( + jdbcServices.getDialect().getSqlAstTranslatorFactory() + .buildSelectTranslator( sessionFactory, selectStatement ) + .translate( jdbcParameterBindings, lockingQueryOptions ), + jdbcParameterBindings, + // IMPORTANT: we need a "clean" ExecutionContext to not further apply locking + new BaseExecutionContext( session ), + row -> row, + Object[].class, + StandardStatementCreator.getStatementCreator( ScrollMode.FORWARD_ONLY ), + ListResultsConsumer.instance( ListResultsConsumer.UniqueSemantic.ALLOW ) + ); if ( isEmpty( results ) ) { throw new AssertionFailure( "Expecting results" ); @@ -258,7 +253,7 @@ public void performActions(Map entityDetailsMap, QueryOpt results.forEach( (row) -> { final Object id = row[0]; - final EntityDetails entityDetails = entityDetailsMap.get( id ); + final var entityDetails = entityDetailsMap.get( id ); for ( int i = 0; i < resultHandlers.size(); i++ ) { // offset 1 because of the id at position 0 resultHandlers.get( i ).applyResult( row[i+1], entityDetails, session ); @@ -324,11 +319,13 @@ public void applyResult(Object stateValue, EntityDetails entityDetails, SharedSe } private static void applyLoadedState(EntityDetails entityDetails, Integer statePosition, Object stateValue) { - if ( entityDetails.entry().getLoadedState() != null ) { - entityDetails.entry().getLoadedState()[statePosition] = stateValue; + final var entry = entityDetails.entry(); + final var loadedState = entry.getLoadedState(); + if ( loadedState != null ) { + loadedState[statePosition] = stateValue; } else { - if ( !entityDetails.entry().isReadOnly() ) { + if ( !entry.isReadOnly() ) { throw new AssertionFailure( "Expecting entity entry to be read-only - " + entityDetails.instance() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperationQueryCall.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperationQueryCall.java index aaaff44f0567..f9a51107a98e 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperationQueryCall.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperationQueryCall.java @@ -27,7 +27,7 @@ public interface JdbcOperationQueryCall extends JdbcOperationQueryAnonBlock { * @apiNote Note that REF_CURSOR parameters should be handled via * {@link #getCallRefCursorExtractors()} */ - List getParameterExtractors(); + List> getParameterExtractors(); /** * Extractors for REF_CURSOR (ResultSet) parameters