hibernate/hibernate-orm · error · UnsupportedOperationException

PostgreSQL only supports REF_CURSOR parameters as the first

Error message

PostgreSQL only supports REF_CURSOR parameters as the first parameter

What it means

PostgreSQL's server/JDBC combination only materializes a refcursor returned as the first OUT parameter of a callable statement. PostgreSQLLegacyDialect.getResultSet(CallableStatement, position) therefore requires position == 1 and throws UnsupportedOperationException for any other position when Hibernate extracts REF_CURSOR output parameters from a StoredProcedureQuery/ProcedureCall.

Source

Thrown at hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java:1163

	public boolean supportsUnboundedLobLocatorMaterialization() {
		return false;
	}

	@Override
	public SelectItemReferenceStrategy getGroupBySelectItemReferenceStrategy() {
		return SelectItemReferenceStrategy.POSITION;
	}


	@Override
	public CallableStatementSupport getCallableStatementSupport() {
		return getVersion().isSameOrAfter( 11 ) ? PostgreSQLCallableStatementSupport.INSTANCE : PostgreSQLCallableStatementSupport.V10_INSTANCE;
	}

	@Override
	public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException {
		if ( position != 1 ) {
			throw new UnsupportedOperationException( "PostgreSQL only supports REF_CURSOR parameters as the first parameter" );
		}
		return (ResultSet) statement.getObject( 1 );
	}

	@Override
	public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
		throw new UnsupportedOperationException( "PostgreSQL only supports accessing REF_CURSOR parameters by position" );
	}

	@Override
	public boolean qualifyIndexName() {
		return false;
	}

	@Override
	public IdentityColumnSupport getIdentityColumnSupport() {
		return PostgreSQLIdentityColumnSupport.INSTANCE;
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Redesign the function to return a single refcursor in the first parameter
  2. Return SETOF rows instead of a refcursor and call it as 'select * from func()'
  3. Fetch additional cursors manually: (ResultSet) callableStatement.getObject(n) outside Hibernate
  4. Access only output position 1 through Hibernate

Example fix

-- before
create function read_orders(out c1 refcursor, out c2 refcursor) ... 
// Java: outputs.getOutputByPosition(2).asResultSet() -> throws

-- after
create function read_orders() returns setof orders ...
List<Order> l = em.createNativeQuery( "select * from read_orders()", Order.class ).getResultList();
Defensive patterns

Strategy: validation

Validate before calling

// PostgreSQL: Hibernate can only retrieve a REF_CURSOR at position 1
int cursorPosition = 1;
if ( cursorPosition != 1 ) {
    throw new IllegalArgumentException(
        "Fetch this cursor manually via callableStatement.getObject(position)" );
}
StoredProcedureQuery q = em.createStoredProcedureQuery( "read_orders" );
q.registerStoredProcedureParameter( 1, void.class, ParameterMode.REF_CURSOR );

Try / catch

try {
    ResultSet rs = dialect.getResultSet( stmt, position );
}
catch ( UnsupportedOperationException e ) {
    // PostgreSQL: fall back to raw JDBC retrieval
    ResultSet rs = (ResultSet) stmt.getObject( position );
}

Prevention

When it happens

Trigger: A PL/pgSQL function with multiple refcursor OUT parameters, then asking Hibernate for the result set at position 2 or higher (iterating outputs / hasMoreResults-style access); StoredProcedureQuery on PostgreSQL registering more than one cursor output.

Common situations: Porting SQL Server/Oracle procedures that return several cursors per call; expecting PostgreSQL to behave like Oracle with multiple cursors; report screens fed by one procedure returning several result sets.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/5dc1eafd6018c2f0. Report an issue: GitHub.