v2-0003-Implement-jsonpath-.boolean-and-.string-methods.patch
application/octet-stream
Filename: v2-0003-Implement-jsonpath-.boolean-and-.string-methods.patch
Type: application/octet-stream
Part: 1
Message:
Re: More new SQL/JSON item methods
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v2-0003
Subject: Implement jsonpath .boolean() and .string() methods
| File | + | − |
|---|---|---|
| doc/src/sgml/func.sgml | 32 | 0 |
| src/backend/catalog/sql_features.txt | 2 | 2 |
| src/backend/utils/adt/jsonpath.c | 16 | 0 |
| src/backend/utils/adt/jsonpath_exec.c | 147 | 0 |
| src/backend/utils/adt/jsonpath_gram.y | 5 | 1 |
| src/backend/utils/adt/jsonpath_scan.l | 2 | 0 |
| src/include/utils/jsonpath.h | 2 | 0 |
| src/test/regress/expected/jsonb_jsonpath.out | 263 | 0 |
| src/test/regress/expected/jsonpath.out | 12 | 0 |
| src/test/regress/sql/jsonb_jsonpath.sql | 58 | 0 |
| src/test/regress/sql/jsonpath.sql | 2 | 0 |
From b7e97e2471e8fc6b09affc885da04d4067601167 Mon Sep 17 00:00:00 2001
From: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Date: Mon, 23 Oct 2023 12:38:44 +0530
Subject: [PATCH v2 3/3] Implement jsonpath .boolean() and .string() methods
This commit implements jsonpath .boolean() and .string() methods.
.boolean() method converts the given JSON string, numeric, or boolean
value to the boolean type representation. In the numeric case, only
integers are allowed, whereas we use the parse_bool() backend function
to convert string to a bool.
.string() method uses the datatype's out function to convert numeric
and various date/time types to the string representation.
Jeevan Chalke.
---
doc/src/sgml/func.sgml | 32 ++++
src/backend/catalog/sql_features.txt | 4 +-
src/backend/utils/adt/jsonpath.c | 16 ++
src/backend/utils/adt/jsonpath_exec.c | 147 +++++++++++++++
src/backend/utils/adt/jsonpath_gram.y | 6 +-
src/backend/utils/adt/jsonpath_scan.l | 2 +
src/include/utils/jsonpath.h | 2 +
src/test/regress/expected/jsonb_jsonpath.out | 263 +++++++++++++++++++++++++++
src/test/regress/expected/jsonpath.out | 12 ++
src/test/regress/sql/jsonb_jsonpath.sql | 58 ++++++
src/test/regress/sql/jsonpath.sql | 2 +
11 files changed, 541 insertions(+), 3 deletions(-)
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index dc8aab3..9610a75 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17626,6 +17626,38 @@ strict $.**.HR
<row>
<entry role="func_table_entry"><para role="func_signature">
+ <replaceable>value</replaceable> <literal>.</literal> <literal>boolean()</literal>
+ <returnvalue><replaceable>boolean</replaceable></returnvalue>
+ </para>
+ <para>
+ Boolean value converted from a JSON boolean, number, or string
+ </para>
+ <para>
+ <literal>jsonb_path_query_array('[1, "yes", false]', '$[*].boolean()')</literal>
+ <returnvalue>[true, true, false]</returnvalue>
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <replaceable>value</replaceable> <literal>.</literal> <literal>string()</literal>
+ <returnvalue><replaceable>string</replaceable></returnvalue>
+ </para>
+ <para>
+ String value converted from a JSON boolean, number, string, or datetime
+ </para>
+ <para>
+ <literal>jsonb_path_query_array('[1.23, "xyz", false]', '$[*].string()')</literal>
+ <returnvalue>["1.23", "xyz", "false"]</returnvalue>
+ </para>
+ <para>
+ <literal>jsonb_path_query('"2023-08-15"', '$.datetime().string()')</literal>
+ <returnvalue>"2023-08-15"</returnvalue>
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
<replaceable>value</replaceable> <literal>.</literal> <literal>double()</literal>
<returnvalue><replaceable>number</replaceable></returnvalue>
</para>
diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt
index 93f2d54..2118d54 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -575,13 +575,13 @@ T862 SQL/JSON simplified accessor: wildcard member accessor NO
T863 SQL/JSON simplified accessor: single-quoted string literal as member accessor NO
T864 SQL/JSON simplified accessor NO
T865 SQL/JSON item method: bigint() YES
-T866 SQL/JSON item method: boolean() NO
+T866 SQL/JSON item method: boolean() YES
T867 SQL/JSON item method: date() YES
T868 SQL/JSON item method: decimal() YES
T869 SQL/JSON item method: decimal() with precision and scale YES
T870 SQL/JSON item method: integer() YES
T871 SQL/JSON item method: number() YES
-T872 SQL/JSON item method: string() NO
+T872 SQL/JSON item method: string() YES
T873 SQL/JSON item method: time() YES
T874 SQL/JSON item method: time_tz() YES
T875 SQL/JSON item method: time precision YES
diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c
index 52d8c2e..a494051 100644
--- a/src/backend/utils/adt/jsonpath.c
+++ b/src/backend/utils/adt/jsonpath.c
@@ -446,6 +446,8 @@ flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
break;
case jpiType:
case jpiSize:
+ case jpiBoolean:
+ case jpiStringFunc:
case jpiAbs:
case jpiFloor:
case jpiCeiling:
@@ -728,6 +730,12 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
case jpiSize:
appendStringInfoString(buf, ".size()");
break;
+ case jpiBoolean:
+ appendStringInfoString(buf, ".boolean()");
+ break;
+ case jpiStringFunc:
+ appendStringInfoString(buf, ".string()");
+ break;
case jpiAbs:
appendStringInfoString(buf, ".abs()");
break;
@@ -864,6 +872,10 @@ jspOperationName(JsonPathItemType type)
return "type";
case jpiSize:
return "size";
+ case jpiBoolean:
+ return "boolean";
+ case jpiStringFunc:
+ return "string";
case jpiKeyValue:
return "keyvalue";
case jpiDouble:
@@ -984,6 +996,8 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
case jpiAnyKey:
case jpiType:
case jpiSize:
+ case jpiBoolean:
+ case jpiStringFunc:
case jpiAbs:
case jpiFloor:
case jpiCeiling:
@@ -1112,6 +1126,8 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
v->type == jpiIsUnknown ||
v->type == jpiType ||
v->type == jpiSize ||
+ v->type == jpiBoolean ||
+ v->type == jpiStringFunc ||
v->type == jpiAbs ||
v->type == jpiFloor ||
v->type == jpiCeiling ||
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 32f5ed7..4a9f79d 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -1021,6 +1021,153 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
break;
+ case jpiBoolean:
+ {
+ JsonbValue jbv;
+ bool bval;
+
+ if (unwrap && JsonbType(jb) == jbvArray)
+ return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
+ false);
+
+ if (jb->type == jbvBool)
+ {
+ bval = jb->val.boolean;
+
+ res = jperOk;
+ }
+ else if (jb->type == jbvNumeric)
+ {
+ int ival;
+ Datum datum;
+ bool noerr;
+ char *tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
+ NumericGetDatum(jb->val.numeric)));
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
+
+ noerr = DirectInputFunctionCallSafe(int4in, tmp,
+ InvalidOid, -1,
+ (Node *) &escontext,
+ &datum);
+
+ if (!noerr || escontext.error_occurred)
+ RETURN_ERROR(ereport(ERROR,
+ (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
+ errmsg("numeric argument of jsonpath item method .%s() is out of range for type boolean",
+ jspOperationName(jsp->type)))));
+
+ ival = DatumGetInt32(datum);
+ if (ival == 0)
+ bval = false;
+ else
+ bval = true;
+
+ res = jperOk;
+ }
+ else if (jb->type == jbvString)
+ {
+ /* cast string as boolean */
+ char *tmp = pnstrdup(jb->val.string.val,
+ jb->val.string.len);
+
+ if (!parse_bool(tmp, &bval))
+ RETURN_ERROR(ereport(ERROR,
+ (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
+ errmsg("string argument of jsonpath item method .%s() is not a valid representation of a boolean",
+ jspOperationName(jsp->type)))));
+
+ res = jperOk;
+ }
+
+ if (res == jperNotFound)
+ RETURN_ERROR(ereport(ERROR,
+ (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
+ errmsg("jsonpath item method .%s() can only be applied to a bool, string, or numeric value",
+ jspOperationName(jsp->type)))));
+
+ jb = &jbv;
+ jb->type = jbvBool;
+ jb->val.boolean = bval;
+
+ res = executeNextItem(cxt, jsp, NULL, jb, found, true);
+ }
+ break;
+
+ case jpiStringFunc:
+ {
+ JsonbValue jbv;
+ char *tmp = NULL;
+
+ switch (JsonbType(jb))
+ {
+ case jbvString:
+ /*
+ * Value is not necessarily null-terminated, so we do
+ * pnstrdup() here.
+ */
+ tmp = pnstrdup(jb->val.string.val,
+ jb->val.string.len);
+ break;
+ case jbvNumeric:
+ tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
+ NumericGetDatum(jb->val.numeric)));
+ break;
+ case jbvBool:
+ tmp = (jb->val.boolean) ? "true" : "false";
+ break;
+ case jbvDatetime:
+ {
+ switch (jb->val.datetime.typid)
+ {
+ case DATEOID:
+ tmp = DatumGetCString(DirectFunctionCall1(date_out,
+ jb->val.datetime.value));
+ break;
+ case TIMEOID:
+ tmp = DatumGetCString(DirectFunctionCall1(time_out,
+ jb->val.datetime.value));
+ break;
+ case TIMETZOID:
+ tmp = DatumGetCString(DirectFunctionCall1(timetz_out,
+ jb->val.datetime.value));
+ break;
+ case TIMESTAMPOID:
+ tmp = DatumGetCString(DirectFunctionCall1(timestamp_out,
+ jb->val.datetime.value));
+ break;
+ case TIMESTAMPTZOID:
+ tmp = DatumGetCString(DirectFunctionCall1(timestamptz_out,
+ jb->val.datetime.value));
+ break;
+ default:
+ elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
+ jb->val.datetime.typid);
+ }
+ }
+ break;
+ case jbvNull:
+ case jbvArray:
+ case jbvObject:
+ case jbvBinary:
+ RETURN_ERROR(ereport(ERROR,
+ (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
+ errmsg("jsonpath item method .%s() can only be applied to a bool, string, numeric, or datetime value",
+ jspOperationName(jsp->type)))));
+ break;
+ }
+
+ res = jperOk;
+
+ jb = &jbv;
+ Assert(tmp != NULL); /* We must have set tmp above */
+ jb->val.string.val = (jb->type == jbvString) ? tmp : pstrdup(tmp);
+ jb->val.string.len = strlen(jb->val.string.val);
+ jb->type = jbvString;
+
+ res = executeNextItem(cxt, jsp, NULL, jb, found, true);
+ }
+ break;
+
case jpiAbs:
return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
found);
diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y
index f23ed2b..2bfef8b 100644
--- a/src/backend/utils/adt/jsonpath_gram.y
+++ b/src/backend/utils/adt/jsonpath_gram.y
@@ -82,7 +82,7 @@ static bool makeItemLikeRegex(JsonPathParseItem *expr,
%token <str> ANY_P STRICT_P LAX_P LAST_P STARTS_P WITH_P LIKE_REGEX_P FLAG_P
%token <str> ABS_P SIZE_P TYPE_P FLOOR_P DOUBLE_P CEILING_P KEYVALUE_P
%token <str> DATETIME_P DATE_P TIME_P TIME_TZ_P TIMESTAMP_P TIMESTAMP_TZ_P
-%token <str> BIGINT_P INTEGER_P NUMBER_P DECIMAL_P
+%token <str> BIGINT_P INTEGER_P NUMBER_P DECIMAL_P BOOLEAN_P STRINGFUNC_P
%type <result> result
@@ -337,6 +337,8 @@ key_name:
| ABS_P
| SIZE_P
| TYPE_P
+ | BOOLEAN_P
+ | STRINGFUNC_P
| FLOOR_P
| DOUBLE_P
| DECIMAL_P
@@ -362,6 +364,8 @@ method:
ABS_P { $$ = jpiAbs; }
| SIZE_P { $$ = jpiSize; }
| TYPE_P { $$ = jpiType; }
+ | BOOLEAN_P { $$ = jpiBoolean; }
+ | STRINGFUNC_P { $$ = jpiStringFunc; }
| FLOOR_P { $$ = jpiFloor; }
| DOUBLE_P { $$ = jpiDouble; }
| BIGINT_P { $$ = jpiBigint; }
diff --git a/src/backend/utils/adt/jsonpath_scan.l b/src/backend/utils/adt/jsonpath_scan.l
index 6a7d72a..d87da14 100644
--- a/src/backend/utils/adt/jsonpath_scan.l
+++ b/src/backend/utils/adt/jsonpath_scan.l
@@ -418,6 +418,8 @@ static const JsonPathKeyword keywords[] = {
{ 6, false, NUMBER_P, "number"},
{ 6, false, STARTS_P, "starts"},
{ 6, false, STRICT_P, "strict"},
+ { 6, false, STRINGFUNC_P, "string"},
+ { 7, false, BOOLEAN_P, "boolean"},
{ 7, false, CEILING_P, "ceiling"},
{ 7, false, DECIMAL_P, "decimal"},
{ 7, false, INTEGER_P, "integer"},
diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h
index f695451..7058563 100644
--- a/src/include/utils/jsonpath.h
+++ b/src/include/utils/jsonpath.h
@@ -85,6 +85,8 @@ typedef enum JsonPathItemType
jpiExists, /* EXISTS (expr) predicate */
jpiType, /* .type() item method */
jpiSize, /* .size() item method */
+ jpiBoolean, /* .boolean() item method */
+ jpiStringFunc, /* .string() item method */
jpiAbs, /* .abs() item method */
jpiFloor, /* .floor() item method */
jpiCeiling, /* .ceiling() item method */
diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out
index a4e9ca3..00d2c85 100644
--- a/src/test/regress/expected/jsonb_jsonpath.out
+++ b/src/test/regress/expected/jsonb_jsonpath.out
@@ -1348,6 +1348,269 @@ select jsonb_path_query('[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 'l
1
(9 rows)
+select jsonb_path_query('null', '$.boolean()');
+ERROR: jsonpath item method .boolean() can only be applied to a bool, string, or numeric value
+select jsonb_path_query('null', '$.boolean()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('[]', '$.boolean()');
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('[]', 'strict $.boolean()');
+ERROR: jsonpath item method .boolean() can only be applied to a bool, string, or numeric value
+select jsonb_path_query('{}', '$.boolean()');
+ERROR: jsonpath item method .boolean() can only be applied to a bool, string, or numeric value
+select jsonb_path_query('[]', 'strict $.boolean()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('{}', '$.boolean()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('1.23', '$.boolean()');
+ERROR: numeric argument of jsonpath item method .boolean() is out of range for type boolean
+select jsonb_path_query('"1.23"', '$.boolean()');
+ERROR: string argument of jsonpath item method .boolean() is not a valid representation of a boolean
+select jsonb_path_query('"1.23aaa"', '$.boolean()');
+ERROR: string argument of jsonpath item method .boolean() is not a valid representation of a boolean
+select jsonb_path_query('1e1000', '$.boolean()');
+ERROR: numeric argument of jsonpath item method .boolean() is out of range for type boolean
+select jsonb_path_query('"nan"', '$.boolean()');
+ERROR: string argument of jsonpath item method .boolean() is not a valid representation of a boolean
+select jsonb_path_query('"NaN"', '$.boolean()');
+ERROR: string argument of jsonpath item method .boolean() is not a valid representation of a boolean
+select jsonb_path_query('"inf"', '$.boolean()');
+ERROR: string argument of jsonpath item method .boolean() is not a valid representation of a boolean
+select jsonb_path_query('"-inf"', '$.boolean()');
+ERROR: string argument of jsonpath item method .boolean() is not a valid representation of a boolean
+select jsonb_path_query('"inf"', '$.boolean()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('"-inf"', '$.boolean()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('"100"', '$.boolean()');
+ERROR: string argument of jsonpath item method .boolean() is not a valid representation of a boolean
+select jsonb_path_query('true', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('false', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('1', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('0', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('-1', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('100', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('"1"', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('"0"', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('"true"', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('"false"', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('"TRUE"', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('"FALSE"', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('"yes"', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('"NO"', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('"T"', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('"f"', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('"y"', '$.boolean()');
+ jsonb_path_query
+------------------
+ true
+(1 row)
+
+select jsonb_path_query('"N"', '$.boolean()');
+ jsonb_path_query
+------------------
+ false
+(1 row)
+
+select jsonb_path_query('true', '$.boolean().type()');
+ jsonb_path_query
+------------------
+ "boolean"
+(1 row)
+
+select jsonb_path_query('123', '$.boolean().type()');
+ jsonb_path_query
+------------------
+ "boolean"
+(1 row)
+
+select jsonb_path_query('"Yes"', '$.boolean().type()');
+ jsonb_path_query
+------------------
+ "boolean"
+(1 row)
+
+select jsonb_path_query_array('[1, "yes", false]', '$[*].boolean()');
+ jsonb_path_query_array
+------------------------
+ [true, true, false]
+(1 row)
+
+select jsonb_path_query('null', '$.string()');
+ERROR: jsonpath item method .string() can only be applied to a bool, string, numeric, or datetime value
+select jsonb_path_query('null', '$.string()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('[]', '$.string()');
+ERROR: jsonpath item method .string() can only be applied to a bool, string, numeric, or datetime value
+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()');
+ERROR: jsonpath item method .string() can only be applied to a bool, string, numeric, or datetime value
+select jsonb_path_query('[]', 'strict $.string()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('{}', '$.string()', silent => true);
+ jsonb_path_query
+------------------
+(0 rows)
+
+select jsonb_path_query('1.23', '$.string()');
+ jsonb_path_query
+------------------
+ "1.23"
+(1 row)
+
+select jsonb_path_query('"1.23"', '$.string()');
+ jsonb_path_query
+------------------
+ "1.23"
+(1 row)
+
+select jsonb_path_query('"1.23aaa"', '$.string()');
+ jsonb_path_query
+------------------
+ "1.23aaa"
+(1 row)
+
+select jsonb_path_query('1234', '$.string()');
+ jsonb_path_query
+------------------
+ "1234"
+(1 row)
+
+select jsonb_path_query('true', '$.string()');
+ jsonb_path_query
+------------------
+ "true"
+(1 row)
+
+select jsonb_path_query('1234', '$.string().type()');
+ jsonb_path_query
+------------------
+ "string"
+(1 row)
+
+select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp().string()');
+ jsonb_path_query
+----------------------------
+ "Tue Aug 15 00:04:56 2023"
+(1 row)
+
+select jsonb_path_query_array('[1.23, "yes", false]', '$[*].string()');
+ jsonb_path_query_array
+--------------------------
+ ["1.23", "yes", "false"]
+(1 row)
+
+select jsonb_path_query_array('[1.23, "yes", false]', '$[*].string().type()');
+ jsonb_path_query_array
+--------------------------------
+ ["string", "string", "string"]
+(1 row)
+
select jsonb_path_query('[0, 1, -2, -3.4, 5.6]', '$[*].abs()');
jsonb_path_query
------------------
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index b47b2e9..6b16cda 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -381,6 +381,18 @@ select 'true.type()'::jsonpath;
true.type()
(1 row)
+select '$.boolean()'::jsonpath;
+ jsonpath
+-------------
+ $.boolean()
+(1 row)
+
+select '$.string()'::jsonpath;
+ jsonpath
+------------
+ $.string()
+(1 row)
+
select '$.double().floor().ceiling().abs()'::jsonpath;
jsonpath
------------------------------------
diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql
index bab6c95..6ff6419 100644
--- a/src/test/regress/sql/jsonb_jsonpath.sql
+++ b/src/test/regress/sql/jsonb_jsonpath.sql
@@ -283,6 +283,64 @@ select jsonb_path_query('[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 's
select jsonb_path_query('[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 'strict $[*].size()', silent => true);
select jsonb_path_query('[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 'lax $[*].size()');
+select jsonb_path_query('null', '$.boolean()');
+select jsonb_path_query('null', '$.boolean()', silent => true);
+select jsonb_path_query('[]', '$.boolean()');
+select jsonb_path_query('[]', 'strict $.boolean()');
+select jsonb_path_query('{}', '$.boolean()');
+select jsonb_path_query('[]', 'strict $.boolean()', silent => true);
+select jsonb_path_query('{}', '$.boolean()', silent => true);
+select jsonb_path_query('1.23', '$.boolean()');
+select jsonb_path_query('"1.23"', '$.boolean()');
+select jsonb_path_query('"1.23aaa"', '$.boolean()');
+select jsonb_path_query('1e1000', '$.boolean()');
+select jsonb_path_query('"nan"', '$.boolean()');
+select jsonb_path_query('"NaN"', '$.boolean()');
+select jsonb_path_query('"inf"', '$.boolean()');
+select jsonb_path_query('"-inf"', '$.boolean()');
+select jsonb_path_query('"inf"', '$.boolean()', silent => true);
+select jsonb_path_query('"-inf"', '$.boolean()', silent => true);
+select jsonb_path_query('"100"', '$.boolean()');
+select jsonb_path_query('true', '$.boolean()');
+select jsonb_path_query('false', '$.boolean()');
+select jsonb_path_query('1', '$.boolean()');
+select jsonb_path_query('0', '$.boolean()');
+select jsonb_path_query('-1', '$.boolean()');
+select jsonb_path_query('100', '$.boolean()');
+select jsonb_path_query('"1"', '$.boolean()');
+select jsonb_path_query('"0"', '$.boolean()');
+select jsonb_path_query('"true"', '$.boolean()');
+select jsonb_path_query('"false"', '$.boolean()');
+select jsonb_path_query('"TRUE"', '$.boolean()');
+select jsonb_path_query('"FALSE"', '$.boolean()');
+select jsonb_path_query('"yes"', '$.boolean()');
+select jsonb_path_query('"NO"', '$.boolean()');
+select jsonb_path_query('"T"', '$.boolean()');
+select jsonb_path_query('"f"', '$.boolean()');
+select jsonb_path_query('"y"', '$.boolean()');
+select jsonb_path_query('"N"', '$.boolean()');
+select jsonb_path_query('true', '$.boolean().type()');
+select jsonb_path_query('123', '$.boolean().type()');
+select jsonb_path_query('"Yes"', '$.boolean().type()');
+select jsonb_path_query_array('[1, "yes", false]', '$[*].boolean()');
+
+select jsonb_path_query('null', '$.string()');
+select jsonb_path_query('null', '$.string()', silent => true);
+select jsonb_path_query('[]', '$.string()');
+select jsonb_path_query('[]', 'strict $.string()');
+select jsonb_path_query('{}', '$.string()');
+select jsonb_path_query('[]', 'strict $.string()', silent => true);
+select jsonb_path_query('{}', '$.string()', silent => true);
+select jsonb_path_query('1.23', '$.string()');
+select jsonb_path_query('"1.23"', '$.string()');
+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('"2023-08-15 12:34:56 +5:30"', '$.timestamp().string()');
+select jsonb_path_query_array('[1.23, "yes", false]', '$[*].string()');
+select jsonb_path_query_array('[1.23, "yes", false]', '$[*].string().type()');
+
select jsonb_path_query('[0, 1, -2, -3.4, 5.6]', '$[*].abs()');
select jsonb_path_query('[0, 1, -2, -3.4, 5.6]', '$[*].floor()');
select jsonb_path_query('[0, 1, -2, -3.4, 5.6]', '$[*].ceiling()');
diff --git a/src/test/regress/sql/jsonpath.sql b/src/test/regress/sql/jsonpath.sql
index 44275c9..8f07b71 100644
--- a/src/test/regress/sql/jsonpath.sql
+++ b/src/test/regress/sql/jsonpath.sql
@@ -69,6 +69,8 @@ select '(1).type()'::jsonpath;
select '1.2.type()'::jsonpath;
select '"aaa".type()'::jsonpath;
select 'true.type()'::jsonpath;
+select '$.boolean()'::jsonpath;
+select '$.string()'::jsonpath;
select '$.double().floor().ceiling().abs()'::jsonpath;
select '$.bigint().integer().number().decimal()'::jsonpath;
select '$.decimal(4,2)'::jsonpath;
--
1.8.3.1