Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,33 @@ public interface HibernateHints {
/**
* Whether to treat a {@link org.hibernate.procedure.ProcedureCall}
* or {@link jakarta.persistence.StoredProcedureQuery} as a call
* to a function rather than a call to a procedure.
* to a function rather than a call to a procedure. Set hint to
* {@link Boolean#TRUE TRUE} or {@code "true"} to indicated that
* the call should be treated as a function call.
* <p>
* When no other return type is indicated, a function is assumed
* to return {@link java.sql.Types#REF_CURSOR REF_CURSOR}.
*
* @see org.hibernate.procedure.ProcedureCall#markAsFunctionCall
* @see #HINT_CALLABLE_FUNCTION_RETURN_TYPE
*/
String HINT_CALLABLE_FUNCTION = "org.hibernate.callableFunction";

/**
* The {@linkplain org.hibernate.type.SqlTypes JDBC type code},
* {@linkplain org.hibernate.query.BindableType type}, or
* {@link Class} of the value returned by a SQL function called
* via {@link org.hibernate.procedure.ProcedureCall} or
* {@link jakarta.persistence.StoredProcedureQuery}. Has the side
* effect of causing the call to be treated as a function call
* rather than a call to a stored procedure.
*
* @see org.hibernate.procedure.ProcedureCall#markAsFunctionCall(int)
* @see org.hibernate.procedure.ProcedureCall#markAsFunctionCall(org.hibernate.query.BindableType)
* @see org.hibernate.procedure.ProcedureCall#markAsFunctionCall(Class)
*/
String HINT_CALLABLE_FUNCTION_RETURN_TYPE = "hibernate.procedure.function_return_jdbc_type_code";

/**
* Hint for specifying the tenant id to use when creating an
* {@link jakarta.persistence.EntityManagerFactory#createEntityManager(java.util.Map) EntityManager}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@
*/
package org.hibernate.procedure;

import org.hibernate.Incubating;
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)
* Describes the function return value of a {@link ProcedureCall}
* executed via a JDBC escape of form ({@code "{? = call ...}}.
* That is, the {@code ?} parameter occurring before the {@code =}.
*
* @author Steve Ebersole
*
* @since 6.0
*/
@Incubating
public interface FunctionReturn<T> extends ProcedureParameter<T> {
/**
* The {@linkplain org.hibernate.type.SqlTypes JDBC type code}
* representing the SQL type of the function return value.
*/
int getJdbcTypeCode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,61 @@
import jakarta.persistence.StoredProcedureQuery;
import jakarta.persistence.TemporalType;

import org.hibernate.Incubating;
import org.hibernate.MappingException;
import org.hibernate.query.BindableType;
import org.hibernate.query.SynchronizeableQuery;
import org.hibernate.query.CommonQueryContract;
import org.hibernate.query.procedure.ProcedureParameter;
import org.hibernate.type.BasicTypeReference;

/**
* Defines support for executing database stored procedures and functions.
* Defines support for executing database stored procedures and functions using the
* {@linkplain java.sql.CallableStatement JDBC stored procedure SQL escape syntax}.
* <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>
* Here we use the terms "procedure" and "function" as follows:<ul>
* <li>A <em>procedure</em> is a named database executable called via:
* {@code {call procedureName(...)}}</li>
* <li>A <em>function</em> is a named database executable called via:
* {@code {? = call functionName(...)}}</li>
* </ul>
* <p>
* 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}.
* Unless explicitly specified, the {@code ProcedureCall} is executed using the
* procedure call syntax. To explicitly specify that the function call syntax
* should be used, call {@link #markAsFunctionCall}. Clients of the JPA-standard
* {@link StoredProcedureQuery} interface may choose between:
* <ul>
* <li>using {@link #unwrap storedProcedureQuery.unwrap(ProcedureCall.class).markAsFunctionCall(returnType)},
* or
* <li>setting the {@value org.hibernate.jpa.HibernateHints#HINT_CALLABLE_FUNCTION}
* or {@value org.hibernate.jpa.HibernateHints#HINT_CALLABLE_FUNCTION_RETURN_TYPE}
* {@linkplain #setHint(String, Object) hint} to avoid the cast to a
* Hibernate-specific class.
* </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>
* When the function call syntax is used:
* <ul>
* <li>parameters must be registered by position (not name),
* <li>the first parameter is considered to represent the function return value
* (corresponding to the {@code ?} which occurs before the {@code =}), and
* <li>the first parameter must have {@linkplain ParameterMode mode} OUT, INOUT,
* or REF_CURSOR; {@linkplain ParameterMode#IN IN} is illegal.
* </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>
* Depending on the {@linkplain org.hibernate.dialect.Dialect SQL dialect},
* further constraints are enforced or inferred. For example, on PostgreSQL:
* <ul>
* <li>If a parameter has mode {@linkplain ParameterMode#REF_CURSOR REF_CURSOR},
* it's automatically inferred that the call is a function call because this
* is the only context in which PostgreSQL returns REF_CURSOR results.
* So it's not necessary to call {@link #markAsFunctionCall} explicitly.
* <li>The restriction that there may be at most one REF_CURSOR mode parameter
* is enforced.
* </ul>
*
* @author Steve Ebersole
*
* @see java.sql.CallableStatement
* @see StoredProcedureQuery
*/
public interface ProcedureCall
extends CommonQueryContract, SynchronizeableQuery, StoredProcedureQuery, AutoCloseable {
Expand All @@ -74,7 +94,7 @@ public interface ProcedureCall
boolean isFunctionCall();

/**
* Mark this ProcedureCall as representing a call to a database function,
* Mark this {@code 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
Expand All @@ -84,7 +104,7 @@ public interface ProcedureCall
ProcedureCall markAsFunctionCall(int sqlType);

/**
* Mark this ProcedureCall as representing a call to a database function,
* Mark this {@code ProcedureCall} as representing a call to a database function,
* rather than a database procedure.
*
* @param resultType The result type for the function return
Expand All @@ -95,15 +115,15 @@ public interface ProcedureCall
ProcedureCall markAsFunctionCall(Class<?> resultType);

/**
* Mark this ProcedureCall as representing a call to a database function,
* Mark this {@code ProcedureCall} as representing a call to a database function,
* rather than a database procedure.
*
* @param typeReference The result type for the function return
*
* @return {@code this}, for method chaining
* @since 6.2
*/
ProcedureCall markAsFunctionCall(BasicTypeReference<?> typeReference);
ProcedureCall markAsFunctionCall(BindableType<?> typeReference);

/**
* Basic form for registering a positional parameter.
Expand All @@ -127,13 +147,13 @@ public interface ProcedureCall
*
* @return The parameter registration memento
*/
<T> ProcedureParameter<T> registerParameter(int position, BasicTypeReference<T> type, ParameterMode mode);
<T> ProcedureParameter<T> registerParameter(int position, BindableType<T> type, ParameterMode mode);

/**
* Like {@link #registerStoredProcedureParameter(int, Class, ParameterMode)} but a basic type reference is given
* Like {@link #registerStoredProcedureParameter(int, Class, ParameterMode)} but a type reference is given
* instead of a class for the parameter type.
*/
ProcedureCall registerStoredProcedureParameter(int position, BasicTypeReference<?> type, ParameterMode mode);
ProcedureCall registerStoredProcedureParameter(int position, BindableType<?> type, ParameterMode mode);

/**
* Retrieve a previously registered parameter memento by the position under which it was registered.
Expand Down Expand Up @@ -176,14 +196,14 @@ <T> ProcedureParameter<T> registerParameter(String parameterName, Class<T> type,
* @throws NamedParametersNotSupportedException When the underlying database is known to not support
* named procedure parameters.
*/
<T> ProcedureParameter<T> registerParameter(String parameterName, BasicTypeReference<T> type, ParameterMode mode)
<T> ProcedureParameter<T> registerParameter(String parameterName, BindableType<T> type, ParameterMode mode)
throws NamedParametersNotSupportedException;

/**
* Like {@link #registerStoredProcedureParameter(String, Class, ParameterMode)} but a basic type reference is given
* Like {@link #registerStoredProcedureParameter(String, Class, ParameterMode)} but a type reference is given
* instead of a class for the parameter type.
*/
ProcedureCall registerStoredProcedureParameter(String parameterName, BasicTypeReference<?> type, ParameterMode mode);
ProcedureCall registerStoredProcedureParameter(String parameterName, BindableType<?> type, ParameterMode mode);

/**
* Retrieve a previously registered parameter memento by the name under which it was registered.
Expand Down Expand Up @@ -215,6 +235,16 @@ <T> ProcedureParameter<T> registerParameter(String parameterName, BasicTypeRefer
*/
ProcedureOutputs getOutputs();

/**
* The {@link FunctionReturn} describing the return value of
* the function, or {@code null} if this {@code ProcedureCall}
* is not a function call.
*
* @since 7.0
*/
@Incubating
FunctionReturn<?> getFunctionReturn();

/**
* Release the underlying JDBC {@link java.sql.CallableStatement}
*/
Expand All @@ -223,9 +253,7 @@ default void close() {
getOutputs().release();
}

/*
Covariant overrides
*/
/* Covariant overrides */

@Override
ProcedureCall addSynchronizedQuerySpace(String querySpace);
Expand Down Expand Up @@ -276,10 +304,10 @@ default void close() {
ProcedureCall registerStoredProcedureParameter(String parameterName, Class<?> type, ParameterMode mode);

/**
* The hint key indicating the function's return {@linkplain java.sql.Types JDBC type code}.
* The hint key indicating the return {@linkplain java.sql.Types JDBC type code} of a function.
*
* @deprecated This hint no longer has any effect. Use {@link #markAsFunctionCall(int)}.
* @deprecated Use {@link org.hibernate.jpa.HibernateHints#HINT_CALLABLE_FUNCTION_RETURN_TYPE}.
*/
@Deprecated(since="7", forRemoval = true)
String FUNCTION_RETURN_TYPE_HINT = "hibernate.procedure.function_return_jdbc_type_code";
String FUNCTION_RETURN_TYPE_HINT = org.hibernate.jpa.HibernateHints.HINT_CALLABLE_FUNCTION_RETURN_TYPE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public OracleCallableStatementSupport(boolean supportsRefCursors) {
@Override
protected void appendNameParameter(
StringBuilder buffer,
ProcedureParameterImplementor parameter,
ProcedureParameterImplementor<?> parameter,
JdbcCallParameterRegistration registration) {
buffer.append( parameter.getName() ).append( " => ?" );
}
Expand Down
Loading
Loading