From 1415e09d6ca860d466939229e6d6a9012bf2bbcf Mon Sep 17 00:00:00 2001 From: Andy Fan Date: Tue, 1 Aug 2023 10:38:29 +0800 Subject: [PATCH v1] Add jsonb operator to return a numeric directly. The binary format of numeric in JOSNB is compatible with the numeric in SQL, so we can get the numeric more effectively. --- doc/src/sgml/func.sgml | 14 +++++++++++ src/backend/utils/adt/jsonfuncs.c | 26 ++++++++++++++++++++ src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_operator.dat | 3 +++ src/include/catalog/pg_proc.dat | 4 +++ src/test/regress/expected/jsonb_jsonpath.out | 20 +++++++++++++++ src/test/regress/sql/jsonb_jsonpath.sql | 4 +++ 7 files changed, 72 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index be2f54c9141..7f4b8970475 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -15699,6 +15699,20 @@ table2-mapping t + + + jsonb @-> jsonpath + numeric + + + Returns the result of a JSON value at the specified path as numeric. + Raise error if the JSON value is not a numeric. + + + '{"a":1}'::jsonb @-> 'a' + 1 + + diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index a4bfa5e4040..5393df0ed7f 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -886,6 +886,32 @@ json_object_field_text(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } +Datum +jsonb_object_field_numeric(PG_FUNCTION_ARGS) +{ + Jsonb *jb = PG_GETARG_JSONB_P(0); + text *key = PG_GETARG_TEXT_PP(1); + JsonbValue *v; + JsonbValue vbuf; + + if (!JB_ROOT_IS_OBJECT(jb)) + PG_RETURN_NULL(); + + v = getKeyJsonValueFromContainer(&jb->root, + VARDATA_ANY(key), + VARSIZE_ANY_EXHDR(key), + &vbuf); + + if (v == NULL || v->type == jbvNull) + PG_RETURN_NULL(); + + if (v->type != jbvNumeric) + elog(ERROR, "field '%s' has non-numeric value.", text_to_cstring(key)); + + return PointerGetDatum(v->val.numeric); +}; + + Datum jsonb_object_field_text(PG_FUNCTION_ARGS) { diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index f507b49bb28..5a534771edb 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202307261 +#define CATALOG_VERSION_NO 202308011 #endif diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat index b2cdea66c4b..d63b9f5188d 100644 --- a/src/include/catalog/pg_operator.dat +++ b/src/include/catalog/pg_operator.dat @@ -3178,6 +3178,9 @@ { oid => '3477', descr => 'get jsonb object field as text', oprname => '->>', oprleft => 'jsonb', oprright => 'text', oprresult => 'text', oprcode => 'jsonb_object_field_text' }, +{ oid => '3814', descr => 'get jsonb object field as numeric', + oprname => '@->', oprleft => 'jsonb', oprright => 'text', oprresult => 'numeric', + oprcode => 'jsonb_object_field_numeric' }, { oid => '3212', descr => 'get jsonb array element', oprname => '->', oprleft => 'jsonb', oprright => 'int4', oprresult => 'jsonb', oprcode => 'jsonb_array_element' }, diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 6996073989a..e93303f3be7 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -9928,6 +9928,10 @@ proname => 'jsonb_object_field_text', prorettype => 'text', proargtypes => 'jsonb text', proargnames => '{from_json, field_name}', prosrc => 'jsonb_object_field_text' }, +{ oid => '3813', + proname => 'jsonb_object_field_numeric', prorettype => 'numeric', + proargtypes => 'jsonb text', proargnames => '{from_json, field_name}', + prosrc => 'jsonb_object_field_numeric' }, { oid => '3215', proname => 'jsonb_array_element', prorettype => 'jsonb', proargtypes => 'jsonb int4', proargnames => '{from_json, element_index}', diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out index 6659bc9091a..bf2351cf9cf 100644 --- a/src/test/regress/expected/jsonb_jsonpath.out +++ b/src/test/regress/expected/jsonb_jsonpath.out @@ -34,6 +34,26 @@ select jsonb '{"a": 12}' @? '$.b + 2'; (1 row) +select jsonb '{"a": 12}' @-> 'a'; + ?column? +---------- + 12 +(1 row) + +select pg_typeof(jsonb '{"a": 12}' @-> 'a'); + pg_typeof +----------- + numeric +(1 row) + +select jsonb '{"a": 12}' @-> 'b'; + ?column? +---------- + +(1 row) + +select jsonb '{"a": "12a"}' @-> 'a'; +ERROR: field 'a' has non-numeric value. select jsonb '{"a": {"a": 12}}' @? '$.a.a'; ?column? ---------- diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql index e0ce509264a..32576566f11 100644 --- a/src/test/regress/sql/jsonb_jsonpath.sql +++ b/src/test/regress/sql/jsonb_jsonpath.sql @@ -4,6 +4,10 @@ select jsonb '{"a": 12}' @? '$.a.b'; select jsonb '{"a": 12}' @? '$.b'; select jsonb '{"a": 12}' @? '$.a + 2'; select jsonb '{"a": 12}' @? '$.b + 2'; +select jsonb '{"a": 12}' @-> 'a'; +select pg_typeof(jsonb '{"a": 12}' @-> 'a'); +select jsonb '{"a": 12}' @-> 'b'; +select jsonb '{"a": "12a"}' @-> 'a'; select jsonb '{"a": {"a": 12}}' @? '$.a.a'; select jsonb '{"a": {"a": 12}}' @? '$.*.a'; select jsonb '{"b": {"a": 12}}' @? '$.*.a'; -- 2.21.0