6 - SQM based on JPA type system

- further work on `org.hibernate.query` (especially `NamedQueryRepository` and friends)
- initial work on `org.hibernate.sql.exec`
- initial work on `org.hibernate.sql.results`
- SemanticPathPart handling
- NamedQueryMemento
- work on ProcedureCal
This commit is contained in:
Steve Ebersole 2019-05-31 10:29:35 -05:00 committed by Andrea Boriero
parent 3a761361fe
commit f52e305ffb
58 changed files with 1589 additions and 1109 deletions

View File

@ -159,7 +159,7 @@ import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.procedure.UnknownSqlResultSetMappingException;
import org.hibernate.query.UnknownSqlResultSetMappingException;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;

View File

@ -454,4 +454,8 @@ public final class ArrayHelper {
System.out.println( "[" + i + "] -> " + batchSizes[i] );
}
}
public static boolean isEmpty(Object[] array) {
return array == null || array.length == 0;
}
}

View File

@ -13,13 +13,21 @@ import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
*
* @author Steve Ebersole
*/
public class StandardBasicValueConverter<O,R> implements BasicValueConverter<O,R> {
public class NoOpBasicValueConverter<O,R> implements BasicValueConverter<O,R> {
/**
* Singleton access
*/
public static final StandardBasicValueConverter INSTANCE = new StandardBasicValueConverter();
public static final NoOpBasicValueConverter INSTANCE = new NoOpBasicValueConverter();
private StandardBasicValueConverter() {
/**
* Typed access to the singleton
*/
public static <O,R> NoOpBasicValueConverter<O,R> instance() {
//noinspection unchecked
return INSTANCE;
}
private NoOpBasicValueConverter() {
}
@Override

View File

@ -15,6 +15,9 @@ package org.hibernate.metamodel.model.convert.spi;
* * implicitly, based on the Java type (e.g., enums)
* * etc
*
* @param <O> The Java type we can use to represent the domain (object) type
* @param <R> The Java type we can use to represent the relational type
*
* @author Steve Ebersole
*/
public interface BasicValueConverter<O,R> {

View File

@ -0,0 +1,22 @@
/*
* 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.metamodel.model.convert.spi;
import org.hibernate.query.sqm.SqmExpressable;
/**
* Describes a part of the domain model to which a value converter can be applied
*
* @author Steve Ebersole
*/
public interface ConvertibleValueMapping<O> extends SqmExpressable<O> {
/**
* Get the value converter associated with this value mapping. May
* return {@code null}
*/
<R> BasicValueConverter<O,R> getValueConverter();
}

View File

@ -6,6 +6,11 @@
*/
package org.hibernate.metamodel.model.domain;
import java.sql.CallableStatement;
import java.sql.SQLException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Specialization of DomainType for types that can be used as a
* parameter output for a {@link org.hibernate.procedure.ProcedureCall}
@ -16,4 +21,38 @@ package org.hibernate.metamodel.model.domain;
* @author Steve Ebersole
*/
public interface AllowableOutputParameterType<J> extends AllowableParameterType<J> {
/**
* Can the given instance of this type actually perform the parameter value extractions?
*
* @return {@code true} indicates that @{link #extract} calls will not fail due to {@link IllegalStateException}.
*/
boolean canDoExtraction();
/**
* Perform the extraction
*
* @param statement The CallableStatement from which to extract the parameter value(s).
* @param startIndex The parameter index from which to start extracting; assumes the values (if multiple) are contiguous
* @param session The originating session
*
* @return The extracted value.
*
* @throws SQLException Indicates an issue calling into the CallableStatement
* @throws IllegalStateException Thrown if this method is called on instances that return {@code false} for {@link #canDoExtraction}
*/
J extract(CallableStatement statement, int startIndex, SharedSessionContractImplementor session) throws SQLException;
/**
* Perform the extraction
*
* @param statement The CallableStatement from which to extract the parameter value(s).
* @param paramNames The parameter names.
* @param session The originating session
*
* @return The extracted value.
*
* @throws SQLException Indicates an issue calling into the CallableStatement
* @throws IllegalStateException Thrown if this method is called on instances that return {@code false} for {@link #canDoExtraction}
*/
J extract(CallableStatement statement, String[] paramNames, SharedSessionContractImplementor session) throws SQLException;
}

View File

@ -13,6 +13,7 @@ import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import org.hibernate.Incubating;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.metamodel.spi.DomainMetamodel;
import org.hibernate.service.ServiceRegistry;
@ -24,6 +25,7 @@ import org.hibernate.type.spi.TypeConfiguration;
* @author Steve Ebersole
* @see DomainMetamodel
*/
@Incubating
public interface JpaMetamodel extends javax.persistence.metamodel.Metamodel {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -53,10 +55,29 @@ public interface JpaMetamodel extends javax.persistence.metamodel.Metamodel {
*/
<X> EntityDomainType<X> resolveHqlEntityReference(String entityName);
/**
* Visitation over all managed types via Consumer
*/
void visitManagedTypes(Consumer<ManagedDomainType<?>> action);
/**
* Same as {@link #managedType} except {@code null} is returned rather
* than throwing an exception
*/
<X> ManagedDomainType<X> findManagedType(Class<X> cls);
/**
* Visitation over all entity types via Consumer
*/
void visitEntityTypes(Consumer<EntityDomainType<?>> action);
/**
* Same as {@link #entity} except {@code null} is returned rather
* than throwing an exception
*/
<X> EntityDomainType<X> findEntityType(Class<X> cls);
/
void visitRootEntityTypes(Consumer<EntityDomainType<?>> action);
void visitEmbeddables(Consumer<EmbeddableDomainType<?>> action);

View File

@ -361,8 +361,10 @@ public class JpaMetamodelImpl implements JpaMetamodel {
type = embeddableDescriptorMap.get( cls );
}
if ( type == null ) {
// per JPA
throw new IllegalArgumentException( "Not a managed type: " + cls );
}
//noinspection unchecked
return (ManagedDomainType<X>) type;
}

View File

@ -9,13 +9,16 @@ package org.hibernate.metamodel.spi;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.UnknownEntityTypeException;
import org.hibernate.Incubating;
import org.hibernate.graph.RootGraph;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -23,13 +26,43 @@ import org.hibernate.type.spi.TypeConfiguration;
*
* @author Steve Ebersole
*/
@Incubating
public interface DomainMetamodel {
/**
* Access to the JPA metamodel sub-set of the overall run-time metamodel
*
* @apiNote The distinction is mainly used in building SQM trees, which rely
* on the JPA type subset
*/
JpaMetamodel getJpaMetamodel();
/**
* The TypeConfiguration this metamodel is associated with
*/
default TypeConfiguration getTypeConfiguration() {
return getJpaMetamodel().getTypeConfiguration();
}
/**
* Given a Java type, determine the corresponding AllowableParameterType to
* use implicitly
*/
default <T> AllowableParameterType<T> resolveQueryParameterType(Class<T> javaType) {
final BasicType basicType = getTypeConfiguration().getBasicTypeForJavaType( javaType );
if ( basicType != null ) {
//noinspection unchecked
return basicType;
}
final ManagedDomainType<T> managedType = getJpaMetamodel().findManagedType( javaType );
if ( managedType instanceof AllowableParameterType ) {
//noinspection unchecked
return (AllowableParameterType) managedType;
}
return null;
}
/**
* Given an (assumed) entity instance, determine its descriptor
*
@ -184,5 +217,4 @@ public interface DomainMetamodel {
List<RootGraph<?>> findRootGraphsForType(Class baseEntityJavaType);
List<RootGraph<?>> findRootGraphsForType(String baseEntityName);
List<RootGraph<?>> findRootGraphsForType(EntityPersister baseEntityDescriptor);
}

View File

@ -190,6 +190,19 @@ public interface EntityPersister extends EntityDefinition {
*/
Serializable[] getQuerySpaces();
/**
* Returns an array of objects that identify spaces in which properties of
* this entity are persisted, for instances of this class and its subclasses.
* <p/>
* Much like {@link #getPropertySpaces()}, except that here we include subclass
* entity spaces.
*
* @return The query spaces.
*/
default String[] getSynchronizedQuerySpaces() {
return (String[]) getQuerySpaces();
}
/**
* Determine whether this entity supports dynamic proxies.
*

View File

@ -0,0 +1,19 @@
/*
* 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.procedure;
import org.hibernate.query.procedure.ProcedureParameter;
/**
* Describes the function return for ProcedureCalls that represent calls to
* a function ({@code "{? = call ...} syntax) rather that a proc ({@code {call ...} syntax)
*
* @author Steve Ebersole
*/
public interface FunctionReturn<T> extends ProcedureParameter<T> {
int getJdbcTypeCode();
}

View File

@ -1,31 +0,0 @@
/*
* 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.procedure;
import javax.persistence.TemporalType;
import org.hibernate.query.spi.QueryParameterBinding;
/**
* Describes an input value binding for any IN/INOUT parameters.
*/
public interface ParameterBind<T> extends QueryParameterBinding<T> {
/**
* Retrieves the bound value.
*
* @return The bound value.
*/
T getValue();
/**
* If {@code <T>} represents a DATE/TIME type value, JPA usually allows specifying the particular parts of
* the DATE/TIME value to be bound. This value represents the particular part the user requested to be bound.
*
* @return The explicitly supplied TemporalType.
*/
TemporalType getExplicitTemporalType();
}

View File

@ -9,7 +9,7 @@ package org.hibernate.procedure;
import org.hibernate.HibernateException;
/**
* Thrown to indicate a misuse of a {@link ParameterRegistration}
* Thrown to indicate a misuse of a parameter
*
* @author Steve Ebersole
*/

View File

@ -1,114 +0,0 @@
/*
* 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.procedure;
import javax.persistence.ParameterMode;
import javax.persistence.TemporalType;
import org.hibernate.query.procedure.ProcedureParameter;
import org.hibernate.type.Type;
/**
* Describes a registered procedure/function parameter.
*
* @author Steve Ebersole
*/
public interface ParameterRegistration<T> extends ProcedureParameter<T> {
/**
* The name under which this parameter was registered. Can be {@code null} which should indicate that
* positional registration was used (and therefore {@link #getPosition()} should return non-null.
*
* @return The name;
*/
@Override
String getName();
/**
* The position at which this parameter was registered. Can be {@code null} which should indicate that
* named registration was used (and therefore {@link #getName()} should return non-null.
*
* @return The name;
*/
@Override
Integer getPosition();
/**
* Return the Java type of the parameter.
*
* @return The Java type of the parameter.
* @deprecated Call {@link #getParameterType()} instead.
*/
@Deprecated
default Class<T> getType() {
return getParameterType();
}
/**
* Retrieves the parameter "mode" which describes how the parameter is defined in the actual database procedure
* definition (is it an INPUT parameter? An OUTPUT parameter? etc).
*
* @return The parameter mode.
*/
@Override
ParameterMode getMode();
/**
* Controls how unbound values for this IN/INOUT parameter registration will be handled prior to
* execution. There are 2 possible options to handle it:<ul>
* <li>bind the NULL to the parameter</li>
* <li>do not bind the NULL to the parameter</li>
* </ul>
* <p/>
* The reason for the distinction comes from default values defined on the corresponding
* database procedure/function argument. Any time a value (including NULL) is bound to the
* argument, its default value will not be used. So effectively this setting controls
* whether the NULL should be interpreted as "pass the NULL" or as "apply the argument default".
* <p/>
* The (global) default this setting is defined by {@link org.hibernate.cfg.AvailableSettings#PROCEDURE_NULL_PARAM_PASSING}
*
* @param enabled {@code true} indicates that the NULL should be passed; {@code false} indicates it should not.
*
* @deprecated (since 6.0) : see {@link #isPassNullsEnabled}
*/
@Override
@Deprecated
void enablePassingNulls(boolean enabled);
/**
* Set the Hibernate mapping type for this parameter.
*
* @param type The Hibernate mapping type.
*/
void setHibernateType(Type type);
/**
* Retrieve the binding associated with this parameter. The binding is only relevant for INPUT parameters. Can
* return {@code null} if nothing has been bound yet. To bind a value to the parameter use one of the
* {@link #bindValue} methods.
*
* @return The parameter binding
*/
ParameterBind<T> getBind();
/**
* Bind a value to the parameter. How this value is bound to the underlying JDBC CallableStatement is
* totally dependent on the Hibernate type.
*
* @param value The value to bind.
*/
void bindValue(T value);
/**
* Bind a value to the parameter, using just a specified portion of the DATE/TIME value. It is illegal to call
* this form if the parameter is not DATE/TIME type. The Hibernate type is circumvented in this case and
* an appropriate "precision" Type is used instead.
*
* @param value The value to bind
* @param explicitTemporalType An explicitly supplied TemporalType.
*/
void bindValue(T value, TemporalType explicitTemporalType);
}

View File

@ -7,38 +7,86 @@
package org.hibernate.procedure;
import java.util.List;
import java.util.Map;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureQuery;
import org.hibernate.BasicQueryContract;
import org.hibernate.MappingException;
import org.hibernate.SynchronizeableQuery;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.query.CommonQueryContract;
import org.hibernate.query.procedure.ProcedureParameter;
import org.hibernate.query.spi.NameableQuery;
/**
* Defines support for executing database stored procedures and functions
* Defines support for executing database stored procedures and functions.
* <p/>
* Note that here we use the terms "procedure" and "function" as follows:<ul>
* <li>procedure is a named database executable we expect to call via : {@code {call procedureName(...)}}</li>
* <li>function is a named database executable we expect to call via : {@code {? = call functionName(...)}}</li>
* </ul>
* Unless explicitly specified, the ProcedureCall is assumed to follow the
* procedure call syntax. To explicitly specify that this should be a function
* call, use {@link #markAsFunctionCall}. JPA users could either:<ul>
* <li>use {@code storedProcedureQuery.unwrap( ProcedureCall.class }.markAsFunctionCall()</li>
* <li>set the {@link #FUNCTION_RETURN_TYPE_HINT} hint (avoids casting to Hibernate-specific classes)</li>
* </ul>
* <p/>
* When using function-call syntax:<ul>
* <li>parameters must be registered by position (not name)</li>
* <li>The first parameter is considered to be the function return (the `?` before the call)</li>
* <li>the first parameter must have mode of OUT, INOUT or REF_CURSOR; IN is invalid</li>
* </ul>
* <p/>
* In some cases, based on the Dialect, we will have other validations and
* assumptions as well. For example, on PGSQL, whenever we see a REF_CURSOR mode
* parameter, we know that:<ul>
* <li>
* this will be a function call (so we call {@link #markAsFunctionCall} implicitly) because
* that is the only way PGSQL supports returning REF_CURSOR results.
* </li>
* <li>there can be only one REF_CURSOR mode parameter</li>
* </ul>
*
* @author Steve Ebersole
*/
public interface ProcedureCall extends BasicQueryContract<CommonQueryContract>, SynchronizeableQuery, StoredProcedureQuery {
@Override
ProcedureCall addSynchronizedQuerySpace(String querySpace);
@Override
ProcedureCall addSynchronizedEntityName(String entityName) throws MappingException;
@Override
ProcedureCall addSynchronizedEntityClass(Class entityClass) throws MappingException;
public interface ProcedureCall
extends CommonQueryContract, SynchronizeableQuery, StoredProcedureQuery, NameableQuery, AutoCloseable {
/**
* The hint key (for use with JPA's "hint system") indicating the function's return JDBC type code
* (aka, {@link java.sql.Types} code)
*/
String FUNCTION_RETURN_TYPE_HINT = "hibernate.procedure.function_return_jdbc_type_code";
/**
* Get the name of the stored procedure to be called.
* Get the name of the stored procedure (or function) to be called.
*
* @return The procedure name.
*/
String getProcedureName();
/**
* Does this ProcedureCall represent a call to a database FUNCTION (as opposed
* to a PROCEDURE call)?
*
* NOTE : this will only report whether this ProcedureCall was marked
* as a function via call to {@link #markAsFunctionCall}. Specifically
* will not return {@code true} when using JPA query hint.
*
* @return {@code true} indicates that this ProcedureCall represents a
* function call; {@code false} indicates a procedure call.
*/
boolean isFunctionCall();
/**
* Mark this ProcedureCall as representing a call to a database function,
* rather than a database procedure.
*
* @param sqlType The {@link java.sql.Types} code for the function return
*
* @return {@code this}, for method chaining
*/
ProcedureCall markAsFunctionCall(int sqlType);
/**
* Basic form for registering a positional parameter.
*
@ -49,7 +97,7 @@ public interface ProcedureCall extends BasicQueryContract<CommonQueryContract>,
*
* @return The parameter registration memento
*/
<T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode);
<T> ProcedureParameter<T> registerParameter(int position, Class<T> type, ParameterMode mode);
/**
* Chained form of {@link #registerParameter(int, Class, javax.persistence.ParameterMode)}
@ -60,7 +108,7 @@ public interface ProcedureCall extends BasicQueryContract<CommonQueryContract>,
*
* @return {@code this}, for method chaining
*/
ProcedureCall registerParameter0(int position, Class type, ParameterMode mode);
<T> ProcedureCall registerParameter0(int position, Class<T> type, ParameterMode mode);
/**
* Retrieve a previously registered parameter memento by the position under which it was registered.
@ -72,7 +120,7 @@ public interface ProcedureCall extends BasicQueryContract<CommonQueryContract>,
* @throws ParameterStrategyException If the ProcedureCall is defined using named parameters
* @throws NoSuchParameterException If no parameter with that position exists
*/
ParameterRegistration getParameterRegistration(int position);
ProcedureParameter getParameterRegistration(int position);
/**
* Basic form for registering a named parameter.
@ -87,7 +135,7 @@ public interface ProcedureCall extends BasicQueryContract<CommonQueryContract>,
* @throws NamedParametersNotSupportedException When the underlying database is known to not support
* named procedure parameters.
*/
<T> ParameterRegistration<T> registerParameter(String parameterName, Class<T> type, ParameterMode mode)
<T> ProcedureParameter<T> registerParameter(String parameterName, Class<T> type, ParameterMode mode)
throws NamedParametersNotSupportedException;
/**
@ -115,14 +163,14 @@ public interface ProcedureCall extends BasicQueryContract<CommonQueryContract>,
* @throws ParameterStrategyException If the ProcedureCall is defined using positional parameters
* @throws NoSuchParameterException If no parameter with that name exists
*/
ParameterRegistration getParameterRegistration(String name);
ProcedureParameter getParameterRegistration(String name);
/**
* Retrieve all registered parameters.
*
* @return The (immutable) list of all registered parameters.
*/
List<ParameterRegistration> getRegisteredParameters();
List<ProcedureParameter> getRegisteredParameters();
/**
* Retrieves access to outputs of this procedure call. Can be called multiple times, returning the same
@ -136,18 +184,22 @@ public interface ProcedureCall extends BasicQueryContract<CommonQueryContract>,
ProcedureOutputs getOutputs();
/**
* Extract the disconnected representation of this call. Used in HEM to allow redefining a named query
*
* @param hints The hints to incorporate into the memento
*
* @return The memento
* Release the underlying JDBC {@link java.sql.CallableStatement}
*/
NamedCallableQueryMemento extractMemento(Map<String, Object> hints);
@Override
default void close() {
getOutputs().release();
}
/**
* Extract the disconnected representation of this call. Used in HEM to allow redefining a named query
* *
* @return The memento
*/
NamedCallableQueryMemento extractMemento();
@Override
ProcedureCall addSynchronizedQuerySpace(String querySpace);
@Override
ProcedureCall addSynchronizedEntityName(String entityName) throws MappingException;
@Override
ProcedureCall addSynchronizedEntityClass(Class entityClass) throws MappingException;
@Override
NamedCallableQueryMemento toMemento(String name);
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.procedure;
import org.hibernate.query.procedure.ProcedureParameter;
import org.hibernate.result.Outputs;
/**
@ -21,13 +22,13 @@ public interface ProcedureOutputs extends Outputs {
* Should NOT be called for parameters registered as REF_CURSOR. REF_CURSOR parameters should be
* accessed via the returns (see {@link #getNextOutput}
*
* @param parameterRegistration The parameter's registration memento.
* @param parameter The parameter's registration memento.
*
* @return The output value.
*
* @see ProcedureCall#registerParameter(String, Class, javax.persistence.ParameterMode)
*/
public <T> T getOutputParameterValue(ParameterRegistration<T> parameterRegistration);
<T> T getOutputParameterValue(ProcedureParameter<T> parameter);
/**
* Retrieve the value of an OUTPUT parameter by the name under which the parameter was registered.
@ -41,7 +42,7 @@ public interface ProcedureOutputs extends Outputs {
*
* @see ProcedureCall#registerParameter(String, Class, javax.persistence.ParameterMode)
*/
public Object getOutputParameterValue(String name);
Object getOutputParameterValue(String name);
/**
* Retrieve the value of an OUTPUT parameter by the name position under which the parameter was registered.
@ -55,5 +56,5 @@ public interface ProcedureOutputs extends Outputs {
*
* @see ProcedureCall#registerParameter(int, Class, javax.persistence.ParameterMode)
*/
public Object getOutputParameterValue(int position);
Object getOutputParameterValue(int position);
}

View File

@ -0,0 +1,123 @@
/*
* 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.procedure.internal;
import java.sql.Types;
import javax.persistence.ParameterMode;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.model.domain.AllowableOutputParameterType;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.procedure.spi.FunctionReturnImplementor;
import org.hibernate.procedure.spi.ProcedureCallImplementor;
import org.hibernate.query.QueryParameter;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
*/
public class FunctionReturnImpl implements FunctionReturnImplementor {
private final ProcedureCallImplementor procedureCall;
private int jdbcTypeCode;
private AllowableOutputParameterType<?> ormType;
public FunctionReturnImpl(ProcedureCallImplementor procedureCall, int jdbcTypeCode) {
this.procedureCall = procedureCall;
this.jdbcTypeCode = jdbcTypeCode;
}
public FunctionReturnImpl(ProcedureCallImplementor procedureCall, AllowableOutputParameterType ormType) {
this.procedureCall = procedureCall;
this.jdbcTypeCode = ormType.getSqlTypeDescriptor().getJdbcTypeCode();
this.ormType = ormType;
}
public JdbcCallFunctionReturn toJdbcFunctionReturn(SharedSessionContractImplementor persistenceContext) {
final AllowableParameterType ormType;
final JdbcCallRefCursorExtractorImpl refCursorExtractor;
final JdbcCallParameterExtractorImpl parameterExtractor;
if ( getJdbcTypeCode() == Types.REF_CURSOR ) {
refCursorExtractor = new JdbcCallRefCursorExtractorImpl( null, 0 );
ormType = null;
parameterExtractor = null;
}
else {
final TypeConfiguration typeConfiguration = persistenceContext.getFactory().getMetamodel().getTypeConfiguration();
final SqlTypeDescriptor sqlTypeDescriptor = typeConfiguration.getSqlTypeDescriptorRegistry()
.getDescriptor( getJdbcTypeCode() );
final JavaTypeDescriptor javaTypeMapping = sqlTypeDescriptor
.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
ormType = typeConfiguration.getBasicTypeRegistry().getBasicType( javaTypeMapping.getJavaType() );
parameterExtractor = new JdbcCallParameterExtractorImpl( procedureCall.getProcedureName(), null, 0, ormType );
refCursorExtractor = null;
}
return new JdbcCallFunctionReturnImpl( getJdbcTypeCode(), ormType, parameterExtractor, refCursorExtractor );
}
@Override
public int getJdbcTypeCode() {
return jdbcTypeCode;
}
@Override
public AllowableParameterType getHibernateType() {
return ormType;
}
@Override
public String getName() {
return null;
}
@Override
public Integer getPosition() {
return 0;
}
@Override
public ParameterMode getMode() {
return ParameterMode.OUT;
}
@Override
public Class getParameterType() {
return ormType == null ? null : ormType.getJavaType();
}
@Override
public void disallowMultiValuedBinding() {
// no-op
}
@Override
public boolean allowsMultiValuedBinding() {
return false;
}
@Override
public ParameterMemento toMemento() {
// todo (6.0) : do we need a FunctionReturnMemento?
return new ParameterMemento() {
@Override
public QueryParameter toQueryParameter(SharedSessionContractImplementor session) {
if ( ormType != null ) {
return new FunctionReturnImpl( procedureCall, ormType );
}
else {
return new FunctionReturnImpl( procedureCall, jdbcTypeCode );
}
}
};
}
}

View File

@ -15,13 +15,13 @@ import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
import org.hibernate.procedure.spi.ParameterStrategy;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.AbstractNamedQueryMemento;
import org.hibernate.query.spi.NamedQueryMemento;
import org.hibernate.type.Type;
/**
* Implementation of NamedCallableQueryMemento
@ -85,6 +85,31 @@ public class NamedCallableQueryMementoImpl extends AbstractNamedQueryMemento imp
return callableName;
}
@Override
public List<ParameterMemento> getParameterMementos() {
return parameterMementos;
}
@Override
public ParameterStrategy getParameterStrategy() {
return parameterStrategy;
}
@Override
public String[] getResultSetMappingNames() {
return resultSetMappingNames;
}
@Override
public Class[] getResultSetMappingClasses() {
return resultSetMappingClasses;
}
@Override
public Set<String> getQuerySpaces() {
return querySpaces;
}
@Override
public ProcedureCall makeProcedureCall(SharedSessionContractImplementor session) {
return new ProcedureCallImpl( session, this );
@ -120,32 +145,22 @@ public class NamedCallableQueryMementoImpl extends AbstractNamedQueryMemento imp
private final String name;
private final ParameterMode mode;
private final Class type;
private final Type hibernateType;
private final boolean passNulls;
private final AllowableParameterType hibernateType;
/**
* Create the memento
*
* @param position The parameter position
* @param name The parameter name
* @param mode The parameter mode
* @param type The Java type of the parameter
* @param hibernateType The Hibernate Type.
* @param passNulls Should NULL values to passed to the database?
*/
public ParameterMementoImpl(
int position,
String name,
ParameterMode mode,
Class type,
Type hibernateType,
boolean passNulls) {
AllowableParameterType hibernateType) {
this.position = position;
this.name = name;
this.mode = mode;
this.type = type;
this.hibernateType = hibernateType;
this.passNulls = passNulls;
}
public Integer getPosition() {
@ -164,16 +179,12 @@ public class NamedCallableQueryMementoImpl extends AbstractNamedQueryMemento imp
return type;
}
public Type getHibernateType() {
public AllowableParameterType getHibernateType() {
return hibernateType;
}
public boolean isPassNullsEnabled() {
return passNulls;
}
@Override
public ParameterRegistrationImplementor resolve(SharedSessionContractImplementor session) {
public ProcedureParameterImplementor resolve(SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception();
}
@ -184,14 +195,13 @@ public class NamedCallableQueryMementoImpl extends AbstractNamedQueryMemento imp
*
* @return The memento
*/
public static ParameterMementoImpl fromRegistration(ParameterRegistrationImplementor registration) {
public static ParameterMementoImpl fromRegistration(ProcedureParameterImplementor registration) {
return new ParameterMementoImpl(
registration.getPosition(),
registration.getName(),
registration.getMode(),
registration.getParameterType(),
registration.getHibernateType(),
registration.isPassNullsEnabled()
registration.getHibernateType()
);
}

View File

@ -15,7 +15,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import javax.persistence.FlushModeType;
@ -24,40 +23,48 @@ import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Parameter;
import javax.persistence.ParameterMode;
import javax.persistence.PersistenceException;
import javax.persistence.TemporalType;
import javax.persistence.TransactionRequiredException;
import org.hibernate.HibernateException;
import org.hibernate.query.spi.AbstractQuery;
import org.hibernate.query.sql.spi.ResultSetMappingDescriptor;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.ScrollMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.RootGraph;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.NoSuchParameterException;
import org.hibernate.procedure.ParameterRegistration;
import org.hibernate.procedure.ParameterStrategyException;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.procedure.ProcedureOutputs;
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.procedure.spi.ParameterStrategy;
import org.hibernate.procedure.spi.ProcedureCallImplementor;
import org.hibernate.query.Query;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.internal.AbstractProducedQuery;
import org.hibernate.query.internal.QueryOptionsImpl;
import org.hibernate.query.procedure.ProcedureParameter;
import org.hibernate.query.procedure.internal.ProcedureParamBindings;
import org.hibernate.query.procedure.internal.ProcedureParameterImpl;
import org.hibernate.query.procedure.internal.ProcedureParameterMetadata;
import org.hibernate.query.procedure.internal.ProcedureParameterMetadataImpl;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.AbstractQuery;
import org.hibernate.query.spi.MutableQueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.result.NoMoreReturnsException;
import org.hibernate.result.Output;
import org.hibernate.result.ResultSetOutput;
import org.hibernate.result.UpdateCountOutput;
import org.hibernate.result.spi.ResultContext;
import org.hibernate.sql.exec.spi.DomainParameterBindingContext;
import org.hibernate.sql.results.NoMoreOutputsException;
import org.hibernate.sql.results.spi.DomainResultProducer;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@ -69,26 +76,28 @@ import org.jboss.logging.Logger;
*/
public class ProcedureCallImpl<R>
extends AbstractQuery<R>
implements ProcedureCallImplementor<R>, ResultContext {
implements ProcedureCallImplementor<R>, ResultContext, DomainParameterBindingContext {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
ProcedureCallImpl.class.getName()
);
private static final NativeSQLQueryReturn[] NO_RETURNS = new NativeSQLQueryReturn[0];
private final String procedureName;
private final NativeSQLQueryReturn[] queryReturns;
private final boolean globalParameterPassNullsSetting;
private FunctionReturnImpl functionReturn;
private final ProcedureParameterMetadata parameterMetadata;
private final ProcedureParameterMetadataImpl parameterMetadata;
private final ProcedureParamBindings paramBindings;
private final List<DomainResultProducer<?>> domainResultProducers;
private Set<String> synchronizedQuerySpaces;
private final QueryOptionsImpl queryOptions = new QueryOptionsImpl();
private ProcedureOutputsImpl outputs;
/**
* The no-returns form.
*
@ -98,14 +107,13 @@ public class ProcedureCallImpl<R>
public ProcedureCallImpl(SharedSessionContractImplementor session, String procedureName) {
super( session );
this.procedureName = procedureName;
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
this.queryReturns = NO_RETURNS;
this.parameterMetadata = new ProcedureParameterMetadata( this );
this.parameterMetadata = new ProcedureParameterMetadataImpl( this );
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
}
this.synchronizedQuerySpaces = null;
this.domainResultProducers = null;
}
/**
* The result Class(es) return form
*
@ -113,39 +121,25 @@ public class ProcedureCallImpl<R>
* @param procedureName The name of the procedure to call
* @param resultClasses The classes making up the result
*/
public ProcedureCallImpl(final SharedSessionContractImplementor session, String procedureName, Class... resultClasses) {
public ProcedureCallImpl(SharedSessionContractImplementor session, String procedureName, Class... resultClasses) {
super( session );
assert resultClasses != null && resultClasses.length > 0;
this.procedureName = procedureName;
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<>();
final Set<String> collectedQuerySpaces = new HashSet<>();
Util.resolveResultClasses(
new Util.ResultClassesResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return session.getFactory();
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
resultClasses
);
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
this.synchronizedQuerySpaces = collectedQuerySpaces;
this.parameterMetadata = new ProcedureParameterMetadata( this );
this.parameterMetadata = new ProcedureParameterMetadataImpl( this );
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
this.domainResultProducers = CollectionHelper.arrayList( resultClasses.length );
this.synchronizedQuerySpaces = new HashSet<>();
Util.resolveResultSetMappingClasses(
resultClasses,
domainResultProducers::add,
synchronizedQuerySpaces::add,
getSession().getFactory()
);
}
/**
@ -153,46 +147,30 @@ public class ProcedureCallImpl<R>
*
* @param session The session
* @param procedureName The name of the procedure to call
* @param resultSetMappings The names of the result set mappings making up the result
* @param resultSetMappingNames The names of the result set mappings making up the result
*/
public ProcedureCallImpl(final SharedSessionContractImplementor session, String procedureName, String... resultSetMappings) {
public ProcedureCallImpl(
final SharedSessionContractImplementor session,
String procedureName,
String... resultSetMappingNames) {
super( session );
assert resultSetMappingNames != null && resultSetMappingNames.length > 0;
this.procedureName = procedureName;
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<>();
final Set<String> collectedQuerySpaces = new HashSet<>();
Util.resolveResultSetMappings(
new Util.ResultSetMappingResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return session.getFactory();
}
@Override
public ResultSetMappingDescriptor findResultSetMapping(String name) {
return session.getFactory().getNamedQueryRepository().getResultSetMappingDefinition( name );
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
resultSetMappings
);
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
this.synchronizedQuerySpaces = collectedQuerySpaces;
this.parameterMetadata = new ProcedureParameterMetadata( this );
this.parameterMetadata = new ProcedureParameterMetadataImpl( this );
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
this.domainResultProducers = CollectionHelper.arrayList( resultSetMappingNames.length );
this.synchronizedQuerySpaces = new HashSet<>();
Util.resolveResultSetMappingNames(
resultSetMappingNames,
domainResultProducers::add,
synchronizedQuerySpaces::add,
getSession().getFactory()
);
}
/**
@ -201,52 +179,39 @@ public class ProcedureCallImpl<R>
* @param session The session
* @param memento The named/stored memento
*/
@SuppressWarnings("unchecked")
ProcedureCallImpl(SharedSessionContractImplementor session, NamedCallableQueryMemento memento) {
super( session );
this.procedureName = memento.getCallableName();
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
this.queryReturns = memento.getQueryReturns();
this.synchronizedQuerySpaces = Util.copy( memento.getSynchronizedQuerySpaces() );
this.parameterMetadata = new ProcedureParameterMetadata( this );
this.parameterMetadata = new ProcedureParameterMetadataImpl( this, memento );
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
for ( NamedCallableQueryMementoImpl.ParameterMemento storedRegistration : memento.getParameterDeclarations() ) {
final ProcedureParameterImplementor<?> registration;
this.domainResultProducers = new ArrayList<>();
this.synchronizedQuerySpaces = CollectionHelper.makeCopy( memento.getQuerySpaces() );
if ( StringHelper.isNotEmpty( storedRegistration.getName() ) ) {
registration = new ProcedureParameterImpl(
this,
storedRegistration.getName(),
storedRegistration.getMode(),
storedRegistration.getType(),
storedRegistration.getHibernateType(),
storedRegistration.isPassNullsEnabled()
);
}
else {
registration = new ProcedureParameterImpl(
this,
storedRegistration.getPosition(),
storedRegistration.getMode(),
storedRegistration.getType(),
storedRegistration.getHibernateType(),
storedRegistration.isPassNullsEnabled()
);
}
Util.resolveResultSetMappings(
memento.getResultSetMappingNames(),
memento.getResultSetMappingClasses(),
domainResultProducers::add,
synchronizedQuerySpaces::add,
getSession().getFactory()
);
getParameterMetadata().registerParameter( registration );
}
for ( Map.Entry<String, Object> entry : memento.getHintsMap().entrySet() ) {
setHint( entry.getKey(), entry.getValue() );
}
applyOptions( memento );
}
@Override
public ProcedureParameterMetadata getParameterMetadata() {
public String getProcedureName() {
return procedureName;
}
@Override
public MutableQueryOptions getQueryOptions() {
return queryOptions;
}
@Override
public ProcedureParameterMetadataImpl getParameterMetadata() {
return parameterMetadata;
}
@ -260,30 +225,85 @@ public class ProcedureCallImpl<R>
}
@Override
public String getProcedureName() {
return procedureName;
public boolean isFunctionCall() {
return functionReturn != null;
}
@Override
public String getSql() {
return getProcedureName();
public ProcedureCall markAsFunctionCall(int sqlType) {
functionReturn = new FunctionReturnImpl( this, sqlType );
return this;
}
@Override
public NativeSQLQueryReturn[] getQueryReturns() {
return queryReturns;
public DomainParameterBindingContext getDomainParameterBindingContext() {
return this;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DomainParameterBindingContext
@Override
public SessionFactoryImplementor getSessionFactory() {
return getSession().getFactory();
}
@Override
public <T> List<T> getLoadIdentifiers() {
return Collections.emptyList();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Parameter registrations
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
getSession().checkOpen( true );
try {
registerParameter( position, type, mode );
}
catch (HibernateException he) {
throw getSession().getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getSession().markForRollbackOnly();
throw e;
}
return this;
}
@Override
@SuppressWarnings("unchecked")
public <T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode) {
public ProcedureCallImplementor<R> registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
getSession().checkOpen( true );
try {
registerParameter( parameterName, type, mode );
}
catch (HibernateException he) {
throw getSession().getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getSession().markForRollbackOnly();
throw e;
}
return this;
}
@Override
@SuppressWarnings("unchecked")
public <T> ProcedureParameter<T> registerParameter(int position, Class<T> javaType, ParameterMode mode) {
final ProcedureParameterImpl procedureParameter = new ProcedureParameterImpl(
this,
position,
mode,
type,
getSession().getFactory().getTypeResolver().heuristicType( type.getName() ),
globalParameterPassNullsSetting
javaType,
getSession().getFactory().getMetamodel().resolveQueryParameterType( javaType )
);
registerParameter( procedureParameter );
@ -302,20 +322,19 @@ public class ProcedureCallImpl<R>
}
@Override
public ParameterRegistrationImplementor getParameterRegistration(int position) {
return (ParameterRegistrationImplementor) getParameterMetadata().getQueryParameter( position );
public ProcedureParameterImplementor getParameterRegistration(int position) {
return getParameterMetadata().getQueryParameter( position );
}
@Override
@SuppressWarnings("unchecked")
public <T> ParameterRegistration<T> registerParameter(String name, Class<T> type, ParameterMode mode) {
public <T> ProcedureParameterImplementor<T> registerParameter(String name, Class<T> type, ParameterMode mode) {
final ProcedureParameterImpl parameter = new ProcedureParameterImpl(
this,
name,
mode,
type,
getSession().getFactory().getTypeResolver().heuristicType( type.getName() ),
globalParameterPassNullsSetting
getSession().getFactory().getMetamodel().resolveQueryParameterType( type )
);
registerParameter( parameter );
@ -331,14 +350,14 @@ public class ProcedureCallImpl<R>
}
@Override
public ParameterRegistrationImplementor getParameterRegistration(String name) {
public ProcedureParameterImplementor getParameterRegistration(String name) {
return getParameterMetadata().getQueryParameter( name );
}
@Override
@SuppressWarnings("unchecked")
public List getRegisteredParameters() {
return new ArrayList( getParameterMetadata().collectAllParameters() );
return new ArrayList( getParameterMetadata().getRegistrations() );
}
@Override
@ -382,13 +401,13 @@ public class ProcedureCallImpl<R>
// prepare parameters
getParameterMetadata().visitRegistrations(
new Consumer<QueryParameter>() {
new Consumer<QueryParameter<?>>() {
int i = 1;
@Override
public void accept(QueryParameter queryParameter) {
try {
final ParameterRegistrationImplementor registration = (ParameterRegistrationImplementor) queryParameter;
final ProcedureParameterImplementor registration = (ProcedureParameterImplementor) queryParameter;
registration.prepare( statement, i );
if ( registration.getMode() == ParameterMode.REF_CURSOR ) {
i++;
@ -416,26 +435,6 @@ public class ProcedureCallImpl<R>
return null;
}
@Override
public String[] getReturnAliases() {
throw new UnsupportedOperationException( "Procedure/function calls do not support returning aliases" );
}
@Override
public Type[] getReturnTypes() {
throw new UnsupportedOperationException( "Procedure/function calls do not support returning 'return types'" );
}
@Override
public ProcedureCallImplementor<R> setEntity(int position, Object val) {
return null;
}
@Override
public ProcedureCallImplementor<R> setEntity(String name, Object val) {
return null;
}
/**
* Use this form instead of {@link #getSynchronizedQuerySpaces()} when you want to make sure the
* underlying Set is instantiated (aka, on add)
@ -451,7 +450,6 @@ public class ProcedureCallImpl<R>
}
@Override
@SuppressWarnings("unchecked")
public Set<String> getSynchronizedQuerySpaces() {
if ( synchronizedQuerySpaces == null ) {
return Collections.emptySet();
@ -484,140 +482,121 @@ public class ProcedureCallImpl<R>
return this;
}
@Override
protected boolean isNativeQuery() {
return false;
}
@Override
public QueryParameters getQueryParameters() {
final QueryParameters qp = super.getQueryParameters();
// both of these are for documentation purposes, they are actually handled directly...
qp.setAutoDiscoverScalarTypes( true );
qp.setCallable( true );
return qp;
}
/**
* Collects any parameter registrations which indicate a REF_CURSOR parameter type/mode.
*
* @return The collected REF_CURSOR type parameters.
*/
public ParameterRegistrationImplementor[] collectRefCursorParameters() {
final List<ParameterRegistrationImplementor> refCursorParams = new ArrayList<>();
public ProcedureParameterImplementor[] collectRefCursorParameters() {
final List<ProcedureParameterImplementor> refCursorParams = new ArrayList<>();
getParameterMetadata().visitRegistrations(
queryParameter -> {
final ParameterRegistrationImplementor registration = (ParameterRegistrationImplementor) queryParameter;
final ProcedureParameterImplementor registration = (ProcedureParameterImplementor) queryParameter;
if ( registration.getMode() == ParameterMode.REF_CURSOR ) {
refCursorParams.add( registration );
}
}
);
return refCursorParams.toArray( new ParameterRegistrationImplementor[refCursorParams.size()] );
return refCursorParams.toArray( new ProcedureParameterImplementor[0] );
}
@Override
public NamedCallableQueryMemento extractMemento(Map<String, Object> hints) {
public NamedCallableQueryMemento toMemento(String name) {
return new NamedCallableQueryMementoImpl(
name,
procedureName,
Util.copy( queryReturns ),
getParameterMetadata().getParameterStrategy(),
toParameterMementos( getParameterMetadata() ),
Util.copy( synchronizedQuerySpaces ),
Util.copy( hints )
getParameterStrategy(),
toParameterMementos( parameterMetadata ),
// todo (6.0) : result-set-mapping names
null,
// todo (6.0) : result-set-mapping class names
null,
getSynchronizedQuerySpaces(),
isCacheable(),
getCacheRegion(),
getCacheMode(),
getHibernateFlushMode(),
isReadOnly(),
getTimeout(),
getFetchSize(),
getComment(),
getHints()
);
}
@Override
public NamedCallableQueryMemento extractMemento() {
return new NamedCallableQueryMementoImpl(
procedureName,
Util.copy( queryReturns ),
getParameterMetadata().getParameterStrategy(),
toParameterMementos( getParameterMetadata() ),
Util.copy( synchronizedQuerySpaces ),
Util.copy( getHints() )
);
}
private static List<NamedCallableQueryMementoImpl.ParameterMemento> toParameterMementos(ProcedureParameterMetadata parameterMetadata) {
private static List<NamedCallableQueryMementoImpl.ParameterMemento> toParameterMementos(
ProcedureParameterMetadataImpl parameterMetadata) {
if ( parameterMetadata.getParameterStrategy() == ParameterStrategy.UNKNOWN ) {
// none...
return Collections.emptyList();
}
final List<NamedCallableQueryMementoImpl.ParameterMemento> copy = new ArrayList<>();
final List<NamedCallableQueryMementoImpl.ParameterMemento> mementos = new ArrayList<>();
parameterMetadata.visitRegistrations(
queryParameter -> {
final ParameterRegistrationImplementor registration = (ParameterRegistrationImplementor) queryParameter;
copy.add( NamedCallableQueryMementoImpl.ParameterMemento.fromRegistration( registration ) );
final ProcedureParameterImplementor procedureParameter = (ProcedureParameterImplementor) queryParameter;
mementos.add(
new NamedCallableQueryMementoImpl.ParameterMementoImpl(
procedureParameter.getPosition(),
procedureParameter.getName(),
procedureParameter.getMode(),
procedureParameter.getParameterType(),
procedureParameter.getHibernateType()
)
);
}
);
return copy;
return mementos;
}
@Override
protected boolean canApplyAliasSpecificLockModes() {
return false;
}
@Override
protected void verifySettingLockMode() {
throw new IllegalStateException( "Illegal attempt to set lock mode on a ProcedureCall / StoredProcedureQuery" );
}
@Override
protected void verifySettingAliasSpecificLockModes() {
throw new IllegalStateException( "Illegal attempt to set lock mode on a ProcedureCall / StoredProcedureQuery" );
}
@Override
protected void applyEntityGraphQueryHint(String hintName, RootGraphImplementor entityGraph) {
throw new IllegalStateException( "EntityGraph hints are not supported for ProcedureCall/StoredProcedureQuery" );
}
@Override
public Query<R> applyGraph(RootGraph<?> graph, GraphSemantic semantic) {
throw new IllegalStateException( "EntityGraph hints are not supported for ProcedureCall/StoredProcedureQuery" );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA StoredProcedureQuery impl
// outputs
private ProcedureOutputs procedureResult;
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
getProducer().checkOpen( true );
try {
registerParameter( position, type, mode );
}
catch (HibernateException he) {
throw getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getProducer().markForRollbackOnly();
throw e;
}
return this;
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
getProducer().checkOpen( true );
try {
registerParameter( parameterName, type, mode );
}
catch (HibernateException he) {
throw getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getProducer().markForRollbackOnly();
throw e;
}
return this;
}
// outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean execute() {
try {
final Output rtn = outputs().getCurrent();
return rtn != null && ResultSetOutput.class.isInstance( rtn );
return ResultSetOutput.class.isInstance( rtn );
}
catch (NoMoreReturnsException e) {
catch (NoMoreOutputsException e) {
return false;
}
catch (HibernateException he) {
throw getExceptionConverter().convert( he );
throw getSession().getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getProducer().markForRollbackOnly();
getSession().markForRollbackOnly();
throw e;
}
}
@ -630,9 +609,10 @@ public class ProcedureCallImpl<R>
}
@Override
public int executeUpdate() {
getSession().checkTransactionNeededForUpdateOperation(
"javax.persistence.Query.executeUpdate requires active transaction" );
protected int doExecuteUpdate() {
if ( ! getSession().isTransactionInProgress() ) {
throw new TransactionRequiredException( "javax.persistence.Query.executeUpdate requires active transaction" );
}
// the expectation is that there is just one Output, of type UpdateCountOutput
try {
@ -691,11 +671,11 @@ public class ProcedureCallImpl<R>
return -1;
}
}
catch (NoMoreReturnsException e) {
catch (NoMoreOutputsException e) {
return -1;
}
catch (HibernateException he) {
throw getExceptionConverter().convert( he );
throw getSession().getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getSession().markForRollbackOnly();
@ -703,6 +683,39 @@ public class ProcedureCallImpl<R>
}
}
@Override
@SuppressWarnings("unchecked")
protected List<R> doList() {
if ( getMaxResults() == 0 ) {
return Collections.EMPTY_LIST;
}
try {
final Output rtn = outputs().getCurrent();
if ( ! ResultSetOutput.class.isInstance( rtn ) ) {
throw new IllegalStateException( "Current CallableStatement ou was not a ResultSet, but getResultList was called" );
}
return ( (ResultSetOutput) rtn ).getResultList();
}
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.
return null;
}
catch (HibernateException he) {
throw getSession().getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getSession().markForRollbackOnly();
throw e;
}
}
@Override
protected ScrollableResultsImplementor doScroll(ScrollMode scrollMode) {
throw new UnsupportedOperationException( "Query#scroll is not valid for ProcedureCall/StoredProcedureQuery" );
}
@Override
@SuppressWarnings("unchecked")
@ -712,7 +725,7 @@ public class ProcedureCallImpl<R>
}
try {
final Output rtn = outputs().getCurrent();
if ( ! ResultSetOutput.class.isInstance( rtn ) ) {
if ( !(rtn instanceof ResultSetOutput) ) {
throw new IllegalStateException( "Current CallableStatement ou was not a ResultSet, but getResultList was called" );
}
@ -725,7 +738,7 @@ public class ProcedureCallImpl<R>
return null;
}
catch (HibernateException he) {
throw getExceptionConverter().convert( he );
throw getSession().getExceptionConverter().convert( he );
}
catch (RuntimeException e) {
getSession().markForRollbackOnly();
@ -762,11 +775,28 @@ public class ProcedureCallImpl<R>
if ( cls.isInstance( this ) ) {
return (T) this;
}
else if ( cls.isInstance( outputs ) ) {
return (T) outputs();
if ( cls.isInstance( parameterMetadata ) ) {
return (T) parameterMetadata;
}
return super.unwrap( cls );
if ( cls.isInstance( paramBindings ) ) {
return (T) paramBindings;
}
if ( cls.isInstance( queryOptions ) ) {
return (T) queryOptions;
}
if ( cls.isInstance( getSession() ) ) {
return (T) getSession();
}
if ( ProcedureOutputs.class.isAssignableFrom( cls ) ) {
return (T) getOutputs();
}
throw new PersistenceException( "Unrecognized unwrap type : " + cls.getName() );
}
@Override
@ -797,121 +827,100 @@ public class ProcedureCallImpl<R>
@Override
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value) {
paramBindings.getBinding( getParameterMetadata().resolve( parameter ) ).setBindValue( value );
return this;
return (ProcedureCallImplementor<R>) super.setParameter( parameter, value );
}
@Override
public <P> ProcedureCallImplementor<R> setParameter(Parameter<P> parameter, P value) {
paramBindings.getBinding( getParameterMetadata().resolve( parameter ) ).setBindValue( value );
return this;
return (ProcedureCallImplementor<R>) super.setParameter( parameter, value );
}
@Override
public ProcedureCallImplementor<R> setParameter(String name, Object value) {
paramBindings.getBinding( getParameterMetadata().getQueryParameter( name ) ).setBindValue( value );
return this;
return (ProcedureCallImplementor<R>) super.setParameter( name, value );
}
@Override
public ProcedureCallImplementor<R> setParameter(int position, Object value) {
paramBindings.getBinding( getParameterMetadata().getQueryParameter( position ) ).setBindValue( value );
return this;
return (ProcedureCallImplementor<R>) super.setParameter( position, value );
}
@Override
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, AllowableParameterType type) {
return (ProcedureCallImplementor<R>) super.setParameter( parameter, value, type );
}
@Override
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, Type type) {
final QueryParameterBinding<P> binding = paramBindings.getBinding( parameter );
binding.setBindValue( value, type );
return this;
return (ProcedureCallImplementor<R>) super.setParameter( parameter, value, type );
}
@Override
public ProcedureCallImplementor<R> setParameter(String name, Object value, AllowableParameterType type) {
return (ProcedureCallImplementor<R>) super.setParameter( name, value, type );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(String name, Object value, Type type) {
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( name ) );
binding.setBindValue( value, type );
return this;
return (ProcedureCallImplementor<R>) super.setParameter( name, value, type );
}
@Override
public ProcedureCallImplementor<R> setParameter(int position, Object value, AllowableParameterType type) {
//noinspection unchecked
return (ProcedureCallImplementor<R>) super.setParameter( position, value, type );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(int position, Object value, Type type) {
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( position ) );
binding.setBindValue( value, type );
return this;
return (ProcedureCallImplementor<R>) super.setParameter( position, value, type );
}
@Override
@SuppressWarnings("unchecked")
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( parameter );
binding.setBindValue( value, temporalType );
return this;
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor<R>) super.setParameter( parameter, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(String name, Object value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( name ) );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(String name, Object value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor<R>) super.setParameter( name, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(int position, Object value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( position ) );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(int position, Object value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor<R>) super.setParameter( position, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Calendar value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().resolve( parameter ) );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Calendar value, TemporalType temporalPrecision) {
//noinspection unchecked
return (ProcedureCallImplementor<R>) super.setParameter( parameter, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Date value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().resolve( parameter ) );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Date value, TemporalType temporalPrecision) {
//noinspection unchecked
return (ProcedureCallImplementor<R>) super.setParameter( parameter, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(String name, Calendar value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( name );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(String name, Calendar value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor<R>) super.setParameter( name, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(String name, Date value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( name );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(String name, Date value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor<R>) super.setParameter( name, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(int position, Calendar value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( position );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(int position, Calendar value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor<R>) super.setParameter( position, value, temporalPrecision );
}
@Override
@SuppressWarnings("unchecked")
public ProcedureCallImplementor<R> setParameter(int position, Date value, TemporalType temporalType) {
final QueryParameterBinding binding = paramBindings.getBinding( position );
binding.setBindValue( value, temporalType );
return this;
public ProcedureCallImplementor<R> setParameter(int position, Date value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor<R>) super.setParameter( position, value, temporalPrecision );
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.procedure.internal;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.internal.QueryParameterBindingImpl;
import org.hibernate.query.procedure.ProcedureParameterBinding;
import org.hibernate.query.procedure.spi.ProcedureParameterBindingImplementor;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
/**
* Implementation of the {@link ProcedureParameterBinding} contract.
*
* @author Steve Ebersole
*/
public class ProcedureParameterBindingImpl<T>
extends QueryParameterBindingImpl<T>
implements ProcedureParameterBindingImplementor<T> {
public ProcedureParameterBindingImpl(
ProcedureParameterImplementor<T> queryParameter,
QueryParameterBindingTypeResolver typeResolver) {
super( queryParameter, typeResolver, true );
}
public ProcedureParameterBindingImpl(
AllowableParameterType<T> bindType,
ProcedureParameterImplementor<T> queryParameter,
QueryParameterBindingTypeResolver typeResolver) {
super( queryParameter, typeResolver, bindType, true );
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.procedure.internal;
import java.util.Objects;
import javax.persistence.ParameterMode;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.query.AbstractQueryParameter;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
/**
* @author Steve Ebersole
*/
public class ProcedureParameterImpl<T> extends AbstractQueryParameter<T> implements ProcedureParameterImplementor<T> {
private final String name;
private final Integer position;
private final ParameterMode mode;
private final Class<T> javaType;
public ProcedureParameterImpl(
String name,
ParameterMode mode,
Class<T> javaType,
AllowableParameterType<T> hibernateType) {
super( false, hibernateType );
this.name = name;
this.position = null;
this.mode = mode;
this.javaType = javaType;
}
public ProcedureParameterImpl(
Integer position,
ParameterMode mode,
Class<T> javaType,
AllowableParameterType<T> hibernateType) {
super( false, hibernateType );
this.name = null;
this.position = position;
this.mode = mode;
this.javaType = javaType;
}
@Override
public String getName() {
return name;
}
@Override
public Integer getPosition() {
return position;
}
@Override
public ParameterMode getMode() {
return mode;
}
@Override
public Class<T> getParameterType() {
return javaType;
}
public NamedCallableQueryMemento.ParameterMemento toMemento() {
return session -> {
if ( getName() != null ) {
//noinspection unchecked
return new ProcedureParameterImpl(
getName(),
getMode(),
javaType,
getHibernateType()
);
}
else {
//noinspection unchecked
return new ProcedureParameterImpl(
getPosition(),
getMode(),
javaType,
getHibernateType()
);
}
};
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
ProcedureParameterImpl<?> that = (ProcedureParameterImpl<?>) o;
return Objects.equals( name, that.name ) &&
Objects.equals( position, that.position ) &&
mode == that.mode;
}
@Override
public int hashCode() {
return Objects.hash( name, position, mode );
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.procedure.internal;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.sql.results.internal.ScalarDomainResultImpl;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.DomainResultProducer;
/**
* @author Steve Ebersole
*/
public class ScalarDomainResultProducer<T> implements DomainResultProducer<T> {
private final SqmExpressable<T> expressableType;
public ScalarDomainResultProducer(SqmExpressable<T> expressableType) {
this.expressableType = expressableType;
}
@Override
public DomainResult<T> createDomainResult(
String resultVariable,
DomainResultCreationState creationState) {
return new ScalarDomainResultImpl<>( resultVariable, expressableType );
}
}

View File

@ -6,18 +6,18 @@
*/
package org.hibernate.procedure.internal;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.query.sql.spi.ResultSetMappingDescriptor;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.UnknownSqlResultSetMappingException;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.spi.DomainMetamodel;
import org.hibernate.query.spi.NamedQueryRepository;
import org.hibernate.query.spi.NamedResultSetMappingMemento;
import org.hibernate.query.spi.ResultSetMapping;
import org.hibernate.sql.results.spi.DomainResultProducer;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
@ -32,148 +32,66 @@ public class Util {
private Util() {
}
/**
* Makes a copy of the given query return array.
*
* @param queryReturns The returns to copy
*
* @return The copy
*/
public static NativeSQLQueryReturn[] copy(NativeSQLQueryReturn[] queryReturns) {
if ( queryReturns == null ) {
return new NativeSQLQueryReturn[0];
public static void resolveResultSetMappings(
String[] resultSetMappingNames,
Class[] resultSetMappingClasses,
Consumer<DomainResultProducer> resultProducerConsumer,
Consumer<String> querySpaceConsumer,
SessionFactoryImplementor sessionFactory) {
if ( ! ArrayHelper.isEmpty( resultSetMappingNames ) ) {
// cannot specify both
if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) {
throw new IllegalArgumentException( "Cannot specify both result-set mapping names and classes" );
}
resolveResultSetMappingNames( resultSetMappingNames, resultProducerConsumer, querySpaceConsumer, sessionFactory );
}
else if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) {
resolveResultSetMappingClasses( resultSetMappingClasses, resultProducerConsumer, querySpaceConsumer, sessionFactory );
}
final NativeSQLQueryReturn[] copy = new NativeSQLQueryReturn[ queryReturns.length ];
System.arraycopy( queryReturns, 0, copy, 0, queryReturns.length );
return copy;
// otherwise, nothing to resolve
}
/**
* Make a (shallow) copy of query spaces to be synchronized
*
* @param synchronizedQuerySpaces The query spaces
*
* @return The copy
*/
public static Set<String> copy(Set<String> synchronizedQuerySpaces) {
return CollectionHelper.makeCopy( synchronizedQuerySpaces );
}
public static void resolveResultSetMappingNames(
String[] resultSetMappingNames,
Consumer<DomainResultProducer> resultProducerConsumer,
Consumer<String> querySpaceConsumer,
SessionFactoryImplementor sessionFactory) {
final NamedQueryRepository namedQueryRepository = sessionFactory.getQueryEngine().getNamedQueryRepository();
/**
* Make a (shallow) copy of the JPA query hints map
*
* @param hints The JPA query hints to copy
*
* @return The copy
*/
public static Map<String,Object> copy(Map<String, Object> hints) {
return CollectionHelper.makeCopy( hints );
}
/**
* Context for resolving result-set-mapping definitions
*/
public static interface ResultSetMappingResolutionContext {
/**
* Access to the SessionFactory
*
* @return SessionFactory
*/
public SessionFactoryImplementor getSessionFactory();
/**
* Locate a ResultSetMappingDefinition by name
*
* @param name The name of the ResultSetMappingDefinition to locate
*
* @return The ResultSetMappingDefinition
*/
public ResultSetMappingDescriptor findResultSetMapping(String name);
/**
* Callback to add query returns indicated by the result set mapping(s)
*
* @param queryReturns The query returns
*/
public void addQueryReturns(NativeSQLQueryReturn... queryReturns);
/**
* Callback to add query spaces indicated by the result set mapping(s)
*
* @param querySpaces The query spaces
*/
public void addQuerySpaces(String... querySpaces);
}
/**
* Resolve the given result set mapping names
*
* @param context The context for the resolution. See {@link ResultSetMappingResolutionContext}
* @param resultSetMappingNames The names of the result-set-mappings to resolve
*/
public static void resolveResultSetMappings(ResultSetMappingResolutionContext context, String... resultSetMappingNames) {
for ( String resultSetMappingName : resultSetMappingNames ) {
log.tracef( "Starting attempt resolve named result-set-mapping : %s", resultSetMappingName );
final ResultSetMappingDescriptor mapping = context.findResultSetMapping( resultSetMappingName );
if ( mapping == null ) {
throw new UnknownSqlResultSetMappingException( "Unknown SqlResultSetMapping [" + resultSetMappingName + "]" );
}
log.tracef( "Found result-set-mapping : %s", mapping.traceLoggableFormat() );
context.addQueryReturns( mapping.getQueryReturns() );
final SQLQueryReturnProcessor processor =
new SQLQueryReturnProcessor( mapping.getQueryReturns(), context.getSessionFactory() );
final SQLQueryReturnProcessor.ResultAliasContext processResult = processor.process();
context.addQuerySpaces( processResult.collectQuerySpaces() );
final NamedResultSetMappingMemento memento = namedQueryRepository.getResultSetMappingMemento( resultSetMappingName );
final ResultSetMapping resultSetMapping = memento.toResultSetMapping();
resultProducerConsumer.accept( resultSetMapping );
// todo (6.0) : determine query spaces - maybe passing the consumer to `NamedResultSetMappingMemento#toResultSetMapping`?
}
}
/**
* Context for resolving result-class definitions
*/
public static interface ResultClassesResolutionContext {
/**
* Access to the SessionFactory
*
* @return SessionFactory
*/
public SessionFactoryImplementor getSessionFactory();
/**
* Callback to add query returns indicated by the result set mapping(s)
*
* @param queryReturns The query returns
*/
public void addQueryReturns(NativeSQLQueryReturn... queryReturns);
public static void resolveResultSetMappingClasses(
Class[] resultSetMappingClasses,
Consumer<DomainResultProducer> resultProducerConsumer,
Consumer<String> querySpaceConsumer,
SessionFactoryImplementor sessionFactory) {
/**
* Callback to add query spaces indicated by the result set mapping(s)
*
* @param querySpaces The query spaces
*/
public void addQuerySpaces(String... querySpaces);
}
final DomainMetamodel domainModel = sessionFactory.getDomainModel();
final TypeConfiguration typeConfiguration = domainModel.getTypeConfiguration();
/**
* Resolve the given result classes
*
* @param context The context for the resolution. See {@link ResultSetMappingResolutionContext}
* @param resultClasses The Classes to which the results should be mapped
*/
public static void resolveResultClasses(ResultClassesResolutionContext context, Class... resultClasses) {
int i = 0;
for ( Class resultClass : resultClasses ) {
context.addQueryReturns(
new NativeSQLQueryRootReturn( "alias" + (++i), resultClass.getName(), LockMode.READ )
);
try {
final EntityPersister persister = context.getSessionFactory().getEntityPersister( resultClass.getName() );
context.addQuerySpaces( (String[]) persister.getQuerySpaces() );
}
catch (Exception ignore) {
for ( Class resultSetMappingClass : resultSetMappingClasses ) {
final BasicType basicType = typeConfiguration.getBasicTypeForJavaType( resultSetMappingClass );
if ( basicType != null ) {
//noinspection unchecked
resultProducerConsumer.accept( new ScalarDomainResultProducer<>( basicType ) );
continue;
}
throw new NotYetImplementedFor6Exception();
// final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( resultSetMappingClass );
// if ( entityDescriptor != null ) {
// resultProducerConsumer.accept( new Entity );
// for ( String querySpace : entityDescriptor.getSynchronizedQuerySpaces() ) {
// querySpaceConsumer.accept( querySpace );
// }
// }
}
}
}

View File

@ -7,44 +7,27 @@
package org.hibernate.procedure.spi;
import java.sql.CallableStatement;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.procedure.internal.FunctionReturnImpl;
import org.hibernate.query.procedure.internal.ProcedureParamBindings;
import org.hibernate.query.procedure.internal.ProcedureParameterMetadata;
import org.hibernate.query.spi.ParameterMetadataImplementor;
/**
* @author Steve Ebersole
*/
public interface CallableStatementSupport {
default String renderCallableStatement(
String name,
ParameterStrategy parameterStrategy,
List<ParameterRegistrationImplementor<?>> parameterRegistrations,
SharedSessionContractImplementor session) {
throw new UnsupportedOperationException(
"Legacy #renderCallableStatement called but implementation does not support that call."
);
}
default String renderCallableStatement(
JdbcCall interpretCall(
String procedureName,
ProcedureParameterMetadata parameterMetadata,
FunctionReturnImpl functionReturn,
ParameterMetadataImplementor parameterMetadata,
ProcedureParamBindings paramBindings,
SharedSessionContractImplementor session) {
return renderCallableStatement(
procedureName,
parameterMetadata.getParameterStrategy(),
new ArrayList( parameterMetadata.collectAllParameters() ),
session
);
}
SharedSessionContractImplementor session);
void registerParameters(
String procedureName,
CallableStatement statement,
ParameterStrategy parameterStrategy,
List<ParameterRegistrationImplementor<?>> parameterRegistrations,
ParameterMetadataImplementor parameterMetadata,
SharedSessionContractImplementor session);
}

View File

@ -0,0 +1,16 @@
/*
* 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.procedure.spi;
import org.hibernate.procedure.FunctionReturn;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
/**
* @author Steve Ebersole
*/
public interface FunctionReturnImplementor extends FunctionReturn, ProcedureParameterImplementor {
}

View File

@ -6,11 +6,15 @@
*/
package org.hibernate.procedure.spi;
import java.util.List;
import java.util.Set;
import org.hibernate.Incubating;
import org.hibernate.Session;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.NamedQueryMemento;
/**
@ -25,6 +29,8 @@ public interface NamedCallableQueryMemento extends NamedQueryMemento {
*/
String getCallableName();
List<ParameterMemento> getParameterMementos();
/**
* Convert the memento back into an executable (connected) form.
*
@ -47,6 +53,14 @@ public interface NamedCallableQueryMemento extends NamedQueryMemento {
return makeProcedureCall( (SharedSessionContractImplementor) session );
}
ParameterStrategy getParameterStrategy();
String[] getResultSetMappingNames();
Class[] getResultSetMappingClasses();
Set<String> getQuerySpaces();
/**
* Convert the memento back into an executable (connected) form.
*
@ -57,6 +71,6 @@ public interface NamedCallableQueryMemento extends NamedQueryMemento {
ProcedureCall makeProcedureCall(SharedSessionContractImplementor session);
interface ParameterMemento {
ParameterRegistrationImplementor resolve(SharedSessionContractImplementor session);
ProcedureParameterImplementor resolve(SharedSessionContractImplementor session);
}
}

View File

@ -1,69 +0,0 @@
/*
* 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.procedure.spi;
import java.sql.CallableStatement;
import java.sql.SQLException;
import org.hibernate.procedure.ParameterRegistration;
import org.hibernate.query.QueryParameter;
import org.hibernate.type.Type;
/**
* Additional internal contract for ParameterRegistration
*
* @author Steve Ebersole
*/
public interface ParameterRegistrationImplementor<T> extends ParameterRegistration<T> {
/**
* Prepare for execution.
*
* @param statement The statement about to be executed
* @param i The parameter index for this registration (used for positional)
*
* @throws SQLException Indicates a problem accessing the statement object
*/
void prepare(CallableStatement statement, int i) throws SQLException;
/**
* Access to the Hibernate type for this parameter registration
*
* @return The Hibernate Type
*/
@Override
Type getHibernateType();
/**
* If no value is bound for this parameter registration, is the passing of NULL
* to the JDBC CallableStatement for that parameter enabled? This effectively controls
* whether default values for the argument as defined in the database are applied or not.
*
* @return {@code true} indicates that NULL will be passed to the JDBC driver, effectively disabling
* the application of the default argument value defined in the database; {@code false} indicates
* that the parameter will simply be ignored, with the assumption that the corresponding argument
* defined a default value.
*/
@Override
boolean isPassNullsEnabled();
/**
* Access to the SQL type(s) for this parameter
*
* @return The SQL types (JDBC type codes)
*/
int[] getSqlTypes();
/**
* Extract value from the statement after execution (used for OUT/INOUT parameters).
*
* @param statement The callable statement
*
* @return The extracted value
*/
T extract(CallableStatement statement);
}

View File

@ -0,0 +1,62 @@
/*
* 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.query;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.spi.QueryParameterImplementor;
/**
* @author Steve Ebersole
*/
public abstract class AbstractQueryParameter<T> implements QueryParameterImplementor<T> {
private boolean allowMultiValuedBinding;
private AllowableParameterType<T> anticipatedType;
public AbstractQueryParameter(
boolean allowMultiValuedBinding,
AllowableParameterType<T> anticipatedType) {
this.allowMultiValuedBinding = allowMultiValuedBinding;
this.anticipatedType = anticipatedType;
}
@Override
public void disallowMultiValuedBinding() {
QueryLogger.QUERY_LOGGER.debugf( "QueryParameter#disallowMultiValuedBinding() called : %s", this );
this.allowMultiValuedBinding = true;
}
@Override
public boolean allowsMultiValuedBinding() {
return allowMultiValuedBinding;
}
@Override
public AllowableParameterType<T> getHibernateType() {
return anticipatedType;
}
@Override
public void applyAnticipatedType(AllowableParameterType type) {
//noinspection unchecked
this.anticipatedType = type;
}
@Override
public String getName() {
return null;
}
@Override
public Integer getPosition() {
return null;
}
@Override
public Class<T> getParameterType() {
return null;
}
}

View File

@ -1,10 +1,10 @@
/*
* 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>.
* 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.procedure;
package org.hibernate.query;
import org.hibernate.MappingException;

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.query.hql.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.spi.NameableQuery;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryImplementor;
@ -16,7 +15,7 @@ import org.hibernate.query.spi.QueryImplementor;
*/
public interface HqlQueryImplementor<R> extends QueryImplementor<R>, NameableQuery {
@Override
NamedHqlQueryMemento toMemento(String name, SessionFactoryImplementor factory);
NamedHqlQueryMemento toMemento(String name);
@Override
ParameterMetadataImplementor getParameterMetadata();

View File

@ -14,6 +14,7 @@ import org.hibernate.boot.spi.NamedHqlQueryDefinition;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
import org.hibernate.query.spi.AbstractNamedQueryMemento;
import org.hibernate.query.spi.NameableQuery;
import org.hibernate.query.spi.NamedQueryMemento;
/**
@ -52,7 +53,7 @@ public interface NamedHqlQueryMemento extends NamedQueryMemento {
* Delegate used in creating named HQL query mementos.
*
* @see NamedHqlQueryDefinition
* @see HqlQueryImplementor#toMemento
* @see NameableQuery#toMemento
*/
class Builder extends AbstractNamedQueryMemento.AbstractBuilder<Builder> {
protected String hqlString;

View File

@ -6,8 +6,8 @@
*/
package org.hibernate.query.internal;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.QueryParameter;
import org.hibernate.type.Type;
/**
* QueryParameter implementation.
@ -17,24 +17,25 @@ import org.hibernate.type.Type;
*
* @author Steve Ebersole
*/
public abstract class QueryParameterImpl<T> implements QueryParameter<T> {
private Type expectedType;
public abstract class AbstractQueryParameterImpl<T> implements QueryParameter<T> {
private AllowableParameterType<T> expectedType;
public QueryParameterImpl(Type expectedType) {
public AbstractQueryParameterImpl(AllowableParameterType<T> expectedType) {
this.expectedType = expectedType;
}
@Override
public Type getHibernateType() {
public AllowableParameterType<T> getHibernateType() {
return expectedType;
}
public void setHibernateType(Type expectedType) {
this.expectedType = expectedType;
public void setHibernateType(AllowableParameterType<?> expectedType) {
//noinspection unchecked
this.expectedType = (AllowableParameterType) expectedType;
}
@Override
public Class<T> getParameterType() {
return expectedType == null ? null : expectedType.getReturnedClass();
return expectedType == null ? null : expectedType.getJavaType();
}
}

View File

@ -19,7 +19,7 @@ import org.hibernate.type.Type;
*
* @author Steve Ebersole
*/
public class QueryParameterNamedImpl<T> extends QueryParameterImpl<T> implements QueryParameter<T> {
public class QueryParameterNamedImpl<T> extends AbstractQueryParameterImpl<T> implements QueryParameter<T> {
private final String name;
private final int[] sourceLocations;

View File

@ -9,7 +9,6 @@ package org.hibernate.query.procedure;
import javax.persistence.ParameterMode;
import org.hibernate.Incubating;
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
import org.hibernate.query.QueryParameter;
/**
@ -33,8 +32,6 @@ public interface ProcedureParameter<T> extends QueryParameter<T> {
* @return {@code true} here indicates that NULL should be passed; {@code false} indicates
* that it is ignored.
*
* @see ParameterRegistrationImplementor#isPassNullsEnabled()
*
* @deprecated (since 6.0) : Passing null or not is now triggered by whether
* setting the parameter was called at all. In other words a distinction is
* made between calling `setParameter` passing {@code null} versus not calling
@ -42,18 +39,19 @@ public interface ProcedureParameter<T> extends QueryParameter<T> {
* the second we do not pass {@code null}.
*/
@Deprecated
boolean isPassNullsEnabled();
default boolean isPassNullsEnabled() {
return false;
}
/**
* Controls how unbound values for this IN/INOUT parameter registration will be handled prior to
* execution. For details see {@link org.hibernate.procedure.ParameterRegistration#enablePassingNulls}
* execution.
*
* @param enabled {@code true} indicates that the NULL should be passed; {@code false} indicates it should not.
*
* @see org.hibernate.procedure.ParameterRegistration#enablePassingNulls
*
* @deprecated (since 6.0) : see {@link #isPassNullsEnabled}
*/
@Deprecated
void enablePassingNulls(boolean enabled);
default void enablePassingNulls(boolean enabled) {
}
}

View File

@ -9,6 +9,8 @@ package org.hibernate.query.procedure;
import org.hibernate.query.spi.QueryParameterBinding;
/**
* Describes an input value binding for any IN/INOUT parameters.
*
* @author Steve Ebersole
*/
public interface ProcedureParameterBinding<T> extends QueryParameterBinding<T> {

View File

@ -10,35 +10,31 @@ import java.util.HashMap;
import java.util.Map;
import javax.persistence.ParameterMode;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.procedure.ParameterBind;
import org.hibernate.procedure.internal.ParameterBindImpl;
import org.hibernate.procedure.internal.ProcedureCallImpl;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.procedure.ProcedureParameterBinding;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterListBinding;
import org.hibernate.type.Type;
import org.hibernate.query.spi.QueryParameterImplementor;
/**
* @author Steve Ebersole
*/
public class ProcedureParamBindings implements QueryParameterBindings {
private final ProcedureParameterMetadata parameterMetadata;
private final ProcedureParameterMetadataImpl parameterMetadata;
private final ProcedureCallImpl procedureCall;
private final Map<ProcedureParameterImplementor, ParameterBind> bindingMap = new HashMap<>();
private final Map<ProcedureParameterImplementor<?>, ProcedureParameterBinding<?>> bindingMap = new HashMap<>();
public ProcedureParamBindings(
ProcedureParameterMetadata parameterMetadata,
ProcedureParameterMetadataImpl parameterMetadata,
ProcedureCallImpl procedureCall) {
this.parameterMetadata = parameterMetadata;
this.procedureCall = procedureCall;
}
public ProcedureParameterMetadata getParameterMetadata() {
public ProcedureParameterMetadataImpl getParameterMetadata() {
return parameterMetadata;
}
@ -47,14 +43,13 @@ public class ProcedureParamBindings implements QueryParameterBindings {
}
@Override
public boolean isBound(QueryParameter parameter) {
return getBinding( parameter ).isBound();
public QueryParameterBinding<?> getBinding(QueryParameterImplementor<?> parameter) {
return getBinding( parameterMetadata.resolve( parameter ) );
}
@Override
public <T> QueryParameterBinding<T> getBinding(QueryParameter<T> parameter) {
final ProcedureParameterImplementor<T> procParam = parameterMetadata.resolve( parameter );
ParameterBind binding = bindingMap.get( procParam );
public QueryParameterBinding<?> getBinding(ProcedureParameterImplementor parameter) {
final ProcedureParameterImplementor procParam = parameterMetadata.resolve( parameter );
ProcedureParameterBinding binding = bindingMap.get( procParam );
if ( binding == null ) {
if ( ! parameterMetadata.containsReference( parameter ) ) {
@ -69,12 +64,12 @@ public class ProcedureParamBindings implements QueryParameterBindings {
}
@Override
public <T> QueryParameterBinding<T> getBinding(String name) {
public ProcedureParameterBinding<?> getBinding(String name) {
return getBinding( parameterMetadata.getQueryParameter( name ) );
}
@Override
public <T> QueryParameterBinding<T> getBinding(int position) {
public ProcedureParameterBinding getBinding(int position) {
return getBinding( parameterMetadata.getQueryParameter( position ) );
}
@ -94,42 +89,4 @@ public class ProcedureParamBindings implements QueryParameterBindings {
);
}
@Override
public String expandListValuedParameters(String queryString, SharedSessionContractImplementor producer) {
return queryString;
}
@Override
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(QueryParameter<T> parameter) {
return null;
}
@Override
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(String name) {
return null;
}
@Override
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(int position) {
return null;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// I think these are not needed for proc call execution
@Override
public Type[] collectPositionalBindTypes() {
return new Type[0];
}
@Override
public Object[] collectPositionalBindValues() {
return new Object[0];
}
@Override
public Map<String, TypedValue> collectNamedParameterBindings() {
return null;
}
}

View File

@ -8,24 +8,20 @@ package org.hibernate.query.procedure.internal;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Calendar;
import javax.persistence.ParameterMode;
import javax.persistence.TemporalType;
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.procedure.ParameterBind;
import org.hibernate.metamodel.model.domain.AllowableOutputParameterType;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType;
import org.hibernate.procedure.ParameterMisuseException;
import org.hibernate.procedure.ParameterRegistration;
import org.hibernate.procedure.internal.ProcedureCallImpl;
import org.hibernate.procedure.spi.ParameterStrategy;
import org.hibernate.query.internal.QueryParameterImpl;
import org.hibernate.query.internal.AbstractQueryParameterImpl;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.type.CalendarDateType;
import org.hibernate.type.CalendarTimeType;
import org.hibernate.type.CalendarType;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.type.ProcedureParameterExtractionAware;
import org.hibernate.type.ProcedureParameterNamedBinder;
import org.hibernate.type.Type;
@ -36,8 +32,8 @@ import org.jboss.logging.Logger;
* @author Steve Ebersole
*/
public class ProcedureParameterImpl<T>
extends QueryParameterImpl<T>
implements ProcedureParameterImplementor<T>, ParameterRegistration<T> {
extends AbstractQueryParameterImpl<T>
implements ProcedureParameterImplementor<T> {
private static final Logger log = Logger.getLogger( ProcedureParameterImpl.class );
private final ProcedureCallImpl procedureCall;
@ -46,9 +42,6 @@ public class ProcedureParameterImpl<T>
private final ParameterMode mode;
private final Class<T> javaType;
private int[] sqlTypes;
private boolean passNullsEnabled;
// in-flight state needed between prepare and extract
private int startIndex;
@ -57,15 +50,13 @@ public class ProcedureParameterImpl<T>
String name,
ParameterMode mode,
Class<T> javaType,
Type hibernateType,
boolean initialPassNullsSetting) {
AllowableParameterType<T> hibernateType) {
super( hibernateType );
this.procedureCall = procedureCall;
this.name = name;
this.position = null;
this.mode = mode;
this.javaType = javaType;
this.passNullsEnabled = initialPassNullsSetting;
setHibernateType( hibernateType );
}
@ -75,15 +66,13 @@ public class ProcedureParameterImpl<T>
Integer position,
ParameterMode mode,
Class<T> javaType,
Type hibernateType,
boolean initialPassNullsSetting) {
AllowableParameterType<T> hibernateType) {
super( hibernateType );
this.procedureCall = procedureCall;
this.name = null;
this.position = position;
this.mode = mode;
this.javaType = javaType;
this.passNullsEnabled = initialPassNullsSetting;
setHibernateType( hibernateType );
}
@ -93,21 +82,6 @@ public class ProcedureParameterImpl<T>
return mode;
}
@Override
public boolean isPassNullsEnabled() {
return passNullsEnabled;
}
@Override
public void enablePassingNulls(boolean enabled) {
this.passNullsEnabled = enabled;
}
@Override
public int[] getSourceLocations() {
return new int[0];
}
@Override
public String getName() {
return name;
@ -119,74 +93,29 @@ public class ProcedureParameterImpl<T>
}
@Override
public void setHibernateType(Type expectedType) {
public void setHibernateType(AllowableParameterType<?> expectedType) {
super.setHibernateType( expectedType );
if ( mode == ParameterMode.REF_CURSOR ) {
sqlTypes = new int[] { Types.REF_CURSOR };
}
else {
if ( expectedType == null ) {
throw new IllegalArgumentException( "Type cannot be null" );
}
else {
sqlTypes = expectedType.sqlTypes( procedureCall.getSession().getFactory() );
if ( mode == ParameterMode.REF_CURSOR || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
if ( ! ( expectedType instanceof AllowableOutputParameterType ) ) {
throw new IllegalArgumentException( "Passed type must implement AllowableOutputParameterType" );
}
}
}
@Override
public Class<T> getParameterType() {
return javaType;
}
@Override
public ParameterBind<T> getBind() {
return (ParameterBind<T>) procedureCall.getQueryParameterBindings().getBinding( this );
}
@Override
@SuppressWarnings("unchecked")
public void bindValue(Object value) {
getBind().setBindValue( (T) value );
}
@Override
@SuppressWarnings("unchecked")
public void bindValue(Object value, TemporalType explicitTemporalType) {
getBind().setBindValue( (T) value, explicitTemporalType );
}
@Override
public void prepare(CallableStatement statement, int startIndex) throws SQLException {
// initially set up the Type we will use for binding as the explicit type.
Type typeToUse = getHibernateType();
int[] sqlTypesToUse = sqlTypes;
final QueryParameterBinding<?> binding = procedureCall.getQueryParameterBindings().getBinding( this );
final ParameterBind bind = getBind();
// initially set up the Type we will use for binding as the explicit type.
AllowableParameterType typeToUse = getHibernateType();
// however, for Calendar binding with an explicit TemporalType we may need to adjust this...
if ( bind != null && bind.getExplicitTemporalType() != null ) {
if ( Calendar.class.isInstance( bind.getValue() ) ) {
switch ( bind.getExplicitTemporalType() ) {
case TIMESTAMP: {
typeToUse = CalendarType.INSTANCE;
sqlTypesToUse = typeToUse.sqlTypes( procedureCall.getSession().getFactory() );
break;
}
case DATE: {
typeToUse = CalendarDateType.INSTANCE;
sqlTypesToUse = typeToUse.sqlTypes( procedureCall.getSession().getFactory() );
break;
}
case TIME: {
typeToUse = CalendarTimeType.INSTANCE;
sqlTypesToUse = typeToUse.sqlTypes( procedureCall.getSession().getFactory() );
break;
}
}
}
if ( binding != null && binding.getExplicitTemporalPrecision() != null ) {
typeToUse = ( (AllowableTemporalParameterType) typeToUse ).resolveTemporalPrecision(
binding.getExplicitTemporalPrecision(),
procedureCall.getSession().getFactory().getTypeConfiguration()
);
}
this.startIndex = startIndex;
@ -226,10 +155,10 @@ public class ProcedureParameterImpl<T>
}
if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
if ( bind == null || bind.getValue() == null ) {
// the user did not bind a value to the parameter being processed. This is the condition
if ( binding == null || binding.getValue() == null ) {
// the user did not binding a value to the parameter being processed. This is the condition
// defined by `passNulls` and that value controls what happens here. If `passNulls` is
// {@code true} we will bind the NULL value into the statement; if `passNulls` is
// {@code true} we will binding the NULL value into the statement; if `passNulls` is
// {@code false} we will not.
//
// Unfortunately there is not a way to reliably know through JDBC metadata whether a procedure
@ -264,13 +193,13 @@ public class ProcedureParameterImpl<T>
if ( this.procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding( typeToUse ) ) {
((ProcedureParameterNamedBinder) typeToUse).nullSafeSet(
statement,
bind.getValue(),
binding.getValue(),
this.getName(),
procedureCall.getSession()
);
}
else {
typeToUse.nullSafeSet( statement, bind.getValue(), startIndex, procedureCall.getSession() );
typeToUse.nullSafeSet( statement, binding.getValue(), startIndex, procedureCall.getSession() );
}
}
}
@ -303,16 +232,6 @@ public class ProcedureParameterImpl<T>
&& ((ProcedureParameterNamedBinder) hibernateType).canDoSetting();
}
@Override
public int[] getSqlTypes() {
if ( mode == ParameterMode.REF_CURSOR ) {
// we could use the Types#REF_CURSOR added in Java 8, but that would require requiring Java 8...
throw new IllegalStateException( "REF_CURSOR parameters do not have a SQL/JDBC type" );
}
return determineHibernateType().sqlTypes( procedureCall.getSession().getFactory() );
}
private Type determineHibernateType() {
final ParameterBind<T> bind = getBind();

View File

@ -7,37 +7,44 @@
package org.hibernate.query.procedure.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.function.Predicate;
import javax.persistence.Parameter;
import org.hibernate.procedure.internal.ProcedureCallImpl;
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.procedure.spi.ParameterStrategy;
import org.hibernate.query.ParameterMetadata;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.procedure.ProcedureParameter;
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryParameterImplementor;
/**
* @author Steve Ebersole
*/
public class ProcedureParameterMetadata implements ParameterMetadataImplementor {
public class ProcedureParameterMetadataImpl implements ParameterMetadataImplementor {
private final ProcedureCallImpl procedureCall;
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
private List<ProcedureParameterImplementor> parameters = new ArrayList<>();
public ProcedureParameterMetadata(ProcedureCallImpl procedureCall) {
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
private List<ProcedureParameterImplementor<?>> parameters = new ArrayList<>();
public ProcedureParameterMetadataImpl(ProcedureCallImpl procedureCall) {
this.procedureCall = procedureCall;
}
public <R> ProcedureParameterMetadataImpl(ProcedureCallImpl procedureCall, NamedCallableQueryMemento memento) {
this( procedureCall );
memento.getParameterMementos().forEach(
parameterMemento -> registerParameter( parameterMemento.resolve( procedureCall.getSession() ) )
);
}
public void registerParameter(ProcedureParameterImplementor parameter) {
if ( parameter.getName() != null ) {
if ( parameterStrategy == ParameterStrategy.POSITIONAL ) {
@ -72,24 +79,6 @@ public class ProcedureParameterMetadata implements ParameterMetadataImplementor
return parameterStrategy == ParameterStrategy.POSITIONAL;
}
@Override
public Set<QueryParameter<?>> collectAllParameters() {
final Set<QueryParameter<?>> rtn = new LinkedHashSet<>();
for ( ProcedureParameter parameter : parameters ) {
rtn.add( parameter );
}
return rtn;
}
@Override
public Set<Parameter<?>> collectAllParametersJpa() {
final Set<Parameter<?>> rtn = new LinkedHashSet<>();
for ( ProcedureParameter parameter : parameters ) {
rtn.add( parameter );
}
return rtn;
}
@Override
public Set<String> getNamedParameterNames() {
if ( !hasNamedParameters() ) {
@ -105,67 +94,6 @@ public class ProcedureParameterMetadata implements ParameterMetadataImplementor
return rtn;
}
@Override
public int getPositionalParameterCount() {
return hasPositionalParameters() ? parameters.size() : 0;
}
@Override
@SuppressWarnings("unchecked")
public <T> ParameterRegistrationImplementor<T> getQueryParameter(String name) {
assert name != null;
if ( hasNamedParameters() ) {
for ( ParameterRegistrationImplementor parameter : parameters ) {
if ( name.equals( parameter.getName() ) ) {
return parameter;
}
}
}
throw new IllegalArgumentException( "Named parameter [" + name + "] is not registered with this procedure call" );
}
@Override
@SuppressWarnings("unchecked")
public <T> ParameterRegistrationImplementor<T> getQueryParameter(Integer position) {
assert position != null;
if ( hasPositionalParameters() ) {
for ( ParameterRegistrationImplementor parameter : parameters ) {
if ( parameter.getPosition() != null && position.intValue() == parameter.getPosition() ) {
return parameter;
}
}
}
throw new IllegalArgumentException( "Positional parameter [" + position + "] is not registered with this procedure call" );
}
@Override
@SuppressWarnings("unchecked")
public <T> ProcedureParameterImplementor<T> resolve(Parameter<T> param) {
if ( ProcedureParameterImplementor.class.isInstance( param ) ) {
for ( ProcedureParameterImplementor parameter : parameters ) {
if ( parameter == param ) {
return parameter;
}
}
}
throw new IllegalArgumentException( "Could not resolve javax.persistence.Parameter to org.hibernate.query.QueryParameter" );
}
@Override
public Collection<QueryParameter> getPositionalParameters() {
return parameters.stream().filter( p -> p.getPosition() != null ).collect( Collectors.toList() );
}
@Override
public Collection<QueryParameter> getNamedParameters() {
return parameters.stream().filter( p -> p.getPosition() == null ).collect( Collectors.toList() );
}
@Override
public int getParameterCount() {
return parameters.size();
@ -182,10 +110,78 @@ public class ProcedureParameterMetadata implements ParameterMetadataImplementor
}
@Override
public void visitRegistrations(Consumer<QueryParameter> action) {
for ( ProcedureParameterImplementor parameter : parameters ) {
action.accept( parameter );
public void collectAllParameters(ParameterCollector collector) {
parameters.forEach( collector::collect );
}
@Override
public boolean hasAnyMatching(Predicate<QueryParameterImplementor<?>> filter) {
if ( parameters.isEmpty() ) {
return false;
}
for ( ProcedureParameterImplementor parameter : parameters ) {
if ( filter.test( parameter ) ) {
return true;
}
}
return false;
}
@Override
public ProcedureParameterImplementor<?> getQueryParameter(String name) {
for ( ProcedureParameterImplementor parameter : parameters ) {
if ( name.equals( parameter.getName() ) ) {
return parameter;
}
}
return null;
}
@Override
public ProcedureParameterImplementor<?> getQueryParameter(int positionLabel) {
for ( ProcedureParameterImplementor parameter : parameters ) {
if ( parameter.getName() == null && positionLabel == parameter.getPosition() ) {
return parameter;
}
}
return null;
}
@Override
public ProcedureParameterImplementor<?> resolve(Parameter param) {
if ( param instanceof ProcedureParameterImplementor ) {
return (ProcedureParameterImplementor) param;
}
return null;
}
@Override
public Set<? extends QueryParameter<?>> getRegistrations() {
//noinspection unchecked
return (Set) parameters;
}
@Override
public void visitRegistrations(Consumer<? extends QueryParameter<?>> action) {
//noinspection unchecked
parameters.forEach( (Consumer) action );
}
@Override
public Set<Integer> getOrdinalParameterLabels() {
final HashSet<Integer> labels = new HashSet<>();
visitRegistrations(
p -> {
if ( p.getPosition() != null ) {
labels.add( p.getPosition() );
}
}
);
return labels;
}
}

View File

@ -6,9 +6,12 @@
*/
package org.hibernate.query.procedure.spi;
import java.sql.CallableStatement;
import java.sql.SQLException;
import org.hibernate.Incubating;
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
import org.hibernate.query.procedure.ProcedureParameter;
import org.hibernate.query.spi.QueryParameterImplementor;
/**
* NOTE: Consider this contract (and its sub-contracts) as incubating as we transition to 6.0 and SQM
@ -16,5 +19,11 @@ import org.hibernate.query.procedure.ProcedureParameter;
* @author Steve Ebersole
*/
@Incubating
public interface ProcedureParameterImplementor<T> extends ProcedureParameter<T>, ParameterRegistrationImplementor<T> {
public interface ProcedureParameterImplementor<T> extends ProcedureParameter<T>, QueryParameterImplementor<T> {
void prepare(CallableStatement statement, int startIndex) throws SQLException;
@Override
default boolean allowsMultiValuedBinding() {
return false;
}
}

View File

@ -225,7 +225,9 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
public QueryImplementor setFlushMode(FlushModeType flushModeType) {
setHibernateFlushMode( FlushModeTypeHelper.getFlushMode( flushModeType ) );
return this;
} @Override
}
@Override
public CacheMode getCacheMode() {
return getQueryOptions().getCacheMode();
}

View File

@ -7,15 +7,17 @@
package org.hibernate.query.spi;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SessionFactoryImplementor;
/**
* Contract for Query impls that can be converted to named queries and
* Contract for Query impls that can be converted to a named query memento to be
* stored in the {@link org.hibernate.query.spi.NamedQueryRepository}
*
* @author Steve Ebersole
*/
@Incubating
public interface NameableQuery {
NamedQueryMemento toMemento(String name, SessionFactoryImplementor factory);
/**
* Convert the query into the memento
*/
NamedQueryMemento toMemento(String name);
}

View File

@ -40,10 +40,14 @@ public interface QueryParameterBinding<T> {
*/
AllowableParameterType<T> getBindType();
/**
* If the parameter represents a temporal type, return the explicitly
* specified precision - if one.
*/
TemporalType getExplicitTemporalPrecision();
/**
* Sets the parameter binding value. The inherent parameter type (if known) is assumed
*
* @param value The bind value
*/
void setBindValue(T value);

View File

@ -475,7 +475,7 @@ public class QuerySqmImpl<R>
}
@Override
public NamedHqlQueryMemento toMemento(String name, SessionFactoryImplementor factory) {
public NamedHqlQueryMemento toMemento(String name) {
return new NamedHqlQueryMementoImpl(
name,
hqlString,

View File

@ -8,20 +8,19 @@ package org.hibernate.result.spi;
import java.util.Set;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.exec.spi.DomainParameterBindingContext;
/**
* @author Steve Ebersole
*/
public interface ResultContext {
SharedSessionContractImplementor getSession();
Set<String> getSynchronizedQuerySpaces();
// for now...
// see Loader-redesign proposal
String getSql();
QueryParameters getQueryParameters();
NativeSQLQueryReturn[] getQueryReturns();
QueryOptions getQueryOptions();
DomainParameterBindingContext getDomainParameterBindingContext();
}

View File

@ -0,0 +1,22 @@
/*
* 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.results;
import org.hibernate.HibernateException;
/**
* @author Steve Ebersole
*/
public class NoMoreOutputsException extends HibernateException {
public NoMoreOutputsException(String message) {
super( message );
}
public NoMoreOutputsException() {
super( "Outputs have been exhausted" );
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.results.internal;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.convert.spi.ConvertibleValueMapping;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class BasicResultAssembler<J> implements DomainResultAssembler<J> {
private final SqmExpressable<J> expressableType;
private final BasicValueConverter<J,?> valueConverter;
public BasicResultAssembler(SqmExpressable<J> expressableType) {
this(
expressableType,
expressableType instanceof ConvertibleValueMapping
? ( (ConvertibleValueMapping<J>) expressableType ).getValueConverter()
: null
);
}
public BasicResultAssembler(SqmExpressable<J> expressableType, BasicValueConverter<J, ?> valueConverter) {
this.expressableType = expressableType;
this.valueConverter = valueConverter;
}
@Override
public Object assemble(
RowProcessingState rowProcessingState,
JdbcValuesSourceProcessingOptions options) {
throw new NotYetImplementedFor6Exception();
}
@Override
public JavaTypeDescriptor<J> getJavaTypeDescriptor() {
return expressableType.getExpressableJavaTypeDescriptor();
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.results.internal;
import java.util.function.Consumer;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.convert.spi.ConvertibleValueMapping;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.ScalarDomainResult;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
private final String resultVariable;
private final SqmExpressable expressableType;
private final DomainResultAssembler<T> assembler;
public ScalarDomainResultImpl(
String resultVariable,
SqmExpressable<T> expressableType) {
this.resultVariable = resultVariable;
this.expressableType = expressableType;
this.assembler = new BasicResultAssembler<>( expressableType );
}
public ScalarDomainResultImpl(
String resultVariable,
SqmExpressable<T> expressableType,
BasicValueConverter<T,?> valueConverter) {
this.resultVariable = resultVariable;
this.expressableType = expressableType;
this.assembler = new BasicResultAssembler<>( expressableType, valueConverter );
}
@Override
public String getResultVariable() {
return resultVariable;
}
@Override
public JavaTypeDescriptor getResultJavaTypeDescriptor() {
return expressableType.getExpressableJavaTypeDescriptor();
}
@Override
public DomainResultAssembler<T> createResultAssembler(
Consumer<Initializer> initializerCollector,
AssemblerCreationState creationState) {
return assembler;
}
}

View File

@ -8,7 +8,7 @@ package org.hibernate.sql.results.spi;
import java.util.function.Consumer;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Represents a result value in the domain query results. Acts as the
@ -31,18 +31,16 @@ import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptor;
*
* @author Steve Ebersole
*/
public interface DomainResult extends ResultSetMappingNode {
public interface DomainResult<J> extends ResultSetMappingNode {
/**
* The result-variable (alias) associated with this result.
*/
String getResultVariable();
JavaTypeDescriptor getJavaTypeDescriptor();
/**
* Create an assembler (and any initializers) for this result.
*/
DomainResultAssembler createResultAssembler(
DomainResultAssembler<J> createResultAssembler(
Consumer<Initializer> initializerCollector,
AssemblerCreationState creationState);
}

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.sql.results.spi;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Responsible for "assembling" a result for inclusion in the domain query
* result. "Assembling" the result basically means building the result object
@ -14,5 +16,22 @@ package org.hibernate.sql.results.spi;
*
* @author Steve Ebersole
*/
public interface DomainResultAssembler {
public interface DomainResultAssembler<J> {
/**
* The main "assembly" contract. Assemble the result and return it.
*/
Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options);
/**
* Convenience form of {@link #assemble(RowProcessingState, JdbcValuesSourceProcessingOptions)}
*/
default Object assemble(RowProcessingState rowProcessingState) {
return assemble( rowProcessingState, rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions() );
}
/**
* The JavaTypeDescriptor describing the Java type that this assembler
* assembles.
*/
JavaTypeDescriptor<J> getJavaTypeDescriptor();
}

View File

@ -13,11 +13,11 @@ package org.hibernate.sql.results.spi;
*
* @author Steve Ebersole
*/
public interface DomainResultProducer {
public interface DomainResultProducer<T> {
/**
* Produce the domain query
*/
DomainResult createDomainResult(
DomainResult<T> createDomainResult(
String resultVariable,
DomainResultCreationState creationState);

View File

@ -9,6 +9,7 @@ package org.hibernate.sql.results.spi;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* The "resolved" form of {@link JdbcValuesMappingProducer} providing access
@ -26,9 +27,13 @@ public interface JdbcValuesMapping {
*/
Set<SqlSelection> getSqlSelections();
List<DomainResult> getDomainResults();
List<DomainResult<?>> getDomainResults();
List<DomainResultAssembler> resolveAssemblers(
default List<DomainResultAssembler<?>> resolveAssemblers(
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState);
AssemblerCreationState creationState) {
return getDomainResults().stream()
.map( domainResult -> domainResult.createResultAssembler( initializerConsumer, creationState ) )
.collect( Collectors.toList() );
}
}

View File

@ -0,0 +1,22 @@
/*
* 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.results.spi;
import java.io.Serializable;
/**
* Essentially processing options only for entity loading
*
* @author Steve Ebersole
*/
public interface JdbcValuesSourceProcessingOptions {
Object getEffectiveOptionalObject();
String getEffectiveOptionalEntityName();
Serializable getEffectiveOptionalId();
boolean shouldReturnProxies();
}

View File

@ -0,0 +1,71 @@
/*
* 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.results.spi;
import org.hibernate.engine.loading.internal.LoadingCollectionEntry;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.exec.spi.ExecutionContext;
/**
* Provides a context for processing the processing of the complete
* set of rows from a JdbcValuesSource. Holds in-flight state
* and provides access to environmental information needed to perform the
* processing.
*
* @author Steve Ebersole
*/
public interface JdbcValuesSourceProcessingState {
ExecutionContext getExecutionContext();
default SharedSessionContractImplementor getSession() {
return getExecutionContext().getSession();
}
default QueryOptions getQueryOptions() {
return getExecutionContext().getQueryOptions();
}
JdbcValuesSourceProcessingOptions getProcessingOptions();
PreLoadEvent getPreLoadEvent();
PostLoadEvent getPostLoadEvent();
/**
* Find a LoadingEntityEntry locally to this context.
*
* @see LoadContexts#findLoadingEntityEntry(EntityKey)
*/
LoadingEntityEntry findLoadingEntityLocally(EntityKey entityKey);
/**
* Registers a LoadingEntityEntry locally to this context
*/
void registerLoadingEntity(
EntityKey entityKey,
LoadingEntityEntry loadingEntry);
/**
* Find a LoadingCollectionEntry locally to this context.
*
* @see LoadContexts#findLoadingCollectionEntry(CollectionKey)
*/
LoadingCollectionEntry findLoadingCollectionLocally(CollectionKey key);
/**
* Registers a LoadingCollectionEntry locally to this context
*/
void registerLoadingCollection(
CollectionKey collectionKey,
LoadingCollectionEntry loadingCollectionEntry);
void finishUp();
}

View File

@ -19,7 +19,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
public interface ResultSetMappingNode {
// todo (6.0) : result variable (selection alias)? - even fetches can have alias
JavaTypeDescriptor getJavaTypeDescriptor();
JavaTypeDescriptor getResultJavaTypeDescriptor();
/**
* The NavigablePath for this node (if one!). Certain nodes will not

View File

@ -0,0 +1,27 @@
/*
* 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.results.spi;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.exec.spi.ExecutionContext;
/**
* State pertaining to the processing of a single row of a JdbcValuesSource
*
* @author Steve Ebersole
*/
public interface RowProcessingState extends ExecutionContext {
/**
* Access to the "parent state" related to the overall processing
* of the results.
*/
JdbcValuesSourceProcessingState getJdbcValuesSourceProcessingState();
void finishRowProcessing();
Initializer resolveInitializer(NavigablePath path);
}

View File

@ -0,0 +1,17 @@
/*
* 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.results.spi;
/**
* Represent a simple scalar return within a query result. Generally this would be values of basic (String, Integer,
* etc) or composite types.
*
* @author Steve Ebersole
* @author Gail Badner
*/
public interface ScalarDomainResult<J> extends DomainResult<J> {
}

View File

@ -6,10 +6,7 @@
*/
package org.hibernate.type;
import java.sql.CallableStatement;
import java.sql.SQLException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.model.domain.AllowableOutputParameterType;
/**
* Optional {@link Type} contract for implementations that are aware of how to extract values from
@ -17,39 +14,5 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
*
* @author Steve Ebersole
*/
public interface ProcedureParameterExtractionAware<T> {
/**
* Can the given instance of this type actually perform the parameter value extractions?
*
* @return {@code true} indicates that @{link #extract} calls will not fail due to {@link IllegalStateException}.
*/
boolean canDoExtraction();
/**
* Perform the extraction
*
* @param statement The CallableStatement from which to extract the parameter value(s).
* @param startIndex The parameter index from which to start extracting; assumes the values (if multiple) are contiguous
* @param session The originating session
*
* @return The extracted value.
*
* @throws SQLException Indicates an issue calling into the CallableStatement
* @throws IllegalStateException Thrown if this method is called on instances that return {@code false} for {@link #canDoExtraction}
*/
T extract(CallableStatement statement, int startIndex, SharedSessionContractImplementor session) throws SQLException;
/**
* Perform the extraction
*
* @param statement The CallableStatement from which to extract the parameter value(s).
* @param paramNames The parameter names.
* @param session The originating session
*
* @return The extracted value.
*
* @throws SQLException Indicates an issue calling into the CallableStatement
* @throws IllegalStateException Thrown if this method is called on instances that return {@code false} for {@link #canDoExtraction}
*/
T extract(CallableStatement statement, String[] paramNames, SharedSessionContractImplementor session) throws SQLException;
public interface ProcedureParameterExtractionAware<T> extends AllowableOutputParameterType<T> {
}

View File

@ -512,6 +512,21 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
private final ConcurrentHashMap<Class,BasicType> basicTypeByJavaType = new ConcurrentHashMap<>();
public BasicType getBasicTypeForJavaType(Class<?> javaType) {
final BasicType existing = basicTypeByJavaType.get( javaType );
if ( existing != null ) {
return existing;
}
final BasicType registeredType = getBasicTypeRegistry().getRegisteredType( javaType );
if ( registeredType != null ) {
basicTypeByJavaType.put( javaType, registeredType );
return registeredType;
}
return null;
}
public BasicType standardBasicTypeForJavaType(Class<?> javaType) {
if ( javaType == null ) {
return null;