diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index f6bef9c1484be..e405791f5d836 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -91,9 +91,9 @@ static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, bool use_line_feeds); static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds); -static void datum_to_json(Datum val, bool is_null, StringInfo result, - JsonTypeCategory tcategory, Oid outfuncoid, - bool key_scalar); +static void datum_to_json_internal(Datum val, bool is_null, StringInfo result, + JsonTypeCategory tcategory, Oid outfuncoid, + bool key_scalar); static void add_json(Datum val, bool is_null, StringInfo result, Oid val_type, bool key_scalar); static text *catenate_stringinfo_string(StringInfo buffer, const char *addon); @@ -173,9 +173,9 @@ json_recv(PG_FUNCTION_ARGS) * it's of an acceptable type, and force it to be quoted. */ static void -datum_to_json(Datum val, bool is_null, StringInfo result, - JsonTypeCategory tcategory, Oid outfuncoid, - bool key_scalar) +datum_to_json_internal(Datum val, bool is_null, StringInfo result, + JsonTypeCategory tcategory, Oid outfuncoid, + bool key_scalar) { char *outputstr; text *jsontext; @@ -421,8 +421,9 @@ array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals, if (dim + 1 == ndims) { - datum_to_json(vals[*valcount], nulls[*valcount], result, tcategory, - outfuncoid, false); + datum_to_json_internal(vals[*valcount], nulls[*valcount], + result, tcategory, + outfuncoid, false); (*valcount)++; } else @@ -549,7 +550,8 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds) json_categorize_type(att->atttypid, false, &tcategory, &outfuncoid); - datum_to_json(val, isnull, result, tcategory, outfuncoid, false); + datum_to_json_internal(val, isnull, result, tcategory, outfuncoid, + false); } appendStringInfoChar(result, '}'); @@ -584,7 +586,8 @@ add_json(Datum val, bool is_null, StringInfo result, json_categorize_type(val_type, false, &tcategory, &outfuncoid); - datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar); + datum_to_json_internal(val, is_null, result, tcategory, outfuncoid, + key_scalar); } /* @@ -704,7 +707,6 @@ to_json(PG_FUNCTION_ARGS) { Datum val = PG_GETARG_DATUM(0); Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0); - StringInfo result; JsonTypeCategory tcategory; Oid outfuncoid; @@ -716,11 +718,23 @@ to_json(PG_FUNCTION_ARGS) json_categorize_type(val_type, false, &tcategory, &outfuncoid); - result = makeStringInfo(); + PG_RETURN_DATUM(datum_to_json(val, tcategory, outfuncoid)); +} - datum_to_json(val, false, result, tcategory, outfuncoid, false); +/* + * Turn a Datum into JSON text. + * + * tcategory and outfuncoid are from a previous call to json_categorize_type. + */ +Datum +datum_to_json(Datum val, JsonTypeCategory tcategory, Oid outfuncoid) +{ + StringInfo result = makeStringInfo(); - PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); + datum_to_json_internal(val, false, result, tcategory, outfuncoid, + false); + + return PointerGetDatum(cstring_to_text_with_len(result->data, result->len)); } /* @@ -780,8 +794,8 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) /* fast path for NULLs */ if (PG_ARGISNULL(1)) { - datum_to_json((Datum) 0, true, state->str, JSONTYPE_NULL, - InvalidOid, false); + datum_to_json_internal((Datum) 0, true, state->str, JSONTYPE_NULL, + InvalidOid, false); PG_RETURN_POINTER(state); } @@ -795,8 +809,8 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) appendStringInfoString(state->str, "\n "); } - datum_to_json(val, false, state->str, state->val_category, - state->val_output_func, false); + datum_to_json_internal(val, false, state->str, state->val_category, + state->val_output_func, false); /* * The transition type for json_agg() is declared to be "internal", which @@ -1059,8 +1073,8 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo, key_offset = out->len; - datum_to_json(arg, false, out, state->key_category, - state->key_output_func, true); + datum_to_json_internal(arg, false, out, state->key_category, + state->key_output_func, true); if (unique_keys) { @@ -1082,8 +1096,9 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo, else arg = PG_GETARG_DATUM(2); - datum_to_json(arg, PG_ARGISNULL(2), state->str, state->val_category, - state->val_output_func, false); + datum_to_json_internal(arg, PG_ARGISNULL(2), state->str, + state->val_category, + state->val_output_func, false); PG_RETURN_POINTER(state); } diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index fc64f56868264..5ea582a8884ce 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -59,9 +59,9 @@ static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *di Datum *vals, bool *nulls, int *valcount, JsonTypeCategory tcategory, Oid outfuncoid); static void array_to_jsonb_internal(Datum array, JsonbInState *result); -static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, - JsonTypeCategory tcategory, Oid outfuncoid, - bool key_scalar); +static void datum_to_jsonb_internal(Datum val, bool is_null, JsonbInState *result, + JsonTypeCategory tcategory, Oid outfuncoid, + bool key_scalar); static void add_jsonb(Datum val, bool is_null, JsonbInState *result, Oid val_type, bool key_scalar); static JsonbParseState *clone_parse_state(JsonbParseState *state); @@ -141,6 +141,19 @@ jsonb_send(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } +/* + * jsonb_from_text + * + * Turns json text string into a jsonb Datum. + */ +Datum +jsonb_from_text(text *js) +{ + return jsonb_from_cstring(VARDATA_ANY(js), + VARSIZE_ANY_EXHDR(js), + NULL); +} + /* * Get the type name of a jsonb container. */ @@ -622,9 +635,9 @@ add_indent(StringInfo out, bool indent, int level) * will be thrown. */ static void -datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, - JsonTypeCategory tcategory, Oid outfuncoid, - bool key_scalar) +datum_to_jsonb_internal(Datum val, bool is_null, JsonbInState *result, + JsonTypeCategory tcategory, Oid outfuncoid, + bool key_scalar) { char *outputstr; bool numeric_error; @@ -859,8 +872,8 @@ array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *v { if (dim + 1 == ndims) { - datum_to_jsonb(vals[*valcount], nulls[*valcount], result, tcategory, - outfuncoid, false); + datum_to_jsonb_internal(vals[*valcount], nulls[*valcount], result, tcategory, + outfuncoid, false); (*valcount)++; } else @@ -982,7 +995,8 @@ composite_to_jsonb(Datum composite, JsonbInState *result) json_categorize_type(att->atttypid, true, &tcategory, &outfuncoid); - datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false); + datum_to_jsonb_internal(val, isnull, result, tcategory, outfuncoid, + false); } result->res = pushJsonbValue(&result->parseState, WJB_END_OBJECT, NULL); @@ -1018,9 +1032,11 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result, json_categorize_type(val_type, true, &tcategory, &outfuncoid); - datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar); + datum_to_jsonb_internal(val, is_null, result, tcategory, outfuncoid, + key_scalar); } + /* * Is the given type immutable when coming out of a JSONB context? * @@ -1072,7 +1088,6 @@ to_jsonb(PG_FUNCTION_ARGS) { Datum val = PG_GETARG_DATUM(0); Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0); - JsonbInState result; JsonTypeCategory tcategory; Oid outfuncoid; @@ -1084,11 +1099,25 @@ to_jsonb(PG_FUNCTION_ARGS) json_categorize_type(val_type, true, &tcategory, &outfuncoid); + PG_RETURN_DATUM(datum_to_jsonb(val, tcategory, outfuncoid)); +} + +/* + * Turn a Datum into jsonb. + * + * tcategory and outfuncoid are from a previous call to json_categorize_type. + */ +Datum +datum_to_jsonb(Datum val, JsonTypeCategory tcategory, Oid outfuncoid) +{ + JsonbInState result; + memset(&result, 0, sizeof(JsonbInState)); - datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false); + datum_to_jsonb_internal(val, false, &result, tcategory, outfuncoid, + false); - PG_RETURN_POINTER(JsonbValueToJsonb(result.res)); + return JsonbPGetDatum(JsonbValueToJsonb(result.res)); } Datum @@ -1525,8 +1554,8 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) memset(&elem, 0, sizeof(JsonbInState)); - datum_to_jsonb(val, PG_ARGISNULL(1), &elem, state->val_category, - state->val_output_func, false); + datum_to_jsonb_internal(val, PG_ARGISNULL(1), &elem, state->val_category, + state->val_output_func, false); jbelem = JsonbValueToJsonb(elem.res); @@ -1726,8 +1755,8 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, memset(&elem, 0, sizeof(JsonbInState)); - datum_to_jsonb(val, false, &elem, state->key_category, - state->key_output_func, true); + datum_to_jsonb_internal(val, false, &elem, state->key_category, + state->key_output_func, true); jbkey = JsonbValueToJsonb(elem.res); @@ -1735,8 +1764,8 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, memset(&elem, 0, sizeof(JsonbInState)); - datum_to_jsonb(val, PG_ARGISNULL(2), &elem, state->val_category, - state->val_output_func, false); + datum_to_jsonb_internal(val, PG_ARGISNULL(2), &elem, state->val_category, + state->val_output_func, false); jbval = JsonbValueToJsonb(elem.res); diff --git a/src/include/utils/jsonfuncs.h b/src/include/utils/jsonfuncs.h index 121dfd5d2480a..2ad648d1b8b2c 100644 --- a/src/include/utils/jsonfuncs.h +++ b/src/include/utils/jsonfuncs.h @@ -82,5 +82,10 @@ typedef enum extern void json_categorize_type(Oid typoid, bool is_jsonb, JsonTypeCategory *tcategory, Oid *outfuncoid); +extern Datum datum_to_json(Datum val, JsonTypeCategory tcategory, + Oid outfuncoid); +extern Datum datum_to_jsonb(Datum val, JsonTypeCategory tcategory, + Oid outfuncoid); +extern Datum jsonb_from_text(text *js); #endif