diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index d1dc87e679..68132aea4b 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -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)); - } /*