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

Commit 18fc4ec

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 f3c6e8a commit 18fc4ec

File tree

6 files changed

+306
-132
lines changed

6 files changed

+306
-132
lines changed

src/backend/utils/adt/json.c

+24-60
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "access/transam.h"
1818
#include "catalog/pg_type.h"
1919
#include "executor/spi.h"
20+
#include "funcapi.h"
2021
#include "lib/stringinfo.h"
2122
#include "libpq/pqformat.h"
2223
#include "mb/pg_wchar.h"
@@ -2111,10 +2112,17 @@ json_build_object(PG_FUNCTION_ARGS)
21112112
{
21122113
int nargs = PG_NARGS();
21132114
int i;
2114-
Datum arg;
21152115
const char *sep = "";
21162116
StringInfo result;
2117-
Oid val_type;
2117+
Datum *args;
2118+
bool *nulls;
2119+
Oid *types;
2120+
2121+
/* fetch argument values to build the object */
2122+
nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
2123+
2124+
if (nargs < 0)
2125+
PG_RETURN_NULL();
21182126

21192127
if (nargs % 2 != 0)
21202128
ereport(ERROR,
@@ -2128,52 +2136,22 @@ json_build_object(PG_FUNCTION_ARGS)
21282136

21292137
for (i = 0; i < nargs; i += 2)
21302138
{
2131-
/*
2132-
* Note: since json_build_object() is declared as taking type "any",
2133-
* the parser will not do any type conversion on unknown-type literals
2134-
* (that is, undecorated strings or NULLs). Such values will arrive
2135-
* here as type UNKNOWN, which fortunately does not matter to us,
2136-
* since unknownout() works fine.
2137-
*/
21382139
appendStringInfoString(result, sep);
21392140
sep = ", ";
21402141

21412142
/* process key */
2142-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
2143-
2144-
if (val_type == InvalidOid)
2145-
ereport(ERROR,
2146-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2147-
errmsg("could not determine data type for argument %d",
2148-
i + 1)));
2149-
2150-
if (PG_ARGISNULL(i))
2143+
if (nulls[i])
21512144
ereport(ERROR,
21522145
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
21532146
errmsg("argument %d cannot be null", i + 1),
21542147
errhint("Object keys should be text.")));
21552148

2156-
arg = PG_GETARG_DATUM(i);
2157-
2158-
add_json(arg, false, result, val_type, true);
2149+
add_json(args[i], false, result, types[i], true);
21592150

21602151
appendStringInfoString(result, " : ");
21612152

21622153
/* process value */
2163-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i + 1);
2164-
2165-
if (val_type == InvalidOid)
2166-
ereport(ERROR,
2167-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2168-
errmsg("could not determine data type for argument %d",
2169-
i + 2)));
2170-
2171-
if (PG_ARGISNULL(i + 1))
2172-
arg = (Datum) 0;
2173-
else
2174-
arg = PG_GETARG_DATUM(i + 1);
2175-
2176-
add_json(arg, PG_ARGISNULL(i + 1), result, val_type, false);
2154+
add_json(args[i + 1], nulls[i + 1], result, types[i + 1], false);
21772155
}
21782156

21792157
appendStringInfoChar(result, '}');
@@ -2196,43 +2174,29 @@ json_build_object_noargs(PG_FUNCTION_ARGS)
21962174
Datum
21972175
json_build_array(PG_FUNCTION_ARGS)
21982176
{
2199-
int nargs = PG_NARGS();
2177+
int nargs;
22002178
int i;
2201-
Datum arg;
22022179
const char *sep = "";
22032180
StringInfo result;
2204-
Oid val_type;
2181+
Datum *args;
2182+
bool *nulls;
2183+
Oid *types;
2184+
2185+
/* fetch argument values to build the array */
2186+
nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
2187+
2188+
if (nargs < 0)
2189+
PG_RETURN_NULL();
22052190

22062191
result = makeStringInfo();
22072192

22082193
appendStringInfoChar(result, '[');
22092194

22102195
for (i = 0; i < nargs; i++)
22112196
{
2212-
/*
2213-
* Note: since json_build_array() is declared as taking type "any",
2214-
* the parser will not do any type conversion on unknown-type literals
2215-
* (that is, undecorated strings or NULLs). Such values will arrive
2216-
* here as type UNKNOWN, which fortunately does not matter to us,
2217-
* since unknownout() works fine.
2218-
*/
22192197
appendStringInfoString(result, sep);
22202198
sep = ", ";
2221-
2222-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
2223-
2224-
if (val_type == InvalidOid)
2225-
ereport(ERROR,
2226-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2227-
errmsg("could not determine data type for argument %d",
2228-
i + 1)));
2229-
2230-
if (PG_ARGISNULL(i))
2231-
arg = (Datum) 0;
2232-
else
2233-
arg = PG_GETARG_DATUM(i);
2234-
2235-
add_json(arg, PG_ARGISNULL(i), result, val_type, false);
2199+
add_json(args[i], nulls[i], result, types[i], false);
22362200
}
22372201

22382202
appendStringInfoChar(result, ']');

src/backend/utils/adt/jsonb.c

