]> 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:09 +0000 (17:41 +0000)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 29 Dec 2009 17:41:09 +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.

13 files changed:
contrib/pg_stat_statements/pg_stat_statements.c
contrib/tablefunc/tablefunc.c
contrib/xml2/xpath.c
src/backend/commands/prepare.c
src/backend/executor/execQual.c
src/backend/executor/functions.c
src/backend/executor/nodeWindowAgg.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 44ba9e766b899061564b9bdd68ef7ee6cd5d6751..85960700ac50804c531b77251d9f7c488d1410d8 100644 (file)
@@ -14,7 +14,7 @@
  * Copyright (c) 2008-2009, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.3.2.2 2009/07/27 04:10:01 tgl Exp $
+ *       $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.3.2.3 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -710,6 +710,8 @@ pg_stat_statements(PG_FUNCTION_ARGS)
        rsinfo->setResult = tupstore;
        rsinfo->setDesc = tupdesc;
 
+       MemoryContextSwitchTo(oldcontext);
+
        LWLockAcquire(pgss->lock, LW_SHARED);
 
        hash_seq_init(&hash_seq, pgss_hash);
@@ -720,9 +722,6 @@ pg_stat_statements(PG_FUNCTION_ARGS)
                int                     i = 0;
                Counters        tmp;
 
-               /* generate junk in short-term context */
-               MemoryContextSwitchTo(oldcontext);
-
                memset(values, 0, sizeof(values));
                memset(nulls, 0, sizeof(nulls));
 
@@ -760,8 +759,6 @@ pg_stat_statements(PG_FUNCTION_ARGS)
 
                Assert(i == PG_STAT_STATEMENTS_COLS);
 
-               /* switch to appropriate context while storing the tuple */
-               MemoryContextSwitchTo(per_query_ctx);
                tuplestore_putvalues(tupstore, tupdesc, values, nulls);
        }
 
@@ -770,8 +767,6 @@ pg_stat_statements(PG_FUNCTION_ARGS)
        /* clean up and return the tuplestore */
        tuplestore_donestoring(tupstore);
 
-       MemoryContextSwitchTo(oldcontext);
-
        return (Datum) 0;
 }
 
index 48512bd9349d8688b945e36ffe1cf4ffb6baf223..272e932a3c1aedb7f26035b991be7dceb180bdd8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/tablefunc/tablefunc.c,v 1.60 2009/06/11 14:48:52 momjian Exp $
+ * $PostgreSQL: pgsql/contrib/tablefunc/tablefunc.c,v 1.60.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  *
  * tablefunc
@@ -567,14 +567,9 @@ crosstab(PG_FUNCTION_ARGS)
                {
                        HeapTuple       tuple;
 
-                       /* build the tuple */
+                       /* build the tuple and store it */
                        tuple = BuildTupleFromCStrings(attinmeta, values);
-
-                       /* switch to appropriate context while storing the tuple */
-                       oldcontext = MemoryContextSwitchTo(per_query_ctx);
                        tuplestore_puttuple(tupstore, tuple);
-                       MemoryContextSwitchTo(oldcontext);
-
                        heap_freetuple(tuple);
                }
 
@@ -807,7 +802,6 @@ get_crosstab_tuplestore(char *sql,
        HeapTuple       tuple;
        int                     ret;
        int                     proc;
-       MemoryContext SPIcontext;
 
        /* initialize our tuplestore (while still in query context!) */
        tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
@@ -907,10 +901,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]);
@@ -943,10 +934,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)
@@ -1232,7 +1220,6 @@ build_tuplestore_recursively(char *key_fld,
                                                         Tuplestorestate *tupstore)
 {
        TupleDesc       tupdesc = attinmeta->tupdesc;
-       MemoryContext oldcontext;
        int                     ret;
        int                     proc;
        int                     serial_column;
@@ -1310,15 +1297,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++;
        }
@@ -1404,15 +1385,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 203e53905be560cd34803dbd6bdcc928d4a183d2..99be6f91d2398c60909c1b716dabc1a85678485f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/xml2/xpath.c,v 1.23 2009/06/11 14:48:53 momjian Exp $
+ * $PostgreSQL: pgsql/contrib/xml2/xpath.c,v 1.23.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  * Parser interface for DOM-based parser (libxml) rather than
  * stream-based SAX-type parser
@@ -821,9 +821,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
@@ -897,9 +895,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 0e948e4b72d76f69051b5df1ee9937f5cc4e14bb..c30ce359044e6940871e981866f22d107ad2f1df 100644 (file)
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2009, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.97 2009/06/11 14:48:56 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.97.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -781,6 +781,9 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
                tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
                                                          false, work_mem);
 
+       /* generate junk in short-term context */
+       MemoryContextSwitchTo(oldcontext);
+
        /* hash table might be uninitialized */
        if (prepared_queries)
        {
@@ -793,9 +796,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] = CStringGetTextDatum(prep_stmt->stmt_name);
@@ -805,8 +805,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
                                                                                  prep_stmt->plansource->num_params);
                        values[4] = BoolGetDatum(prep_stmt->from_sql);
 
