diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 4e2fff7cd7481ef2a717957a4308fa3fccd1b254..6e2fbda6c23fa882091644ae65071f037594a3b4 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -10443,9 +10443,15 @@ table2-mapping <indexterm> <primary>json_to_record</primary> </indexterm> + <indexterm> + <primary>jsonb_to_record</primary> + </indexterm> <indexterm> <primary>json_to_recordset</primary> </indexterm> + <indexterm> + <primary>jsonb_to_recordset</primary> + </indexterm> <table id="functions-json-processing-table"> <title>JSON Processing Functions</title> @@ -10649,9 +10655,9 @@ table2-mapping <entry><literal>number</literal></entry> </row> <row> - <entry> - <literal>json_to_record(json, nested_as_text bool)</literal> - </entry> + <entry><para><literal>json_to_record(json [, nested_as_text bool=false])</literal> + </para><para><literal>jsonb_to_record(jsonb [, nested_as_text bool=false])</literal> + </para></entry> <entry><type>record</type></entry> <entry> Returns an arbitrary record from a JSON object. As with all functions @@ -10670,9 +10676,9 @@ table2-mapping </entry> </row> <row> - <entry> - <literal>json_to_recordset(json, nested_as_text bool)</literal> - </entry> + <entry><para><literal>json_to_recordset(json [, nested_as_text bool=false])</literal> + </para><para><literal>jsonb_to_recordset(jsonb [, nested_as_text bool=false])</literal> + </para></entry> <entry><type>setof record</type></entry> <entry> Returns an arbitrary set of records from a JSON object. As with diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 662040261e968dbc1846c12f7a9439cc792879cd..42a4c00a1ed8ad69881ad56110f15225e359a8c1 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -833,6 +833,22 @@ CREATE OR REPLACE FUNCTION jsonb_populate_recordset(base anyelement, from_json jsonb, use_json_as_text boolean DEFAULT false) RETURNS SETOF anyelement LANGUAGE internal STABLE ROWS 100 AS 'jsonb_populate_recordset'; +CREATE OR REPLACE FUNCTION + json_to_record(from_json json, nested_as_text boolean DEFAULT false) + RETURNS record LANGUAGE internal STABLE AS 'json_to_record'; + +CREATE OR REPLACE FUNCTION + json_to_recordset(from_json json, nested_as_text boolean DEFAULT false) + RETURNS SETOF record LANGUAGE internal STABLE ROWS 100 AS 'json_to_recordset'; + +CREATE OR REPLACE FUNCTION + jsonb_to_record(from_json jsonb, nested_as_text boolean DEFAULT false) + RETURNS record LANGUAGE internal STABLE AS 'jsonb_to_record'; + +CREATE OR REPLACE FUNCTION + jsonb_to_recordset(from_json jsonb, nested_as_text boolean DEFAULT false) + RETURNS SETOF record LANGUAGE internal STABLE ROWS 100 AS 'jsonb_to_recordset'; + CREATE OR REPLACE FUNCTION pg_logical_slot_get_changes( IN slotname name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}', OUT location pg_lsn, OUT xid xid, OUT data text) diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 94595998029667ff6629882f46e1403748c99717..bf1646771423fe8faaa12898e53fdd3fbbd92fef 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -2014,6 +2014,12 @@ jsonb_populate_record(PG_FUNCTION_ARGS) return populate_record_worker(fcinfo, true); } +Datum +jsonb_to_record(PG_FUNCTION_ARGS) +{ + return populate_record_worker(fcinfo, false); +} + Datum json_populate_record(PG_FUNCTION_ARGS) { @@ -2449,6 +2455,24 @@ jsonb_populate_recordset(PG_FUNCTION_ARGS) return populate_recordset_worker(fcinfo, true); } +Datum +jsonb_to_recordset(PG_FUNCTION_ARGS) +{ + return populate_recordset_worker(fcinfo, false); +} + +Datum +json_populate_recordset(PG_FUNCTION_ARGS) +{ + return populate_recordset_worker(fcinfo, true); +} + +Datum +json_to_recordset(PG_FUNCTION_ARGS) +{ + return populate_recordset_worker(fcinfo, false); +} + static void make_row_from_rec_and_jsonb(Jsonb * element, PopulateRecordsetState *state) { @@ -2571,18 +2595,6 @@ make_row_from_rec_and_jsonb(Jsonb * element, PopulateRecordsetState *state) tuplestore_puttuple(state->tuple_store, rettuple); } -Datum -json_populate_recordset(PG_FUNCTION_ARGS) -{ - return populate_recordset_worker(fcinfo, true); -} - -Datum -json_to_recordset(PG_FUNCTION_ARGS) -{ - return populate_recordset_worker(fcinfo, false); -} - /* * common worker for json_populate_recordset() and json_to_recordset() */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 60f78d24a968f299e1d840137f85e6196a9c2dff..3c74fa0a5150bf9cc2c1bada1d696f8dad1ef344 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201403121 +#define CATALOG_VERSION_NO 201403261 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 56f0f11ebe27d1826b0db6c518e789c37fa85ac9..334e6b8d15578e24f5a8a56f696394f031aafeb6 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4546,6 +4546,10 @@ DATA(insert OID = 3209 ( jsonb_populate_record PGNSP PGUID 12 1 0 0 0 f f f DESCR("get record fields from a jsonb object"); DATA(insert OID = 3475 ( jsonb_populate_recordset PGNSP PGUID 12 1 100 0 0 f f f f f t s 3 0 2283 "2283 3802 16" _null_ _null_ _null_ _null_ jsonb_populate_recordset _null_ _null_ _null_ )); DESCR("get set of records with fields from a jsonb array of objects"); +DATA(insert OID = 3490 ( jsonb_to_record PGNSP PGUID 12 1 0 0 0 f f f f f f s 2 0 2249 "3802 16" _null_ _null_ _null_ _null_ jsonb_to_record _null_ _null_ _null_ )); +DESCR("get record fields from a json object"); +DATA(insert OID = 3491 ( jsonb_to_recordset PGNSP PGUID 12 1 100 0 0 f f f f f t s 2 0 2249 "3802 16" _null_ _null_ _null_ _null_ jsonb_to_recordset _null_ _null_ _null_ )); +DESCR("get set of records with fields from a json array of objects"); DATA(insert OID = 3210 ( jsonb_typeof PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "3802" _null_ _null_ _null_ _null_ jsonb_typeof _null_ _null_ _null_ )); DESCR("get the type of a jsonb value"); DATA(insert OID = 4038 ( jsonb_ne PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_ne _null_ _null_ _null_ )); diff --git a/src/include/utils/json.h b/src/include/utils/json.h index b5e947bd7af39622cb1879c8af7a0d3bc3ea66e8..82cc48b7113e1b0bb30da53f5e96fedb85d18299 100644 --- a/src/include/utils/json.h +++ b/src/include/utils/json.h @@ -78,5 +78,7 @@ extern Datum jsonb_array_elements_text(PG_FUNCTION_ARGS); extern Datum jsonb_array_elements(PG_FUNCTION_ARGS); extern Datum jsonb_populate_record(PG_FUNCTION_ARGS); extern Datum jsonb_populate_recordset(PG_FUNCTION_ARGS); +extern Datum jsonb_to_record(PG_FUNCTION_ARGS); +extern Datum jsonb_to_recordset(PG_FUNCTION_ARGS); #endif /* JSON_H */ diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index f368530a193fed70d877d9a8b1913a0fe0726326..8bd0131100d3db18be89611d7ec432dc67107785 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -1430,6 +1430,22 @@ SELECT jsonb '{ "a": "null \u0000 escape" }' ->> 'a' AS not_unescaped; null \u0000 escape (1 row) +-- jsonb_to_record and jsonb_to_recordset +select * from jsonb_to_record('{"a":1,"b":"foo","c":"bar"}',true) + as x(a int, b text, d text); + a | b | d +---+-----+--- + 1 | foo | +(1 row) + +select * from jsonb_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar","c":true}]',false) + as x(a int, b text, c boolean); + a | b | c +---+-----+--- + 1 | foo | + 2 | bar | t +(2 rows) + -- indexing SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; count diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expected/jsonb_1.out index 856c55af7176af2f91b41fb92e12891a356dc08c..35524fb9a7e17c34b49bfaa6903ad58ac45f1e39 100644 --- a/src/test/regress/expected/jsonb_1.out +++ b/src/test/regress/expected/jsonb_1.out @@ -1430,6 +1430,22 @@ SELECT jsonb '{ "a": "null \u0000 escape" }' ->> 'a' AS not_unescaped; null \u0000 escape (1 row) +-- jsonb_to_record and jsonb_to_recordset +select * from jsonb_to_record('{"a":1,"b":"foo","c":"bar"}',true) + as x(a int, b text, d text); + a | b | d +---+-----+--- + 1 | foo | +(1 row) + +select * from jsonb_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar","c":true}]',false) + as x(a int, b text, c boolean); + a | b | c +---+-----+--- + 1 | foo | + 2 | bar | t +(2 rows) + -- indexing SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; count diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index e460b1bb2a704f8a75db7f91cc007c0e82d62b5f..3ee43e93470f371f37a06715635441090d148db4 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -319,6 +319,14 @@ SELECT jsonb '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' AS correct_in_utf8; SELECT jsonb '{ "a": "dollar \u0024 character" }' ->> 'a' AS correct_everyWHERE; SELECT jsonb '{ "a": "null \u0000 escape" }' ->> 'a' AS not_unescaped; +-- jsonb_to_record and jsonb_to_recordset + +select * from jsonb_to_record('{"a":1,"b":"foo","c":"bar"}',true) + as x(a int, b text, d text); + +select * from jsonb_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar","c":true}]',false) + as x(a int, b text, c boolean); + -- indexing SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';