0001-Teach-jsonpath-to-handle-missing-variables-v2.patch
application/octet-stream
Filename: 0001-Teach-jsonpath-to-handle-missing-variables-v2.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v2-0001
Subject: Teach jsonpath to handle missing variables
| File | + | − |
|---|---|---|
| src/backend/utils/adt/jsonpath_exec.c | 36 | 11 |
| src/test/regress/expected/jsonb_jsonpath.out | 4 | 1 |
From 042ae7d0cfdb8683e1a07f691a21e47d17ea2b39 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Mon, 5 Dec 2022 17:02:29 +0300
Subject: [PATCH] Teach jsonpath to handle 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 jsonpath code to handle variables in the similar way to
key accessors. The existence is now checked runtime, and error suppression is
also applied.
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
Backpatch-through: 12
---
src/backend/utils/adt/jsonpath_exec.c | 47 +++++++++++++++-----
src/test/regress/expected/jsonb_jsonpath.out | 5 ++-
2 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 8d83b2edb35..e15ced19c4e 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -224,8 +224,9 @@ static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt,
JsonPathItem *jsp, JsonValueList *found, JsonPathBool res);
static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
JsonbValue *value);
-static void getJsonPathVariable(JsonPathExecContext *cxt,
- JsonPathItem *variable, Jsonb *vars, JsonbValue *value);
+static JsonPathExecResult getJsonPathVariable(JsonPathExecContext *cxt,
+ JsonPathItem *variable,
+ JsonbValue *value);
static int JsonbArraySize(JsonbValue *jb);
static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv,
JsonbValue *rv, void *p);
@@ -952,7 +953,6 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
case jpiBool:
case jpiNumeric:
case jpiString:
- case jpiVariable:
{
JsonbValue vbuf;
JsonbValue *v;
@@ -975,6 +975,24 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
break;
+ case jpiVariable:
+ {
+ JsonbValue vbuf;
+ JsonbValue *v;
+ bool hasNext = jspGetNext(jsp, &elem);
+
+ v = hasNext ? &vbuf : palloc(sizeof(*v));
+
+ baseObject = cxt->baseObject;
+ res = getJsonPathVariable(cxt, jsp, v);
+
+ if (res == jperOk)
+ res = executeNextItem(cxt, jsp, &elem,
+ v, found, hasNext);
+ cxt->baseObject = baseObject;
+ }
+ break;
+
case jpiType:
{
JsonbValue *jbv = palloc(sizeof(*jbv));
@@ -2092,9 +2110,6 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
value->val.string.val = jspGetString(item,
&value->val.string.len);
break;
- case jpiVariable:
- getJsonPathVariable(cxt, item, cxt->vars, value);
- return;
default:
elog(ERROR, "unexpected jsonpath item type");
}
@@ -2103,19 +2118,20 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
/*
* Get the value of variable passed to jsonpath executor
*/
-static void
+static JsonPathExecResult
getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
- Jsonb *vars, JsonbValue *value)
+ JsonbValue *value)
{
char *varName;
int varNameLength;
JsonbValue tmp;
JsonbValue *v;
+ Jsonb *vars = cxt->vars;
+ JsonPathExecResult res;
if (!vars)
{
- value->type = jbvNull;
- return;
+ return jperNotFound;
}
Assert(variable->type == jpiVariable);
@@ -2130,17 +2146,26 @@ getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
{
*value = *v;
pfree(v);
+ res = jperOk;
}
- else
+ else if (!jspIgnoreStructuralErrors(cxt))
{
+ if (!jspThrowErrors(cxt))
+ res = jperError;
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find jsonpath variable \"%s\"",
pnstrdup(varName, varNameLength))));
}
+ else
+ {
+ res = jperNotFound;
+ }
JsonbInitBinary(&tmp, vars);
setBaseObject(cxt, &tmp, 1);
+
+ return res;
}
/**************** Support functions for JsonPath execution *****************/
diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out
index 508ddd797ed..19c6bdc72c7 100644
--- a/src/test/regress/expected/jsonb_jsonpath.out
+++ b/src/test/regress/expected/jsonb_jsonpath.out
@@ -486,7 +486,10 @@ select * from jsonb_path_query('{"a": 10}', '$');
(1 row)
select * from jsonb_path_query('{"a": 10}', '$ ? (@.a < $value)');
-ERROR: could not find jsonpath variable "value"
+ jsonb_path_query
+------------------
+(0 rows)
+
select * from jsonb_path_query('{"a": 10}', '$ ? (@.a < $value)', '1');
ERROR: "vars" argument is not an object
DETAIL: Jsonpath parameters should be encoded as key-value pairs of "vars" object.
--
2.24.3 (Apple Git-128)