From afda692608a7d354b9a320d6ca02c1af451d294f Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 5 Dec 2025 10:07:12 +0100 Subject: [PATCH 1/3] refactoring and cleanup to the procedure.internal package --- .../NamedProcedureCallDefinitionImpl.java | 7 +- .../internal/EntityDomainResultBuilder.java | 4 +- .../internal/FunctionReturnImpl.java | 13 +- .../procedure/internal/ProcedureCallImpl.java | 317 ++++++++---------- .../internal/ProcedureOutputsImpl.java | 26 +- .../internal/ProcedureParamBindings.java | 57 ++-- .../ProcedureParameterBindingImpl.java | 4 +- .../internal/ProcedureParameterImpl.java | 75 +++-- .../ProcedureParameterMetadataImpl.java | 16 +- .../internal/ScalarDomainResultBuilder.java | 4 +- .../hibernate/procedure/internal/Util.java | 37 +- ...ProcedureParameterMetadataImplementor.java | 16 + 12 files changed, 275 insertions(+), 301 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java index 8cc3c7e380c6..a0eb40699f28 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java @@ -20,7 +20,6 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.procedure.internal.NamedCallableQueryMementoImpl; -import org.hibernate.procedure.internal.Util; import org.hibernate.procedure.spi.NamedCallableQueryMemento; import org.hibernate.procedure.spi.ParameterStrategy; import org.hibernate.query.results.ResultSetMapping; @@ -29,6 +28,8 @@ import jakarta.persistence.ParameterMode; import jakarta.persistence.StoredProcedureParameter; +import static org.hibernate.procedure.internal.Util.resolveResultSetMappingClasses; +import static org.hibernate.procedure.internal.Util.resolveResultSetMappingNames; import static org.hibernate.procedure.spi.NamedCallableQueryMemento.ParameterMemento; /** @@ -96,7 +97,7 @@ public NamedCallableQueryMemento resolve(SessionFactoryImplementor sessionFactor final ResultSetMapping resultSetMapping = buildResultSetMapping( registeredName, sessionFactory ); if ( specifiesResultClasses ) { - Util.resolveResultSetMappingClasses( + resolveResultSetMappingClasses( resultClasses, resultSetMapping, collectedQuerySpaces::add, @@ -104,7 +105,7 @@ public NamedCallableQueryMemento resolve(SessionFactoryImplementor sessionFactor ); } else if ( specifiesResultSetMappings ) { - Util.resolveResultSetMappingNames( + resolveResultSetMappingNames( resultSetMappings, resultSetMapping, collectedQuerySpaces::add, diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java index 11a3f45b0955..3474537561be 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java @@ -19,13 +19,13 @@ /** * @author Christian Beikov */ -public class EntityDomainResultBuilder implements ResultBuilder { +class EntityDomainResultBuilder implements ResultBuilder { private final NavigablePath navigablePath; private final EntityMappingType entityDescriptor; private final FetchBuilderBasicValued discriminatorFetchBuilder; - public EntityDomainResultBuilder(EntityMappingType entityDescriptor) { + EntityDomainResultBuilder(EntityMappingType entityDescriptor) { this.entityDescriptor = entityDescriptor; this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() ); final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/FunctionReturnImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/FunctionReturnImpl.java index fce45e336280..887f9ecdc258 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/FunctionReturnImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/FunctionReturnImpl.java @@ -17,23 +17,20 @@ import org.hibernate.sql.exec.internal.JdbcCallParameterExtractorImpl; import org.hibernate.sql.exec.internal.JdbcCallRefCursorExtractorImpl; import org.hibernate.sql.exec.spi.JdbcCallFunctionReturn; -import org.hibernate.type.BasicType; -import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.spi.TypeConfiguration; import jakarta.persistence.ParameterMode; /** * @author Steve Ebersole */ -public class FunctionReturnImpl implements FunctionReturnImplementor { +class FunctionReturnImpl implements FunctionReturnImplementor { private final ProcedureCallImplementor procedureCall; private final int sqlTypeCode; private OutputableType ormType; - public FunctionReturnImpl(ProcedureCallImplementor procedureCall, int sqlTypeCode) { + FunctionReturnImpl(ProcedureCallImplementor procedureCall, int sqlTypeCode) { this.procedureCall = procedureCall; this.sqlTypeCode = sqlTypeCode; } @@ -67,11 +64,11 @@ private OutputableType getOrmType(SharedSessionContractImplementor persistenc return ormType; } else { - final TypeConfiguration typeConfiguration = persistenceContext.getFactory().getTypeConfiguration(); - final JavaType javaType = + final var typeConfiguration = persistenceContext.getFactory().getTypeConfiguration(); + final var javaType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( getJdbcTypeCode() ) .getJdbcRecommendedJavaTypeMapping( null, null, typeConfiguration ); - final BasicType basicType = + final var basicType = typeConfiguration.standardBasicTypeForJavaType( javaType.getJavaTypeClass() ); //noinspection unchecked return (OutputableType) basicType; diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java index 798d3f729b57..3cc5a614cee4 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java @@ -31,11 +31,13 @@ import org.hibernate.procedure.ProcedureOutputs; import org.hibernate.procedure.spi.FunctionReturnImplementor; import org.hibernate.procedure.spi.NamedCallableQueryMemento; +import org.hibernate.procedure.spi.NamedCallableQueryMemento.ParameterMemento; import org.hibernate.procedure.spi.ParameterStrategy; import org.hibernate.procedure.spi.ProcedureCallImplementor; import org.hibernate.procedure.spi.ProcedureParameterImplementor; import org.hibernate.query.KeyedPage; import org.hibernate.query.KeyedResultList; +import org.hibernate.query.spi.ProcedureParameterMetadataImplementor; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmBindableType; import org.hibernate.sql.exec.spi.JdbcOperationQueryCall; @@ -50,8 +52,6 @@ import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.ScrollableResultsImplementor; -import org.hibernate.query.sqm.SqmExpressible; -import org.hibernate.result.Output; import org.hibernate.result.ResultSetOutput; import org.hibernate.result.UpdateCountOutput; import org.hibernate.result.internal.OutputsExecutionContext; @@ -78,6 +78,7 @@ import jakarta.persistence.metamodel.Type; import static java.lang.Boolean.parseBoolean; +import static java.lang.Integer.parseInt; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; @@ -89,6 +90,7 @@ import static org.hibernate.jpa.HibernateHints.HINT_CALLABLE_FUNCTION_RETURN_TYPE; import static org.hibernate.procedure.internal.NamedCallableQueryMementoImpl.ParameterMementoImpl.fromRegistration; import static org.hibernate.procedure.internal.Util.resolveResultSetMappingClasses; +import static org.hibernate.procedure.internal.Util.resolveResultSetMappingNames; import static org.hibernate.procedure.internal.Util.resolveResultSetMappings; import static org.hibernate.query.results.ResultSetMapping.resolveResultSetMapping; @@ -105,7 +107,7 @@ public class ProcedureCallImpl private FunctionReturnImpl functionReturn; - private final ProcedureParameterMetadataImpl parameterMetadata; + private final ProcedureParameterMetadataImplementor parameterMetadata; private final ProcedureParamBindings parameterBindings; private final ResultSetMapping resultSetMapping; @@ -117,29 +119,45 @@ public class ProcedureCallImpl private ProcedureOutputsImpl outputs; private static String mappingId(String procedureName, Class[] resultClasses) { + assert resultClasses != null && resultClasses.length > 0; return procedureName + ":" + join( ",", resultClasses ); } private static String mappingId(String procedureName, String[] resultSetMappingNames) { + assert resultSetMappingNames != null && resultSetMappingNames.length > 0; return procedureName + ":" + join( ",", resultSetMappingNames ); } + private void registerParameters(SharedSessionContractImplementor session, NamedCallableQueryMemento memento) { + memento.getParameterMementos() + .forEach( parameterMemento -> registerParameter( parameterMemento.resolve( session ) ) ); + } + + private ProcedureCallImpl( + SharedSessionContractImplementor session, + String procedureName, + String resultSetMappingName, + boolean resultSetMappingDynamic, + Set synchronizedQuerySpaces) { + super( session ); + this.procedureName = procedureName; + this.synchronizedQuerySpaces = synchronizedQuerySpaces; + final var factory = session.getSessionFactory(); + resultSetMapping = resolveResultSetMapping( resultSetMappingName, resultSetMappingDynamic, factory ); + parameterMetadata = new ProcedureParameterMetadataImpl(); + parameterBindings = new ProcedureParamBindings( parameterMetadata, factory ); + } + /** * The no-returns form. * * @param session The session * @param procedureName The name of the procedure to call */ - public ProcedureCallImpl(SharedSessionContractImplementor session, String procedureName) { - super( session ); - this.procedureName = procedureName; - - parameterMetadata = new ProcedureParameterMetadataImpl(); - parameterBindings = new ProcedureParamBindings( parameterMetadata, getSessionFactory() ); - - resultSetMapping = resolveResultSetMapping( procedureName, true, session.getSessionFactory() ); - - synchronizedQuerySpaces = null; + public ProcedureCallImpl( + SharedSessionContractImplementor session, + String procedureName) { + this( session, procedureName, procedureName, true, null ); } /** @@ -149,22 +167,14 @@ public ProcedureCallImpl(SharedSessionContractImplementor session, String proced * @param procedureName The name of the procedure to call * @param resultClasses The classes making up the result */ - public ProcedureCallImpl(SharedSessionContractImplementor session, String procedureName, Class... resultClasses) { - super( session ); - - assert resultClasses != null && resultClasses.length > 0; - - this.procedureName = procedureName; - - final var factory = session.getSessionFactory(); - - parameterMetadata = new ProcedureParameterMetadataImpl(); - parameterBindings = new ProcedureParamBindings( parameterMetadata, factory ); - - synchronizedQuerySpaces = new HashSet<>(); - - resultSetMapping = resolveResultSetMapping( mappingId( procedureName, resultClasses ), factory ); - + public ProcedureCallImpl( + SharedSessionContractImplementor session, + String procedureName, + Class... resultClasses) { + this( session, procedureName, + mappingId( procedureName, resultClasses ), + false, + new HashSet<>() ); resolveResultSetMappingClasses( resultClasses, resultSetMapping, @@ -184,22 +194,11 @@ public ProcedureCallImpl( final SharedSessionContractImplementor session, String procedureName, String... resultSetMappingNames) { - super( session ); - - assert resultSetMappingNames != null && resultSetMappingNames.length > 0; - - this.procedureName = procedureName; - - final var factory = session.getSessionFactory(); - - parameterMetadata = new ProcedureParameterMetadataImpl(); - parameterBindings = new ProcedureParamBindings( parameterMetadata, factory ); - - synchronizedQuerySpaces = new HashSet<>(); - - resultSetMapping = resolveResultSetMapping( mappingId( procedureName, resultSetMappingNames ), factory ); - - Util.resolveResultSetMappingNames( + this( session, procedureName, + mappingId( procedureName, resultSetMappingNames ), + false, + new HashSet<>() ); + resolveResultSetMappingNames( resultSetMappingNames, resultSetMapping, synchronizedQuerySpaces::add, @@ -213,20 +212,13 @@ public ProcedureCallImpl( * @param session The session * @param memento The named/stored memento */ - ProcedureCallImpl(SharedSessionContractImplementor session, NamedCallableQueryMemento memento) { - super( session ); - - procedureName = memento.getCallableName(); - - final var factory = session.getSessionFactory(); - - parameterMetadata = new ProcedureParameterMetadataImpl( memento, session ); - parameterBindings = new ProcedureParamBindings( parameterMetadata, factory ); - - synchronizedQuerySpaces = makeCopy( memento.getQuerySpaces() ); - - resultSetMapping = resolveResultSetMapping( memento.getRegistrationName(), factory ); - + ProcedureCallImpl( + SharedSessionContractImplementor session, + NamedCallableQueryMemento memento) { + this( session, memento.getCallableName(), + memento.getRegistrationName(), + false, + makeCopy( memento.getQuerySpaces() ) ); resolveResultSetMappings( memento.getResultSetMappingNames(), memento.getResultSetMappingClasses(), @@ -234,7 +226,7 @@ public ProcedureCallImpl( synchronizedQuerySpaces::add, this::getSessionFactory ); - + registerParameters( session, memento ); applyOptions( memento ); } @@ -248,19 +240,10 @@ public ProcedureCallImpl( SharedSessionContractImplementor session, NamedCallableQueryMemento memento, Class... resultTypes) { - super( session ); - - procedureName = memento.getCallableName(); - - final var factory = session.getSessionFactory(); - - parameterMetadata = new ProcedureParameterMetadataImpl( memento, session ); - parameterBindings = new ProcedureParamBindings( parameterMetadata, factory ); - - synchronizedQuerySpaces = makeCopy( memento.getQuerySpaces() ); - - resultSetMapping = resolveResultSetMapping( mappingId( procedureName, resultTypes ), factory ); - + this( session, memento.getCallableName(), + mappingId( memento.getCallableName(), resultTypes ), + false, + makeCopy( memento.getQuerySpaces() ) ); resolveResultSetMappings( null, resultTypes, @@ -268,7 +251,7 @@ public ProcedureCallImpl( synchronizedQuerySpaces::add, this::getSessionFactory ); - + registerParameters( session, memento ); applyOptions( memento ); } @@ -276,19 +259,10 @@ public ProcedureCallImpl( SharedSessionContractImplementor session, NamedCallableQueryMementoImpl memento, String... resultSetMappingNames) { - super( session ); - - procedureName = memento.getCallableName(); - - final var factory = session.getSessionFactory(); - - parameterMetadata = new ProcedureParameterMetadataImpl( memento, session ); - parameterBindings = new ProcedureParamBindings( parameterMetadata, factory ); - - synchronizedQuerySpaces = makeCopy( memento.getQuerySpaces() ); - - resultSetMapping = resolveResultSetMapping( mappingId( procedureName, resultSetMappingNames ), factory ); - + this( session, memento.getCallableName(), + mappingId( memento.getCallableName(), resultSetMappingNames ), + false, + makeCopy( memento.getQuerySpaces() ) ); resolveResultSetMappings( resultSetMappingNames, null, @@ -296,7 +270,7 @@ public ProcedureCallImpl( synchronizedQuerySpaces::add, this::getSessionFactory ); - + registerParameters( session, memento ); applyOptions( memento ); } @@ -332,7 +306,7 @@ public MutableQueryOptions getQueryOptions() { } @Override - public ProcedureParameterMetadataImpl getParameterMetadata() { + public ProcedureParameterMetadataImplementor getParameterMetadata() { return parameterMetadata; } @@ -369,7 +343,7 @@ private void markAsFunctionCallRefRefCursor() { public ProcedureCallImpl markAsFunctionCall(Class resultType) { final var basicType = getTypeConfiguration().getBasicTypeForJavaType( resultType ); if ( basicType == null ) { - throw new IllegalArgumentException( "Could not resolve a BasicType for the java type: " + resultType.getName() ); + throw new IllegalArgumentException( "Could not resolve a BasicType for the Java type: " + resultType.getName() ); } markAsFunctionCall( basicType ); return this; @@ -381,7 +355,7 @@ public ProcedureCall markAsFunctionCall(Type typeReference) { throw new IllegalArgumentException( "Given type is not an OutputableType: " + typeReference ); } if ( resultSetMapping.getNumberOfResultBuilders() == 0 ) { - final SqmExpressible expressible = resolveExpressible( typeReference ); + final var expressible = resolveExpressible( typeReference ); // Function returns might not be represented as callable parameters, // but we still want to convert the result to the requested java type if possible resultSetMapping.addResultBuilder( new ScalarDomainResultBuilder<>( expressible.getExpressibleJavaType() ) ); @@ -510,12 +484,12 @@ private SqmBindableType resolveExpressible(Type typeReference) { } private void registerParameter(ProcedureParameterImplementor parameter) { - getParameterMetadata().registerParameter( parameter ); + parameterMetadata.registerParameter( parameter ); } @Override public ProcedureParameterImplementor getParameterRegistration(int position) { - return getParameterMetadata().getQueryParameter( position ); + return parameterMetadata.getQueryParameter( position ); } @Override @@ -556,12 +530,12 @@ public ProcedureParameterImplementor registerParameter( @Override public ProcedureParameterImplementor getParameterRegistration(String name) { - return getParameterMetadata().getQueryParameter( name ); + return parameterMetadata.getQueryParameter( name ); } @Override public List> getRegisteredParameters() { - return unmodifiableList( getParameterMetadata().getRegistrationsAsList() ); + return unmodifiableList( parameterMetadata.getRegistrationsAsList() ); } @Override @@ -651,8 +625,9 @@ private ProcedureOutputsImpl buildOutputs() { private Map, JdbcCallParameterRegistration> collectParameterRegistrations(JdbcOperationQueryCall call) { final Map, JdbcCallParameterRegistration> parameterRegistrations = new IdentityHashMap<>(); - if ( call.getFunctionReturn() != null ) { - parameterRegistrations.put( functionReturn, call.getFunctionReturn() ); + final var funReturn = call.getFunctionReturn(); + if ( funReturn != null ) { + parameterRegistrations.put( functionReturn, funReturn ); } final var registrations = getParameterMetadata().getRegistrationsAsList(); final var jdbcParameters = call.getParameterRegistrations(); @@ -665,8 +640,9 @@ private Map, JdbcCallParameterRegistration> collectParamet private List collectRefCursorExtractors(JdbcOperationQueryCall call) { final List refCursorExtractors = new ArrayList<>(); - if ( call.getFunctionReturn() != null ) { - final var refCursorExtractor = call.getFunctionReturn().getRefCursorExtractor(); + final var funReturn = call.getFunctionReturn(); + if ( funReturn != null ) { + final var refCursorExtractor = funReturn.getRefCursorExtractor(); if ( refCursorExtractor != null ) { refCursorExtractors.add( refCursorExtractor ); } @@ -674,8 +650,7 @@ private List collectRefCursorExtractors(JdbcOperatio final var registrations = getParameterMetadata().getRegistrationsAsList(); final var jdbcParameters = call.getParameterRegistrations(); for ( int i = 0; i < registrations.size(); i++ ) { - final var jdbcCallParameterRegistration = jdbcParameters.get( i ); - final var refCursorExtractor = jdbcCallParameterRegistration.getRefCursorExtractor(); + final var refCursorExtractor = jdbcParameters.get( i ).getRefCursorExtractor(); if ( refCursorExtractor != null ) { refCursorExtractors.add( refCursorExtractor ); } @@ -685,7 +660,7 @@ private List collectRefCursorExtractors(JdbcOperatio private JdbcParameterBindings parameterBindings( Map, JdbcCallParameterRegistration> parameterRegistrations) { - final JdbcParameterBindings jdbcParameterBindings = + final var jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterRegistrations.size() ); for ( var entry : parameterRegistrations.entrySet() ) { final var registration = entry.getValue(); @@ -694,20 +669,18 @@ private JdbcParameterBindings parameterBindings( final var parameter = entry.getKey(); final var binding = getParameterBindings().getBinding( parameter ); if ( !binding.isBound() ) { - if ( parameter.getPosition() == null ) { - throw new IllegalArgumentException( "The parameter named [" + parameter + "] was not set! You need to call the setParameter method." ); + if ( parameter.isNamed() ) { + throw new IllegalArgumentException( "The parameter named '" + parameter + "' was not set" ); } else { - throw new IllegalArgumentException( "The parameter at position [" + parameter + "] was not set! You need to call the setParameter method." ); + throw new IllegalArgumentException( "The parameter at position " + parameter + " was not set" ); } } final var parameterType = (JdbcMapping) registration.getParameterType(); jdbcParameterBindings.addBinding( (JdbcParameter) parameterBinder, - new JdbcParameterBindingImpl( - parameterType, - parameterType.convertToRelationalValue( binding.getBindValue() ) - ) + new JdbcParameterBindingImpl( parameterType, + parameterType.convertToRelationalValue( binding.getBindValue() ) ) ); } } @@ -785,14 +758,13 @@ public NamedCallableQueryMemento toMemento(String name) { ); } - private static List toParameterMementos( - ProcedureParameterMetadataImpl parameterMetadata) { + private static List toParameterMementos( + ProcedureParameterMetadataImplementor parameterMetadata) { if ( parameterMetadata.getParameterStrategy() == ParameterStrategy.UNKNOWN ) { - // none... return emptyList(); } else { - final List mementos = new ArrayList<>(); + final List mementos = new ArrayList<>(); parameterMetadata.visitRegistrations( queryParameter -> mementos.add( fromRegistration( (ProcedureParameterImplementor) queryParameter ) ) @@ -815,12 +787,10 @@ public Query applyGraph(@SuppressWarnings("rawtypes") RootGraph graph, GraphS // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // outputs - private ProcedureOutputs procedureResult; - @Override public boolean execute() { try { - return outputs().getCurrent() instanceof ResultSetOutput; + return getOutputs().getCurrent() instanceof ResultSetOutput; } catch (NoMoreOutputsException e) { return false; @@ -834,30 +804,23 @@ public boolean execute() { } } - protected ProcedureOutputs outputs() { - if ( procedureResult == null ) { - procedureResult = getOutputs(); - } - return procedureResult; - } - @Override protected int doExecuteUpdate() { - // the expectation is that there is just one Output, of type UpdateCountOutput + // The expectation is that there is just one Output, of type UpdateCountOutput try { execute(); return getUpdateCount(); } finally { - outputs().release(); + getOutputs().release(); } } @Override public Object getOutputParameterValue(int position) { - // NOTE : according to spec (specifically), an exception thrown from this method should not mark for rollback. + // According to spec, an exception thrown from this method should not mark for rollback. try { - return outputs().getOutputParameterValue( position ); + return getOutputs().getOutputParameterValue( position ); } catch (ParameterStrategyException e) { throw new IllegalArgumentException( "Invalid mix of named and positional parameters", e ); @@ -869,9 +832,9 @@ public Object getOutputParameterValue(int position) { @Override public Object getOutputParameterValue(String parameterName) { - // NOTE : according to spec (specifically), an exception thrown from this method should not mark for rollback. + // According to spec, an exception thrown from this method should not mark for rollback. try { - return outputs().getOutputParameterValue( parameterName ); + return getOutputs().getOutputParameterValue( parameterName ); } catch (ParameterStrategyException e) { throw new IllegalArgumentException( "Invalid mix of named and positional parameters", e ); @@ -883,17 +846,19 @@ public Object getOutputParameterValue(String parameterName) { @Override public boolean hasMoreResults() { - return outputs().goToNext() && outputs().getCurrent() instanceof ResultSetOutput; + final var outputs = getOutputs(); + return outputs.goToNext() + && outputs.getCurrent() instanceof ResultSetOutput; } @Override public int getUpdateCount() { try { - final Output rtn = outputs().getCurrent(); - if ( rtn == null ) { + final var output = getOutputs().getCurrent(); + if ( output == null ) { return -1; } - else if ( rtn instanceof UpdateCountOutput updateCount ) { + else if ( output instanceof UpdateCountOutput updateCount ) { return updateCount.getUpdateCount(); } else { @@ -919,7 +884,7 @@ protected List doList() { } else { try { - if ( outputs().getCurrent() instanceof ResultSetOutput resultSetOutput ) { + if ( getOutputs().getCurrent() instanceof ResultSetOutput resultSetOutput ) { return ((ResultSetOutput) resultSetOutput).getResultList(); } else { @@ -928,9 +893,9 @@ protected List doList() { } } catch (NoMoreOutputsException e) { - // todo : the spec is completely silent on these type of edge-case scenarios. - // Essentially here we'd have a case where there are no more results (ResultSets nor updateCount) but - // getResultList was called. + // TODO: the spec is completely silent on these type of edge-case scenarios. + // Essentially here we'd have a case where there are no more results + // (ResultSets nor updateCount) but getResultList() was called. return null; } catch (HibernateException he) { @@ -972,22 +937,13 @@ public List getResultList() { public R getSingleResult() { final var resultList = getResultList(); if ( resultList == null || resultList.isEmpty() ) { - throw new NoResultException( - String.format( - "Call to stored procedure [%s] returned no results", - getProcedureName() - ) - ); + throw new NoResultException( "Call to stored procedure '" + getProcedureName() + + "' returned no results" ); } else if ( resultList.size() > 1 ) { - throw new NonUniqueResultException( - String.format( - "Call to stored procedure [%s] returned multiple results", - getProcedureName() - ) - ); + throw new NonUniqueResultException( "Call to stored procedure '" + getProcedureName() + + "' returned multiple results" ); } - return resultList.get( 0 ); } @@ -998,14 +954,9 @@ public R getSingleResultOrNull() { return null; } else if ( resultList.size() > 1 ) { - throw new NonUniqueResultException( - String.format( - "Call to stored procedure [%s] returned multiple results", - getProcedureName() - ) - ); + throw new NonUniqueResultException( "Call to stored procedure '" + getProcedureName() + + "' returned multiple results" ); } - return resultList.get( 0 ); } @@ -1046,7 +997,7 @@ public T unwrap(Class type) { public ProcedureCallImplementor setLockMode(LockModeType lockMode) { // the JPA spec requires IllegalStateException here, even // though it's logically an UnsupportedOperationException - throw new IllegalStateException( "Illegal attempt to set lock mode for a procedure calls" ); + throw new IllegalStateException( "Illegal attempt to set lock mode for a procedure call" ); } @Override @@ -1062,7 +1013,7 @@ public ProcedureCallImplementor setTimeout(Integer timeout) { public LockModeType getLockMode() { // the JPA spec requires IllegalStateException here, even // though it's logically an UnsupportedOperationException - throw new IllegalStateException( "Illegal attempt to get lock mode on a native-query" ); + throw new IllegalStateException( "Illegal attempt to get lock mode for a procedure call" ); } @Override @Deprecated @@ -1070,39 +1021,33 @@ public QueryImplementor setLockOptions(LockOptions lockOptions) { throw new UnsupportedOperationException( "setLockOptions does not apply to procedure calls" ); } - @Override + @Override @SuppressWarnings("resource") public ProcedureCallImplementor setHint(String hintName, Object value) { switch ( hintName ) { case HINT_CALLABLE_FUNCTION: - if ( value != null ) { - if ( value instanceof Boolean bool ) { - if ( bool ) { - applyCallableFunctionHint(); - } - } - else if ( parseBoolean( value.toString() ) ) { - applyCallableFunctionHint(); - } + if ( value instanceof Boolean bool && bool + || value instanceof String string && parseBoolean( string ) ) { + applyCallableFunctionHint(); + } + else { + throw new IllegalArgumentException( "Illegal value for hint '" + hintName + "'" ); } break; case HINT_CALLABLE_FUNCTION_RETURN_TYPE: - if ( value != null ) { - if ( value instanceof Integer code ) { - //noinspection resource - markAsFunctionCall( code ); - } - else if ( value instanceof Type type ) { - //noinspection resource - markAsFunctionCall( type ); - } - else if ( value instanceof Class type ) { - //noinspection resource - markAsFunctionCall( type ); - } - else { - //noinspection resource - markAsFunctionCall( Integer.parseInt( value.toString() ) ); - } + if ( value instanceof Integer code ) { + markAsFunctionCall( code ); + } + else if ( value instanceof Type type ) { + markAsFunctionCall( type ); + } + else if ( value instanceof Class type ) { + markAsFunctionCall( type ); + } + else if ( value instanceof String string ) { + markAsFunctionCall( parseInt( string ) ); + } + else { + throw new IllegalArgumentException( "Illegal value for hint '" + hintName + "'" ); } break; default: diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureOutputsImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureOutputsImpl.java index d4686e03774f..5e7942736e49 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureOutputsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureOutputsImpl.java @@ -5,7 +5,6 @@ package org.hibernate.procedure.internal; import java.sql.CallableStatement; -import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -26,7 +25,7 @@ * * @author Steve Ebersole */ -public class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutputs { +class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutputs { private final ProcedureCallImpl procedureCall; private final CallableStatement callableStatement; @@ -53,7 +52,7 @@ public T getOutputParameterValue(ProcedureParameter parameter) { if ( parameter.getMode() == ParameterMode.IN ) { throw new ParameterMisuseException( "IN parameter not valid for output extraction" ); } - final JdbcCallParameterRegistration registration = parameterRegistrations.get( parameter ); + final var registration = parameterRegistrations.get( parameter ); if ( registration == null ) { throw new IllegalArgumentException( "Parameter [" + parameter + "] is not registered with this procedure call" ); } @@ -108,7 +107,7 @@ private ProcedureCurrentReturnState(boolean isResultSet, int updateCount, int re @Override public boolean indicatesMoreOutputs() { return super.indicatesMoreOutputs() - || ProcedureOutputsImpl.this.refCursorParamIndex < refCursorParameters.length; + || ProcedureOutputsImpl.this.refCursorParamIndex < refCursorParameters.length; } @Override @@ -118,8 +117,8 @@ protected boolean hasExtendedReturns() { @Override protected Output buildExtendedReturn() { - final JdbcCallRefCursorExtractor refCursorParam = refCursorParameters[ProcedureOutputsImpl.this.refCursorParamIndex++]; - final ResultSet resultSet = refCursorParam.extractResultSet( + final var refCursorParam = refCursorParameters[ProcedureOutputsImpl.this.refCursorParamIndex++]; + final var resultSet = refCursorParam.extractResultSet( callableStatement, procedureCall.getSession() ); @@ -133,13 +132,14 @@ protected boolean hasFunctionReturns() { @Override protected Output buildFunctionReturn() { - final Object result = parameterRegistrations.get( procedureCall.getFunctionReturn() ) - .getParameterExtractor() - .extractValue( - callableStatement, - false, - procedureCall.getSession() - ); + final Object result = + parameterRegistrations.get( procedureCall.getFunctionReturn() ) + .getParameterExtractor() + .extractValue( + callableStatement, + false, + procedureCall.getSession() + ); final List results = new ArrayList<>( 1 ); results.add( result ); return buildResultSetOutput( () -> results ); diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParamBindings.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParamBindings.java index f53fb220006a..95ed5c205ac4 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParamBindings.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParamBindings.java @@ -14,6 +14,7 @@ import org.hibernate.procedure.spi.ProcedureParameterBinding; import org.hibernate.procedure.spi.ProcedureParameterImplementor; import org.hibernate.query.QueryParameter; +import org.hibernate.query.spi.ProcedureParameterMetadataImplementor; import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterImplementor; @@ -29,87 +30,89 @@ public class ProcedureParamBindings implements QueryParameterBindings { private static final Logger LOG = Logger.getLogger( QueryParameterBindings.class ); - private final ProcedureParameterMetadataImpl parameterMetadata; + private final ProcedureParameterMetadataImplementor parameterMetadata; private final SessionFactoryImplementor sessionFactory; private final Map, ProcedureParameterBinding> bindingMap = new HashMap<>(); public ProcedureParamBindings( - ProcedureParameterMetadataImpl parameterMetadata, + ProcedureParameterMetadataImplementor parameterMetadata, SessionFactoryImplementor sessionFactory) { this.parameterMetadata = parameterMetadata; this.sessionFactory = sessionFactory; } - public ProcedureParameterMetadataImpl getParameterMetadata() { + public ProcedureParameterMetadataImplementor getParameterMetadata() { return parameterMetadata; } @Override public boolean isBound(QueryParameterImplementor parameter) { - //noinspection SuspiciousMethodCalls - return bindingMap.containsKey( parameter ); + return parameter instanceof ProcedureParameterImplementor + && bindingMap.containsKey( parameter ); } @Override public

ProcedureParameterBinding

getBinding(QueryParameterImplementor

parameter) { - return getQueryParamerBinding( (ProcedureParameterImplementor

) parameter ); + return getQueryParameterBinding( (ProcedureParameterImplementor

) parameter ); } - public

ProcedureParameterBinding

getQueryParamerBinding(ProcedureParameterImplementor

parameter) { + public

ProcedureParameterBinding

getQueryParameterBinding(ProcedureParameterImplementor

parameter) { final var procParam = parameterMetadata.resolve( parameter ); - var binding = bindingMap.get( procParam ); + final var binding = bindingMap.get( procParam ); if ( binding == null ) { if ( !parameterMetadata.containsReference( parameter ) ) { throw new IllegalArgumentException( "Passed parameter is not registered with this query" ); } - binding = new ProcedureParameterBindingImpl<>( procParam, sessionFactory ); - bindingMap.put( procParam, binding ); + final var parameterBinding = new ProcedureParameterBindingImpl<>( procParam, sessionFactory ); + bindingMap.put( procParam, parameterBinding ); + return parameterBinding; + } + else { + //noinspection unchecked + return (ProcedureParameterBinding

) binding; } - //noinspection unchecked - return (ProcedureParameterBinding

) binding; } @Override public

ProcedureParameterBinding

getBinding(String name) { - //noinspection unchecked - final var parameter = - (ProcedureParameterImplementor

) - parameterMetadata.getQueryParameter( name ); + final var parameter = parameterMetadata.getQueryParameter( name ); if ( parameter == null ) { - throw new IllegalArgumentException( "Parameter does not exist: " + name ); + throw new IllegalArgumentException( "Parameter with name '" + name + "' does not exist" ); } - return getQueryParamerBinding( parameter ); + //noinspection unchecked + return getQueryParameterBinding( (ProcedureParameterImplementor

) parameter ); } @Override public

ProcedureParameterBinding

getBinding(int position) { - //noinspection unchecked - final var parameter = - (ProcedureParameterImplementor

) - parameterMetadata.getQueryParameter( position ); + final var parameter = parameterMetadata.getQueryParameter( position ); if ( parameter == null ) { throw new IllegalArgumentException( "Parameter at position " + position + "does not exist" ); } - return getQueryParamerBinding( parameter ); + //noinspection unchecked + return getQueryParameterBinding( (ProcedureParameterImplementor

) parameter ); } @Override public void validate() { - parameterMetadata.visitRegistrations( parameter -> validate( (ProcedureParameterImplementor) parameter ) ); + if ( LOG.isDebugEnabled() ) { + parameterMetadata.visitRegistrations( + parameter -> validate( (ProcedureParameterImplementor) parameter ) ); + } } private void validate(ProcedureParameterImplementor procParam) { - final ParameterMode mode = procParam.getMode(); + final var mode = procParam.getMode(); if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT ) { if ( !getBinding( procParam ).isBound() ) { // depending on "pass nulls" this might be OK - for now, just log a warning - if ( procParam.getPosition() != null ) { + if ( procParam.isOrdinal() ) { LOG.debugf( "Procedure parameter at position %s is not bound", procParam.getPosition() ); } else { - LOG.debugf( "Procedure parameter %s is not bound", procParam.getName() ); + LOG.debugf( "Procedure parameter '%s' is not bound", procParam.getName() ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterBindingImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterBindingImpl.java index 8b1cf5a39536..cf80e1e8d8ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterBindingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterBindingImpl.java @@ -14,10 +14,10 @@ * * @author Steve Ebersole */ -public class ProcedureParameterBindingImpl +class ProcedureParameterBindingImpl extends QueryParameterBindingImpl implements ProcedureParameterBinding { - public ProcedureParameterBindingImpl( + ProcedureParameterBindingImpl( ProcedureParameterImplementor queryParameter, SessionFactoryImplementor sessionFactory) { super( queryParameter, sessionFactory ); diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java index 4ba366ceef69..9bb664d6874d 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java @@ -8,7 +8,6 @@ import java.util.Objects; import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; -import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.procedure.ParameterTypeException; import org.hibernate.procedure.spi.NamedCallableQueryMemento; import org.hibernate.procedure.spi.ParameterStrategy; @@ -16,7 +15,6 @@ import org.hibernate.procedure.spi.ProcedureParameterImplementor; import org.hibernate.type.BindableType; import org.hibernate.type.OutputableType; -import org.hibernate.type.internal.BindingTypeHelper; import org.hibernate.query.spi.AbstractQueryParameter; import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.sql.exec.internal.JdbcCallParameterExtractorImpl; @@ -30,10 +28,12 @@ import jakarta.persistence.ParameterMode; +import static org.hibernate.type.internal.BindingTypeHelper.resolveTemporalPrecision; + /** * @author Steve Ebersole */ -public class ProcedureParameterImpl extends AbstractQueryParameter implements ProcedureParameterImplementor { +class ProcedureParameterImpl extends AbstractQueryParameter implements ProcedureParameterImplementor { private final String name; private final Integer position; @@ -43,7 +43,7 @@ public class ProcedureParameterImpl extends AbstractQueryParameter impleme /** * Used for named Query parameters */ - public ProcedureParameterImpl( + ProcedureParameterImpl( String name, ParameterMode mode, Class javaType, @@ -101,12 +101,16 @@ public NamedCallableQueryMemento.ParameterMemento toMemento() { public JdbcCallParameterRegistration toJdbcParameterRegistration( int startIndex, ProcedureCallImplementor procedureCall) { - final QueryParameterBinding binding = procedureCall.getParameterBindings().getBinding( this ); - final boolean isNamed = procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && this.name != null; - final SharedSessionContractImplementor session = procedureCall.getSession(); + final QueryParameterBinding binding = + procedureCall.getParameterBindings() + .getBinding( this ); + final boolean isNamed = + procedureCall.getParameterStrategy() == ParameterStrategy.NAMED + && name != null; + final var session = procedureCall.getSession(); - final OutputableType typeToUse = (OutputableType) - BindingTypeHelper.resolveTemporalPrecision( + final var typeToUse = (OutputableType) + resolveTemporalPrecision( binding == null ? null : binding.getExplicitTemporalPrecision(), getBindableType( binding ), session.getFactory().getQueryEngine().getCriteriaBuilder() @@ -116,14 +120,20 @@ public JdbcCallParameterRegistration toJdbcParameterRegistration( final JdbcParameterBinder parameterBinder; final JdbcCallRefCursorExtractorImpl refCursorExtractor; final JdbcCallParameterExtractorImpl parameterExtractor; - final ExtractedDatabaseMetaData databaseMetaData = + final var databaseMetaData = session.getFactory().getJdbcServices().getJdbcEnvironment() .getExtractedDatabaseMetaData(); final boolean passProcedureParameterNames = - session.getFactory().getSessionFactoryOptions().isPassProcedureParameterNames(); + session.getFactory().getSessionFactoryOptions() + .isPassProcedureParameterNames(); switch ( mode ) { case REF_CURSOR: - jdbcParamName = this.name != null && databaseMetaData.supportsNamedParameters() && passProcedureParameterNames ? this.name : null; + jdbcParamName = + name != null + && databaseMetaData.supportsNamedParameters() + && passProcedureParameterNames + ? name + : null; refCursorExtractor = new JdbcCallRefCursorExtractorImpl( startIndex ); parameterBinder = null; parameterExtractor = null; @@ -151,12 +161,21 @@ public JdbcCallParameterRegistration toJdbcParameterRegistration( break; } - return new JdbcCallParameterRegistrationImpl( jdbcParamName, startIndex, mode, typeToUse, parameterBinder, parameterExtractor, refCursorExtractor ); + return new JdbcCallParameterRegistrationImpl( + jdbcParamName, + startIndex, + mode, + typeToUse, + parameterBinder, + parameterExtractor, + refCursorExtractor + ); } private BindableType getBindableType(QueryParameterBinding binding) { - if ( getHibernateType() != null ) { - return getHibernateType(); + final var type = getHibernateType(); + if ( type != null ) { + return type; } else if ( binding != null ) { //noinspection unchecked @@ -175,7 +194,7 @@ private String getJdbcParamName( ExtractedDatabaseMetaData databaseMetaData) { return isNamed && passProcedureParameterNames && canDoNameParameterBinding( typeToUse, procedureCall, databaseMetaData ) - ? this.name + ? name : null; } @@ -203,8 +222,8 @@ private JdbcParameterBinder getParameterBinder(BindableType typeToUse, String ) ); } - else if ( typeToUse instanceof BasicType ) { - return new JdbcParameterImpl( (BasicType) typeToUse ); + else if ( typeToUse instanceof BasicType basicType ) { + return new JdbcParameterImpl( basicType ); } else { throw new UnsupportedOperationException(); @@ -217,8 +236,8 @@ private boolean canDoNameParameterBinding( ExtractedDatabaseMetaData databaseMetaData) { return procedureCall.getFunctionReturn() == null && databaseMetaData.supportsNamedParameters() - && hibernateType instanceof ProcedureParameterNamedBinder - && ( (ProcedureParameterNamedBinder) hibernateType ).canDoSetting(); + && hibernateType instanceof ProcedureParameterNamedBinder binder + && binder.canDoSetting(); } @Override @@ -227,19 +246,21 @@ public int hashCode() { } @Override - public boolean equals(Object o) { - if ( this == o ) { + public boolean equals(Object object) { + if ( this == object ) { return true; } - if ( o == null ) { + else if ( object == null ) { return false; } - if ( !(o instanceof ProcedureParameterImpl that) ) { + else if ( !(object instanceof ProcedureParameterImpl that) ) { return false; } - return Objects.equals( name, that.name ) - && Objects.equals( position, that.position ) - && mode == that.mode; + else { + return Objects.equals( name, that.name ) + && Objects.equals( position, that.position ) + && mode == that.mode; + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java index ac0d02d98462..69c406535a22 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java @@ -14,8 +14,6 @@ import jakarta.persistence.Parameter; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.procedure.spi.NamedCallableQueryMemento; import org.hibernate.procedure.spi.ParameterStrategy; import org.hibernate.type.BindableType; import org.hibernate.query.QueryParameter; @@ -36,18 +34,19 @@ * * @author Steve Ebersole */ -public class ProcedureParameterMetadataImpl implements ProcedureParameterMetadataImplementor { +class ProcedureParameterMetadataImpl implements ProcedureParameterMetadataImplementor { private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN; private List> parameters; - public ProcedureParameterMetadataImpl() { + ProcedureParameterMetadataImpl() { } - public ProcedureParameterMetadataImpl(NamedCallableQueryMemento memento, SharedSessionContractImplementor session) { - memento.getParameterMementos() - .forEach( parameterMemento -> registerParameter( parameterMemento.resolve( session ) ) ); - } +// public ProcedureParameterMetadataImpl(NamedCallableQueryMemento memento, SharedSessionContractImplementor session) { +// memento.getParameterMementos() +// .forEach( parameterMemento -> registerParameter( parameterMemento.resolve( session ) ) ); +// } + @Override public void registerParameter(ProcedureParameterImplementor parameter) { if ( parameter.isNamed() ) { if ( parameterStrategy == ParameterStrategy.POSITIONAL ) { @@ -123,6 +122,7 @@ public boolean containsReference(QueryParameter parameter) { && parameters.contains( (ProcedureParameterImplementor) parameter ); } + @Override public ParameterStrategy getParameterStrategy() { return parameterStrategy; } diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java index 240436770c6c..3c21c2a2987f 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java @@ -20,10 +20,10 @@ /** * @author Steve Ebersole */ -public class ScalarDomainResultBuilder implements ResultBuilder { +class ScalarDomainResultBuilder implements ResultBuilder { private final JavaType typeDescriptor; - public ScalarDomainResultBuilder(JavaType typeDescriptor) { + ScalarDomainResultBuilder(JavaType typeDescriptor) { this.typeDescriptor = typeDescriptor; } diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java index 9145aaf77bca..319ff33ac5ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java @@ -6,15 +6,11 @@ import java.util.function.Consumer; -import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.metamodel.MappingMetamodel; -import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.UnknownSqlResultSetMappingException; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.named.NamedObjectRepository; -import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.results.ResultSetMapping; -import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry; + +import static org.hibernate.internal.util.collections.ArrayHelper.isEmpty; /** * Utilities used to implement procedure call support. @@ -28,18 +24,18 @@ private Util() { public static void resolveResultSetMappings( String[] resultSetMappingNames, - Class[] resultSetMappingClasses, + Class[] resultSetMappingClasses, ResultSetMapping resultSetMapping, Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { - if ( ! ArrayHelper.isEmpty( resultSetMappingNames ) ) { + if ( !isEmpty( resultSetMappingNames ) ) { // cannot specify both - if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) { + if ( !isEmpty( resultSetMappingClasses ) ) { throw new IllegalArgumentException( "Cannot specify both result-set mapping names and classes" ); } resolveResultSetMappingNames( resultSetMappingNames, resultSetMapping, querySpaceConsumer, context ); } - else if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) { + else if ( !isEmpty( resultSetMappingClasses ) ) { resolveResultSetMappingClasses( resultSetMappingClasses, resultSetMapping, querySpaceConsumer, context ); } @@ -51,31 +47,26 @@ public static void resolveResultSetMappingNames( ResultSetMapping resultSetMapping, Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { - final NamedObjectRepository namedObjectRepository = context.getNamedObjectRepository(); + final var namedObjectRepository = context.getNamedObjectRepository(); for ( String resultSetMappingName : resultSetMappingNames ) { - final NamedResultSetMappingMemento memento = + final var memento = namedObjectRepository.getResultSetMappingMemento( resultSetMappingName ); if ( memento == null ) { throw new UnknownSqlResultSetMappingException( "Unknown SqlResultSetMapping [" + resultSetMappingName + "]" ); } - memento.resolve( - resultSetMapping, - querySpaceConsumer, - context - ); + memento.resolve( resultSetMapping, querySpaceConsumer, context ); } } public static void resolveResultSetMappingClasses( - Class[] resultSetMappingClasses, + Class[] resultSetMappingClasses, ResultSetMapping resultSetMapping, Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { - final MappingMetamodel mappingMetamodel = context.getMappingMetamodel(); - final JavaTypeRegistry javaTypeRegistry = mappingMetamodel.getTypeConfiguration().getJavaTypeRegistry(); - - for ( Class resultSetMappingClass : resultSetMappingClasses ) { - final EntityPersister entityDescriptor = mappingMetamodel.findEntityDescriptor( resultSetMappingClass ); + final var mappingMetamodel = context.getMappingMetamodel(); + final var javaTypeRegistry = mappingMetamodel.getTypeConfiguration().getJavaTypeRegistry(); + for ( var resultSetMappingClass : resultSetMappingClasses ) { + final var entityDescriptor = mappingMetamodel.findEntityDescriptor( resultSetMappingClass ); if ( entityDescriptor != null ) { resultSetMapping.addResultBuilder( new EntityDomainResultBuilder( entityDescriptor ) ); for ( String querySpace : entityDescriptor.getSynchronizedQuerySpaces() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/ProcedureParameterMetadataImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/spi/ProcedureParameterMetadataImplementor.java index 4382ae09c303..25c86cac9e96 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/ProcedureParameterMetadataImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/ProcedureParameterMetadataImplementor.java @@ -6,9 +6,25 @@ import java.util.List; +import jakarta.persistence.Parameter; +import org.hibernate.procedure.spi.ParameterStrategy; import org.hibernate.procedure.spi.ProcedureParameterImplementor; public interface ProcedureParameterMetadataImplementor extends ParameterMetadataImplementor { + ParameterStrategy getParameterStrategy(); + + @Override + ProcedureParameterImplementor getQueryParameter(String name); + + @Override + ProcedureParameterImplementor getQueryParameter(int positionLabel); + + @Override +

ProcedureParameterImplementor

resolve(Parameter

parameter); + + void registerParameter(ProcedureParameterImplementor parameter); + List> getRegistrationsAsList(); + } From 47543b78f565d7ddafd67a830c3c7ecb48cdc869 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 5 Dec 2025 10:35:51 +0100 Subject: [PATCH 2/3] fix lots of NPEs in ProcedureParameterMetadataImpl these could happen when no parameter was registered due to the optimization of lazily initializing the list of parameters --- .../ProcedureParameterMetadataImpl.java | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java index 69c406535a22..cd77b4e06cba 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java @@ -18,7 +18,6 @@ import org.hibernate.type.BindableType; import org.hibernate.query.QueryParameter; import org.hibernate.query.internal.QueryParameterBindingsImpl; -import org.hibernate.procedure.ProcedureParameter; import org.hibernate.procedure.spi.ProcedureParameterImplementor; import org.hibernate.query.spi.ProcedureParameterMetadataImplementor; import org.hibernate.query.spi.QueryParameterBindings; @@ -38,14 +37,6 @@ class ProcedureParameterMetadataImpl implements ProcedureParameterMetadataImplem private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN; private List> parameters; - ProcedureParameterMetadataImpl() { - } - -// public ProcedureParameterMetadataImpl(NamedCallableQueryMemento memento, SharedSessionContractImplementor session) { -// memento.getParameterMementos() -// .forEach( parameterMemento -> registerParameter( parameterMemento.resolve( session ) ) ); -// } - @Override public void registerParameter(ProcedureParameterImplementor parameter) { if ( parameter.isNamed() ) { @@ -98,17 +89,18 @@ public boolean hasPositionalParameters() { @Override public Set getNamedParameterNames() { - if ( !hasNamedParameters() ) { - return emptySet(); - } - - final Set rtn = new HashSet<>(); - for ( ProcedureParameter parameter : parameters ) { - if ( parameter.getName() != null ) { - rtn.add( parameter.getName() ); + if ( hasNamedParameters() && parameters != null ) { + final Set names = new HashSet<>(); + for ( var parameter : parameters ) { + if ( parameter.getName() != null ) { + names.add( parameter.getName() ); + } } + return names; + } + else { + return emptySet(); } - return rtn; } @Override @@ -129,7 +121,7 @@ public ParameterStrategy getParameterStrategy() { @Override public boolean hasAnyMatching(Predicate> filter) { - if ( parameters.isEmpty() ) { + if ( parameters == null || parameters.isEmpty() ) { return false; } else { @@ -144,9 +136,11 @@ public boolean hasAnyMatching(Predicate> filter) { @Override public ProcedureParameterImplementor findQueryParameter(String name) { - for ( var parameter : parameters ) { - if ( name.equals( parameter.getName() ) ) { - return parameter; + if ( parameters != null ) { + for ( var parameter : parameters ) { + if ( name.equals( parameter.getName() ) ) { + return parameter; + } } } return null; @@ -163,9 +157,12 @@ public ProcedureParameterImplementor getQueryParameter(String name) { @Override public ProcedureParameterImplementor findQueryParameter(int positionLabel) { - for ( var parameter : parameters ) { - if ( parameter.getName() == null && positionLabel == parameter.getPosition() ) { - return parameter; + if ( parameters != null ) { + for ( var parameter : parameters ) { + if ( parameter.getName() == null + && positionLabel == parameter.getPosition() ) { + return parameter; + } } } return null; @@ -174,18 +171,20 @@ public ProcedureParameterImplementor findQueryParameter(int positionLabel) { @Override public ProcedureParameterImplementor getQueryParameter(int positionLabel) { final var queryParameter = findQueryParameter( positionLabel ); - if ( queryParameter != null ) { - return queryParameter; + if ( queryParameter == null ) { + throw new IllegalArgumentException( + "Positional parameter " + positionLabel + " is not registered with this procedure call" ); } - throw new IllegalArgumentException( "Positional parameter [" + positionLabel + "] is not registered with this procedure call" ); + return queryParameter; } @Override public

ProcedureParameterImplementor

resolve(Parameter

parameter) { - if ( parameter instanceof ProcedureParameterImplementor

parameterImplementor ) { + if ( parameters != null + && parameter instanceof ProcedureParameterImplementor

procedureParam ) { for ( var registered : parameters ) { if ( registered == parameter ) { - return parameterImplementor; + return procedureParam; } } } From 6872d80c5f2157cf3793e2c42097a63e8feab391 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 5 Dec 2025 11:15:42 +0100 Subject: [PATCH 3/3] fix annoying assertions that test error message text --- .../procedure/MySQLStoredProcedureTest.java | 5 +--- .../PostgreSQLFunctionProcedureTest.java | 29 ++++++++++--------- .../PostgreSQLStoredProcedureTest.java | 20 +++++-------- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/MySQLStoredProcedureTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/MySQLStoredProcedureTest.java index 68e09cc4e0af..0879dfab9c80 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/MySQLStoredProcedureTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/MySQLStoredProcedureTest.java @@ -408,10 +408,7 @@ public void testStoredProcedureNullParameterHibernateWithoutSettingTheParameter( fail( "Should have thrown exception" ); } catch (IllegalArgumentException e) { - assertEquals( - "The parameter at position [1] was not set! You need to call the setParameter method.", - e.getMessage() - ); + assertTrue( e.getMessage().contains( "parameter at position 1" ) ); } } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLFunctionProcedureTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLFunctionProcedureTest.java index 0aef95778b52..db9cc4f187af 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLFunctionProcedureTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLFunctionProcedureTest.java @@ -35,8 +35,10 @@ import java.time.ZoneOffset; import java.util.Set; -import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; /** @@ -186,7 +188,7 @@ public void testFunctionProcedureOutParameter() { query.execute(); Long phoneCount = (Long) query.getSingleResult(); - assertThat( phoneCount ).isEqualTo( 2 ); + assertEquals( 2, phoneCount ); } ); } @@ -199,7 +201,7 @@ public void testFunctionProcedureRefCursor() { query.setParameter( 1, 1L ); - assertThat( query.getResultList() ).hasSize( 2 ); + assertEquals( 2, query.getResultList().size() ); } ); } @@ -213,7 +215,7 @@ public void testFunctionProcedureRefCursorOld() { query.setParameter( 2, 1L ); - assertThat( query.getResultList() ).hasSize( 2 ); + assertEquals( 2, query.getResultList().size() ); } ); } @@ -236,7 +238,7 @@ public void testFunctionWithJDBC() { } } } ); - assertThat( phoneCount ).isEqualTo( 2 ); + assertEquals( 2, phoneCount ); } ); } @@ -270,7 +272,7 @@ public void testSysRefCursorAsOutParameter() { catch (Exception e) { fail( e.getMessage() ); } - assertThat( value ).isEqualTo( 1 ); + assertEquals( 1, value ); StoredProcedureQuery function = entityManager.createStoredProcedureQuery( "singleRefCursor" ); @@ -280,7 +282,7 @@ public void testSysRefCursorAsOutParameter() { value = (Integer) function.getSingleResult(); - assertThat( value ).isEqualTo( 1 ); + assertEquals( 1, value ); } ); } @@ -294,7 +296,7 @@ public void testSysRefCursorAsOutParameterOld() { function.execute(); - assertThat( function.hasMoreResults() ).isFalse(); + assertFalse( function.hasMoreResults() ); Integer value = null; try (ResultSet resultSet = (ResultSet) function.getOutputParameterValue( 1 )) { @@ -306,7 +308,7 @@ public void testSysRefCursorAsOutParameterOld() { fail( e.getMessage() ); } - assertThat( value ).isEqualTo( 1 ); + assertEquals( 1, value ); } ); } @@ -323,7 +325,7 @@ public void testFunctionProcedureNullParameterHibernate() { Boolean result = (Boolean) procedureCall.getSingleResult(); - assertThat( result ).isTrue(); + assertTrue( result ); } ); inTransaction( entityManager -> { @@ -335,7 +337,7 @@ public void testFunctionProcedureNullParameterHibernate() { Boolean result = (Boolean) procedureCall.getSingleResult(); - assertThat( result ).isFalse(); + assertFalse( result ); } ); } @@ -352,7 +354,7 @@ public void testFunctionProcedureNullParameterHibernateWithoutEnablePassingNulls Boolean result = (Boolean) procedureCall.getSingleResult(); - assertThat( result ).isTrue(); + assertTrue( result ); } ); } @@ -369,7 +371,6 @@ public void testFunctionProcedureNullParameterHibernateWithoutSettingTheParamete procedureCall.execute(); } ) ); - assertThat( exception.getMessage() ) - .isEqualTo( "The parameter named [param] was not set! You need to call the setParameter method." ); + assertTrue( exception.getMessage().contains( "parameter named 'param'" ) ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLStoredProcedureTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLStoredProcedureTest.java index 60befa8191cf..f25da5e7dd43 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLStoredProcedureTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/procedure/PostgreSQLStoredProcedureTest.java @@ -26,7 +26,6 @@ import org.hibernate.testing.orm.junit.RequiresDialect; import org.hibernate.testing.orm.junit.Setting; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -39,10 +38,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Vlad Mihalcea @@ -230,10 +229,7 @@ public void testStoredProcedureNullParameterHibernateWithoutSettingTheParameter( fail( "Should have thrown exception" ); } catch (IllegalArgumentException e) { - assertEquals( - "The parameter named [param] was not set! You need to call the setParameter method.", - e.getMessage() - ); + assertTrue( e.getMessage().contains( "parameter named 'param'" ) ); } } ); } @@ -253,7 +249,7 @@ public void testStoredProcedureInAndOutAndRefCursorParameters(EntityManagerFacto query.execute(); ResultSet rs = (ResultSet) query.getOutputParameterValue( "rec_out" ); try { - Assertions.assertTrue( rs.next() ); + assertTrue( rs.next() ); assertThat( rs.getString( "street" ), is( STREET ) ); assertThat( rs.getString( "city" ), is( CITY ) ); assertThat( rs.getString( "zip" ), is( ZIP ) ); @@ -280,7 +276,7 @@ public void testStoredProcedureInAndOutAndRefCursorParametersDifferentRegistrati query.execute(); ResultSet rs = (ResultSet) query.getOutputParameterValue( "rec_out" ); try { - Assertions.assertTrue( rs.next() ); + assertTrue( rs.next() ); assertThat( rs.getString( "street" ), is( STREET ) ); assertThat( rs.getString( "city" ), is( CITY ) ); assertThat( rs.getString( "zip" ), is( ZIP ) ); @@ -307,7 +303,7 @@ public void testStoredProcedureInAndOutAndRefCursorParametersDifferentRegistrati query.execute(); ResultSet rs = (ResultSet) query.getOutputParameterValue( "rec_out" ); try { - Assertions.assertTrue( rs.next() ); + assertTrue( rs.next() ); assertThat( rs.getString( "street" ), is( STREET ) ); assertThat( rs.getString( "city" ), is( CITY ) ); assertThat( rs.getString( "zip" ), is( ZIP ) );