Skip to content

Commit 9cb28e9

Browse files
committed
Process variadic arguments consistently in json functions
json_build_object and json_build_array and the jsonb equivalents did not correctly process explicit VARIADIC arguments. They are modified to use the new extract_variadic_args() utility function which abstracts away the details of the call method. Michael Paquier, reviewed by Tom Lane and Dmitry Dolgov. Backpatch to 9.5 for the jsonb fixes and 9.4 for the json fixes, as that's where they originated.
1 parent 7f89fc4 commit 9cb28e9

File tree

3 files changed

+152
-60
lines changed

3 files changed

+152
-60
lines changed

src/backend/utils/adt/json.c

Lines changed: 24 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "catalog/pg_cast.h"
1919
#include "catalog/pg_type.h"
2020
#include "executor/spi.h"
21+
#include "funcapi.h"
2122
#include "lib/stringinfo.h"
2223
#include "libpq/pqformat.h"
2324
#include "mb/pg_wchar.h"
@@ -2035,10 +2036,17 @@ json_build_object(PG_FUNCTION_ARGS)
20352036
{
20362037
int nargs = PG_NARGS();
20372038
int i;
2038-
Datum arg;
20392039
const char *sep = "";
20402040
StringInfo result;
2041-
Oid val_type;
2041+
Datum *args;
2042+
bool *nulls;
2043+
Oid *types;
2044+
2045+
/* fetch argument values to build the object */
2046+
nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
2047+
2048+
if (nargs < 0)
2049+
PG_RETURN_NULL();
20422050

20432051
if (nargs % 2 != 0)
20442052
ereport(ERROR,
@@ -2052,52 +2060,22 @@ json_build_object(PG_FUNCTION_ARGS)
20522060

20532061
for (i = 0; i < nargs; i += 2)
20542062
{
2055-
/*
2056-
* Note: since json_build_object() is declared as taking type "any",
2057-
* the parser will not do any type conversion on unknown-type literals
2058-
* (that is, undecorated strings or NULLs). Such values will arrive
2059-
* here as type UNKNOWN, which fortunately does not matter to us,
2060-
* since unknownout() works fine.
2061-
*/
20622063
appendStringInfoString(result, sep);
20632064
sep = ", ";
20642065

20652066
/* process key */
2066-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
2067-
2068-
if (val_type == InvalidOid)
2069-
ereport(ERROR,
2070-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2071-
errmsg("could not determine data type for argument %d",
2072-
i + 1)));
2073-
2074-
if (PG_ARGISNULL(i))
2067+
if (nulls[i])
20752068
ereport(ERROR,
20762069
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20772070
errmsg("argument %d cannot be null", i + 1),
20782071
errhint("Object keys should be text.")));
20792072

2080-
arg = PG_GETARG_DATUM(i);
2081-
2082-
add_json(arg, false, result, val_type, true);
2073+
add_json(args[i], false, result, types[i], true);
20832074

20842075
appendStringInfoString(result, " : ");
20852076

20862077
/* process value */
2087-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i + 1);
2088-
2089-
if (val_type == InvalidOid)
2090-
ereport(ERROR,
2091-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2092-
errmsg("could not determine data type for argument %d",
2093-
i + 2)));
2094-
2095-
if (PG_ARGISNULL(i + 1))
2096-
arg = (Datum) 0;
2097-
else
2098-
arg = PG_GETARG_DATUM(i + 1);
2099-
2100-
add_json(arg, PG_ARGISNULL(i + 1), result, val_type, false);
2078+
add_json(args[i + 1], nulls[i + 1], result, types[i + 1], false);
21012079
}
21022080

