From 8cd8e82676f1cb1ea9eba9db3df6ce3f73650ef3 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Tue, 4 Jun 2024 20:35:43 -0400 Subject: [PATCH] Add tests for jsonpath `.*` on arrays There was no coverage for the path to unwrap an array before applying `.*` to it, so add tests that explicitly test `.*` for both objects and arrays, showing how no results are returned for an array of scalars, but results are returned when the array contains an object. Also test the behavior in strict mode and with the `@?` operator. While at it, teach `executeAnyItem()` to return `jperOk` when `found` exist, not because it will be used (the result and `found` are inspected by different functions), but because it seems like the proper thing to return from `executeAnyItem()` when considered in isolation. Unrelated but potentially useful to future source readers: document `GetJsonPathVar` and `CountJsonPathVars`. --- src/backend/utils/adt/jsonpath_exec.c | 11 ++++- src/test/regress/expected/jsonb_jsonpath.out | 44 ++++++++++++++++++++ src/test/regress/sql/jsonb_jsonpath.sql | 9 ++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 8a0a2dbc85..5ef168e978 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -2002,8 +2002,10 @@ executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc, if (res == jperOk && !found) break; } - else if (found) + else if (found) { JsonValueListAppend(found, copyJsonbValue(&v)); + res = jperOk; + } else return jperOk; } @@ -2976,7 +2978,8 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, } /* - * Returns the computed value of a JSON path variable with given name. + * Definition of JsonPathGetVarCallback for when JsonPathExecContext.vars + * is specified as a List value. */ static JsonbValue * GetJsonPathVar(void *cxt, char *varName, int varNameLen, @@ -3022,6 +3025,10 @@ GetJsonPathVar(void *cxt, char *varName, int varNameLen, return result; } +/* + * Definition of JsonPathCountVarsCallback for when JsonPathExecContext.vars + * is specified as a List value. + */ static int CountJsonPathVars(void *cxt) { diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out index c3f8e8249d..7ec4a0ef38 100644 --- a/src/test/regress/expected/jsonb_jsonpath.out +++ b/src/test/regress/expected/jsonb_jsonpath.out @@ -245,6 +245,50 @@ select jsonb_path_exists('[{"a": 1}, {"a": 2}, 3]', 'strict $[*].a', silent => t (1 row) +select jsonb_path_query('{"a": [1,2,3], "b": [3,4,5]}', '$.*'); + jsonb_path_query +------------------ + [1, 2, 3] + [3, 4, 5] +(2 rows) + +select jsonb_path_query('[1,2,3]', '$.*'); + jsonb_path_query +------------------ +(0 rows) + +select jsonb_path_query('[1,2,3,{"b": [3,4,5]}]', '$.*'); + jsonb_path_query +------------------ + [3, 4, 5] +(1 row) + +select jsonb_path_query('[1,2,3,{"b": [3,4,5]}]', 'strict $.*'); +ERROR: jsonpath wildcard member accessor can only be applied to an object +select jsonb '{"a": [1,2,3], "b": [3,4,5]}' @? '$.*'; + ?column? +---------- + t +(1 row) + +select jsonb '[1,2,3]' @? '$.*'; + ?column? +---------- + f +(1 row) + +select jsonb '[1,2,3,{"b": [3,4,5]}]' @? '$.*'; + ?column? +---------- + t +(1 row) + +select jsonb '[1,2,3,{"b": [3,4,5]}]' @? 'strict $.*'; + ?column? +---------- + +(1 row) + select jsonb_path_query('1', 'lax $.a'); jsonb_path_query ------------------ diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql index cbd2db533d..fa6f3cd5f9 100644 --- a/src/test/regress/sql/jsonb_jsonpath.sql +++ b/src/test/regress/sql/jsonb_jsonpath.sql @@ -44,6 +44,15 @@ select jsonb_path_exists('[{"a": 1}, {"a": 2}, 3]', 'lax $[*].a', silent => true select jsonb_path_exists('[{"a": 1}, {"a": 2}, 3]', 'strict $[*].a', silent => false); select jsonb_path_exists('[{"a": 1}, {"a": 2}, 3]', 'strict $[*].a', silent => true); +select jsonb_path_query('{"a": [1,2,3], "b": [3,4,5]}', '$.*'); +select jsonb_path_query('[1,2,3]', '$.*'); +select jsonb_path_query('[1,2,3,{"b": [3,4,5]}]', '$.*'); +select jsonb_path_query('[1,2,3,{"b": [3,4,5]}]', 'strict $.*'); +select jsonb '{"a": [1,2,3], "b": [3,4,5]}' @? '$.*'; +select jsonb '[1,2,3]' @? '$.*'; +select jsonb '[1,2,3,{"b": [3,4,5]}]' @? '$.*'; +select jsonb '[1,2,3,{"b": [3,4,5]}]' @? 'strict $.*'; + select jsonb_path_query('1', 'lax $.a'); select jsonb_path_query('1', 'strict $.a'); select jsonb_path_query('1', 'strict $.*'); -- 2.45.2