]> granicus.if.org Git - postgresql/commitdiff
Previous fix for temporary file management broke returning a set from
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 29 Dec 2009 17:41:18 +0000 (17:41 +0000)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 29 Dec 2009 17:41:18 +0000 (17:41 +0000)
PL/pgSQL function within an exception handler. Make sure we use the right
resource owner when we create the tuplestore to hold returned tuples.

Simplify tuplestore API so that the caller doesn't need to be in the right
memory context when calling tuplestore_put* functions. tuplestore.c
automatically switches to the memory context used when the tuplestore was
created. Tuplesort was already modified like this earlier. This patch also
removes the now useless MemoryContextSwitch calls from callers.

Report by Aleksei on pgsql-bugs on Dec 22 2009. Backpatch to 8.1, like
the previous patch that broke this.

contrib/tablefunc/tablefunc.c
contrib/xml2/xpath.c
src/backend/commands/prepare.c
src/backend/executor/execQual.c
src/backend/executor/tstoreReceiver.c
src/backend/utils/mmgr/portalmem.c
src/backend/utils/sort/tuplestore.c
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/plpgsql.h

index 9c9d0aa7a29f499bea7fae2517a4da6561d7f691..019c2175bb29180f35a8561df2321b522916930f 100644 (file)
@@ -765,7 +765,6 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
        HASHCTL         ctl;
        int                     ret;
        int                     proc;
-       MemoryContext SPIcontext;
 
        /* initialize the category hash table */
        MemSet(&ctl, 0, sizeof(ctl));
