aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2009-12-29 17:41:35 +0000
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2009-12-29 17:41:35 +0000
commit56a87f2721a7157d0cd720e0743760e107100d43 (patch)
tree753c7e9a8fe1d57ab81938ecebe86cde69dd55a8 /src
parent3bd13da63ba3be6ff143190fc234e15783d51357 (diff)
downloadpostgresql-56a87f2721a7157d0cd720e0743760e107100d43.tar.gz
postgresql-56a87f2721a7157d0cd720e0743760e107100d43.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execQual.c5
-rw-r--r--src/backend/executor/tstoreReceiver.c9
-rw-r--r--src/backend/utils/sort/tuplestore.c29
-rw-r--r--src/pl/plperl/plperl.c6
-rw-r--r--src/pl/plpgsql/src/pl_exec.c32
-rw-r--r--src/pl/plpgsql/src/plpgsql.h3
6 files changed, 56 insertions, 28 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 06fe23e6376..57536cd0938 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.183.2.6 2007/02/06 17:35:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.183.2.7 2009/12/29 17:41:35 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1522,9 +1522,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?
@@ -1576,6 +1574,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);
}
}
diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c
index fb2aa843fd6..e99ed15a955 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.15.2.1 2008/12/01 17:06:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.15.2.2 2009/12/29 17:41:35 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -95,11 +95,8 @@ static void
tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
{
TStoreState *myState = (TStoreState *) self;
- MemoryContext oldcxt = MemoryContextSwitchTo(myState->cxt);
tuplestore_puttuple(myState->tstore, ExecFetchSlotTuple(slot));
-
- MemoryContextSwitchTo(oldcxt);
}
/*
@@ -116,7 +113,6 @@ tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
int nfree;
int i;
HeapTuple tuple;
- MemoryContext oldcxt;
/* Make sure the tuple is fully deconstructed */
slot_getallattrs(slot);
@@ -126,6 +122,7 @@ tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
* myState->outvalues[] (but we can re-use the slot's isnull array).
* Also, remember the fetched values to free afterwards.
*/
+
nfree = 0;
for (i = 0; i < natts; i++)
{
@@ -151,9 +148,7 @@ tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
*/
tuple = heap_form_tuple(typeinfo,
myState->outvalues, slot->tts_isnull);
- oldcxt = MemoryContextSwitchTo(myState->cxt);
tuplestore_puttuple(myState->tstore, tuple);
- MemoryContextSwitchTo(oldcxt);
heap_freetuple(tuple);
/* And release any temporary detoasted values */
diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c
index fd283e4959d..bad943bcab0 100644
--- a/src/backend/utils/sort/tuplestore.c
+++ b/src/backend/utils/sort/tuplestore.c
@@ -36,7 +36,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.23.2.2 2007/08/02 17:48:57 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.23.2.3 2009/12/29 17:41:35 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,6 +46,7 @@
#include "access/heapam.h"
#include "storage/buffile.h"
#include "utils/memutils.h"
+#include "utils/resowner.h"
#include "utils/tuplestore.h"
@@ -70,6 +71,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
@@ -219,6 +222,8 @@ tuplestore_begin_common(bool randomAccess, 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 */
@@ -244,9 +249,9 @@ tuplestore_begin_common(bool randomAccess, 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.
@@ -309,6 +314,9 @@ tuplestore_ateof(Tuplestorestate *state)
void
tuplestore_puttuple(Tuplestorestate *state, void *tuple)
{
+ MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
+ ResourceOwner oldowner;
+
/*
* Copy the tuple. (Must do this even in WRITEFILE case.)
*/
@@ -339,12 +347,21 @@ tuplestore_puttuple(Tuplestorestate *state, void *tuple)
* Done if we still fit in available memory.
*/
if (!LACKMEM(state))
+ {
+ MemoryContextSwitchTo(oldcxt);
return;
+ }
/*
* Nope; time to switch to tape-based operation.
*/
- state->myfile = BufFileCreateTemp(state->interXact);
+
+ /* 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;
@@ -370,6 +387,8 @@ tuplestore_puttuple(Tuplestorestate *state, void *tuple)
elog(ERROR, "invalid tuplestore state");
break;
}
+
+ MemoryContextSwitchTo(oldcxt);
}
/*
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 1fe7a6a7b2c..bbe1424e692 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -33,7 +33,7 @@
* ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.94.2.13 2009/09/28 17:30:04 adunstan Exp $
+ * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.94.2.14 2009/12/29 17:41:35 heikki Exp $
*
**********************************************************************/
@@ -1825,11 +1825,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);
}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 4744097b2be..1b400341af4 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.8 2009/02/27 10:27:53 heikki Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.9 2009/12/29 17:41:35 heikki Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -2001,11 +2001,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);
@@ -2019,6 +2015,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
@@ -2030,10 +2027,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;
@@ -2145,7 +2152,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 fef84a77dcb..5a47b9d629d 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.65.2.4 2008/10/09 16:35:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.65.2.5 2009/12/29 17:41:35 heikki Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -625,6 +625,7 @@ typedef struct
Tuplestorestate *tuple_store; /* SRFs accumulate results here */
MemoryContext tuple_store_cxt;
+ ResourceOwner tuple_store_owner;
ReturnSetInfo *rsi;
int trig_nargs;