Clean up handling of unknown-type inputs in json_build_object and friends.

There's actually no need for any special case for unknown-type literals,
since we only need to push the value through its output function and
unknownout() works fine.  The code that was here was completely bizarre
anyway, and would fail outright in cases that should work, not to mention
suffering from some copy-and-paste bugs.
This commit is contained in:
Tom Lane 2014-08-09 17:31:13 -04:00
parent 495cadda5e
commit 92f57c9ae9

View File

@ -1869,10 +1869,10 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
if (PG_ARGISNULL(0))
{
/*
* Make this StringInfo in a context where it will persist for the
* duration off the aggregate call. It's only needed for this initial
* piece, as the StringInfo routines make sure they use the right
* context to enlarge the object if necessary.
* Make the StringInfo in a context where it will persist for the
* duration of the aggregate call. Switching context is only needed
* for this initial step, as the StringInfo routines make sure they
* use the right context to enlarge the object if necessary.
*/
oldcontext = MemoryContextSwitchTo(aggcontext);
state = makeStringInfo();
@ -1886,56 +1886,43 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
appendStringInfoString(state, ", ");
}
/*
* Note: since json_object_agg() 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.
*/
val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
if (val_type == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine data type for argument %d", 1)));
if (PG_ARGISNULL(1))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("field name must not be null")));
val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
/*
* turn a constant (more or less literal) value that's of unknown type
* into text. Unknowns come in as a cstring pointer.
*/
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, 1))
{
val_type = TEXTOID;
arg = CStringGetTextDatum(PG_GETARG_POINTER(1));
}
else
{
arg = PG_GETARG_DATUM(1);
}
if (val_type == InvalidOid || val_type == UNKNOWNOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine data type for argument %d", 1)));
arg = PG_GETARG_DATUM(1);
add_json(arg, false, state, val_type, true);
appendStringInfoString(state, " : ");
val_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
/* see comments above */
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, 2))
{
val_type = TEXTOID;
if (PG_ARGISNULL(2))
arg = (Datum) 0;
else
arg = CStringGetTextDatum(PG_GETARG_POINTER(2));
}
else
{
arg = PG_GETARG_DATUM(2);
}
if (val_type == InvalidOid || val_type == UNKNOWNOID)
if (val_type == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine data type for argument %d", 2)));
if (PG_ARGISNULL(2))
arg = (Datum) 0;
else
arg = PG_GETARG_DATUM(2);
add_json(arg, PG_ARGISNULL(2), state, val_type, false);
PG_RETURN_POINTER(state);
@ -1972,7 +1959,7 @@ json_build_object(PG_FUNCTION_ARGS)
int nargs = PG_NARGS();
int i;
Datum arg;
char *sep = "";
const char *sep = "";
StringInfo result;
Oid val_type;
@ -1988,60 +1975,51 @@ 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))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument %d cannot be null", i + 1),
errhint("Object keys should be text.")));
val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
/*
* turn a constant (more or less literal) value that's of unknown type
* into text. Unknowns come in as a cstring pointer.
*/
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i))
{
val_type = TEXTOID;
arg = CStringGetTextDatum(PG_GETARG_POINTER(i));
}
else
{
arg = PG_GETARG_DATUM(i);
}
if (val_type == InvalidOid || val_type == UNKNOWNOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine data type for argument %d",
i + 1)));
appendStringInfoString(result, sep);
sep = ", ";
arg = PG_GETARG_DATUM(i);
add_json(arg, false, result, val_type, true);
appendStringInfoString(result, " : ");
/* process value */
val_type = get_fn_expr_argtype(fcinfo->flinfo, i + 1);
/* see comments above */
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i + 1))
{
val_type = TEXTOID;
if (PG_ARGISNULL(i + 1))
arg = (Datum) 0;
else
arg = CStringGetTextDatum(PG_GETARG_POINTER(i + 1));
}
else
{
arg = PG_GETARG_DATUM(i + 1);
}
if (val_type == InvalidOid || val_type == UNKNOWNOID)
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);
}
@ -2068,45 +2046,45 @@ json_build_array(PG_FUNCTION_ARGS)
int nargs = PG_NARGS();
int i;
Datum arg;
char *sep = "";
const char *sep = "";
StringInfo result;
Oid val_type;
result = makeStringInfo();
appendStringInfoChar(result, '[');
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);
arg = PG_GETARG_DATUM(i + 1);
/* see comments in json_build_object above */
if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i))
{
val_type = TEXTOID;
if (PG_ARGISNULL(i))
arg = (Datum) 0;
else
arg = CStringGetTextDatum(PG_GETARG_POINTER(i));
}
else
{
arg = PG_GETARG_DATUM(i);
}
if (val_type == InvalidOid || val_type == UNKNOWNOID)
if (val_type == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine data type for argument %d",
i + 1)));
appendStringInfoString(result, sep);
sep = ", ";
if (PG_ARGISNULL(i))
arg = (Datum) 0;
else
arg = PG_GETARG_DATUM(i);
add_json(arg, PG_ARGISNULL(i), result, val_type, false);
}
appendStringInfoChar(result, ']');
PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
/*