1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Fix possible failures when a tuplestore switches from in-memory to on-disk

mode while callers hold pointers to in-memory tuples.  I reported this for
the case of nodeWindowAgg's primary scan tuple, but inspection of the code
shows that all of the calls in nodeWindowAgg and nodeCtescan are at risk.
For the moment, fix it with a rather brute-force approach of copying
whenever one of the at-risk callers requests a tuple.  Later we might
think of some sort of reference-count approach to reduce tuple copying.
This commit is contained in:
Tom Lane
2009-03-27 18:30:21 +00:00
parent a95307b639
commit 25bf7f8b9b
10 changed files with 53 additions and 25 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.242 2009/03/26 22:26:06 petere Exp $
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.243 2009/03/27 18:30:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1385,7 +1385,7 @@ restart:
if (fcache->funcResultStore)
{
Assert(isDone); /* it was provided before ... */
if (tuplestore_gettupleslot(fcache->funcResultStore, true,
if (tuplestore_gettupleslot(fcache->funcResultStore, true, false,
fcache->funcResultSlot))
{
*isDone = ExprMultipleResult;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.132 2009/01/02 20:42:00 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.133 2009/03/27 18:30:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -736,7 +736,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
/* Re-use the junkfilter's output slot to fetch back the tuple */
Assert(fcache->junkFilter);
slot = fcache->junkFilter->jf_resultSlot;
if (!tuplestore_gettupleslot(fcache->tstore, true, slot))
if (!tuplestore_gettupleslot(fcache->tstore, true, false, slot))
elog(ERROR, "failed to fetch lazy-eval tuple");
/* Extract the result as a datum, and copy out from the slot */
result = postquel_get_single_result(slot, fcinfo,
@ -822,7 +822,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
{
/* Re-use the junkfilter's output slot to fetch back the tuple */
slot = fcache->junkFilter->jf_resultSlot;
if (tuplestore_gettupleslot(fcache->tstore, true, slot))
if (tuplestore_gettupleslot(fcache->tstore, true, false, slot))
result = postquel_get_single_result(slot, fcinfo,
fcache, oldcontext);
else

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeCtescan.c,v 1.3 2009/01/01 17:23:41 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeCtescan.c,v 1.4 2009/03/27 18:30:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -71,10 +71,14 @@ CteScanNext(CteScanState *node)
/*
* If we can fetch another tuple from the tuplestore, return it.
*
* Note: we have to use copy=true in the tuplestore_gettupleslot call,
* because we are sharing the tuplestore with other nodes that might
* write into the tuplestore before we get called again.
*/
if (!eof_tuplestore)
{
if (tuplestore_gettupleslot(tuplestorestate, forward, slot))
if (tuplestore_gettupleslot(tuplestorestate, forward, true, slot))
return slot;
if (forward)
eof_tuplestore = true;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.50 2009/01/01 17:23:41 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.51 2009/03/27 18:30:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -74,6 +74,7 @@ FunctionNext(FunctionScanState *node)
slot = node->ss.ss_ScanTupleSlot;
(void) tuplestore_gettupleslot(tuplestorestate,
ScanDirectionIsForward(direction),
false,
slot);
return slot;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.65 2009/01/01 17:23:42 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.66 2009/03/27 18:30:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -104,7 +104,7 @@ ExecMaterial(MaterialState *node)
slot = node->ss.ps.ps_ResultTupleSlot;
if (!eof_tuplestore)
{
if (tuplestore_gettupleslot(tuplestorestate, forward, slot))
if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
return slot;
if (forward)
eof_tuplestore = true;

View 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.3 2009/01/01 17:23:42 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeWindowAgg.c,v 1.4 2009/03/27 18:30:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -480,7 +480,8 @@ eval_windowaggregates(WindowAggState *winstate)
spool_tuples(winstate, winstate->aggregatedupto);
tuplestore_select_read_pointer(winstate->buffer,
winstate->agg_ptr);
if (!tuplestore_gettupleslot(winstate->buffer, true, agg_row_slot))
if (!tuplestore_gettupleslot(winstate->buffer, true, true,
agg_row_slot))
break; /* must be end of partition */
}
@ -1001,12 +1002,14 @@ restart:
/*
* Read the current row from the tuplestore, and save in ScanTupleSlot.
* (We can't rely on the outerplan's output slot because we may have to
* read beyond the current row.)
* read beyond the current row. Also, we have to actually copy the row
* out of the tuplestore, since window function evaluation might cause
* the tuplestore to dump its state to disk.)
*
* Current row must be in the tuplestore, since we spooled it above.
*/
tuplestore_select_read_pointer(winstate->buffer, winstate->current_ptr);
if (!tuplestore_gettupleslot(winstate->buffer, true,
if (!tuplestore_gettupleslot(winstate->buffer, true, true,
winstate->ss.ss_ScanTupleSlot))
elog(ERROR, "unexpected end of tuplestore");
@ -1589,14 +1592,14 @@ window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
while (winobj->seekpos > pos)
{
if (!tuplestore_gettupleslot(winstate->buffer, false, slot))
if (!tuplestore_gettupleslot(winstate->buffer, false, true, slot))
elog(ERROR, "unexpected end of tuplestore");
winobj->seekpos--;
}
while (winobj->seekpos < pos)
{
if (!tuplestore_gettupleslot(winstate->buffer, true, slot))
if (!tuplestore_gettupleslot(winstate->buffer, true, true, slot))
elog(ERROR, "unexpected end of tuplestore");
winobj->seekpos++;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.5 2009/01/01 17:23:42 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.6 2009/03/27 18:30:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -43,6 +43,10 @@ WorkTableScanNext(WorkTableScanState *node)
* worktable plan node, since it cannot appear high enough in the plan
* tree of a scrollable cursor to be exposed to a backward-scan
* requirement. So it's not worth expending effort to support it.
*
* Note: we are also assuming that this node is the only reader of the
* worktable. Therefore, we don't need a private read pointer for the
* tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
*/
estate = node->ss.ps.state;
Assert(ScanDirectionIsForward(estate->es_direction));
@ -53,7 +57,7 @@ WorkTableScanNext(WorkTableScanState *node)
* Get the next tuple from tuplestore. Return NULL if no more tuples.
*/
slot = node->ss.ss_ScanTupleSlot;
(void) tuplestore_gettupleslot(tuplestorestate, true, slot);
(void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
return slot;
}