hibernate/hibernate-orm · error · HibernateException
PostgreSQL supports only one REF_CURSOR parameter, but multi
Error message
PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered
What it means
When rendering function-style calls on PostgreSQL, PostgreSQLCallableStatementSupport iterates remaining parameter registrations and rejects any additional ParameterMode.REF_CURSOR beyond the special first-position one, because a PostgreSQL function call cannot materialize multiple refcursor results in one callable statement. The check is explicit (supportsProcedures == false branch) and throws HibernateException.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/procedure/internal/PostgreSQLCallableStatementSupport.java:147
else {
jdbcParameterOffset = 1;
startIndex = 0;
callMode = CallMode.CALL;
}
final StringBuilder buffer = new StringBuilder( callMode.start.length() + callMode.end.length() + procedureName.length() + paramStringSizeEstimate )
.append( callMode.start );
buffer.append( procedureName );
if ( startIndex == registrations.size() ) {
buffer.append( '(' );
}
else {
char sep = '(';
for ( int i = startIndex; i < registrations.size(); i++ ) {
final ProcedureParameterImplementor<?> parameter = registrations.get( i );
if ( !supportsProcedures && parameter.getMode() == ParameterMode.REF_CURSOR ) {
throw new HibernateException(
"PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered" );
}
buffer.append( sep );
final JdbcCallParameterRegistration registration = parameter.toJdbcParameterRegistration(
i + jdbcParameterOffset,
procedureCall
);
final OutputableType<?> type = registration.getParameterType();
final String castType;
if ( parameter.getName() != null ) {
buffer.append( parameter.getName() ).append( " => " );
}
if ( type != null
&& type.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType structJdbcType ) {
// We have to cast struct type parameters so that PostgreSQL understands nulls
castType = structJdbcType.getStructTypeName();
buffer.append( "cast(" );
}View on GitHub (pinned to fad1729dce)
Solutions
- Collapse to one cursor returning a composite/RECORD row type that carries what the multiple cursors carried.
- Return TABLE(...) / SETOF and read results with getResultList(), or issue one call per cursor.
- If multiple refcursors are unavoidable, use native SQL with explicit cursors (BEGIN; SELECT f(); FETCH ALL IN "cur1"; COMMIT;) instead of the procedure API.
Example fix
-- before: function returning two refcursors (Oracle style)
CREATE FUNCTION order_report(uid bigint) RETURNS refcursor AS ...
-- after: single cursor of a composite type
CREATE TYPE order_line AS (id bigint, qty int);
CREATE FUNCTION order_report(uid bigint)
RETURNS TABLE(order_id bigint, lines order_line[]) AS $$ ... $$ LANGUAGE plpgsql; Defensive patterns
Strategy: validation
Validate before calling
long refCursorCount = proc.getParameters().stream()
.filter( p -> p.getMode() == ParameterMode.REF_CURSOR )
.count();
if ( refCursorCount > 1 ) {
throw new IllegalArgumentException(
"PostgreSQL supports one REF_CURSOR per call; restructure to a single cursor or multiple calls" );
} Prevention
- Design PostgreSQL functions to return a single cursor/SETOF result, not multiple cursors.
- Add a dialect-aware build check that rejects multi-cursor registrations when targeting PostgreSQL.
- Keep Oracle-specific multi-cursor procedures behind Oracle-only code paths.
When it happens
Trigger: Registering two or more REF_CURSOR parameters, e.g. Oracle-style proc.registerStoredProcedureParameter(1, void.class, ParameterMode.REF_CURSOR) and again at position 2, on PostgreSQL before procedure support applies.
Common situations: Direct ports of Oracle reporting packages that return several cursors (header + lines pattern); cross-dialect DAOs written against Oracle and pointed at PostgreSQL.
Related errors
- Cannot mix named parameters and REF_CURSOR parameter on Post
- GaussDB only supports REF_CURSOR parameters as the first par
- GaussDB only supports accessing REF_CURSOR parameters by pos
- PostgreSQL only supports REF_CURSOR parameters as the first
- PostgreSQL only supports accessing REF_CURSOR parameters by
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/16262657c60fc917.
Report an issue: GitHub.