]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix jsonpath existense checking of missing variables
authorAlexander Korotkov <akorotkov@postgresql.org>
Thu, 12 Jan 2023 15:16:34 +0000 (18:16 +0300)
committerAlexander Korotkov <akorotkov@postgresql.org>
Thu, 12 Jan 2023 15:19:19 +0000 (18:19 +0300)
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

src/backend/utils/adt/jsonpath_exec.c
src/test/regress/expected/jsonb_jsonpath.out
src/test/regress/sql/jsonb_jsonpath.sql

index a557ed1ce1ef12106974166d47ed168adf6ae18f..37b08f1742a5270545fa17920108e0b2fa1f49c1 100644 (file)
@@ -891,9 +891,13 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
                                JsonbValue *v;
                                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;
                                }
 
index fb0fed11ac7b9f24911ff74e1a58cba674b7bdad..db577e3427be895861c01bde19ce376c850662ec 100644 (file)
@@ -1666,6 +1666,14 @@ SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*] ? (@.a > 10)');
 ------------------
 (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');
 ERROR:  JSON object does not contain key "a"
 SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a');
@@ -1736,6 +1744,14 @@ SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].
  
 (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)';
  ?column? 
 ----------
@@ -1766,6 +1782,14 @@ SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.
  f
 (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);
  jsonb_path_match 
 ------------------
@@ -1828,6 +1852,14 @@ SELECT jsonb_path_match('[{"a": 1}, {"a": 2}]', '$[*].a > 1');
  t
 (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)
 WITH str(j, num) AS
 (
index 7a65c6caeba757d449b7e1c28c2ce626faeb22a3..cf883a5e4c2fd4da72d520afab166efa0724ab10 100644 (file)
@@ -351,6 +351,8 @@ select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ lik
 
 SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*]');
 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}]', '$[*].a');
@@ -366,12 +368,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": 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}]', '$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 > 2)';
 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": 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('false', '$', silent => false);
@@ -388,6 +394,8 @@ SELECT jsonb_path_match('[true, true]', '$[*]', silent => false);
 SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 1';
 SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 2';
 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)
 WITH str(j, num) AS