aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Korotkov <akorotkov@postgresql.org>2023-01-12 18:16:34 +0300
committerAlexander Korotkov <akorotkov@postgresql.org>2023-01-12 18:19:19 +0300
commit9e24e4781750ca92a0a5ff0aaa8e2091785c3bed (patch)
treeb98e97613fe5551722c26f004854e22bb5b4e177
parentc0ee6943ca1ded4b1a09be5832ef6e6bc257fb13 (diff)
downloadpostgresql-9e24e4781750ca92a0a5ff0aaa8e2091785c3bed.tar.gz
postgresql-9e24e4781750ca92a0a5ff0aaa8e2091785c3bed.zip
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
-rw-r--r--src/backend/utils/adt/jsonpath_exec.c8
-rw-r--r--src/test/regress/expected/jsonb_jsonpath.out32
-rw-r--r--src/test/regress/sql/jsonb_jsonpath.sql8
3 files changed, 46 insertions, 2 deletions
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index a557ed1ce1e..37b08f1742a 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -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;
}
diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out
index fb0fed11ac7..db577e3427b 100644
--- a/src/test/regress/expected/jsonb_jsonpath.out
+++ b/src/test/regress/expected/jsonb_jsonpath.out
@@ -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
(
diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql
index 7a65c6caeba..cf883a5e4c2 100644
--- a/src/test/regress/sql/jsonb_jsonpath.sql
+++ b/src/test/regress/sql/jsonb_jsonpath.sql
@@ -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