{"record":{"id":"c00f6e4a2da18d2d","repo":"hibernate/hibernate-orm","slug":"h2-json-table-passing-clause-only-supports-liter","errorCode":null,"errorMessage":"H2 json_table() passing clause only supports literal json path passing values, but got {expression}","messagePattern":"H2 json_table\\(\\) passing clause only supports literal json path passing values, but got (.+?)","errorType":"exception","errorClass":"QueryException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonValueFunction.java","lineNumber":193,"sourceCode":"\t\t\t\tsb.append( \" format json\" );\n\t\t\t}\n\t\t\tsb.append( ')' );\n\t\t}\n\t\tfor ( int i = 0; i < jsonPathElements.size(); i++ ) {\n\t\t\tfinal JsonPathHelper.JsonPathElement jsonPathElement = jsonPathElements.get( i );\n\t\t\tif ( jsonPathElement instanceof JsonPathHelper.JsonAttribute attribute ) {\n\t\t\t\tsb.append( \".\" );\n\t\t\t\tQuotingHelper.appendDoubleQuoteEscapedString( sb, attribute.attribute() );\n\t\t\t}\n\t\t\telse if ( jsonPathElement instanceof JsonPathHelper.JsonParameterIndexAccess parameterIndexAccess ) {\n\t\t\t\tassert passingClause != null;\n\t\t\t\tfinal String parameterName = parameterIndexAccess.parameterName();\n\t\t\t\tfinal Expression expression = passingClause.getPassingExpressions().get( parameterName );\n\t\t\t\tif ( expression == null ) {\n\t\t\t\t\tthrow new QueryException( \"JSON path [\" + jsonPath + \"] uses parameter [\" + parameterName + \"] that is not passed\" );\n\t\t\t\t}\n\t\t\t\tif ( !( expression instanceof Literal literal) ) {\n\t\t\t\t\tthrow new QueryException( \"H2 json_table() passing clause only supports literal json path passing values, but got \" + expression );\n\t\t\t\t}\n\n\t\t\t\tsb.append( '[' );\n\t\t\t\tsb.append( literal.getLiteralValue() );\n\t\t\t\tsb.append( \"+1]\" );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsb.append( '[' );\n\t\t\t\tsb.append( ( (JsonPathHelper.JsonIndexAccess) jsonPathElement ).index() + 1 );\n\t\t\t\tsb.append( ']' );\n\t\t\t}\n\t\t}\n\t\treturn sb.toString();\n\t}\n}\n","sourceCodeStart":175,"sourceCodeEnd":209,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonValueFunction.java#L175-L209","documentation":"For json_table() on H2, the emulation inlines passing values directly into the rebuilt path text, so every passing expression must be a Literal. If the expression bound in the PASSING clause is a bind parameter or any computed expression, this QueryException reports the unsupported expression.","triggerScenarios":"A json_table() query on H2 passes a query parameter, for example PASSING :offset AS i. The instanceof Literal check fails because the expression is a junction or parameter node, and rendering aborts.","commonSituations":"Developers bind the index as a JDBC parameter to allow plan caching, which H2 emulation cannot inline. Queries written for Oracle or PostgreSQL json_table run unchanged on H2 test databases.","solutions":["Replace the bind parameter with a literal value in the PASSING clause, for example PASSING 3 AS i.","Build the HQL with the literal value interpolated so the passing expression stays a literal node.","Switch this statement to a native query when the value must stay a bind parameter.","Test such statements on a dialect with native json_table support."],"exampleFix":"// before\nQuery q = session.createQuery(\n  \"select t.name from Entity e, json_table(e.doc, '$.rows[$i]' passing :n as i columns(name varchar)) t\");\nq.setParameter(\"n\", 2);\n\n// after\nQuery q = session.createQuery(\n  \"select t.name from Entity e, json_table(e.doc, '$.rows[$i]' passing 2 as i columns(name varchar)) t\");","handlingStrategy":"validation","validationCode":"// H2 json_table emulation: passing values must be literals.\nboolean isH2 = session.getJdbcServices().getDialect() instanceof org.hibernate.dialect.H2Dialect;\nif (isH2 && usesBindParameterInPassing) {\n    throw new IllegalStateException(\"H2 json_table PASSING requires literal values; interpolate the value into HQL\");\n}\nString hql = \"select t.name from Entity e, json_table(e.doc, '$.rows[$i]' passing \" + n + \" as i columns(name varchar)) t\";","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql).getResultList();\n} catch (org.hibernate.QueryException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"literal json path passing values\")) {\n        throw new UnsupportedOperationException(\"Interpolate a literal value into the H2 json_table PASSING clause\", e);\n    }\n    throw e;\n}","preventionTips":["Treat H2 json_table as a test-only convenience; keep production paths on native dialects.","When tests run on H2, generate HQL with interpolated literals instead of bind parameters for passing values."],"tags":["hibernate","h2","json","json-table","passing-clause","literal-required"],"backgroundTag":"json-passing-literal-required","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}