Fix jsonpath existense checking of missing variables

The current jsonpath code assumes that the referenced variable always exists.
It could only throw an error at the value valuation time.  At the same time
existence checking assumes variable is present without valuation, and error
suppression doesn't work for missing variables.

This commit makes existense checking trigger an error for missing variables.
This makes the overall behavior consistent.

Backpatch to 12 where jsonpath was introduced.

Reported-by: David G. Johnston
Discussion: https://postgr.es/m/CAKFQuwbeytffJkVnEqDyLZ%3DrQsznoTh1OgDoOF3VmOMkxcTMjA%40mail.gmail.com
Author: Alexander Korotkov, David G. Johnston
Backpatch-through: 12
This commit is contained in:
Alexander Korotkov 2023-01-12 18:16:34 +03:00
parent 72b6098be4
commit 2ff3ac3b5f
3 changed files with 46 additions and 2 deletions

View File

@ -960,9 +960,13 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
JsonbValue *v; JsonbValue *v;
bool hasNext = jspGetNext(jsp, &elem); bool hasNext = jspGetNext(jsp, &elem);
if (!hasNext && !found) if (!hasNext && !found && jsp->type != jpiVariable)
{ {
res = jperOk; /* skip evaluation */ /*
* Skip evaluation, but not for variables. We must
* trigger an error for the missing variable.
*/
res = jperOk;
break; break;
} }

View File

@ -2212,6 +2212,14 @@ SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*] ? (@.a > 10)');
------------------ ------------------
(0 rows) (0 rows)
SELECT jsonb_path_query('[{"a": 1}]', '$undefined_var');
ERROR: could not find jsonpath variable "undefined_var"
SELECT jsonb_path_query('[{"a": 1}]', 'false');
jsonb_path_query
------------------
false
(1 row)
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a'); SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
ERROR: JSON object does not contain key "a" ERROR: JSON object does not contain key "a"
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a'); SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a');
@ -2282,6 +2290,14 @@ SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].
(1 row) (1 row)
SELECT jsonb_path_query_first('[{"a": 1}]', '$undefined_var');
ERROR: could not find jsonpath variable "undefined_var"
SELECT jsonb_path_query_first('[{"a": 1}]', 'false');
jsonb_path_query_first
------------------------
false
(1 row)
SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*].a ? (@ > 1)'; SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*].a ? (@ > 1)';
?column? ?column?
---------- ----------
@ -2312,6 +2328,14 @@ SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.
f f
(1 row) (1 row)
SELECT jsonb_path_exists('[{"a": 1}]', '$undefined_var');
ERROR: could not find jsonpath variable "undefined_var"
SELECT jsonb_path_exists('[{"a": 1}]', 'false');
jsonb_path_exists
-------------------
t
(1 row)
SELECT jsonb_path_match('true', '$', silent => false); SELECT jsonb_path_match('true', '$', silent => false);
jsonb_path_match jsonb_path_match
------------------ ------------------
@ -2374,6 +2398,14 @@ SELECT jsonb_path_match('[{"a": 1}, {"a": 2}]', '$[*].a > 1');
t t
(1 row) (1 row)
SELECT jsonb_path_match('[{"a": 1}]', '$undefined_var');
ERROR: could not find jsonpath variable "undefined_var"
SELECT jsonb_path_match('[{"a": 1}]', 'false');
jsonb_path_match
------------------
f
(1 row)
-- test string comparison (Unicode codepoint collation) -- test string comparison (Unicode codepoint collation)
WITH str(j, num) AS WITH str(j, num) AS
( (

View File

@ -532,6 +532,8 @@ set time zone default;
SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*]'); SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*]');
SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*] ? (@.a > 10)'); SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*] ? (@.a > 10)');
SELECT jsonb_path_query('[{"a": 1}]', '$undefined_var');
SELECT jsonb_path_query('[{"a": 1}]', 'false');
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a'); SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a'); SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a');
@ -547,12 +549,16 @@ SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ == 1)');
SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 10)'); SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 10)');
SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 1, "max": 4}'); SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 1, "max": 4}');
SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 3, "max": 4}'); SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 3, "max": 4}');
SELECT jsonb_path_query_first('[{"a": 1}]', '$undefined_var');
SELECT jsonb_path_query_first('[{"a": 1}]', 'false');
SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*].a ? (@ > 1)'; SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*].a ? (@ > 1)';
SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*] ? (@.a > 2)'; SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*] ? (@.a > 2)';
SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 1)'); SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 1)');
SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 1, "max": 4}'); SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 1, "max": 4}');
SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 3, "max": 4}'); SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 3, "max": 4}');
SELECT jsonb_path_exists('[{"a": 1}]', '$undefined_var');
SELECT jsonb_path_exists('[{"a": 1}]', 'false');
SELECT jsonb_path_match('true', '$', silent => false); SELECT jsonb_path_match('true', '$', silent => false);
SELECT jsonb_path_match('false', '$', silent => false); SELECT jsonb_path_match('false', '$', silent => false);
@ -569,6 +575,8 @@ SELECT jsonb_path_match('[true, true]', '$[*]', silent => false);
SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 1'; SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 1';
SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 2'; SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 2';
SELECT jsonb_path_match('[{"a": 1}, {"a": 2}]', '$[*].a > 1'); SELECT jsonb_path_match('[{"a": 1}, {"a": 2}]', '$[*].a > 1');
SELECT jsonb_path_match('[{"a": 1}]', '$undefined_var');
SELECT jsonb_path_match('[{"a": 1}]', 'false');
-- test string comparison (Unicode codepoint collation) -- test string comparison (Unicode codepoint collation)
WITH str(j, num) AS WITH str(j, num) AS