Repair problems with the result of lookup_rowtype_tupdesc() possibly being
authorTom Lane <[email protected]>
Tue, 17 Jan 2006 17:33:37 +0000 (17:33 +0000)
committerTom Lane <[email protected]>
Tue, 17 Jan 2006 17:33:37 +0000 (17:33 +0000)
discarded by cache flush while still in use.  This is a minimal patch that
just copies the tupdesc anywhere it could be needed across a flush.  Applied
to back branches only; Neil Conway is working on a better long-term solution
for HEAD.

src/backend/access/heap/tuptoaster.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_target.c
src/backend/utils/adt/rowtypes.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/typcache.c
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpython/plpython.c
src/pl/tcl/pltcl.c

index afde5b556cb5c9f415881a3e94b84e6f850edf0f..4b3a4c55da9711c066fef8dd10f391022c624d3c 100644 (file)
@@ -820,6 +820,7 @@ toast_flatten_tuple_attribute(Datum value,
        if (tupleDesc == NULL)
                return value;                   /* not a composite type */
 
+       tupleDesc = CreateTupleDescCopy(tupleDesc);
        att = tupleDesc->attrs;
        numAttrs = tupleDesc->natts;
 
@@ -866,7 +867,10 @@ toast_flatten_tuple_attribute(Datum value,
         * 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
@@ -903,6 +907,7 @@ toast_flatten_tuple_attribute(Datum value,
        for (i = 0; i < numAttrs; i++)
                if (toast_free[i])
                        pfree(DatumGetPointer(toast_values[i]));
+       FreeTupleDesc(tupleDesc);
 
        return PointerGetDatum(new_data);
 }
index 838ff01a7de58df29707d548960d32a39ad40f7b..fe87c23a5b0d345947da5f10e4001bbaf351f924 100644 (file)
@@ -700,7 +700,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
                                                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);
@@ -758,6 +758,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
                                                format_type_be(targetTypeId)),
                                 errdetail("Input has too many columns.")));
 
+       FreeTupleDesc(tupdesc);
+
        rowexpr = makeNode(RowExpr);
        rowexpr->args = newargs;
        rowexpr->row_typeid = targetTypeId;
index fa72a9bdeb07c24ea8b92693867496e277e3846b..dc5c55daba80ad464e1d28931ca4529df292e65e 100644 (file)
@@ -839,6 +839,7 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind)
 
        /* 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;
@@ -889,6 +890,8 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind)
                te_list = lappend(te_list, te);
        }
 
+       FreeTupleDesc(tupleDesc);
+
        return te_list;
 }
 
index debb779dfa4b9d6ac264a53dac44fc7141a877e0..bb25ec3c75e53d025c9da6c396262dbfa56428c1 100644 (file)
@@ -54,6 +54,7 @@ record_in(PG_FUNCTION_ARGS)
 {
        char       *string = PG_GETARG_CSTRING(0);
        Oid                     tupType = PG_GETARG_OID(1);
+       HeapTupleHeader result;
        int32           tupTypmod;
        TupleDesc       tupdesc;
        HeapTuple       tuple;
@@ -78,6 +79,7 @@ record_in(PG_FUNCTION_ARGS)
                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;
 
        /*
@@ -244,11 +246,21 @@ record_in(PG_FUNCTION_ARGS)
 
        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);
 }
 
 /*
@@ -258,7 +270,7 @@ Datum
 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;
@@ -270,19 +282,11 @@ record_out(PG_FUNCTION_ARGS)
        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 */
@@ -407,6 +411,7 @@ record_out(PG_FUNCTION_ARGS)
 
        pfree(values);
        pfree(nulls);
+       FreeTupleDesc(tupdesc);
 
        PG_RETURN_CSTRING(buf.data);
 }
@@ -419,6 +424,7 @@ record_recv(PG_FUNCTION_ARGS)
 {
        StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
        Oid                     tupType = PG_GETARG_OID(1);
+       HeapTupleHeader result;
        int32           tupTypmod;
        TupleDesc       tupdesc;
        HeapTuple       tuple;
@@ -442,6 +448,7 @@ record_recv(PG_FUNCTION_ARGS)
                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;
 
        /*
@@ -580,10 +587,20 @@ record_recv(PG_FUNCTION_ARGS)
 
        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);
 }
 
 /*
@@ -593,7 +610,7 @@ Datum
 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;
@@ -605,19 +622,11 @@ record_send(PG_FUNCTION_ARGS)
        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 */
@@ -720,6 +729,7 @@ record_send(PG_FUNCTION_ARGS)
 
        pfree(values);
        pfree(nulls);
+       FreeTupleDesc(tupdesc);
 
        PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
index f35991903615dd34782a4324c0b5d0145ba55956..c185b05a9dead981f5679df2aea14241bab7a911 100644 (file)
@@ -3245,6 +3245,7 @@ get_rule_expr(Node *node, deparse_context *context,
                                if (rowexpr->row_typeid != RECORDOID)
                                {
                                        tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
+                                       tupdesc = CreateTupleDescCopy(tupdesc);
                                        Assert(list_length(rowexpr->args) <= tupdesc->natts);
                                }
 
index 03c26d9325ec84e132096cc83b040789b813823d..d3553b9e40d00eacf641b36ab5995eda3030b72e 100644 (file)
@@ -383,6 +383,8 @@ lookup_default_opclass(Oid type_id, Oid am_id)
  *
  * 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)
index 1cd4dce259658ff0d888f35f24a4a39c0c60a47b..016b0cfd5f318eb4a53987d7bfdb1e35c3cb6f78 100644 (file)
@@ -705,12 +705,14 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
                        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
                {
@@ -1009,7 +1011,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
                 */
                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);
index 588c880118f69f03f33bc02e69e64582ecd8d133..13f1c17c8264362e4cdc8c8c92c02eeb776636b6 100644 (file)
@@ -273,12 +273,14 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
                                                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
                                        {
@@ -2948,12 +2950,14 @@ exec_assign_value(PLpgSQL_execstate *estate,
                                        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;
                        }
@@ -2990,12 +2994,14 @@ exec_assign_value(PLpgSQL_execstate *estate,
                                        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;
                        }
index 160531b7ffee874c5333f9f53efff47ff3f62e39..8a75fa2ba5d06e80274e8b91f84b7c07be9fe3c7 100644 (file)
@@ -861,6 +861,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
                                        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)
@@ -871,6 +872,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
                                        tmptup.t_data = td;
 
                                        arg = PLyDict_FromTuple(&(proc->args[i]), &tmptup, tupdesc);
+                                       FreeTupleDesc(tupdesc);
                                }
                        }
                        else
index 64b5185f69e10abcd9a03612b1d93ad0613a1794..f4ecb390cadb31e6a93209cb47dc2faeaae5f5a4 100644 (file)
@@ -533,6 +533,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
                                        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;
@@ -541,6 +542,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
                                        pltcl_build_tuple_argument(&tmptup, tupdesc, &list_tmp);
                                        Tcl_DStringAppendElement(&tcl_cmd,
                                                                                         Tcl_DStringValue(&list_tmp));
+                                       FreeTupleDesc(tupdesc);
                                }
                        }
                        else