{"record":{"id":"712957337ef9fde9","repo":"hibernate/hibernate-orm","slug":"recognizing-native-query-as-a-function-call-is-no","errorCode":null,"errorMessage":"Recognizing native query as a function call is no longer supported","messagePattern":"Recognizing native query as a function call is no longer supported","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterParser.java","lineNumber":241,"sourceCode":"\t\tfinal String fixture = \"?=call\";\n\t\tint fixturePosition = 0;\n\t\tboolean matches = true;\n\t\tfinal int max = checkString.length();\n\t\tfor ( int i = 0; i < max; i++ ) {\n\t\t\tfinal char c = Character.toLowerCase( checkString.charAt( i ) );\n\t\t\tif ( Character.isWhitespace( c ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( c == fixture.charAt( fixturePosition ) ) {\n\t\t\t\tfixturePosition++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmatches = false;\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( matches ) {\n\t\t\tthrow new UnsupportedOperationException(\n\t\t\t\t\t\"Recognizing native query as a function call is no longer supported\" );\n\n\t\t}\n\t}\n\n}\n","sourceCodeStart":223,"sourceCodeEnd":248,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterParser.java#L223-L248","documentation":"Before parsing, ParameterParser.checkIsNotAFunctionCall rejects the legacy JDBC function-call escape form: a query wrapped in '{...}' whose prefix (ignoring whitespace and case) matches '?=call'. Hibernate 6 no longer recognizes native queries written as '{? = call myFunc(...)}' as stored-function calls and throws UnsupportedOperationException instead of silently misinterpreting it.","triggerScenarios":"Creating any native query whose trimmed text starts with '{', ends with '}', and whose leading part before 'call' matches '?=' — e.g. session.createNativeQuery(\"{? = call calculate_total(:id)}\"). The check runs first in ParameterParser.parse, so it fails immediately at query creation.","commonSituations":"Applications migrated from Hibernate 5 or plain JDBC where '{? = call ...}' was the standard way to call stored functions and read the return value; stored-function code copied from old EJB/Hibernate tutorials.","solutions":["Rewrite the call as a scalar native query: select myFunc(?) and read the single result (optionally with an explicit result type).","For stored procedures with OUT parameters, use session.createStoredProcedureCall(...) or em.createStoredProcedureQuery(...) which handle parameter registration properly.","If the wrapped text is not meant as a function call, remove the enclosing braces so the pattern no longer matches '?=call'."],"exampleFix":"// before\nList<?> r = session.createNativeQuery(\"{? = call calculate_total(:id)}\").getResultList(); // UnsupportedOperationException\n\n// after\nBigDecimal total = session.createNativeQuery(\"select calculate_total(:id)\", BigDecimal.class)\n        .setParameter(\"id\", id)\n        .getSingleResult();","handlingStrategy":"validation","validationCode":"static void assertNotLegacyFunctionCall(String sql) {\n    if (sql.trim().matches(\"(?i)\\\\{\\\\s*\\\\?\\\\s*=\\\\s*call.*}\")) throw new UnsupportedOperationException(\"Rewrite {? = call f(?)} as select f(?) or use createStoredProcedureCall\");\n}","typeGuard":null,"tryCatchPattern":"try { session.createNativeQuery(sql); } catch (UnsupportedOperationException e) { if (e.getMessage().contains(\"function call\")) { /* rewrite to select f(...) or StoredProcedureCall */ } else throw e; }","preventionTips":["Grep the codebase for '{? = call' and '?=' patterns during Hibernate 6 migrations.","Use session.createStoredProcedureCall / em.createStoredProcedureQuery for stored routines with OUT params.","Select scalar function results via 'select func(?)' native queries."],"tags":["hibernate","native-query","stored-procedure","hibernate-6-migration","unsupportedoperationexception"],"backgroundTag":"legacy-jdbc-call-escape-removed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}