diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java index 62d9f1520a..9931f40e42 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java @@ -179,6 +179,17 @@ public class BulkOperationCleanupAction implements Executable, Serializable { } } + public static void schedule(ExecutionContext executionContext, Set affectedQueryables) { + final SharedSessionContractImplementor session = executionContext.getSession(); + final BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, affectedQueryables ); + if ( session.isEventSource() ) { + ( (EventSource) session ).getActionQueue().addAction( action ); + } + else { + action.getAfterTransactionCompletionProcess().doAfterTransactionCompletion( true, session ); + } + } + /** * Check whether we should consider an entity as affected by the query. This diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java index a8af2d09c5..f4e358691f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java @@ -166,7 +166,7 @@ public class DomainResultCreationStateImpl @Override public boolean forceIdentifierSelection() { - return false; + return true; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeNonSelectQueryPlanImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeNonSelectQueryPlanImpl.java index 5b52ba46a6..ee5bd472fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeNonSelectQueryPlanImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeNonSelectQueryPlanImpl.java @@ -6,24 +6,133 @@ */ package org.hibernate.query.sql.internal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.action.internal.BulkOperationCleanupAction; import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.mapping.BasicValuedMapping; +import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.MappingModelHelper; +import org.hibernate.metamodel.model.domain.AllowableParameterType; +import org.hibernate.query.NavigablePath; import org.hibernate.query.spi.NonSelectQueryPlan; +import org.hibernate.query.spi.QueryParameterBinding; +import org.hibernate.query.spi.QueryParameterBindings; +import org.hibernate.query.spi.QueryParameterImplementor; +import org.hibernate.query.spi.SqlOmittingQueryOptions; import org.hibernate.query.sql.spi.NativeQueryImplementor; +import org.hibernate.query.sqm.internal.SqmUtil; +import org.hibernate.query.sqm.mutation.internal.SqmMutationStrategyHelper; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.sql.ast.tree.from.MutatingTableReferenceGroupWrapper; +import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; +import org.hibernate.sql.ast.tree.select.QuerySpec; +import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl; +import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; +import org.hibernate.sql.exec.internal.JdbcParameterImpl; +import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl; +import org.hibernate.sql.exec.internal.StandardJdbcMutationExecutor; import org.hibernate.sql.exec.spi.ExecutionContext; +import org.hibernate.sql.exec.spi.JdbcDelete; +import org.hibernate.sql.exec.spi.JdbcMutation; +import org.hibernate.sql.exec.spi.JdbcMutationExecutor; +import org.hibernate.sql.exec.spi.JdbcParameterBinder; +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.exec.spi.NativeJdbcMutation; +import org.hibernate.sql.results.internal.SqlSelectionImpl; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; +import org.hibernate.sql.results.spi.RowTransformer; +import org.hibernate.type.StandardBasicTypes; /** * @author Steve Ebersole */ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan { - private final NativeQueryImplementor nativeQuery; + private final String sql; + private final Set affectedTableNames; - public NativeNonSelectQueryPlanImpl(NativeQueryImplementor nativeQuery) { - this.nativeQuery = nativeQuery; + private final List> parameterList; + + public NativeNonSelectQueryPlanImpl( + String sql, + Set affectedTableNames, + List> parameterList) { + this.sql = sql; + this.affectedTableNames = affectedTableNames; + this.parameterList = parameterList; } @Override public int executeUpdate(ExecutionContext executionContext) { - throw new NotYetImplementedFor6Exception(); + executionContext.getSession().autoFlushIfRequired( affectedTableNames ); + BulkOperationCleanupAction.schedule( executionContext, affectedTableNames ); + final List jdbcParameterBinders; + final JdbcParameterBindings jdbcParameterBindings; + + final QueryParameterBindings queryParameterBindings = executionContext.getQueryParameterBindings(); + if ( parameterList == null || parameterList.isEmpty() ) { + jdbcParameterBinders = Collections.emptyList(); + jdbcParameterBindings = JdbcParameterBindings.NO_BINDINGS; + } + else { + jdbcParameterBinders = new ArrayList<>( parameterList.size() ); + jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() ); + + for ( QueryParameterImplementor param : parameterList ) { + QueryParameterBinding binding = queryParameterBindings.getBinding( param ); + AllowableParameterType type = binding.getBindType(); + if ( type == null ) { + type = param.getHibernateType(); + } + if ( type == null ) { + type = StandardBasicTypes.OBJECT_TYPE; + } + + final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping(); + final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); + + jdbcParameterBinders.add( jdbcParameter ); + + jdbcParameterBindings.addBinding( + jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() ) + ); + } + } + + final JdbcMutation jdbcMutation = new NativeJdbcMutation( + sql, + jdbcParameterBinders, + affectedTableNames + ); + + final JdbcMutationExecutor executor = StandardJdbcMutationExecutor.INSTANCE; + + final SharedSessionContractImplementor session = executionContext.getSession(); + // TODO: use configurable executor instead? +// final SessionFactoryImplementor factory = session.getFactory(); +// final JdbcServices jdbcServices = factory.getJdbcServices(); +// return jdbcServices.getJdbcMutationExecutor().execute( + return executor.execute( + jdbcMutation, + jdbcParameterBindings, + sql -> session + .getJdbcCoordinator() + .getStatementPreparer() + .prepareStatement( sql ), + (integer, preparedStatement) -> {}, + executionContext + ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java index 5e6d8e9fcb..a7d0f3bb0f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java @@ -266,6 +266,7 @@ public class NativeQueryImpl this.parameterMetadata = parameterInterpretation.toParameterMetadata( session ); this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters(); this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() ); + this.querySpaces = new HashSet<>(); this.resultSetMapping = new ResultSetMappingImpl( resultSetMappingMemento.getName() ); resultSetMappingMemento.resolve( @@ -301,7 +302,10 @@ public class NativeQueryImpl protected void applyOptions(NamedNativeQueryMemento memento) { super.applyOptions( memento ); - this.querySpaces = CollectionHelper.makeCopy( memento.getQuerySpaces() ); + final Set copy = CollectionHelper.makeCopy( memento.getQuerySpaces() ); + if ( copy != null ) { + this.querySpaces = copy; + } // todo (6.0) : query returns } @@ -579,7 +583,7 @@ public class NativeQueryImpl } if ( queryPlan == null ) { - queryPlan = new NativeNonSelectQueryPlanImpl( this ); + queryPlan = new NativeNonSelectQueryPlanImpl( sqlString, querySpaces, occurrenceOrderedParamList ); if ( cacheKey != null ) { getSession().getFactory().getQueryEngine().getInterpretationCache().cacheNonSelectQueryPlan( cacheKey, queryPlan ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java index bf0e805daa..d91e614bba 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java @@ -18,6 +18,7 @@ import org.hibernate.internal.EmptyScrollableResults; import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.model.domain.AllowableParameterType; +import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterImplementor; import org.hibernate.query.spi.ScrollableResultsImplementor; @@ -87,27 +88,26 @@ public class NativeSelectQueryPlanImpl implements NativeSelectQueryPlan { jdbcParameterBinders = new ArrayList<>( parameterList.size() ); jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() ); - queryParameterBindings.visitBindings( - (param, binding) -> { - AllowableParameterType type = binding.getBindType(); - if ( type == null ) { - type = param.getHibernateType(); - } - if ( type == null ) { - type = StandardBasicTypes.OBJECT_TYPE; - } + for ( QueryParameterImplementor param : parameterList ) { + QueryParameterBinding binding = queryParameterBindings.getBinding( param ); + AllowableParameterType type = binding.getBindType(); + if ( type == null ) { + type = param.getHibernateType(); + } + if ( type == null ) { + type = StandardBasicTypes.OBJECT_TYPE; + } - final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping(); - final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); + final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping(); + final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping ); - jdbcParameterBinders.add( jdbcParameter ); + jdbcParameterBinders.add( jdbcParameter ); - jdbcParameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() ) - ); - } - ); + jdbcParameterBindings.addBinding( + jdbcParameter, + new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() ) + ); + } } executionContext.getSession().autoFlushIfRequired( affectedTableNames ); @@ -122,6 +122,11 @@ public class NativeSelectQueryPlanImpl implements NativeSelectQueryPlan { final JdbcSelectExecutor executor = JdbcSelectExecutorStandardImpl.INSTANCE; + // TODO: use configurable executor instead? +// final SharedSessionContractImplementor session = executionContext.getSession(); +// final SessionFactoryImplementor factory = session.getFactory(); +// final JdbcServices jdbcServices = factory.getJdbcServices(); +// return jdbcServices.getJdbcMutationExecutor().execute( return executor.list( jdbcSelect, jdbcParameterBindings, diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/NativeJdbcMutation.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/NativeJdbcMutation.java new file mode 100644 index 0000000000..1faab96913 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/NativeJdbcMutation.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.exec.spi; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.hibernate.internal.FilterJdbcParameter; + +/** + * Executable JDBC command + * + * @author Christian Beikov + */ +public class NativeJdbcMutation implements JdbcMutation { + private final String sql; + private final List parameterBinders; + private final Set affectedTableNames; + + public NativeJdbcMutation( + String sql, + List parameterBinders, + Set affectedTableNames) { + this.sql = sql; + this.parameterBinders = parameterBinders; + this.affectedTableNames = affectedTableNames; + } + + @Override + public String getSql() { + return sql; + } + + @Override + public List getParameterBinders() { + return parameterBinders; + } + + @Override + public Set getAffectedTableNames() { + return affectedTableNames; + } + + @Override + public Set getFilterJdbcParameters() { + return Collections.EMPTY_SET; + } + +}