Get rid of more cases of the "must detoast before output function" meme.

I missed that json.c was doing this too, because for some bizarre reason
it wasn't doing it adjacent to the output function call.
This commit is contained in:
Tom Lane 2013-11-03 11:55:37 -05:00
parent b006f4ddb9
commit e36ce0c7f7

View File

@ -1425,8 +1425,7 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
for (i = 0; i < tupdesc->natts; i++) for (i = 0; i < tupdesc->natts; i++)
{ {
Datum val, Datum val;
origval;
bool isnull; bool isnull;
char *attname; char *attname;
TYPCATEGORY tcategory; TYPCATEGORY tcategory;
@ -1445,7 +1444,7 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
escape_json(result, attname); escape_json(result, attname);
appendStringInfoChar(result, ':'); appendStringInfoChar(result, ':');
origval = heap_getattr(tuple, i + 1, tupdesc, &isnull); val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
getTypeOutputInfo(tupdesc->attrs[i]->atttypid, getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
&typoutput, &typisvarlena); &typoutput, &typisvarlena);
@ -1480,20 +1479,7 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
else else
tcategory = TypeCategory(tupdesc->attrs[i]->atttypid); tcategory = TypeCategory(tupdesc->attrs[i]->atttypid);
/*
* If we have a toasted datum, forcibly detoast it here to avoid
* memory leakage inside the type's output routine.
*/
if (typisvarlena && !isnull)
val = PointerGetDatum(PG_DETOAST_DATUM(origval));
else
val = origval;
datum_to_json(val, isnull, result, tcategory, typoutput); datum_to_json(val, isnull, result, tcategory, typoutput);
/* Clean up detoasted copy, if any */
if (val != origval)
pfree(DatumGetPointer(val));
} }
appendStringInfoChar(result, '}'); appendStringInfoChar(result, '}');
@ -1572,10 +1558,9 @@ row_to_json_pretty(PG_FUNCTION_ARGS)
Datum Datum
to_json(PG_FUNCTION_ARGS) to_json(PG_FUNCTION_ARGS)
{ {
Datum val = PG_GETARG_DATUM(0);
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0); Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
StringInfo result; StringInfo result;
Datum orig_val,
val;
TYPCATEGORY tcategory; TYPCATEGORY tcategory;
Oid typoutput; Oid typoutput;
bool typisvarlena; bool typisvarlena;
@ -1586,11 +1571,8 @@ to_json(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine input data type"))); errmsg("could not determine input data type")));
result = makeStringInfo(); result = makeStringInfo();
orig_val = PG_ARGISNULL(0) ? (Datum) 0 : PG_GETARG_DATUM(0);
getTypeOutputInfo(val_type, &typoutput, &typisvarlena); getTypeOutputInfo(val_type, &typoutput, &typisvarlena);
if (val_type > FirstNormalObjectId) if (val_type > FirstNormalObjectId)
@ -1623,21 +1605,8 @@ to_json(PG_FUNCTION_ARGS)
else else
tcategory = TypeCategory(val_type); tcategory = TypeCategory(val_type);
/*
* If we have a toasted datum, forcibly detoast it here to avoid memory
* leakage inside the type's output routine.
*/
if (typisvarlena && orig_val != (Datum) 0)
val = PointerGetDatum(PG_DETOAST_DATUM(orig_val));
else
val = orig_val;
datum_to_json(val, false, result, tcategory, typoutput); datum_to_json(val, false, result, tcategory, typoutput);
/* Clean up detoasted copy, if any */
if (val != orig_val)
pfree(DatumGetPointer(val));
PG_RETURN_TEXT_P(cstring_to_text(result->data)); PG_RETURN_TEXT_P(cstring_to_text(result->data));
} }
@ -1651,8 +1620,7 @@ json_agg_transfn(PG_FUNCTION_ARGS)
MemoryContext aggcontext, MemoryContext aggcontext,
oldcontext; oldcontext;
StringInfo state; StringInfo state;
Datum orig_val, Datum val;
val;
TYPCATEGORY tcategory; TYPCATEGORY tcategory;
Oid typoutput; Oid typoutput;
bool typisvarlena; bool typisvarlena;
@ -1692,13 +1660,12 @@ json_agg_transfn(PG_FUNCTION_ARGS)
/* fast path for NULLs */ /* fast path for NULLs */
if (PG_ARGISNULL(1)) if (PG_ARGISNULL(1))
{ {
orig_val = (Datum) 0; val = (Datum) 0;
datum_to_json(orig_val, true, state, 0, InvalidOid); datum_to_json(val, true, state, 0, InvalidOid);
PG_RETURN_POINTER(state); PG_RETURN_POINTER(state);
} }
val = PG_GETARG_DATUM(1);
orig_val = PG_GETARG_DATUM(1);
getTypeOutputInfo(val_type, &typoutput, &typisvarlena); getTypeOutputInfo(val_type, &typoutput, &typisvarlena);
@ -1732,15 +1699,6 @@ json_agg_transfn(PG_FUNCTION_ARGS)
else else
tcategory = TypeCategory(val_type); tcategory = TypeCategory(val_type);
/*
* If we have a toasted datum, forcibly detoast it here to avoid memory
* leakage inside the type's output routine.
*/
if (typisvarlena)
val = PointerGetDatum(PG_DETOAST_DATUM(orig_val));
else
val = orig_val;
if (!PG_ARGISNULL(0) && if (!PG_ARGISNULL(0) &&
(tcategory == TYPCATEGORY_ARRAY || tcategory == TYPCATEGORY_COMPOSITE)) (tcategory == TYPCATEGORY_ARRAY || tcategory == TYPCATEGORY_COMPOSITE))
{ {
@ -1749,10 +1707,6 @@ json_agg_transfn(PG_FUNCTION_ARGS)
datum_to_json(val, false, state, tcategory, typoutput); datum_to_json(val, false, state, tcategory, typoutput);
/* Clean up detoasted copy, if any */
if (val != orig_val)
pfree(DatumGetPointer(val));
/* /*
* The transition type for array_agg() is declared to be "internal", which * The transition type for array_agg() is declared to be "internal", which
* is a pass-by-value type the same size as a pointer. So we can safely * is a pass-by-value type the same size as a pointer. So we can safely