aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/json.c84
-rw-r--r--src/test/regress/expected/json.out107
-rw-r--r--src/test/regress/sql/json.sql21
3 files changed, 152 insertions, 60 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 7c3992661f5..72f4781c461 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -18,6 +18,7 @@
#include "catalog/pg_cast.h"
#include "catalog/pg_type.h"
#include "executor/spi.h"
+#include "funcapi.h"
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
@@ -2035,10 +2036,17 @@ json_build_object(PG_FUNCTION_ARGS)
{
int nargs = PG_NARGS();
int i;
- Datum arg;
const char *sep = "";
StringInfo result;
- Oid val_type;
+ Datum *args;
+ bool *nulls;
+ Oid *types;
+
+ /* fetch argument values to build the object */
+ nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
+
+ if (nargs < 0)
+ PG_RETURN_NULL();
if (nargs % 2 != 0)
ereport(ERROR,
@@ -2052,52 +2060,22 @@ json_build_object(PG_FUNCTION_ARGS)
for (i = 0; i < nargs; i += 2)
{
- /*
- * Note: since json_build_object() is declared as taking type "any",
- * the parser will not do any type conversion on unknown-type literals
- * (that is, undecorated strings or NULLs). Such values will arrive
- * here as type UNKNOWN, which fortunately does not matter to us,
- * since unknownout() works fine.
- */
appendStringInfoString(result, sep);
sep = ", ";
/* process key */
- val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
-
- if (val_type == InvalidOid)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not determine data type for argument %d",
- i + 1)));
-
- if (PG_ARGISNULL(i))
+ if (nulls[i])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument %d cannot be null", i + 1),
errhint("Object keys should be text.")));
- arg = PG_GETARG_DATUM(i);
-
- add_json(arg, false, result, val_type, true);
+ add_json(args[i], false, result, types[i], true);
appendStringInfoString(result, " : ");
/* process value */
- val_type = get_fn_expr_argtype(fcinfo->flinfo, i + 1);
-
- if (val_type == InvalidOid)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not determine data type for argument %d",
- i + 2)));
-
- if (PG_ARGISNULL(i + 1))
- arg = (Datum) 0;
- else
- arg = PG_GETARG_DATUM(i + 1);
-
- add_json(arg, PG_ARGISNULL(i + 1), result, val_type, false);
+ add_json(args[i + 1], nulls[i + 1], result, types[i + 1], false);
}
appendStringInfoChar(result, '}');
@@ -2120,12 +2098,19 @@ json_build_object_noargs(PG_FUNCTION_ARGS)
Datum
json_build_array(PG_FUNCTION_ARGS)
{
- int nargs = PG_NARGS();
+ int nargs;
int i;
- Datum arg;
const char *sep = "";
StringInfo result;
- Oid val_type;
+ Datum *args;
+ bool *nulls;
+ Oid *types;
+
+ /* fetch argument values to build the array */
+ nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
+
+ if (nargs < 0)
+ PG_RETURN_NULL();
result = makeStringInfo();
@@ -2133,30 +2118,9 @@ json_build_array(PG_FUNCTION_ARGS)
for (i = 0; i < nargs; i++)
{
- /*
- * Note: since json_build_array() is declared as taking type "any",
- * the parser will not do any type conversion on unknown-type literals
- * (that is, undecorated strings or NULLs). Such values will arrive
- * here as type UNKNOWN, which fortunately does not matter to us,
- * since unknownout() works fine.
- */
appendStringInfoString(result, sep);
sep = ", ";
-
- val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
-
- if (val_type == InvalidOid)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not determine data type for argument %d",
- i + 1)));
-
- if (PG_ARGISNULL(i))
- arg = (Datum) 0;
- else
- arg = PG_GETARG_DATUM(i);
-
- add_json(arg, PG_ARGISNULL(i), result, val_type, false);
+ add_json(args[i], nulls[i], result, types[i], false);
}
appendStringInfoChar(result, ']');
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 8573b58e7c4..d0d95f2adb3 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -1420,6 +1420,54 @@ SELECT json_build_array('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y":
["a", 1, "b", 1.2, "c", true, "d", null, "e", {"x": 3, "y": [1,2,3]}]
(1 row)
+SELECT json_build_array('a', NULL); -- ok
+ json_build_array
+------------------
+ ["a", null]
+(1 row)
+
+SELECT json_build_array(VARIADIC NULL::text[]); -- ok
+ json_build_array
+------------------
+
+(1 row)
+
+SELECT json_build_array(VARIADIC '{}'::text[]); -- ok
+ json_build_array
+------------------
+ []
+(1 row)
+
+SELECT json_build_array(VARIADIC '{a,b,c}'::text[]); -- ok
+ json_build_array
+------------------
+ ["a", "b", "c"]
+(1 row)
+
+SELECT json_build_array(VARIADIC ARRAY['a', NULL]::text[]); -- ok
+ json_build_array
+------------------
+ ["a", null]
+(1 row)
+
+SELECT json_build_array(VARIADIC '{1,2,3,4}'::text[]); -- ok
+ json_build_array
+----------------------
+ ["1", "2", "3", "4"]
+(1 row)
+
+SELECT json_build_array(VARIADIC '{1,2,3,4}'::int[]); -- ok
+ json_build_array
+------------------
+ [1, 2, 3, 4]
+(1 row)
+
+SELECT json_build_array(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
+ json_build_array
+--------------------
+ [1, 4, 2, 5, 3, 6]
+(1 row)
+
SELECT json_build_object('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
json_build_object
----------------------------------------------------------------------------
@@ -1435,6 +1483,65 @@ SELECT json_build_object(
{"a" : {"b" : false, "c" : 99}, "d" : {"e" : [9,8,7], "f" : {"relkind":"r","name":"pg_class"}}}
(1 row)
+SELECT json_build_object('{a,b,c}'::text[]); -- error
+ERROR: argument list must have even number of elements
+HINT: The arguments of json_build_object() must consist of alternating keys and values.
+SELECT json_build_object('{a,b,c}'::text[], '{d,e,f}'::text[]); -- error, key cannot be array
+ERROR: key value must be scalar, not array, composite, or json
+SELECT json_build_object('a', 'b', 'c'); -- error
+ERROR: argument list must have even number of elements
+HINT: The arguments of json_build_object() must consist of alternating keys and values.
+SELECT json_build_object(NULL, 'a'); -- error, key cannot be NULL
+ERROR: argument 1 cannot be null
+HINT: Object keys should be text.
+SELECT json_build_object('a', NULL); -- ok
+ json_build_object
+-------------------
+ {"a" : null}
+(1 row)
+
+SELECT json_build_object(VARIADIC NULL::text[]); -- ok
+ json_build_object
+-------------------
+
+(1 row)
+
+SELECT json_build_object(VARIADIC '{}'::text[]); -- ok
+ json_build_object
+-------------------
+ {}
+(1 row)
+
+SELECT json_build_object(VARIADIC '{a,b,c}'::text[]); -- error
+ERROR: argument list must have even number of elements
+HINT: The arguments of json_build_object() must consist of alternating keys and values.
+SELECT json_build_object(VARIADIC ARRAY['a', NULL]::text[]); -- ok
+ json_build_object
+-------------------
+ {"a" : null}
+(1 row)
+
+SELECT json_build_object(VARIADIC ARRAY[NULL, 'a']::text[]); -- error, key cannot be NULL
+ERROR: argument 1 cannot be null
+HINT: Object keys should be text.
+SELECT json_build_object(VARIADIC '{1,2,3,4}'::text[]); -- ok
+ json_build_object
+------------------------
+ {"1" : "2", "3" : "4"}
+(1 row)
+
+SELECT json_build_object(VARIADIC '{1,2,3,4}'::int[]); -- ok
+ json_build_object
+--------------------
+ {"1" : 2, "3" : 4}
+(1 row)
+
+SELECT json_build_object(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
+ json_build_object
+-----------------------------
+ {"1" : 4, "2" : 5, "3" : 6}
+(1 row)
+
-- empty objects/arrays
SELECT json_build_array();
json_build_array
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 346e5b8363f..587bcb8dd4a 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -412,6 +412,14 @@ select value, json_typeof(value)
-- json_build_array, json_build_object, json_object_agg
SELECT json_build_array('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
+SELECT json_build_array('a', NULL); -- ok
+SELECT json_build_array(VARIADIC NULL::text[]); -- ok
+SELECT json_build_array(VARIADIC '{}'::text[]); -- ok
+SELECT json_build_array(VARIADIC '{a,b,c}'::text[]); -- ok
+SELECT json_build_array(VARIADIC ARRAY['a', NULL]::text[]); -- ok
+SELECT json_build_array(VARIADIC '{1,2,3,4}'::text[]); -- ok
+SELECT json_build_array(VARIADIC '{1,2,3,4}'::int[]); -- ok
+SELECT json_build_array(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
SELECT json_build_object('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
@@ -419,6 +427,19 @@ SELECT json_build_object(
'a', json_build_object('b',false,'c',99),
'd', json_build_object('e',array[9,8,7]::int[],
'f', (select row_to_json(r) from ( select relkind, oid::regclass as name from pg_class where relname = 'pg_class') r)));
+SELECT json_build_object('{a,b,c}'::text[]); -- error
+SELECT json_build_object('{a,b,c}'::text[], '{d,e,f}'::text[]); -- error, key cannot be array
+SELECT json_build_object('a', 'b', 'c'); -- error
+SELECT json_build_object(NULL, 'a'); -- error, key cannot be NULL
+SELECT json_build_object('a', NULL); -- ok
+SELECT json_build_object(VARIADIC NULL::text[]); -- ok
+SELECT json_build_object(VARIADIC '{}'::text[]); -- ok
+SELECT json_build_object(VARIADIC '{a,b,c}'::text[]); -- error
+SELECT json_build_object(VARIADIC ARRAY['a', NULL]::text[]); -- ok
+SELECT json_build_object(VARIADIC ARRAY[NULL, 'a']::text[]); -- error, key cannot be NULL
+SELECT json_build_object(VARIADIC '{1,2,3,4}'::text[]); -- ok
+SELECT json_build_object(VARIADIC '{1,2,3,4}'::int[]); -- ok
+SELECT json_build_object(VARIADIC '{{1,4},{2,5},{3,6}}'::int[][]); -- ok
-- empty objects/arrays