1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-28 11:44:57 +03:00

Fix error reporting for SQL/JSON path type mismatches

transformJsonFuncExpr() used exprType()/exprLocation() on the
possibly coerced path expression, which could be NULL when
coercion to jsonpath failed, leading to "cache lookup failed
for type 0" errors.

Preserve the original expression node so that type and location
in the "must be of type jsonpath" error are reported correctly.
Add regression tests to cover these cases.

Reported-by: Jian He <jian.universality@gmail.com>
Author: Jian He <jian.universality@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Discussion: https://postgr.es/m/CACJufxHunVg81JMuNo8Yvv_hJD0DicgaVN2Wteu8aJbVJPBjZA@mail.gmail.com
Backpatch-through: 17
This commit is contained in:
Amit Langote
2025-11-27 10:43:29 +09:00
parent 0ca3b16973
commit 519fa0433b
3 changed files with 25 additions and 8 deletions

View File

@@ -4285,6 +4285,9 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
{
JsonExpr *jsexpr;
Node *path_spec;
Oid pathspec_type;
int pathspec_loc;
Node *coerced_path_spec;
const char *func_name = NULL;
JsonFormatType default_format;
@@ -4500,17 +4503,21 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
jsexpr->format = func->context_item->format;
path_spec = transformExprRecurse(pstate, func->pathspec);
path_spec = coerce_to_target_type(pstate, path_spec, exprType(path_spec),
JSONPATHOID, -1,
COERCION_EXPLICIT, COERCE_IMPLICIT_CAST,
exprLocation(path_spec));
if (path_spec == NULL)
pathspec_type = exprType(path_spec);
pathspec_loc = exprLocation(path_spec);
coerced_path_spec = coerce_to_target_type(pstate, path_spec,
pathspec_type,
JSONPATHOID, -1,
COERCION_EXPLICIT,
COERCE_IMPLICIT_CAST,
pathspec_loc);
if (coerced_path_spec == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("JSON path expression must be of type %s, not of type %s",
"jsonpath", format_type_be(exprType(path_spec))),
parser_errposition(pstate, exprLocation(path_spec))));
jsexpr->path_spec = path_spec;
"jsonpath", format_type_be(pathspec_type)),
parser_errposition(pstate, pathspec_loc)));
jsexpr->path_spec = coerced_path_spec;
/* Transform and coerce the PASSING arguments to jsonb. */
transformJsonPassingArgs(pstate, func_name,

View File

@@ -1331,6 +1331,10 @@ SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
[123]
(1 row)
SELECT JSON_QUERY(jsonb '{"a": 123}', ('$' || '.' || 'a' || NULL)::date WITH WRAPPER);
ERROR: JSON path expression must be of type jsonpath, not of type date
LINE 1: SELECT JSON_QUERY(jsonb '{"a": 123}', ('$' || '.' || 'a' || ...
^
-- Should fail (invalid path)
SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
ERROR: syntax error at or near " " of jsonpath input
@@ -1355,6 +1359,10 @@ SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
"aaa"
(1 row)
SELECT json_value('"aaa"', jsonpaths RETURNING json) FROM jsonpaths;
ERROR: JSON path expression must be of type jsonpath, not of type jsonpaths
LINE 1: SELECT json_value('"aaa"', jsonpaths RETURNING json) FROM js...
^
-- Test PASSING argument parsing
SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);
ERROR: could not find jsonpath variable "xyz"

View File

@@ -450,6 +450,7 @@ SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'a');
SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'b' DEFAULT 'foo' ON EMPTY);
SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a');
SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
SELECT JSON_QUERY(jsonb '{"a": 123}', ('$' || '.' || 'a' || NULL)::date WITH WRAPPER);
-- Should fail (invalid path)
SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
@@ -460,6 +461,7 @@ SELECT JSON_QUERY(NULL FORMAT JSON, '$');
-- Test non-const jsonpath
CREATE TEMP TABLE jsonpaths (path) AS SELECT '$';
SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
SELECT json_value('"aaa"', jsonpaths RETURNING json) FROM jsonpaths;
-- Test PASSING argument parsing
SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);