21032081
appendStringInfoChar(result, '}');
@@ -2120,43 +2098,29 @@ json_build_object_noargs(PG_FUNCTION_ARGS)
21202098
Datum
21212099
json_build_array(PG_FUNCTION_ARGS)
21222100
{
2123-
int nargs = PG_NARGS();
2101+
int nargs;
21242102
int i;
2125-
Datum arg;
21262103
const char *sep = "";
21272104
StringInfo result;
2128-
Oid val_type;
2105+
Datum *args;
2106+
bool *nulls;
2107+
Oid *types;
2108+
2109+
/* fetch argument values to build the array */
2110+
nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
2111+
2112+
if (nargs < 0)
2113+
PG_RETURN_NULL();
21292114

21302115
result = makeStringInfo();
21312116

21322117
appendStringInfoChar(result, '[');
21332118

21342119
for (i = 0; i < nargs; i++)
21352120
{
2136-
/*
2137-
* Note: since json_build_array() is declared as taking type "any",
2138-
* the parser will not do any type conversion on unknown-type literals
2139-
* (that is, undecorated strings or NULLs). Such values will arrive
2140-
* here as type UNKNOWN, which fortunately does not matter to us,
2141-
* since unknownout() works fine.
2142-
*/
21432121
appendStringInfoString(result, sep);
21442122
sep = ", ";
2145-
2146-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
2147-
2148-
if (val_type == InvalidOid)
2149-
ereport(ERROR,
2150-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2151-
errmsg("could not determine data type for argument %d",
2152-
i + 1)));
2153-
2154-
if (PG_ARGISNULL(i))
2155-
arg = (Datum) 0;
2156-
else
2157-
arg = PG_GETARG_DATUM(i);
2158-
2159-
add_json(arg, PG_ARGISNULL(i), result, val_type, false);
2123+
add_json(args[i], nulls[i], result, types[i], false);
21602124
}
21612125

21622126
appendStringInfoChar(result, ']');