-                       /* switch to appropriate context while storing the tuple */
-                       MemoryContextSwitchTo(per_query_ctx);
                        tuplestore_putvalues(tupstore, tupdesc, values, nulls);
                }
        }
@@ -814,8 +812,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 7cac1060afe2661a7c809fc5b7dc2a1637f86845..86f005b104c20e62b4772fb9e3c9d939fdb90548 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.250.2.1 2009/12/14 02:16:03 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.250.2.2 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2000,15 +2000,10 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
                                tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
                                tmptup.t_data = td;
 
-                               oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
                                tuplestore_puttuple(tupstore, &tmptup);
                        }
                        else
-                       {
-                               oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
                                tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo.isnull);
-                       }
-                       MemoryContextSwitchTo(oldcontext);
 
                        /*
                         * Are we done?
index 2f3f4971db9b4132ce6c336826dfa96ea193641f..9d4ca42fdc19b0f9d92ed31f83aad676e32ce5e9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.135.2.1 2009/12/14 02:16:03 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.135.2.2 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1400,15 +1400,12 @@ static void
 sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self)
 {
        DR_sqlfunction *myState = (DR_sqlfunction *) self;
-       MemoryContext oldcxt;
 
        /* Filter tuple as needed */
        slot = ExecFilterJunk(myState->filter, slot);
 
        /* Store the filtered tuple into the tuplestore */
-       oldcxt = MemoryContextSwitchTo(myState->cxt);
        tuplestore_puttupleslot(myState->tstore, slot);
-       MemoryContextSwitchTo(oldcxt);
 }
 
 /*
index 7343cb3752ecec1a7246d51851bf80090230bcfb..3cd71eb9f034d8d511c8ff84386715d30fef3db0 100644 (file)
@@ -27,7 +27,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeWindowAgg.c,v 1.6 2009/06/20 18:45:28 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeWindowAgg.c,v 1.6.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -723,7 +723,7 @@ spool_tuples(WindowAggState *winstate, int64 pos)
 
        outerPlan = outerPlanState(winstate);
 
-       /* Must be in query context to call outerplan or touch tuplestore */
+       /* Must be in query context to call outerplan */
        oldcontext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_query_memory);
 
        while (winstate->spooled_rows <= pos || pos == -1)
index 19f348f13f699996da1963d1842d68a235b166a3..10723a501468e6c9a37145c145302d77c7c0356f 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.23 2009/06/11 14:48:57 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.23.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -94,11 +94,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 b8b2923c7d4d8d78f82d88fa698bf674504a8570..a8ee35f08a7dfbf71cce43eed60774885435728c 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.113 2009/01/01 17:23:53 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.113.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -923,6 +923,9 @@ pg_cursor(PG_FUNCTION_ARGS)
                tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
                                                          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)
        {
@@ -934,9 +937,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] = CStringGetTextDatum(portal->name);
@@ -946,16 +946,12 @@ pg_cursor(PG_FUNCTION_ARGS)
                values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
                values[5] = TimestampTzGetDatum(portal->creation_time);
 
-               /* switch to appropriate context while storing the tuple */
-               MemoryContextSwitchTo(per_query_ctx);
                tuplestore_putvalues(tupstore, tupdesc, values, nulls);
        }
 
        /* clean up and return the tuplestore */
        tuplestore_donestoring(tupstore);
 
-       MemoryContextSwitchTo(oldcontext);
-
        rsinfo->returnMode = SFRM_Materialize;
        rsinfo->setResult = tupstore;
        rsinfo->setDesc = tupdesc;
index 5b900b7a5ea6bae5aec397349496510255447b7e..b160c6a2b3d04f5572fe0a659166018a4f2ee1fc 100644 (file)
@@ -47,7 +47,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.48 2009/06/11 14:49:06 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.48.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,6 +58,7 @@
 #include "executor/executor.h"
 #include "storage/buffile.h"
 #include "utils/memutils.h"
+#include "utils/resowner.h"
 #include "utils/tuplestore.h"
 
 
@@ -105,6 +106,8 @@ struct Tuplestorestate
        bool            truncated;              /* tuplestore_trim has removed tuples? */
        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
@@ -246,6 +249,8 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
        state->truncated = false;
        state->availMem = maxKBytes * 1024L;
        state->myfile = NULL;
+       state->context = CurrentMemoryContext;
+       state->resowner = CurrentResourceOwner;
 
        state->memtupcount = 0;
        state->memtupsize = 1024;       /* initial guess */
