if (tupleDesc == NULL)
return value; /* not a composite type */
+ tupleDesc = CreateTupleDescCopy(tupleDesc);
att = tupleDesc->attrs;
numAttrs = tupleDesc->natts;
* If nothing to untoast, just return the original tuple.
*/
if (!need_change)
+ {
+ FreeTupleDesc(tupleDesc);
return value;
+ }
/*
* Calculate the new size of the tuple. Header size should not
for (i = 0; i < numAttrs; i++)
if (toast_free[i])
pfree(DatumGetPointer(toast_values[i]));
+ FreeTupleDesc(tupleDesc);
return PointerGetDatum(new_data);
}
format_type_be(RECORDOID),
format_type_be(targetTypeId))));
- tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1);
+ tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(targetTypeId, -1));
newargs = NIL;
ucolno = 1;
arg = list_head(args);
format_type_be(targetTypeId)),
errdetail("Input has too many columns.")));
+ FreeTupleDesc(tupdesc);
+
rowexpr = makeNode(RowExpr);
rowexpr->args = newargs;
rowexpr->row_typeid = targetTypeId;
/* Verify it's a composite type, and get the tupdesc */
tupleDesc = lookup_rowtype_tupdesc(exprType(expr), exprTypmod(expr));
+ tupleDesc = CreateTupleDescCopy(tupleDesc);
/* Generate a list of references to the individual fields */
numAttrs = tupleDesc->natts;
te_list = lappend(te_list, te);
}
+ FreeTupleDesc(tupleDesc);
+
return te_list;
}
{
char *string = PG_GETARG_CSTRING(0);
Oid tupType = PG_GETARG_OID(1);
+ HeapTupleHeader result;
int32 tupTypmod;
TupleDesc tupdesc;
HeapTuple tuple;
errmsg("input of anonymous composite types is not implemented")));
tupTypmod = -1; /* for all non-anonymous types */
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
ncolumns = tupdesc->natts;
/*
tuple = heap_formtuple(tupdesc, values, nulls);
+ /*
+ * We cannot return tuple->t_data because heap_formtuple allocates it
+ * as part of a larger chunk, and our caller may expect to be able to
+ * pfree our result. So must copy the info into a new palloc chunk.
+ */
+ result = (HeapTupleHeader) palloc(tuple->t_len);
+ memcpy(result, tuple->t_data, tuple->t_len);
+
+ heap_freetuple(tuple);
pfree(buf.data);
pfree(values);
pfree(nulls);
+ FreeTupleDesc(tupdesc);
- PG_RETURN_HEAPTUPLEHEADER(tuple->t_data);
+ PG_RETURN_HEAPTUPLEHEADER(result);
}
/*
record_out(PG_FUNCTION_ARGS)
{
HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
- Oid tupType = PG_GETARG_OID(1);
+ Oid tupType;
int32 tupTypmod;
TupleDesc tupdesc;
HeapTupleData tuple;
char *nulls;
StringInfoData buf;
- /*
- * Use the passed type unless it's RECORD; in that case, we'd better
- * get the type info out of the datum itself. Note that for RECORD,
- * what we'll probably actually get is RECORD's typelem, ie, zero.
- */
- if (tupType == InvalidOid || tupType == RECORDOID)
- {
- tupType = HeapTupleHeaderGetTypeId(rec);
- tupTypmod = HeapTupleHeaderGetTypMod(rec);
- }
- else
- tupTypmod = -1;
+ /* Extract type info from the tuple itself */
+ tupType = HeapTupleHeaderGetTypeId(rec);
+ tupTypmod = HeapTupleHeaderGetTypMod(rec);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
ncolumns = tupdesc->natts;
/* Build a temporary HeapTuple control structure */
pfree(values);
pfree(nulls);
+ FreeTupleDesc(tupdesc);
PG_RETURN_CSTRING(buf.data);
}
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
Oid tupType = PG_GETARG_OID(1);
+ HeapTupleHeader result;
int32 tupTypmod;
TupleDesc tupdesc;
HeapTuple tuple;
errmsg("input of anonymous composite types is not implemented")));
tupTypmod = -1; /* for all non-anonymous types */
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
ncolumns = tupdesc->natts;
/*
tuple = heap_formtuple(tupdesc, values, nulls);
+ /*
+ * We cannot return tuple->t_data because heap_formtuple allocates it
+ * as part of a larger chunk, and our caller may expect to be able to
+ * pfree our result. So must copy the info into a new palloc chunk.
+ */
+ result = (HeapTupleHeader) palloc(tuple->t_len);
+ memcpy(result, tuple->t_data, tuple->t_len);
+
+ heap_freetuple(tuple);
pfree(values);
pfree(nulls);
+ FreeTupleDesc(tupdesc);
- PG_RETURN_HEAPTUPLEHEADER(tuple->t_data);
+ PG_RETURN_HEAPTUPLEHEADER(result);
}
/*
record_send(PG_FUNCTION_ARGS)
{
HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
- Oid tupType = PG_GETARG_OID(1);
+ Oid tupType;
int32 tupTypmod;
TupleDesc tupdesc;
HeapTupleData tuple;
char *nulls;
StringInfoData buf;
- /*
- * Use the passed type unless it's RECORD; in that case, we'd better
- * get the type info out of the datum itself. Note that for RECORD,
- * what we'll probably actually get is RECORD's typelem, ie, zero.
- */
- if (tupType == InvalidOid || tupType == RECORDOID)
- {
- tupType = HeapTupleHeaderGetTypeId(rec);
- tupTypmod = HeapTupleHeaderGetTypMod(rec);
- }
- else
- tupTypmod = -1;
+ /* Extract type info from the tuple itself */
+ tupType = HeapTupleHeaderGetTypeId(rec);
+ tupTypmod = HeapTupleHeaderGetTypMod(rec);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
ncolumns = tupdesc->natts;
/* Build a temporary HeapTuple control structure */
pfree(values);
pfree(nulls);
+ FreeTupleDesc(tupdesc);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
if (rowexpr->row_typeid != RECORDOID)
{
tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
+ tupdesc = CreateTupleDescCopy(tupdesc);
Assert(list_length(rowexpr->args) <= tupdesc->natts);
}
*
* Note: returned TupleDesc points to cached copy; caller must copy it
* if intending to scribble on it or keep a reference for a long time.
+ * ("A long time" basically means "across any possible cache flush",
+ * which typically could occur at any relation open or catalog lookup.)
*/
TupleDesc
lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
tupType = HeapTupleHeaderGetTypeId(td);
tupTypmod = HeapTupleHeaderGetTypMod(td);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
/* Build a temporary HeapTuple control structure */
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
tmptup.t_data = td;
hashref = plperl_hash_from_tuple(&tmptup, tupdesc);
XPUSHs(sv_2mortal(hashref));
+ FreeTupleDesc(tupdesc);
}
else
{
*/
td = get_function_tupdesc(prodesc->result_oid,
(ReturnSetInfo *) fcinfo->resultinfo);
- /* td = CreateTupleDescCopy(td); */
+ td = CreateTupleDescCopy(td);
attinmeta = TupleDescGetAttInMetadata(td);
tup = plperl_build_tuple_result(perlhash, attinmeta);
tupType = HeapTupleHeaderGetTypeId(td);
tupTypmod = HeapTupleHeaderGetTypMod(td);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
/* Build a temporary HeapTuple control structure */
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
ItemPointerSetInvalid(&(tmptup.t_self));
tmptup.t_tableOid = InvalidOid;
tmptup.t_data = td;
exec_move_row(&estate, NULL, row, &tmptup, tupdesc);
+ FreeTupleDesc(tupdesc);
}
else
{
tupType = HeapTupleHeaderGetTypeId(td);
tupTypmod = HeapTupleHeaderGetTypMod(td);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
/* Build a temporary HeapTuple control structure */
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
ItemPointerSetInvalid(&(tmptup.t_self));
tmptup.t_tableOid = InvalidOid;
tmptup.t_data = td;
exec_move_row(estate, NULL, row, &tmptup, tupdesc);
+ FreeTupleDesc(tupdesc);
}
break;
}
tupType = HeapTupleHeaderGetTypeId(td);
tupTypmod = HeapTupleHeaderGetTypMod(td);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
/* Build a temporary HeapTuple control structure */
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
ItemPointerSetInvalid(&(tmptup.t_self));
tmptup.t_tableOid = InvalidOid;
tmptup.t_data = td;
exec_move_row(estate, rec, NULL, &tmptup, tupdesc);
+ FreeTupleDesc(tupdesc);
}
break;
}
tupType = HeapTupleHeaderGetTypeId(td);
tupTypmod = HeapTupleHeaderGetTypMod(td);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
/* Set up I/O funcs if not done yet */
if (proc->args[i].is_rowtype != 1)
tmptup.t_data = td;
arg = PLyDict_FromTuple(&(proc->args[i]), &tmptup, tupdesc);
+ FreeTupleDesc(tupdesc);
}
}
else
tupType = HeapTupleHeaderGetTypeId(td);
tupTypmod = HeapTupleHeaderGetTypMod(td);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ tupdesc = CreateTupleDescCopy(tupdesc);
/* Build a temporary HeapTuple control structure */
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
tmptup.t_data = td;
pltcl_build_tuple_argument(&tmptup, tupdesc, &list_tmp);
Tcl_DStringAppendElement(&tcl_cmd,
Tcl_DStringValue(&list_tmp));
+ FreeTupleDesc(tupdesc);
}
}
else