{"record":{"id":"19b6dbb07252bb39","repo":"hibernate/hibernate-orm","slug":"gaussdb-only-supports-ref-cursor-parameters-as-the","errorCode":null,"errorMessage":"GaussDB only supports REF_CURSOR parameters as the first parameter","messagePattern":"GaussDB only supports REF_CURSOR parameters as the first parameter","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/GaussDBDialect.java","lineNumber":901,"sourceCode":"\t@Override\n\tpublic boolean supportsUnboundedLobLocatorMaterialization() {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic SelectItemReferenceStrategy getGroupBySelectItemReferenceStrategy() {\n\t\treturn SelectItemReferenceStrategy.POSITION;\n\t}\n\n\t@Override\n\tpublic CallableStatementSupport getCallableStatementSupport() {\n\t\treturn GaussDBCallableStatementSupport.INSTANCE;\n\t}\n\n\t@Override\n\tpublic ResultSet getResultSet(CallableStatement statement, int position) throws SQLException {\n\t\tif ( position != 1 ) {\n\t\t\tthrow new UnsupportedOperationException( \"GaussDB only supports REF_CURSOR parameters as the first parameter\" );\n\t\t}\n\t\treturn (ResultSet) statement.getObject( 1 );\n\t}\n\n\t@Override\n\tpublic ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {\n\t\tthrow new UnsupportedOperationException( \"GaussDB only supports accessing REF_CURSOR parameters by position\" );\n\t}\n\n\t@Override\n\tpublic boolean qualifyIndexName() {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic IdentityColumnSupport getIdentityColumnSupport() {\n\t\treturn GaussDBIdentityColumnSupport.INSTANCE;\n\t}","sourceCodeStart":883,"sourceCodeEnd":919,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/GaussDBDialect.java#L883-L919","documentation":"Dialect.getResultSet(CallableStatement, position) retrieves REF_CURSOR out-parameters from stored procedures. GaussDB returns refcursors through a single mechanism that only exposes the first parameter, so GaussDBDialect throws UnsupportedOperationException whenever Hibernate asks for a refcursor at any position other than 1.","triggerScenarios":"A StoredProcedureQuery/@NamedStoredProcedureQuery registered with two or more REF_CURSOR parameters (or a refcursor registered at a position after 1), then calling getResultList()/execute() - Hibernate iterates refcursor positions and the second call with position 2 throws.","commonSituations":"Migrating Oracle-style procedures returning multiple cursors to GaussDB; reusable procedure-call wrappers that register cursors after scalar OUT parameters; tests written against PostgreSQL getResultSet behavior being run on GaussDB.","solutions":["Declare exactly one REF_CURSOR parameter and make it the first parameter of the procedure call (register it at position 1)","Return additional result sets inside the cursor (e.g. as rows tagged by type, or a refcursor set column) instead of multiple cursor parameters","Split the multi-cursor procedure into several single-cursor procedures and call each separately","If you need all cursors in one round trip, fetch them via a native CallableStatement using the driver-specific pattern and bypass the dialect hook"],"exampleFix":"// before (two refcursors -> second one throws on GaussDB)\nStoredProcedureQuery q = em.createStoredProcedureQuery(\"get_data\");\nq.registerStoredProcedureParameter(1, void.class, ParameterMode.REF_CURSOR);\nq.registerStoredProcedureParameter(2, void.class, ParameterMode.REF_CURSOR);\nq.execute();\n\n// after (single refcursor at position 1, second set via separate call)\nStoredProcedureQuery q = em.createStoredProcedureQuery(\"get_data_a\");\nq.registerStoredProcedureParameter(1, void.class, ParameterMode.REF_CURSOR);\nq.execute();\nList<?> a = q.getResultList();","handlingStrategy":"validation","validationCode":"// before executing, verify at most one REF_CURSOR and at position 1\nlong cursorCount = parameters.stream().filter(p -> p.mode == ParameterMode.REF_CURSOR).count();\nif (sessionFactory.getJdbcServices().getDialect() instanceof GaussDBDialect && cursorCount > 1) {\n    throw new IllegalArgumentException(\"GaussDB supports a single REF_CURSOR as first parameter only\");\n}","typeGuard":"static boolean refCursorLayoutSafe(Dialect d, List<Param> params) {\n    if (d instanceof GaussDBDialect) {\n        return params.stream().filter(p -> p.mode == ParameterMode.REF_CURSOR).count() <= 1\n            && params.get(0).mode == ParameterMode.REF_CURSOR;\n    }\n    return true;\n}","tryCatchPattern":"try {\n    query.execute();\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage().contains(\"first parameter\")) {\n        // split into multiple single-cursor procedure calls\n    } else throw e;\n}","preventionTips":["Design procedures with one cursor result set; return composite rows instead of multiple cursors","Always register the REF_CURSOR parameter first (position 1)","Encapsulate procedure calls in a repository layer so per-database cursor strategies stay in one place"],"tags":["hibernate","gaussdb","stored-procedure","ref-cursor","callable-statement"],"backgroundTag":"stored-procedure-refcursor-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}