提交 67d25e5a 编写于 作者: H Heikki Linnakangas

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.
上级 f216f56e
...@@ -765,7 +765,6 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx) ...@@ -765,7 +765,6 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
HASHCTL ctl; HASHCTL ctl;
int ret; int ret;
int proc; int proc;
MemoryContext SPIcontext;
/* initialize the category hash table */ /* initialize the category hash table */
MemSet(&ctl, 0, sizeof(ctl)); MemSet(&ctl, 0, sizeof(ctl));
...@@ -956,10 +955,7 @@ get_crosstab_tuplestore(char *sql, ...@@ -956,10 +955,7 @@ get_crosstab_tuplestore(char *sql,
/* rowid changed, flush the previous output row */ /* rowid changed, flush the previous output row */
tuple = BuildTupleFromCStrings(attinmeta, values); tuple = BuildTupleFromCStrings(attinmeta, values);
/* switch to appropriate context while storing the tuple */
SPIcontext = MemoryContextSwitchTo(per_query_ctx);
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
MemoryContextSwitchTo(SPIcontext);
for (j = 0; j < result_ncols; j++) for (j = 0; j < result_ncols; j++)
xpfree(values[j]); xpfree(values[j]);
...@@ -992,10 +988,7 @@ get_crosstab_tuplestore(char *sql, ...@@ -992,10 +988,7 @@ get_crosstab_tuplestore(char *sql,
/* flush the last output row */ /* flush the last output row */
tuple = BuildTupleFromCStrings(attinmeta, values); tuple = BuildTupleFromCStrings(attinmeta, values);
/* switch to appropriate context while storing the tuple */
SPIcontext = MemoryContextSwitchTo(per_query_ctx);
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
MemoryContextSwitchTo(SPIcontext);
} }
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
...@@ -1277,7 +1270,6 @@ build_tuplestore_recursively(char *key_fld, ...@@ -1277,7 +1270,6 @@ build_tuplestore_recursively(char *key_fld,
Tuplestorestate *tupstore) Tuplestorestate *tupstore)
{ {
TupleDesc tupdesc = attinmeta->tupdesc; TupleDesc tupdesc = attinmeta->tupdesc;
MemoryContext oldcontext;
int ret; int ret;
int proc; int proc;
int serial_column; int serial_column;
...@@ -1355,15 +1347,9 @@ build_tuplestore_recursively(char *key_fld, ...@@ -1355,15 +1347,9 @@ build_tuplestore_recursively(char *key_fld,
/* construct the tuple */ /* construct the tuple */
tuple = BuildTupleFromCStrings(attinmeta, values); tuple = BuildTupleFromCStrings(attinmeta, values);
/* switch to long lived context while storing the tuple */
oldcontext = MemoryContextSwitchTo(per_query_ctx);
/* now store it */ /* now store it */
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
/* now reset the context */
MemoryContextSwitchTo(oldcontext);
/* increment level */ /* increment level */
level++; level++;
} }
...@@ -1449,15 +1435,9 @@ build_tuplestore_recursively(char *key_fld, ...@@ -1449,15 +1435,9 @@ build_tuplestore_recursively(char *key_fld,
xpfree(current_key); xpfree(current_key);
xpfree(current_key_parent); xpfree(current_key_parent);
/* switch to long lived context while storing the tuple */
oldcontext = MemoryContextSwitchTo(per_query_ctx);
/* store the tuple for later use */ /* store the tuple for later use */
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
/* now reset the context */
MemoryContextSwitchTo(oldcontext);
heap_freetuple(tuple); heap_freetuple(tuple);
/* recurse using current_key_parent as the new start_with */ /* recurse using current_key_parent as the new start_with */
......
...@@ -834,9 +834,7 @@ xpath_table(PG_FUNCTION_ARGS) ...@@ -834,9 +834,7 @@ xpath_table(PG_FUNCTION_ARGS)
{ {
/* not well-formed, so output all-NULL tuple */ /* not well-formed, so output all-NULL tuple */
ret_tuple = BuildTupleFromCStrings(attinmeta, values); ret_tuple = BuildTupleFromCStrings(attinmeta, values);
oldcontext = MemoryContextSwitchTo(per_query_ctx);
tuplestore_puttuple(tupstore, ret_tuple); tuplestore_puttuple(tupstore, ret_tuple);
MemoryContextSwitchTo(oldcontext);
heap_freetuple(ret_tuple); heap_freetuple(ret_tuple);
} }
else else
...@@ -910,9 +908,7 @@ xpath_table(PG_FUNCTION_ARGS) ...@@ -910,9 +908,7 @@ xpath_table(PG_FUNCTION_ARGS)
if (had_values) if (had_values)
{ {
ret_tuple = BuildTupleFromCStrings(attinmeta, values); ret_tuple = BuildTupleFromCStrings(attinmeta, values);
oldcontext = MemoryContextSwitchTo(per_query_ctx);
tuplestore_puttuple(tupstore, ret_tuple); tuplestore_puttuple(tupstore, ret_tuple);
MemoryContextSwitchTo(oldcontext);
heap_freetuple(ret_tuple); heap_freetuple(ret_tuple);
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright (c) 2002-2008, PostgreSQL Global Development Group * Copyright (c) 2002-2008, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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) ...@@ -759,6 +759,9 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
*/ */
tupstore = tuplestore_begin_heap(true, false, work_mem); tupstore = tuplestore_begin_heap(true, false, work_mem);
/* generate junk in short-term context */
MemoryContextSwitchTo(oldcontext);
/* hash table might be uninitialized */ /* hash table might be uninitialized */
if (prepared_queries) if (prepared_queries)
{ {
...@@ -772,9 +775,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS) ...@@ -772,9 +775,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
Datum values[5]; Datum values[5];
bool nulls[5]; bool nulls[5];
/* generate junk in short-term context */
MemoryContextSwitchTo(oldcontext);
MemSet(nulls, 0, sizeof(nulls)); MemSet(nulls, 0, sizeof(nulls));
values[0] = DirectFunctionCall1(textin, values[0] = DirectFunctionCall1(textin,
...@@ -792,9 +792,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS) ...@@ -792,9 +792,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
values[4] = BoolGetDatum(prep_stmt->from_sql); values[4] = BoolGetDatum(prep_stmt->from_sql);
tuple = heap_form_tuple(tupdesc, values, nulls); tuple = heap_form_tuple(tupdesc, values, nulls);
/* switch to appropriate context while storing the tuple */
MemoryContextSwitchTo(per_query_ctx);
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
} }
} }
...@@ -802,8 +799,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS) ...@@ -802,8 +799,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
/* clean up and return the tuplestore */ /* clean up and return the tuplestore */
tuplestore_donestoring(tupstore); tuplestore_donestoring(tupstore);
MemoryContextSwitchTo(oldcontext);
rsinfo->returnMode = SFRM_Materialize; rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore; rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc; rsinfo->setDesc = tupdesc;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -1656,9 +1656,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
tuple = heap_form_tuple(tupdesc, &result, &fcinfo.isnull); tuple = heap_form_tuple(tupdesc, &result, &fcinfo.isnull);
} }
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
MemoryContextSwitchTo(oldcontext);
/* /*
* Are we done? * Are we done?
...@@ -1710,6 +1708,7 @@ no_function_result: ...@@ -1710,6 +1708,7 @@ no_function_result:
memset(nullflags, true, natts * sizeof(bool)); memset(nullflags, true, natts * sizeof(bool));
tuple = heap_form_tuple(expectedDesc, nulldatums, nullflags); tuple = heap_form_tuple(expectedDesc, nulldatums, nullflags);
MemoryContextSwitchTo(econtext->ecxt_per_query_memory); MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
} }
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 ...@@ -95,11 +95,8 @@ static void
tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self) tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
{ {
TStoreState *myState = (TStoreState *) self; TStoreState *myState = (TStoreState *) self;
MemoryContext oldcxt = MemoryContextSwitchTo(myState->cxt);
tuplestore_puttupleslot(myState->tstore, slot); tuplestore_puttupleslot(myState->tstore, slot);
MemoryContextSwitchTo(oldcxt);
} }
/* /*
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -911,6 +911,9 @@ pg_cursor(PG_FUNCTION_ARGS)
*/ */
tupstore = tuplestore_begin_heap(true, false, work_mem); tupstore = tuplestore_begin_heap(true, false, work_mem);
/* generate junk in short-term context */
MemoryContextSwitchTo(oldcontext);
hash_seq_init(&hash_seq, PortalHashTable); hash_seq_init(&hash_seq, PortalHashTable);
while ((hentry = hash_seq_search(&hash_seq)) != NULL) while ((hentry = hash_seq_search(&hash_seq)) != NULL)
{ {
...@@ -923,9 +926,6 @@ pg_cursor(PG_FUNCTION_ARGS) ...@@ -923,9 +926,6 @@ pg_cursor(PG_FUNCTION_ARGS)
if (!portal->visible) if (!portal->visible)
continue; continue;
/* generate junk in short-term context */
MemoryContextSwitchTo(oldcontext);
MemSet(nulls, 0, sizeof(nulls)); MemSet(nulls, 0, sizeof(nulls));
values[0] = DirectFunctionCall1(textin, CStringGetDatum(portal->name)); values[0] = DirectFunctionCall1(textin, CStringGetDatum(portal->name));
...@@ -941,16 +941,12 @@ pg_cursor(PG_FUNCTION_ARGS) ...@@ -941,16 +941,12 @@ pg_cursor(PG_FUNCTION_ARGS)
tuple = heap_form_tuple(tupdesc, values, nulls); tuple = heap_form_tuple(tupdesc, values, nulls);
/* switch to appropriate context while storing the tuple */
MemoryContextSwitchTo(per_query_ctx);
tuplestore_puttuple(tupstore, tuple); tuplestore_puttuple(tupstore, tuple);
} }
/* clean up and return the tuplestore */ /* clean up and return the tuplestore */
tuplestore_donestoring(tupstore); tuplestore_donestoring(tupstore);
MemoryContextSwitchTo(oldcontext);
rsinfo->returnMode = SFRM_Materialize; rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore; rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc; rsinfo->setDesc = tupdesc;
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -50,6 +50,7 @@
#include "executor/executor.h" #include "executor/executor.h"
#include "storage/buffile.h" #include "storage/buffile.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/resowner.h"
#include "utils/tuplestore.h" #include "utils/tuplestore.h"
...@@ -74,6 +75,8 @@ struct Tuplestorestate ...@@ -74,6 +75,8 @@ struct Tuplestorestate
bool interXact; /* keep open through transactions? */ bool interXact; /* keep open through transactions? */
long availMem; /* remaining memory available, in bytes */ long availMem; /* remaining memory available, in bytes */
BufFile *myfile; /* underlying file, or NULL if none */ 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 * These function pointers decouple the routines that must know what kind
...@@ -225,6 +228,8 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes) ...@@ -225,6 +228,8 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
state->interXact = interXact; state->interXact = interXact;
state->availMem = maxKBytes * 1024L; state->availMem = maxKBytes * 1024L;
state->myfile = NULL; state->myfile = NULL;
state->context = CurrentMemoryContext;
state->resowner = CurrentResourceOwner;
state->memtupcount = 0; state->memtupcount = 0;
state->memtupsize = 1024; /* initial guess */ state->memtupsize = 1024; /* initial guess */
...@@ -250,9 +255,9 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes) ...@@ -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 * 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 * 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 * create such a tuplestore in a memory context and resource owner that will
* transaction boundaries, and to ensure the tuplestore is closed when it's * also survive transaction boundaries, and to ensure the tuplestore is closed
* no longer wanted. * when it's no longer wanted.
* *
* maxKBytes: how much data to store in memory (any data beyond this * maxKBytes: how much data to store in memory (any data beyond this
* amount is paged to disk). When in doubt, use work_mem. * amount is paged to disk). When in doubt, use work_mem.
...@@ -353,6 +358,7 @@ tuplestore_puttupleslot(Tuplestorestate *state, ...@@ -353,6 +358,7 @@ tuplestore_puttupleslot(Tuplestorestate *state,
TupleTableSlot *slot) TupleTableSlot *slot)
{ {
MinimalTuple tuple; MinimalTuple tuple;
MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
/* /*
* Form a MinimalTuple in working memory * Form a MinimalTuple in working memory
...@@ -361,6 +367,8 @@ tuplestore_puttupleslot(Tuplestorestate *state, ...@@ -361,6 +367,8 @@ tuplestore_puttupleslot(Tuplestorestate *state,
USEMEM(state, GetMemoryChunkSpace(tuple)); USEMEM(state, GetMemoryChunkSpace(tuple));
tuplestore_puttuple_common(state, (void *) tuple); tuplestore_puttuple_common(state, (void *) tuple);
MemoryContextSwitchTo(oldcxt);
} }
/* /*
...@@ -372,17 +380,23 @@ tuplestore_puttupleslot(Tuplestorestate *state, ...@@ -372,17 +380,23 @@ tuplestore_puttupleslot(Tuplestorestate *state,
void void
tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple) tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
{ {
MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
/* /*
* Copy the tuple. (Must do this even in WRITEFILE case.) * Copy the tuple. (Must do this even in WRITEFILE case.)
*/ */
tuple = COPYTUP(state, tuple); tuple = COPYTUP(state, tuple);
tuplestore_puttuple_common(state, (void *) tuple); tuplestore_puttuple_common(state, (void *) tuple);
MemoryContextSwitchTo(oldcxt);
} }
static void static void
tuplestore_puttuple_common(Tuplestorestate *state, void *tuple) tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
{ {
ResourceOwner oldowner;
switch (state->status) switch (state->status)
{ {
case TSS_INMEM: case TSS_INMEM:
...@@ -429,7 +443,15 @@ tuplestore_puttuple_common(Tuplestorestate *state, void *tuple) ...@@ -429,7 +443,15 @@ tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
* the temp file(s) are created in suitable temp tablespaces. * the temp file(s) are created in suitable temp tablespaces.
*/ */
PrepareTempTablespaces(); PrepareTempTablespaces();
/* associate the file with the store's resource owner */
oldowner = CurrentResourceOwner;
CurrentResourceOwner = state->resowner;
state->myfile = BufFileCreateTemp(state->interXact); state->myfile = BufFileCreateTemp(state->interXact);
CurrentResourceOwner = oldowner;
state->status = TSS_WRITEFILE; state->status = TSS_WRITEFILE;
dumptuples(state); dumptuples(state);
break; break;
......
/********************************************************************** /**********************************************************************
* plperl.c - perl as a procedural language for PostgreSQL * 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) ...@@ -1995,11 +1995,9 @@ plperl_return_next(SV *sv)
tuple = heap_form_tuple(current_call_data->ret_tdesc, &ret, &isNull); 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); tuplestore_puttuple(current_call_data->tuple_store, tuple);
MemoryContextSwitchTo(old_cxt);
MemoryContextSwitchTo(old_cxt);
MemoryContextReset(current_call_data->tmp_cxt); MemoryContextReset(current_call_data->tmp_cxt);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -2132,11 +2132,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
if (HeapTupleIsValid(tuple)) if (HeapTupleIsValid(tuple))
{ {
MemoryContext oldcxt;
oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
tuplestore_puttuple(estate->tuple_store, tuple); tuplestore_puttuple(estate->tuple_store, tuple);
MemoryContextSwitchTo(oldcxt);
if (free_tuple) if (free_tuple)
heap_freetuple(tuple); heap_freetuple(tuple);
...@@ -2174,21 +2170,18 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, ...@@ -2174,21 +2170,18 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
while (true) while (true)
{ {
MemoryContext old_cxt;
int i; int i;
SPI_cursor_fetch(portal, true, 50); SPI_cursor_fetch(portal, true, 50);
if (SPI_processed == 0) if (SPI_processed == 0)
break; break;
old_cxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
for (i = 0; i < SPI_processed; i++) for (i = 0; i < SPI_processed; i++)
{ {
HeapTuple tuple = SPI_tuptable->vals[i]; HeapTuple tuple = SPI_tuptable->vals[i];
tuplestore_puttuple(estate->tuple_store, tuple); tuplestore_puttuple(estate->tuple_store, tuple);
} }
MemoryContextSwitchTo(old_cxt);
SPI_freetuptable(SPI_tuptable); SPI_freetuptable(SPI_tuptable);
} }
...@@ -2204,6 +2197,7 @@ exec_init_tuple_store(PLpgSQL_execstate *estate) ...@@ -2204,6 +2197,7 @@ exec_init_tuple_store(PLpgSQL_execstate *estate)
{ {
ReturnSetInfo *rsi = estate->rsi; ReturnSetInfo *rsi = estate->rsi;
MemoryContext oldcxt; MemoryContext oldcxt;
ResourceOwner oldowner;
/* /*
* Check caller can handle a set result in the way we want * Check caller can handle a set result in the way we want
...@@ -2215,10 +2209,20 @@ exec_init_tuple_store(PLpgSQL_execstate *estate) ...@@ -2215,10 +2209,20 @@ exec_init_tuple_store(PLpgSQL_execstate *estate)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set"))); 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); oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
oldowner = CurrentResourceOwner;
CurrentResourceOwner = estate->tuple_store_owner;
estate->tuple_store = tuplestore_begin_heap(true, false, work_mem); estate->tuple_store = tuplestore_begin_heap(true, false, work_mem);
CurrentResourceOwner = oldowner;
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
estate->rettupdesc = rsi->expectedDesc; estate->rettupdesc = rsi->expectedDesc;
...@@ -2330,7 +2334,16 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate, ...@@ -2330,7 +2334,16 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
estate->exitlabel = NULL; estate->exitlabel = NULL;
estate->tuple_store = NULL; estate->tuple_store = 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_cxt = NULL;
estate->tuple_store_owner = NULL;
}
estate->rsi = rsi; estate->rsi = rsi;
estate->trig_nargs = 0; estate->trig_nargs = 0;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 ...@@ -622,6 +622,7 @@ typedef struct
Tuplestorestate *tuple_store; /* SRFs accumulate results here */ Tuplestorestate *tuple_store; /* SRFs accumulate results here */
MemoryContext tuple_store_cxt; MemoryContext tuple_store_cxt;
ResourceOwner tuple_store_owner;
ReturnSetInfo *rsi; ReturnSetInfo *rsi;
int trig_nargs; int trig_nargs;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册