Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4d212ba

Browse files
committed
json_typeof function.
Andrew Tipton.
1 parent 4b7b9a7 commit 4d212ba

File tree

8 files changed

+158
-4
lines changed

8 files changed

+158
-4
lines changed

doc/src/sgml/func.sgml

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10095,7 +10095,7 @@ table2-mapping
1009510095
</entry>
1009610096
<entry><type>json</type></entry>
1009710097
<entry>
10098-
Returns JSON object pointed to by <parameter>path_elems</parameter>.
10098+
Returns JSON value pointed to by <parameter>path_elems</parameter>.
1009910099
</entry>
1010010100
<entry><literal>json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}','f4')</literal></entry>
1010110101
<entry><literal>{"f5":99,"f6":"foo"}</literal></entry>
@@ -10109,7 +10109,7 @@ table2-mapping
1010910109
</entry>
1011010110
<entry><type>text</type></entry>
1011110111
<entry>
10112-
Returns JSON object pointed to by <parameter>path_elems</parameter>.
10112+
Returns JSON value pointed to by <parameter>path_elems</parameter>.
1011310113
</entry>
1011410114
<entry><literal>json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}','f4', 'f6')</literal></entry>
1011510115
<entry><literal>foo</literal></entry>
@@ -10192,7 +10192,7 @@ table2-mapping
1019210192
</entry>
1019310193
<entry><type>SETOF json</type></entry>
1019410194
<entry>
10195-
Expands a JSON array to a set of JSON elements.
10195+
Expands a JSON array to a set of JSON values.
1019610196
</entry>
1019710197
<entry><literal>json_array_elements('[1,true, [2,false]]')</literal></entry>
1019810198
<entry>
@@ -10205,6 +10205,23 @@ table2-mapping
1020510205
</programlisting>
1020610206
</entry>
1020710207
</row>
10208+
<row>
10209+
<entry>
10210+
<indexterm>
10211+
<primary>json_typeof</primary>
10212+
</indexterm>
10213+
<literal>json_typeof(json)</literal>
10214+
</entry>
10215+
<entry><type>text</type></entry>
10216+
<entry>
10217+
Returns the type of the outermost JSON value as a text string. The types are
10218+
<literal>object</>, <literal>array</>, <literal>string</>, <literal>number</>,
10219+
<literal>boolean</>, and <literal>null</>. (See note below regarding the
10220+
distinction between a JSON <literal>null</> and a SQL NULL.)
10221+
</entry>
10222+
<entry><literal>json_typeof('-123.4')</literal></entry>
10223+
<entry><literal>number</literal></entry>
10224+
</row>
1020810225
</tbody>
1020910226
</tgroup>
1021010227
</table>
@@ -10237,6 +10254,14 @@ table2-mapping
1023710254
</para>
1023810255
</note>
1023910256

10257+
<note>
10258+
<para>
10259+
The <literal>json_typeof</> function's <literal>null</> return value should not be confused
10260+
with a SQL NULL. While calling <literal>json_typeof('null'::json)</> will return <literal>null</>,
10261+
calling <literal>json_typeof(NULL::json)</> will return a SQL NULL.
10262+
</para>
10263+
</note>
10264+
1024010265
<para>
1024110266
See also <xref linkend="functions-aggregate"> about the aggregate
1024210267
function <function>json_agg</function> which aggregates record