@@ -278,9 +283,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.
@@ -533,6 +538,7 @@ tuplestore_puttupleslot(Tuplestorestate *state,
                                                TupleTableSlot *slot)
 {
        MinimalTuple tuple;
+       MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
 
        /*
         * Form a MinimalTuple in working memory
@@ -541,6 +547,8 @@ tuplestore_puttupleslot(Tuplestorestate *state,
        USEMEM(state, GetMemoryChunkSpace(tuple));
 
        tuplestore_puttuple_common(state, (void *) tuple);
+
+       MemoryContextSwitchTo(oldcxt);
 }
 
 /*
@@ -550,12 +558,16 @@ 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);
 }
 
 /*
@@ -568,10 +580,13 @@ tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc,
                                         Datum *values, bool *isnull)
 {
        MinimalTuple tuple;
+       MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
 
        tuple = heap_form_minimal_tuple(tdesc, values, isnull);
 
        tuplestore_puttuple_common(state, (void *) tuple);
+
+       MemoryContextSwitchTo(oldcxt);  
 }
 
 static void
@@ -579,6 +594,7 @@ tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
 {
        TSReadPointer *readptr;
        int                     i;
+       ResourceOwner oldowner;
 
        switch (state->status)
        {
@@ -635,8 +651,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;
+
                        /*
                         * Freeze the decision about whether trailing length words will be
                         * used.  We can't change this choice once data is on tape, even
index b807fcc3c0ed3bb0d20b5bdd07304f176e74e0ec..c0bc6ff5fb4518062d26e033860bc903f939038e 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plperl.c - perl as a procedural language for PostgreSQL
  *
- *       $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.150.2.3 2009/11/29 21:02:22 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.150.2.4 2009/12/29 17:41:09 heikki Exp $
  *
  **********************************************************************/
 
@@ -1981,11 +1981,7 @@ plperl_return_next(SV *sv)
 
                tuple = plperl_build_tuple_result((HV *) SvRV(sv),
                                                                                  current_call_data->attinmeta);
-
-               /* 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);
        }
        else
        {
@@ -2015,14 +2011,12 @@ plperl_return_next(SV *sv)
                        isNull = true;
                }
 
-               /* Make sure to store the tuple in a long-lived memory context */
-               MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
                tuplestore_putvalues(current_call_data->tuple_store,
                                                         current_call_data->ret_tdesc,
                                                         &ret, &isNull);
-               MemoryContextSwitchTo(old_cxt);
        }
 
+       MemoryContextSwitchTo(old_cxt);
        MemoryContextReset(current_call_data->tmp_cxt);
 }
 
index c8f7288ced2cea0f9c236b02ab10a60cb190260c..e73539d6719a5b6fde597eb393f7ab0d41edfdd0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.244.2.1 2009/07/18 19:15:50 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.244.2.2 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2140,7 +2140,6 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 {
        TupleDesc       tupdesc;
        int                     natts;
-       MemoryContext oldcxt;
        HeapTuple       tuple = NULL;
        bool            free_tuple = false;
 
@@ -2180,10 +2179,8 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                                                                                                tupdesc->attrs[0]->atttypmod,
                                                                                                        isNull);
 
-                                       oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
                                        tuplestore_putvalues(estate->tuple_store, tupdesc,
                                                                                 &retval, &isNull);
-                                       MemoryContextSwitchTo(oldcxt);
                                }
                                break;
 
@@ -2245,10 +2242,8 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                                                                                tupdesc->attrs[0]->atttypmod,
                                                                                isNull);
 
-               oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
                tuplestore_putvalues(estate->tuple_store, tupdesc,
                                                         &retval, &isNull);
-               MemoryContextSwitchTo(oldcxt);
 
                exec_eval_cleanup(estate);
        }
@@ -2261,9 +2256,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 
        if (HeapTupleIsValid(tuple))
        {
-               oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
                tuplestore_puttuple(estate->tuple_store, tuple);
-               MemoryContextSwitchTo(oldcxt);
 
                if (free_tuple)
                        heap_freetuple(tuple);
@@ -2311,14 +2304,12 @@ 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];
@@ -2326,7 +2317,6 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
                        tuplestore_puttuple(estate->tuple_store, tuple);
                        processed++;
                }
-               MemoryContextSwitchTo(old_cxt);
 
                SPI_freetuptable(SPI_tuptable);
        }
@@ -2345,6 +2335,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
@@ -2356,12 +2347,22 @@ 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(rsi->allowedModes & SFRM_Materialize_Random,
                                                          false, work_mem);
+
+       CurrentResourceOwner = oldowner;
        MemoryContextSwitchTo(oldcxt);
 
        estate->rettupdesc = rsi->expectedDesc;
@@ -2581,7 +2582,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 8f21f3beb947a81e003a928f0ac70643170987a6..c7d43a1f80725d40008a975ed48e42b56751ed8e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.113 2009/06/11 14:49:14 momjian Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.113.2.1 2009/12/29 17:41:09 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -705,6 +705,7 @@ typedef struct
 
        Tuplestorestate *tuple_store;           /* SRFs accumulate results here */
        MemoryContext tuple_store_cxt;
+       ResourceOwner tuple_store_owner;
        ReturnSetInfo *rsi;
 
        int                     trig_nargs;