{"record":{"id":"45f25643a9d5e97d","repo":"hibernate/hibernate-orm","slug":"singlestore-json-query-only-support-literal-json-p","errorCode":null,"errorMessage":"SingleStore json_query only support literal json paths, but got \" + arguments.jsonPath() + \"","messagePattern":"SingleStore json_query only support literal json paths, but got \" \\+ arguments\\.jsonPath\\(\\) \\+ \"","errorType":"exception","errorClass":"QueryException","httpStatus":null,"severity":"error","filePath":"hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/json/SingleStoreJsonQueryFunction.java","lineNumber":47,"sourceCode":"\t@Override\n\tprotected void render(\n\t\t\tSqlAppender sqlAppender,\n\t\t\tJsonQueryArguments arguments,\n\t\t\tReturnableType<?> returnType,\n\t\t\tSqlAstTranslator<?> walker) {\n\t\tif ( arguments.errorBehavior() != null && arguments.errorBehavior() != JsonQueryErrorBehavior.ERROR ) {\n\t\t\tthrow new QueryException( \"Can't emulate on error clause on SingleStore\" );\n\t\t}\n\t\tif ( arguments.emptyBehavior() != null && arguments.emptyBehavior() != JsonQueryEmptyBehavior.NULL ) {\n\t\t\tthrow new QueryException( \"Can't emulate on empty clause on SingleStore\" );\n\t\t}\n\t\telse {\n\t\t\tfinal String jsonPath;\n\t\t\ttry {\n\t\t\t\tjsonPath = walker.getLiteralValue( arguments.jsonPath() );\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new QueryException( \"SingleStore json_query only support literal json paths, but got \" + arguments.jsonPath() );\n\t\t\t}\n\t\t\tfinal List<JsonPathHelper.JsonPathElement> jsonPathElements = JsonPathHelper.parseJsonPathElements( jsonPath );\n\t\t\tfinal JsonQueryWrapMode wrapMode = arguments.wrapMode();\n\t\t\tfinal DecorationMode decorationMode = determineDecorationMode( wrapMode );\n\t\t\tif ( decorationMode == DecorationMode.WRAP ) {\n\t\t\t\tsqlAppender.appendSql( \"concat('[',\" );\n\t\t\t}\n\t\t\tsqlAppender.appendSql( \"nullif(json_extract_string(\" );\n\t\t\targuments.jsonDocument().accept( walker );\n\t\t\tfor ( JsonPathHelper.JsonPathElement pathElement : jsonPathElements ) {\n\t\t\t\tsqlAppender.appendSql( ',' );\n\t\t\t\tif ( pathElement instanceof JsonPathHelper.JsonAttribute attribute ) {\n\t\t\t\t\tsqlAppender.appendSingleQuoteEscapedString( attribute.attribute() );\n\t\t\t\t}\n\t\t\t\telse if ( pathElement instanceof JsonPathHelper.JsonParameterIndexAccess indexParameter) {\n\t\t\t\t\tfinal String parameterName = indexParameter.parameterName();\n\t\t\t\t\tthrow new QueryException( \"JSON path [\" + jsonPath + \"] uses parameter [\" + parameterName + \"] that is not passed\" );\n\t\t\t\t}","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/json/SingleStoreJsonQueryFunction.java#L29-L65","documentation":"SingleStoreJsonQueryFunction decomposes the SQL/JSON path into individual json_extract_string(doc, 'attr', 'attr2') arguments at SQL-render time, so the path string must be known when the query is translated. It calls walker.getLiteralValue(arguments.jsonPath()) to read it; if the second argument is a bind parameter/parameter marker rather than a string literal, that call throws and the dialect rethrows this QueryException.","triggerScenarios":"HQL/JPA query like: select json_query(e.doc, :path) from Event e, then query.setParameter(\"path\", \"$.status\"). Any parameter expression (named or positional) in the jsonpath argument position triggers it; string literals like '$.status' do not.","commonSituations":"Generic 'query any JSON path' repository APIs that bind the path at runtime; code migrated from Oracle/PostgreSQL dialects that accept parameterized paths; dynamically choosing among a set of paths without rewriting the query string.","solutions":["Inline the JSON path as a string literal in the HQL: json_query(e.doc, '$.headers.status').","Build the HQL dynamically with the literal path interpolated - validate/whitelist the path (no quotes, no user-controlled syntax) to avoid injection.","Keep a small set of pre-built queries (one per path) and select among them at runtime.","Fall back to a native SQL query where the path is a real bind parameter to SingleStore's own JSON functions."],"exampleFix":"// before - throws: path is a bind parameter\nList<String> r = session.createQuery(\"select json_query(e.doc, :p) from Event e\", String.class)\n        .setParameter(\"p\", \"$.status\").getResultList();\n\n// after - literal path\nList<String> r = session.createQuery(\"select json_query(e.doc, '$.status') from Event e\", String.class)\n        .getResultList();","handlingStrategy":"fallback","validationCode":"// Validate a dynamic path, then inline it as a literal\nboolean safe = path.matches(\"^\\$[.A-Za-z0-9_\\[\\]'-]*$\");\nif (!safe) throw new IllegalArgumentException(\"untrusted json path\");\nString hql = \"select json_query(e.doc, '\" + path + \"') from Event e\";","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql, String.class).getResultList();\n} catch (QueryException e) {\n    if (e.getMessage().contains(\"literal json paths\")) {\n        throw new IllegalArgumentException(\"json path must be a literal: \" + path, e);\n    }\n    throw e;\n}","preventionTips":["Never bind the jsonpath argument as a query parameter on SingleStore","Whitelist and inline dynamic paths as literals","Cache pre-built query strings per path instead of parameterizing the path"],"tags":["singlestore","json","json-query","hql","bind-parameter","literal-required"],"backgroundTag":"unsupported-bind-parameter","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}