From b1ffbaeddcd05f61b0ad115ec3c13b2a1c65d721 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Tue, 29 Dec 2009 17:41:09 +0000 Subject: [PATCH] Previous fix for temporary file management broke returning a set from 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. --- .../pg_stat_statements/pg_stat_statements.c | 11 ++---- contrib/tablefunc/tablefunc.c | 29 +------------- contrib/xml2/xpath.c | 6 +-- src/backend/commands/prepare.c | 12 ++---- src/backend/executor/execQual.c | 7 +--- src/backend/executor/functions.c | 5 +-- src/backend/executor/nodeWindowAgg.c | 4 +- src/backend/executor/tstoreReceiver.c | 5 +-- src/backend/utils/mmgr/portalmem.c | 12 ++---- src/backend/utils/sort/tuplestore.c | 31 +++++++++++++-- src/pl/plperl/plperl.c | 10 +---- src/pl/plpgsql/src/pl_exec.c | 38 ++++++++++++------- src/pl/plpgsql/src/plpgsql.h | 3 +- 13 files changed, 74 insertions(+), 99 deletions(-) diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 44ba9e766b8..85960700ac5 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -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; } diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index 48512bd9349..272e932a3c1 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -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 */ diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 203e53905be..99be6f91d23 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -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); } diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 0e948e4b72d..c30ce359044 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -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; diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 7cac1060afe..86f005b104c 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -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? diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 2f3f4971db9..9d4ca42fdc1 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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); } /* diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 7343cb3752e..3cd71eb9f03 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -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) diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c index 19f348f13f6..10723a50146 100644 --- a/src/backend/executor/tstoreReceiver.c +++ b/src/backend/executor/tstoreReceiver.c @@ -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); } /* diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index b8b2923c7d4..a8ee35f08a7 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -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; diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c index 5b900b7a5ea..b160c6a2b3d 100644 --- a/src/backend/utils/sort/tuplestore.c +++ b/src/backend/utils/sort/tuplestore.c @@ -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 diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index b807fcc3c0e..c0bc6ff5fb4 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -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); } diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index c8f7288ced2..e73539d6719 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -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; diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 8f21f3beb94..c7d43a1f807 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -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;