src/backend/utils/adt/json.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,3 +1826,55 @@ escape_json(StringInfo buf, const char *str)
18261826
}
18271827
appendStringInfoCharMacro(buf, '\"');
18281828
}
1829+
1830+
/*
1831+
* SQL function json_typeof(json) -> text
1832+
*
1833+
* Returns the type of the outermost JSON value as TEXT. Possible types are
1834+
* "object", "array", "string", "number", "boolean", and "null".
1835+
*
1836+
* Performs a single call to json_lex() to get the first token of the supplied
1837+
* value. This initial token uniquely determines the value's type. As our
1838+
* input must already have been validated by json_in() or json_recv(), the
1839+
* initial token should never be JSON_TOKEN_OBJECT_END, JSON_TOKEN_ARRAY_END,
1840+
* JSON_TOKEN_COLON, JSON_TOKEN_COMMA, or JSON_TOKEN_END.
1841+
*/
1842+
Datum
1843+
json_typeof(PG_FUNCTION_ARGS)
1844+
{
1845+
text *json = PG_GETARG_TEXT_P(0);
1846+
1847+
JsonLexContext *lex = makeJsonLexContext(json, false);
1848+
JsonTokenType tok;
1849+
char *type;
1850+
1851+
/* Lex exactly one token from the input and check its type. */
1852+
json_lex(lex);
1853+
tok = lex_peek(lex);
1854+
switch (tok)
1855+
{
1856+
case JSON_TOKEN_OBJECT_START:
1857+
type = "object";
1858+
break;
1859+
case JSON_TOKEN_ARRAY_START:
1860+
type = "array";
1861+
break;
1862+
case JSON_TOKEN_STRING:
1863+
type = "string";
1864+
break;
1865+
case JSON_TOKEN_NUMBER:
1866+
type = "number";
1867+
break;
1868+
case JSON_TOKEN_TRUE:
1869+
case JSON_TOKEN_FALSE:
1870+
type = "boolean";
1871+
break;
1872+
case JSON_TOKEN_NULL:
1873+
type = "null";
1874+
break;
1875+
default:
1876+
elog(ERROR, "unexpected json token: %d", tok);
1877+
}
1878+
1879+
PG_RETURN_TEXT_P(cstring_to_text(type));
1880+
}

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201310091
56+
#define CATALOG_VERSION_NO 201310101
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4150,6 +4150,8 @@ DATA(insert OID = 3960 ( json_populate_record PGNSP PGUID 12 1 0 0 0 f f f f
41504150
DESCR("get record fields from a json object");
41514151
DATA(insert OID = 3961 ( json_populate_recordset PGNSP PGUID 12 1 100 0 0 f f f f f t s 3 0 2283 "2283 114 16" _null_ _null_ _null_ _null_ json_populate_recordset _null_ _null_ _null_ ));
41524152
DESCR("get set of records with fields from a json array of objects");
4153+
DATA(insert OID = 3968 ( json_typeof PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "114" _null_ _null_ _null_ _null_ json_typeof _null_ _null_ _null_ ));
4154+
DESCR("get the type of a json value");
41534155

41544156
/* uuid */
41554157
DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2950 "2275" _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ ));

src/include/utils/json.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ extern Datum json_agg_finalfn(PG_FUNCTION_ARGS);
3333

3434
extern void escape_json(StringInfo buf, const char *str);
3535

36+
extern Datum json_typeof(PG_FUNCTION_ARGS);
37+
3638
/* functions in jsonfuncs.c */
3739
extern Datum json_object_field(PG_FUNCTION_ARGS);
3840
extern Datum json_object_field_text(PG_FUNCTION_ARGS);

src/test/regress/expected/json.out

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,3 +962,32 @@ select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_unescaped;
962962
null \u0000 escape
963963
(1 row)
964964

965+
--json_typeof() function
966+
select value, json_typeof(value)
967+
from (values (json '123.4'),
968+
(json '-1'),
969+
(json '"foo"'),
970+
(json 'true'),
971+
(json 'false'),
972+
(json 'null'),
973+
(json '[1, 2, 3]'),
974+
(json '[]'),
975+
(json '{"x":"foo", "y":123}'),
976+
(json '{}'),
977+
(NULL::json))
978+
as data(value);
979+
value | json_typeof
980+
----------------------+-------------
981+
123.4 | number
982+
-1 | number
983+
"foo" | string
984+
true | boolean
985+
false | boolean
986+
null | null
987+
[1, 2, 3] | array
988+
[] | array
989+
{"x":"foo", "y":123} | object
990+
{} | object
991+
|
992+
(11 rows)
993+

src/test/regress/expected/json_1.out

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,3 +958,32 @@ select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_unescaped;
958958
null \u0000 escape
959959
(1 row)
960960

961+
--json_typeof() function
962+
select value, json_typeof(value)
963+
from (values (json '123.4'),
964+
(json '-1'),
965+
(json '"foo"'),
966+
(json 'true'),
967+
(json 'false'),
968+
(json 'null'),
969+
(json '[1, 2, 3]'),
970+
(json '[]'),
971+
(json '{"x":"foo", "y":123}'),
972+
(json '{}'),
973+
(NULL::json))
974+
as data(value);
975+
value | json_typeof
976+
----------------------+-------------
977+
123.4 | number
978+
-1 | number
979+
"foo" | string
980+
true | boolean
981+
false | boolean
982+
null | null
983+
[1, 2, 3] | array
984+
[] | array
985+
{"x":"foo", "y":123} | object
986+
{} | object
987+
|
988+
(11 rows)
989+

src/test/regress/sql/json.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,18 @@ select json '{ "a": "\ude04X" }' -> 'a'; -- orphan low surrogate
310310
select json '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
311311
select json '{ "a": "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
312312
select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_unescaped;
313+
314+
--json_typeof() function
315+
select value, json_typeof(value)
316+
from (values (json '123.4'),
317+
(json '-1'),
318+
(json '"foo"'),
319+
(json 'true'),
320+
(json 'false'),
321+
(json 'null'),
322+
(json '[1, 2, 3]'),
323+
(json '[]'),
324+
(json '{"x":"foo", "y":123}'),
325+
(json '{}'),
326+
(NULL::json))
327+
as data(value);

0 commit comments

Comments
 (0)