From a8b386df15fa4dba9c80ebfaab8d2a732d85ac82 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Sat, 15 Jun 2024 19:44:21 +0530 Subject: [PATCH v3] Teach jsonpath string() to unwrap in lax mode All other jsonpath methods, aside from type() and .size(), will unwrap an array in lax mode, but string(), added in 66ea94e, overlooked this behavior. A discussion on pgsql-hackers[1] cites the SQL standard: > General Rule 11 g ii 6) A) says just "if MODE is lax and > is not type or size, then let BASE be Unwrap(BASE)." No special > exemption there for string(), nor further below at C) XV) for the > operation of string(). So teach string() to also unwrap in lax mode, update the test for this behavior, and add a line to the docs about the behavior of methods in lax mode. [1]: https://www.postgresql.org/message-id/flat/A64AE04F-4410-42B7-A141-7A7349260F4D%40justatheory.com --- doc/src/sgml/func.sgml | 5 ++++- src/backend/utils/adt/jsonpath_exec.c | 3 +++ src/test/regress/expected/jsonb_jsonpath.out | 12 +++++++++++- src/test/regress/sql/jsonb_jsonpath.sql | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 17c44bc..2609269 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17792,7 +17792,10 @@ ERROR: jsonpath member accessor can only be applied to an object methods available in jsonpath. Note that while the unary operators and methods can be applied to multiple values resulting from a preceding path step, the binary operators (addition etc.) can only be - applied to single values. + applied to single values. In lax mode, methods applied to an array will be + executed for each value in the array. The exceptions are + .type() and .size(), which apply to + the array itself. diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index ceb3003..c30d059 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -1606,6 +1606,9 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue jbv; char *tmp = NULL; + if (unwrap && JsonbType(jb) == jbvArray) + return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false); + switch (JsonbType(jb)) { case jbvString: diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out index c3f8e82..a6112e8 100644 --- a/src/test/regress/expected/jsonb_jsonpath.out +++ b/src/test/regress/expected/jsonb_jsonpath.out @@ -2525,7 +2525,10 @@ select jsonb_path_query('null', '$.string()', silent => true); (0 rows) select jsonb_path_query('[]', '$.string()'); -ERROR: jsonpath item method .string() can only be applied to a bool, string, numeric, or datetime value + jsonb_path_query +------------------ +(0 rows) + select jsonb_path_query('[]', 'strict $.string()'); ERROR: jsonpath item method .string() can only be applied to a bool, string, numeric, or datetime value select jsonb_path_query('{}', '$.string()'); @@ -2576,6 +2579,13 @@ select jsonb_path_query('1234', '$.string().type()'); "string" (1 row) +select jsonb_path_query('[2, true]', '$.string()'); + jsonb_path_query +------------------ + "2" + "true" +(2 rows) + select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp().string()'); ERROR: cannot convert value from timestamptz to timestamp without time zone usage HINT: Use *_tz() function for time zone support. diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql index cbd2db5..5e14f77 100644 --- a/src/test/regress/sql/jsonb_jsonpath.sql +++ b/src/test/regress/sql/jsonb_jsonpath.sql @@ -586,6 +586,7 @@ select jsonb_path_query('"1.23aaa"', '$.string()'); select jsonb_path_query('1234', '$.string()'); select jsonb_path_query('true', '$.string()'); select jsonb_path_query('1234', '$.string().type()'); +select jsonb_path_query('[2, true]', '$.string()'); select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp().string()'); select jsonb_path_query_tz('"2023-08-15 12:34:56 +5:30"', '$.timestamp().string()'); -- should work select jsonb_path_query_array('[1.23, "yes", false]', '$[*].string()'); -- 1.8.3.1