+28-71
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* jsonb.c
44
* I/O routines for jsonb type
55
*
6-
* Copyright (c) 2014-2017, PostgreSQL Global Development Group
6+
* COPYRIGHT (c) 2014-2017, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
99
* src/backend/utils/adt/jsonb.c
@@ -16,6 +16,7 @@
1616
#include "access/htup_details.h"
1717
#include "access/transam.h"
1818
#include "catalog/pg_type.h"
19+
#include "funcapi.h"
1920
#include "libpq/pqformat.h"
2021
#include "parser/parse_coerce.h"
2122
#include "utils/builtins.h"
@@ -1171,16 +1172,24 @@ to_jsonb(PG_FUNCTION_ARGS)
11711172
Datum
11721173
jsonb_build_object(PG_FUNCTION_ARGS)
11731174
{
1174-
int nargs = PG_NARGS();
1175+
int nargs;
11751176
int i;
1176-
Datum arg;
1177-
Oid val_type;
11781177
JsonbInState result;
1178+
Datum *args;
1179+
bool *nulls;
1180+
Oid *types;
1181+
1182+
/* build argument values to build the object */
1183+
nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1184+
1185+
if (nargs < 0)
1186+
PG_RETURN_NULL();
11791187

11801188
if (nargs % 2 != 0)
11811189
ereport(ERROR,
11821190
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1183-
errmsg("invalid number of arguments: object must be matched key value pairs")));
1191+
errmsg("argument list must have even number of elements"),
1192+
errhint("The arguments of jsonb_build_object() must consist of alternating keys and values.")));
11841193

11851194
memset(&result, 0, sizeof(JsonbInState));
11861195

@@ -1189,54 +1198,15 @@ jsonb_build_object(PG_FUNCTION_ARGS)
11891198
for (i = 0; i < nargs; i += 2)
11901199
{
11911200
/* process key */
1192-
1193-
if (PG_ARGISNULL(i))
1201+
if (nulls[i])
11941202
ereport(ERROR,
11951203
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11961204
errmsg("argument %d: key must not be null", i + 1)));
1197-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
1198-
1199-
/*
1200-
* turn a constant (more or less literal) value that's of unknown type
1201-
* into text. Unknowns come in as a cstring pointer.
1202-
*/
1203-
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i))
1204-
{
1205-
val_type = TEXTOID;
1206-
arg = CStringGetTextDatum(PG_GETARG_POINTER(i));
1207-
}
1208-
else
1209-
{
1210-
arg = PG_GETARG_DATUM(i);
1211-
}
1212-
if (val_type == InvalidOid || val_type == UNKNOWNOID)
1213-
ereport(ERROR,
1214-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1215-
errmsg("could not determine data type for argument %d", i + 1)));
12161205

1217-
add_jsonb(arg, false, &result, val_type, true);
1206+
add_jsonb(args[i], false, &result, types[i], true);
12181207

12191208
/* process value */
1220-
1221-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i + 1);
1222-
/* see comments above */
1223-
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i + 1))
1224-
{
1225-
val_type = TEXTOID;
1226-
if (PG_ARGISNULL(i + 1))
1227-
arg = (Datum) 0;
1228-
else
1229-
arg = CStringGetTextDatum(PG_GETARG_POINTER(i + 1));
1230-
}
1231-
else
1232-
{
1233-
arg = PG_GETARG_DATUM(i + 1);
1234-
}
1235-
if (val_type == InvalidOid || val_type == UNKNOWNOID)
1236-
ereport(ERROR,
1237-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1238-
errmsg("could not determine data type for argument %d", i + 2)));
1239-
add_jsonb(arg, PG_ARGISNULL(i + 1), &result, val_type, false);
1209+
add_jsonb(args[i + 1], nulls[i + 1], &result, types[i + 1], false);
12401210
}
12411211

12421212
result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
@@ -1266,38 +1236,25 @@ jsonb_build_object_noargs(PG_FUNCTION_ARGS)
12661236
Datum
12671237
jsonb_build_array(PG_FUNCTION_ARGS)
12681238
{
1269-
int nargs = PG_NARGS();
1239+
int nargs;
12701240
int i;
1271-
Datum arg;
1272-
Oid val_type;
12731241
JsonbInState result;
1242+
Datum *args;
1243+
bool *nulls;
1244+
Oid *types;
1245+
1246+
/* build argument values to build the array */
1247+
nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1248+
1249+
if (nargs < 0)
1250+
PG_RETURN_NULL();
12741251

12751252
memset(&result, 0, sizeof(JsonbInState));
12761253

12771254
result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
12781255

12791256
for (i = 0; i < nargs; i++)
1280-
{
1281-
val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
1282-
/* see comments in jsonb_build_object above */
1283-
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i))
1284-
{
1285-
val_type = TEXTOID;
1286-
if (PG_ARGISNULL(i))
1287-
arg = (Datum) 0;
1288-
else
1289-
arg = CStringGetTextDatum(PG_GETARG_POINTER(i));
1290-
}
1291-
else
1292-
{
1293-
arg = PG_GETARG_DATUM(i);
1294-
}
1295-
if (val_type == InvalidOid || val_type == UNKNOWNOID)
1296-
ereport(ERROR,
1297-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1298-
errmsg("could not determine data type for argument %d", i + 1)));
1299-
add_jsonb(arg, PG_ARGISNULL(i), &result, val_type, false);
1300-
}
1257+
add_jsonb(args[i], nulls[i], &result, types[i], false);
13011258

13021259
result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
13031260

0 commit comments

Comments
 (0)