@@ -956,10 +955,7 @@ get_crosstab_tuplestore(char *sql,
                                        /* rowid changed, flush the previous output row */
                                        tuple = BuildTupleFromCStrings(attinmeta, values);
 
-                                       /* switch to appropriate context while storing the tuple */
-                                       SPIcontext = MemoryContextSwitchTo(per_query_ctx);
                                        tuplestore_puttuple(tupstore, tuple);
-                                       MemoryContextSwitchTo(SPIcontext);
 
                                        for (j = 0; j < result_ncols; j++)
                                                xpfree(values[j]);
@@ -992,10 +988,7 @@ get_crosstab_tuplestore(char *sql,
                /* flush the last output row */
                tuple = BuildTupleFromCStrings(attinmeta, values);
 
-               /* switch to appropriate context while storing the tuple */
-               SPIcontext = MemoryContextSwitchTo(per_query_ctx);
                tuplestore_puttuple(tupstore, tuple);
-               MemoryContextSwitchTo(SPIcontext);
        }
 
        if (SPI_finish() != SPI_OK_FINISH)
@@ -1277,7 +1270,6 @@ build_tuplestore_recursively(char *key_fld,
                                                         Tuplestorestate *tupstore)
 {
        TupleDesc       tupdesc = attinmeta->tupdesc;
-       MemoryContext oldcontext;
        int                     ret;
        int                     proc;
        int                     serial_column;
@@ -1355,15 +1347,9 @@ build_tuplestore_recursively(char *key_fld,
                /* construct the tuple */
                tuple = BuildTupleFromCStrings(attinmeta, values);
 
-               /* switch to long lived context while storing the tuple */
-               oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
                /* now store it */
                tuplestore_puttuple(tupstore, tuple);
 
-               /* now reset the context */
-               MemoryContextSwitchTo(oldcontext);
-
                /* increment level */
                level++;
        }
@@ -1449,15 +1435,9 @@ build_tuplestore_recursively(char *key_fld,
                        xpfree(current_key);
                        xpfree(current_key_parent);
 
-                       /* switch to long lived context while storing the tuple */
-                       oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
                        /* store the tuple for later use */
                        tuplestore_puttuple(tupstore, tuple);
 
-                       /* now reset the context */
-                       MemoryContextSwitchTo(oldcontext);
-
                        heap_freetuple(tuple);
 
                        /* recurse using current_key_parent as the new start_with */
index 828545c763c4f6fcef4929cbb07da5a0c3142f6b..b4452cfd840b8d34fe5ad5c39b05923b709df40a 100644 (file)
@@ -834,9 +834,7 @@ xpath_table(PG_FUNCTION_ARGS)
                {
                        /* not well-formed, so output all-NULL tuple */
                        ret_tuple = BuildTupleFromCStrings(attinmeta, values);
-                       oldcontext = MemoryContextSwitchTo(per_query_ctx);
                        tuplestore_puttuple(tupstore, ret_tuple);
-                       MemoryContextSwitchTo(oldcontext);
                        heap_freetuple(ret_tuple);
                }
                else
@@ -910,9 +908,7 @@ xpath_table(PG_FUNCTION_ARGS)
                                if (had_values)
                                {
                                        ret_tuple = BuildTupleFromCStrings(attinmeta, values);
-                                       oldcontext = MemoryContextSwitchTo(per_query_ctx);
                                        tuplestore_puttuple(tupstore, ret_tuple);
-                                       MemoryContextSwitchTo(oldcontext);
                                        heap_freetuple(ret_tuple);
                                }
 
index 7dcd3cb5a85901b810d209555d1b4904508e6586..f09140967892d6d3a2e3fee26dee2cefe1185bf0 100644 (file)
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.80.2.1 2008/04/02 18:32:00 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.80.2.2 2009/12/29 17:41:18 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -759,6 +759,9 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
         */
        tupstore = tuplestore_begin_heap(true, false, work_mem);
 
+       /* generate junk in short-term context */
+       MemoryContextSwitchTo(oldcontext);
+
        /* hash table might be uninitialized */
        if (prepared_queries)
        {
@@ -772,9 +775,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
                        Datum           values[5];
                        bool            nulls[5];
 
-                       /* generate junk in short-term context */
-                       MemoryContextSwitchTo(oldcontext);
-
                        MemSet(nulls, 0, sizeof(nulls));
 
                        values[0] = DirectFunctionCall1(textin,
@@ -792,9 +792,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
                        values[4] = BoolGetDatum(prep_stmt->from_sql);
 
                        tuple = heap_form_tuple(tupdesc, values, nulls);
-
-                       /* switch to appropriate context while storing the tuple */
-                       MemoryContextSwitchTo(per_query_ctx);
                        tuplestore_puttuple(tupstore, tuple);
                }
        }
@@ -802,8 +799,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
        /* clean up and return the tuplestore */
        tuplestore_donestoring(tupstore);
 
-       MemoryContextSwitchTo(oldcontext);
-
        rsinfo->returnMode = SFRM_Materialize;
        rsinfo->setResult = tupstore;
        rsinfo->setDesc = tupdesc;
index 27e764c19a970d7d8a500ff29a957780a624e9f4..f26a4437da3d8e82368b5ccb1a2d22e016fc87a1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.226.2.1 2008/11/15 20:53:40 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.226.2.2 2009/12/29 17:41:18 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1656,9 +1656,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
                                tuple = heap_form_tuple(tupdesc, &result, &fcinfo.isnull);
                        }
 
-                       oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
                        tuplestore_puttuple(tupstore, tuple);
-                       MemoryContextSwitchTo(oldcontext);
 
                        /*
                         * Are we done?
@@ -1710,6 +1708,7 @@ no_function_result:
                        memset(nullflags, true, natts * sizeof(bool));
                        tuple = heap_form_tuple(expectedDesc, nulldatums, nullflags);
                        MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+
                        tuplestore_puttuple(tupstore, tuple);
                }
        }
index 197aa3c0774b2ef856799579b83272123d55906f..9645365ac1f953deefb98c05b48b2d477d946a9e 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.19.2.1 2008/12/01 17:06:27 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.19.2.2 2009/12/29 17:41:18 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -95,11 +95,8 @@ static void
 tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
 {
        TStoreState *myState = (TStoreState *) self;
-       MemoryContext oldcxt = MemoryContextSwitchTo(myState->cxt);
 
        tuplestore_puttupleslot(myState->tstore, slot);
-
-       MemoryContextSwitchTo(oldcxt);
 }
 
 /*
index b977396fb420c55fe61ce756b81b828737777229..217c6b1234b6e3c8cce637b8408d6c8a69d0eba7 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.106.2.1 2008/04/02 18:32:00 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.106.2.2 2009/12/29 17:41:18 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -911,6 +911,9 @@ pg_cursor(PG_FUNCTION_ARGS)
         */
        tupstore = tuplestore_begin_heap(true, false, work_mem);
 
+       /* generate junk in short-term context */
+       MemoryContextSwitchTo(oldcontext);
+
        hash_seq_init(&hash_seq, PortalHashTable);
        while ((hentry = hash_seq_search(&hash_seq)) != NULL)
        {
@@ -923,9 +926,6 @@ pg_cursor(PG_FUNCTION_ARGS)
                if (!portal->visible)
                        continue;
 
-               /* generate junk in short-term context */
-               MemoryContextSwitchTo(oldcontext);
-
                MemSet(nulls, 0, sizeof(nulls));
 
                values[0] = DirectFunctionCall1(textin, CStringGetDatum(portal->name));
@@ -941,16 +941,12 @@ pg_cursor(PG_FUNCTION_ARGS)
 
                tuple = heap_form_tuple(tupdesc, values, nulls);
 
-               /* switch to appropriate context while storing the tuple */
-               MemoryContextSwitchTo(per_query_ctx);
                tuplestore_puttuple(tupstore, tuple);
        }
 
        /* clean up and return the tuplestore */
        tuplestore_donestoring(tupstore);
 
-       MemoryContextSwitchTo(oldcontext);
-
        rsinfo->returnMode = SFRM_Materialize;
        rsinfo->setResult = tupstore;
        rsinfo->setDesc = tupdesc;
index e297579674a23354ccfd527999f62114f9223b04..81106e513a424e59c830f52673d0d9e9a910cd90 100644 (file)
@@ -38,7 +38,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.36 2008/01/01 19:45:55 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.36.2.1 2009/12/29 17:41:18 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,6 +50,7 @@
 #include "executor/executor.h"
 #include "storage/buffile.h"
 #include "utils/memutils.h"
+#include "utils/resowner.h"
 #include "utils/tuplestore.h"
 
 
@@ -74,6 +75,8 @@ struct Tuplestorestate
        bool            interXact;              /* keep open through transactions? */
        long            availMem;               /* remaining memory available, in bytes */
        BufFile    *myfile;                     /* underlying file, or NULL if none */
+       MemoryContext context;          /* memory context for holding tuples */
+       ResourceOwner resowner;         /* resowner for holding temp files */
 
        /*
         * These function pointers decouple the routines that must know what kind
@@ -225,6 +228,8 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
        state->interXact = interXact;
        state->availMem = maxKBytes * 1024L;
        state->myfile = NULL;
+       state->context = CurrentMemoryContext;
+       state->resowner = CurrentResourceOwner;
 
        state->memtupcount = 0;
        state->memtupsize = 1024;       /* initial guess */
@@ -250,9 +255,9 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
  *
  * interXact: if true, the files used for on-disk storage persist beyond the
  * end of the current transaction.     NOTE: It's the caller's responsibility to
- * create such a tuplestore in a memory context that will also survive
- * transaction boundaries, and to ensure the tuplestore is closed when it's
- * no longer wanted.
+ * create such a tuplestore in a memory context and resource owner that will
+ * also survive transaction boundaries, and to ensure the tuplestore is closed
+ * when it's no longer wanted.
  *
  * maxKBytes: how much data to store in memory (any data beyond this
  * amount is paged to disk).  When in doubt, use work_mem.
@@ -353,6 +358,7 @@ tuplestore_puttupleslot(Tuplestorestate *state,
                                                TupleTableSlot *slot)
 {
        MinimalTuple tuple;
+       MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
 
        /*
         * Form a MinimalTuple in working memory
@@ -361,6 +367,8 @@ tuplestore_puttupleslot(Tuplestorestate *state,
        USEMEM(state, GetMemoryChunkSpace(tuple));
 
        tuplestore_puttuple_common(state, (void *) tuple);
+
+       MemoryContextSwitchTo(oldcxt);
 }
 
 /*
@@ -372,17 +380,23 @@ tuplestore_puttupleslot(Tuplestorestate *state,
 void
 tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
 {
+       MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
+
        /*
         * Copy the tuple.      (Must do this even in WRITEFILE case.)
         */
        tuple = COPYTUP(state, tuple);
 
        tuplestore_puttuple_common(state, (void *) tuple);
+
+       MemoryContextSwitchTo(oldcxt);
 }
 
 static void
 tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
 {
+       ResourceOwner oldowner;
+
        switch (state->status)
        {
                case TSS_INMEM:
@@ -429,7 +443,15 @@ tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
                         * the temp file(s) are created in suitable temp tablespaces.
                         */
                        PrepareTempTablespaces();
+
+                       /* associate the file with the store's resource owner */
+                       oldowner = CurrentResourceOwner;
+                       CurrentResourceOwner = state->resowner;
+
                        state->myfile = BufFileCreateTemp(state->interXact);
+
+                       CurrentResourceOwner = oldowner;
+
                        state->status = TSS_WRITEFILE;
                        dumptuples(state);
                        break;
index 0a6f8f7861689561f32a039d00431756cceaa253..6a6fcd0db53b212a84b06db6d959043d937c058d 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plperl.c - perl as a procedural language for PostgreSQL
  *
- *       $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.136.2.5 2009/11/29 21:02:28 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.136.2.6 2009/12/29 17:41:18 heikki Exp $
  *
  **********************************************************************/
 
@@ -1995,11 +1995,9 @@ plperl_return_next(SV *sv)
                tuple = heap_form_tuple(current_call_data->ret_tdesc, &ret, &isNull);
        }
 
-       /* Make sure to store the tuple in a long-lived memory context */
-       MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
        tuplestore_puttuple(current_call_data->tuple_store, tuple);
-       MemoryContextSwitchTo(old_cxt);
 
+       MemoryContextSwitchTo(old_cxt);
        MemoryContextReset(current_call_data->tmp_cxt);
 }
 
index 49f6fb4c84d5e31640d7f696a391130353cea8e1..b487f6567258d208760b6266c1cb43dd5ba89e30 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.202.2.5 2009/04/02 01:16:17 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.202.2.6 2009/12/29 17:41:18 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2132,11 +2132,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 
        if (HeapTupleIsValid(tuple))
        {
-               MemoryContext oldcxt;
-
-               oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
                tuplestore_puttuple(estate->tuple_store, tuple);
-               MemoryContextSwitchTo(oldcxt);
 
                if (free_tuple)
                        heap_freetuple(tuple);
@@ -2174,21 +2170,18 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
 
        while (true)
        {
-               MemoryContext old_cxt;
                int                     i;
 
                SPI_cursor_fetch(portal, true, 50);
                if (SPI_processed == 0)
                        break;
 
-               old_cxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
                for (i = 0; i < SPI_processed; i++)
                {
                        HeapTuple       tuple = SPI_tuptable->vals[i];
 
                        tuplestore_puttuple(estate->tuple_store, tuple);
                }
-               MemoryContextSwitchTo(old_cxt);
 
                SPI_freetuptable(SPI_tuptable);
        }
@@ -2204,6 +2197,7 @@ exec_init_tuple_store(PLpgSQL_execstate *estate)
 {
        ReturnSetInfo *rsi = estate->rsi;
        MemoryContext oldcxt;
+       ResourceOwner oldowner;
 
        /*
         * Check caller can handle a set result in the way we want
@@ -2215,10 +2209,20 @@ exec_init_tuple_store(PLpgSQL_execstate *estate)
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("set-valued function called in context that cannot accept a set")));
 
-       estate->tuple_store_cxt = rsi->econtext->ecxt_per_query_memory;
-
+       /*
+        * Switch to the right memory context and resource owner for storing
+        * the tuplestore for return set. If we're within a subtransaction opened
+        * for an exception-block, for example, we must still create the
+        * tuplestore in the resource owner that was active when this function was
+        * entered, and not in the subtransaction resource owner.
+        */
        oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
+       oldowner = CurrentResourceOwner;
+       CurrentResourceOwner = estate->tuple_store_owner;
+
        estate->tuple_store = tuplestore_begin_heap(true, false, work_mem);
+
+       CurrentResourceOwner = oldowner;
        MemoryContextSwitchTo(oldcxt);
 
        estate->rettupdesc = rsi->expectedDesc;
@@ -2330,7 +2334,16 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
        estate->exitlabel = NULL;
 
        estate->tuple_store = NULL;
-       estate->tuple_store_cxt = NULL;
+       if (rsi)
+       {
+               estate->tuple_store_cxt = rsi->econtext->ecxt_per_query_memory;
+               estate->tuple_store_owner = CurrentResourceOwner;
+       }
+       else
+       {
+               estate->tuple_store_cxt = NULL;
+               estate->tuple_store_owner = NULL;
+       }
        estate->rsi = rsi;
 
        estate->trig_nargs = 0;
index 9736befcc8fa5508cda4daaa62f009b760f6f2e9..b954f88f2476289b58f2f1ce859045212a006258 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.95.2.1 2008/10/09 16:35:13 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.95.2.2 2009/12/29 17:41:18 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -622,6 +622,7 @@ typedef struct
 
        Tuplestorestate *tuple_store;           /* SRFs accumulate results here */
        MemoryContext tuple_store_cxt;
+       ResourceOwner tuple_store_owner;
        ReturnSetInfo *rsi;
 
        int                     trig_nargs;