src/test/regress/expected/json.out

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,54 @@ SELECT json_build_array('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y":
14201420
["a", 1, "b", 1.2, "c", true, "d", null, "e", {"x": 3, "y": [1,2,3]}]
14211421
(1 row)
14221422

1423+
SELECT json_build_array('a', NULL); -- ok
1424+
json_build_array
1425+
------------------
1426+
["a", null]
1427+
(1 row)
1428+
1429+
SELECT json_build_array(VARIADIC NULL::text[]); -- ok
1430+
json_build_array
1431+
------------------
1432+
1433+
(1 row)
1434+
1435+
SELECT json_build_array(VARIADIC '{}'::text[]); -- ok
1436+
json_build_array
1437+
------------------
1438+
[]
1439+
(1 row)
1440+
1441+
SELECT json_build_array(VARIADIC '{a,b,c}'::text[]); -- ok
1442+
json_build_array
1443+
------------------
1444+
["a", "b", "c"]
1445+
(1 row)
1446+
1447+
SELECT json_build_array(VARIADIC ARRAY['a', NULL]::text[]); -- ok
1448+
json_build_array
1449+
------------------
1450+
["a", null]
1451+
(1 row)
1452+
1453+
SELECT json_build_array(VARIADIC '{1,2,3,4}'::text[]); -- ok
1454+
json_build_array
1455+
----------------------
1456+
["1", "2", "3", "4"]
1457+
(1 row)
1458+
1459+
SELECT json_build_array(VARIADIC '{1,2,3,4}'::int[]); -- ok
1460+
json_build_array
1461+
------------------
1462+
[1, 2, 3, 4]
1463+
(1 row)
1464+
1465+
SELECT json_build_array(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
1466+
json_build_array
1467+
--------------------
1468+
[1, 4, 2, 5, 3, 6]
1469+
(1 row)
1470+
14231471
SELECT json_build_object('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
14241472
json_build_object
14251473
----------------------------------------------------------------------------
@@ -1435,6 +1483,65 @@ SELECT json_build_object(
14351483
{"a" : {"b" : false, "c" : 99}, "d" : {"e" : [9,8,7], "f" : {"relkind":"r","name":"pg_class"}}}
14361484
(1 row)
14371485

1486+
SELECT json_build_object('{a,b,c}'::text[]); -- error
1487+
ERROR: argument list must have even number of elements
1488+
HINT: The arguments of json_build_object() must consist of alternating keys and values.
1489+
SELECT json_build_object('{a,b,c}'::text[], '{d,e,f}'::text[]); -- error, key cannot be array
1490+
ERROR: key value must be scalar, not array, composite, or json
1491+
SELECT json_build_object('a', 'b', 'c'); -- error
1492+
ERROR: argument list must have even number of elements
1493+
HINT: The arguments of json_build_object() must consist of alternating keys and values.
1494+
SELECT json_build_object(NULL, 'a'); -- error, key cannot be NULL
1495+
ERROR: argument 1 cannot be null
1496+
HINT: Object keys should be text.
1497+
SELECT json_build_object('a', NULL); -- ok
1498+
json_build_object
1499+
-------------------
1500+
{"a" : null}
1501+
(1 row)
1502+
1503+
SELECT json_build_object(VARIADIC NULL::text[]); -- ok
1504+
json_build_object
1505+
-------------------
1506+
1507+
(1 row)
1508+
1509+
SELECT json_build_object(VARIADIC '{}'::text[]); -- ok
1510+
json_build_object
1511+
-------------------
1512+
{}
1513+
(1 row)
1514+
1515+
SELECT json_build_object(VARIADIC '{a,b,c}'::text[]); -- error
1516+
ERROR: argument list must have even number of elements
1517+
HINT: The arguments of json_build_object() must consist of alternating keys and values.
1518+
SELECT json_build_object(VARIADIC ARRAY['a', NULL]::text[]); -- ok
1519+
json_build_object
1520+
-------------------
1521+
{"a" : null}
1522+
(1 row)
1523+
1524+
SELECT json_build_object(VARIADIC ARRAY[NULL, 'a']::text[]); -- error, key cannot be NULL
1525+
ERROR: argument 1 cannot be null
1526+
HINT: Object keys should be text.
1527+
SELECT json_build_object(VARIADIC '{1,2,3,4}'::text[]); -- ok
1528+
json_build_object
1529+
------------------------
1530+
{"1" : "2", "3" : "4"}
1531+
(1 row)
1532+
1533+
SELECT json_build_object(VARIADIC '{1,2,3,4}'::int[]); -- ok
1534+
json_build_object
1535+
--------------------
1536+
{"1" : 2, "3" : 4}
1537+
(1 row)
1538+
1539+
SELECT json_build_object(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
1540+
json_build_object
1541+
-----------------------------
1542+
{"1" : 4, "2" : 5, "3" : 6}
1543+
(1 row)
1544+
14381545
-- empty objects/arrays
14391546
SELECT json_build_array();
14401547
json_build_array

src/test/regress/sql/json.sql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,13 +412,34 @@ select value, json_typeof(value)
412412
-- json_build_array, json_build_object, json_object_agg
413413

414414
SELECT json_build_array('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
415+
SELECT json_build_array('a', NULL); -- ok
416+
SELECT json_build_array(VARIADIC NULL::text[]); -- ok
417+
SELECT json_build_array(VARIADIC '{}'::text[]); -- ok
418+
SELECT json_build_array(VARIADIC '{a,b,c}'::text[]); -- ok
419+
SELECT json_build_array(VARIADIC ARRAY['a', NULL]::text[]); -- ok
420+
SELECT json_build_array(VARIADIC '{1,2,3,4}'::text[]); -- ok
421+
SELECT json_build_array(VARIADIC '{1,2,3,4}'::int[]); -- ok
422+
SELECT json_build_array(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
415423

416424
SELECT json_build_object('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
417425

418426
SELECT json_build_object(
419427
'a', json_build_object('b',false,'c',99),
420428
'd', json_build_object('e',array[9,8,7]::int[],
421429
'f', (select row_to_json(r) from ( select relkind, oid::regclass as name from pg_class where relname = 'pg_class') r)));
430+
SELECT json_build_object('{a,b,c}'::text[]); -- error
431+
SELECT json_build_object('{a,b,c}'::text[], '{d,e,f}'::text[]); -- error, key cannot be array
432+
SELECT json_build_object('a', 'b', 'c'); -- error
433+
SELECT json_build_object(NULL, 'a'); -- error, key cannot be NULL
434+
SELECT json_build_object('a', NULL); -- ok
435+
SELECT json_build_object(VARIADIC NULL::text[]); -- ok
436+
SELECT json_build_object(VARIADIC '{}'::text[]); -- ok
437+
SELECT json_build_object(VARIADIC '{a,b,c}'::text[]); -- error
438+
SELECT json_build_object(VARIADIC ARRAY['a', NULL]::text[]); -- ok
439+
SELECT json_build_object(VARIADIC ARRAY[NULL, 'a']::text[]); -- error, key cannot be NULL
440+
SELECT json_build_object(VARIADIC '{1,2,3,4}'::text[]); -- ok
441+
SELECT json_build_object(VARIADIC '{1,2,3,4}'::int[]); -- ok
442+
SELECT json_build_object(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
422443

423444

424445
-- empty objects/arrays

0 commit comments

Comments
 (0)