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:
@@ -4285,6 +4285,9 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
|
|||||||
{
|
{
|
||||||
JsonExpr *jsexpr;
|
JsonExpr *jsexpr;
|
||||||
Node *path_spec;
|
Node *path_spec;
|
||||||
|
Oid pathspec_type;
|
||||||
|
int pathspec_loc;
|
||||||
|
Node *coerced_path_spec;
|
||||||
const char *func_name = NULL;
|
const char *func_name = NULL;
|
||||||
JsonFormatType default_format;
|
JsonFormatType default_format;
|
||||||
|
|
||||||
@@ -4500,17 +4503,21 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
|
|||||||
jsexpr->format = func->context_item->format;
|
jsexpr->format = func->context_item->format;
|
||||||
|
|
||||||
path_spec = transformExprRecurse(pstate, func->pathspec);
|
path_spec = transformExprRecurse(pstate, func->pathspec);
|
||||||
path_spec = coerce_to_target_type(pstate, path_spec, exprType(path_spec),
|
pathspec_type = exprType(path_spec);
|
||||||
JSONPATHOID, -1,
|
pathspec_loc = exprLocation(path_spec);
|
||||||
COERCION_EXPLICIT, COERCE_IMPLICIT_CAST,
|
coerced_path_spec = coerce_to_target_type(pstate, path_spec,
|
||||||
exprLocation(path_spec));
|
pathspec_type,
|
||||||
if (path_spec == NULL)
|
JSONPATHOID, -1,
|
||||||
|
COERCION_EXPLICIT,
|
||||||
|
COERCE_IMPLICIT_CAST,
|
||||||
|
pathspec_loc);
|
||||||
|
if (coerced_path_spec == NULL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("JSON path expression must be of type %s, not of type %s",
|
errmsg("JSON path expression must be of type %s, not of type %s",
|
||||||
"jsonpath", format_type_be(exprType(path_spec))),
|
"jsonpath", format_type_be(pathspec_type)),
|
||||||
parser_errposition(pstate, exprLocation(path_spec))));
|
parser_errposition(pstate, pathspec_loc)));
|
||||||
jsexpr->path_spec = path_spec;
|
jsexpr->path_spec = coerced_path_spec;
|
||||||
|
|
||||||
/* Transform and coerce the PASSING arguments to jsonb. */
|
/* Transform and coerce the PASSING arguments to jsonb. */
|
||||||
transformJsonPassingArgs(pstate, func_name,
|
transformJsonPassingArgs(pstate, func_name,
|
||||||
|
|||||||
@@ -1331,6 +1331,10 @@ SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
|
|||||||
[123]
|
[123]
|
||||||
(1 row)
|
(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)
|
-- Should fail (invalid path)
|
||||||
SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
|
SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
|
||||||
ERROR: syntax error at or near " " of jsonpath input
|
ERROR: syntax error at or near " " of jsonpath input
|
||||||
@@ -1355,6 +1359,10 @@ SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
|
|||||||
"aaa"
|
"aaa"
|
||||||
(1 row)
|
(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
|
-- Test PASSING argument parsing
|
||||||
SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);
|
SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);
|
||||||
ERROR: could not find jsonpath variable "xyz"
|
ERROR: could not find jsonpath variable "xyz"
|
||||||
|
|||||||
@@ -450,6 +450,7 @@ SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'a');
|
|||||||
SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'b' DEFAULT 'foo' ON EMPTY);
|
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');
|
||||||
SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
|
SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
|
||||||
|
SELECT JSON_QUERY(jsonb '{"a": 123}', ('$' || '.' || 'a' || NULL)::date WITH WRAPPER);
|
||||||
-- Should fail (invalid path)
|
-- Should fail (invalid path)
|
||||||
SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
|
SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
|
||||||
|
|
||||||
@@ -460,6 +461,7 @@ SELECT JSON_QUERY(NULL FORMAT JSON, '$');
|
|||||||
-- Test non-const jsonpath
|
-- Test non-const jsonpath
|
||||||
CREATE TEMP TABLE jsonpaths (path) AS SELECT '$';
|
CREATE TEMP TABLE jsonpaths (path) AS SELECT '$';
|
||||||
SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
|
SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
|
||||||
|
SELECT json_value('"aaa"', jsonpaths RETURNING json) FROM jsonpaths;
|
||||||
|
|
||||||
-- Test PASSING argument parsing
|
-- Test PASSING argument parsing
|
||||||
SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);
|
SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);
|
||||||
|
|||||||
Reference in New Issue
Block a user