Commit a4155d3b authored by Tom Lane's avatar Tom Lane

EvalPlanQual was thoroughly broken for concurrent update/delete on inheritance

trees (mostly my fault).  Repair.  Also fix long-standing bug in ExecReplace:
after recomputing a concurrently updated tuple, we must recheck constraints.
Make EvalPlanQual leak memory with somewhat less enthusiasm than before,
although plugging leaks fully will require more changes than I care to risk
in a dot-release.
parent e6113488
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.41 2001/05/08 19:47:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.42 2001/05/15 00:33:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
static bool exec_append_initialize_next(Append *node); static bool exec_append_initialize_next(Append *node);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* exec_append_initialize_next * exec_append_initialize_next
* *
...@@ -79,7 +80,6 @@ exec_append_initialize_next(Append *node) ...@@ -79,7 +80,6 @@ exec_append_initialize_next(Append *node)
EState *estate; EState *estate;
AppendState *appendstate; AppendState *appendstate;
int whichplan; int whichplan;
int nplans;
/* /*
* get information from the append node * get information from the append node
...@@ -87,9 +87,8 @@ exec_append_initialize_next(Append *node) ...@@ -87,9 +87,8 @@ exec_append_initialize_next(Append *node)
estate = node->plan.state; estate = node->plan.state;
appendstate = node->appendstate; appendstate = node->appendstate;
whichplan = appendstate->as_whichplan; whichplan = appendstate->as_whichplan;
nplans = appendstate->as_nplans;
if (whichplan < 0) if (whichplan < appendstate->as_firstplan)
{ {
/* /*
...@@ -98,17 +97,17 @@ exec_append_initialize_next(Append *node) ...@@ -98,17 +97,17 @@ exec_append_initialize_next(Append *node)
* ExecProcAppend that we are at the end of the line by returning * ExecProcAppend that we are at the end of the line by returning
* FALSE * FALSE
*/ */
appendstate->as_whichplan = 0; appendstate->as_whichplan = appendstate->as_firstplan;
return FALSE; return FALSE;
} }
else if (whichplan >= nplans) else if (whichplan > appendstate->as_lastplan)
{ {
/* /*
* as above, end the scan if we go beyond the last scan in our * as above, end the scan if we go beyond the last scan in our
* list.. * list..
*/ */
appendstate->as_whichplan = nplans - 1; appendstate->as_whichplan = appendstate->as_lastplan;
return FALSE; return FALSE;
} }
else else
...@@ -145,7 +144,9 @@ exec_append_initialize_next(Append *node) ...@@ -145,7 +144,9 @@ exec_append_initialize_next(Append *node)
* structures get allocated in the executor's top level memory * structures get allocated in the executor's top level memory
* block instead of that of the call to ExecProcAppend.) * block instead of that of the call to ExecProcAppend.)
* *
* Returns the scan result of the first scan. * Special case: during an EvalPlanQual recheck query of an inherited
* target relation, we only want to initialize and scan the single
* subplan that corresponds to the target relation being checked.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
bool bool
...@@ -175,12 +176,32 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent) ...@@ -175,12 +176,32 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
* create new AppendState for our append node * create new AppendState for our append node
*/ */
appendstate = makeNode(AppendState); appendstate = makeNode(AppendState);
appendstate->as_whichplan = 0;
appendstate->as_nplans = nplans; appendstate->as_nplans = nplans;
appendstate->as_initialized = initialized; appendstate->as_initialized = initialized;
node->appendstate = appendstate; node->appendstate = appendstate;
/*
* Do we want to scan just one subplan? (Special case for EvalPlanQual)
* XXX pretty dirty way of determining that this case applies ...
*/
if (node->isTarget && estate->es_evTuple != NULL)
{
int tplan;
tplan = estate->es_result_relation_info - estate->es_result_relations;
Assert(tplan >= 0 && tplan < nplans);
appendstate->as_firstplan = tplan;
appendstate->as_lastplan = tplan;
}
else
{
/* normal case, scan all subplans */
appendstate->as_firstplan = 0;
appendstate->as_lastplan = nplans - 1;
}
/* /*
* Miscellaneous initialization * Miscellaneous initialization
* *
...@@ -197,10 +218,10 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent) ...@@ -197,10 +218,10 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
ExecInitResultTupleSlot(estate, &appendstate->cstate); ExecInitResultTupleSlot(estate, &appendstate->cstate);
/* /*
* call ExecInitNode on each of the plans in our list and save the * call ExecInitNode on each of the plans to be executed and save the
* results into the array "initialized" * results into the array "initialized"
*/ */
for (i = 0; i < nplans; i++) for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
{ {
appendstate->as_whichplan = i; appendstate->as_whichplan = i;
exec_append_initialize_next(node); exec_append_initialize_next(node);
...@@ -218,7 +239,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent) ...@@ -218,7 +239,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
/* /*
* return the result from the first subplan's initialization * return the result from the first subplan's initialization
*/ */
appendstate->as_whichplan = 0; appendstate->as_whichplan = appendstate->as_firstplan;
exec_append_initialize_next(node); exec_append_initialize_next(node);
return TRUE; return TRUE;
...@@ -357,10 +378,9 @@ void ...@@ -357,10 +378,9 @@ void
ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent) ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
{ {
AppendState *appendstate = node->appendstate; AppendState *appendstate = node->appendstate;
int nplans = length(node->appendplans);
int i; int i;
for (i = 0; i < nplans; i++) for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
{ {
Plan *subnode; Plan *subnode;
...@@ -383,6 +403,6 @@ ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent) ...@@ -383,6 +403,6 @@ ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
ExecReScan(subnode, exprCtxt, (Plan *) node); ExecReScan(subnode, exprCtxt, (Plan *) node);
} }
} }
appendstate->as_whichplan = 0; appendstate->as_whichplan = appendstate->as_firstplan;
exec_append_initialize_next(node); exec_append_initialize_next(node);
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execnodes.h,v 1.58 2001/05/07 00:43:25 tgl Exp $ * $Id: execnodes.h,v 1.59 2001/05/15 00:33:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -353,6 +353,8 @@ typedef struct ResultState ...@@ -353,6 +353,8 @@ typedef struct ResultState
* AppendState information * AppendState information
* *
* whichplan which plan is being executed (0 .. n-1) * whichplan which plan is being executed (0 .. n-1)
* firstplan first plan to execute (usually 0)
* lastplan last plan to execute (usually n-1)
* nplans how many plans are in the list * nplans how many plans are in the list
* initialized array of ExecInitNode() results * initialized array of ExecInitNode() results
* ---------------- * ----------------
...@@ -361,6 +363,8 @@ typedef struct AppendState ...@@ -361,6 +363,8 @@ typedef struct AppendState
{ {
CommonState cstate; /* its first field is NodeTag */ CommonState cstate; /* its first field is NodeTag */
int as_whichplan; int as_whichplan;
int as_firstplan;
int as_lastplan;
int as_nplans; int as_nplans;
bool *as_initialized; bool *as_initialized;
} AppendState; } AppendState;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment