mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
Move the handling of SELECT FOR UPDATE locking and rechecking out of
execMain.c and into a new plan node type LockRows. Like the recent change to put table updating into a ModifyTable plan node, this increases planning flexibility by allowing the operations to occur below the top level of the plan tree. It's necessary in any case to restore the previous behavior of having FOR UPDATE locking occur before ModifyTable does. This partially refactors EvalPlanQual to allow multiple rows-under-test to be inserted into the EPQ machinery before starting an EPQ test query. That isn't sufficient to fix EPQ's general bogosity in the face of plans that return multiple rows per test row, though. Since this patch is mostly about getting some plan node infrastructure in place and not about fixing ten-year-old bugs, I will leave EPQ improvements for another day. Another behavioral change that we could now think about is doing FOR UPDATE before LIMIT, but that too seems like it should be treated as a followon patch.
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.151 2009/10/10 01:43:49 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.152 2009/10/12 18:10:48 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -166,12 +166,14 @@ static bool extract_query_dependencies_walker(Node *node,
|
||||
* glob: global data for planner run
|
||||
* plan: the topmost node of the plan
|
||||
* rtable: the rangetable for the current subquery
|
||||
* rowmarks: the RowMarkClause list for the current subquery
|
||||
*
|
||||
* The return value is normally the same Plan node passed in, but can be
|
||||
* different when the passed-in Plan is a SubqueryScan we decide isn't needed.
|
||||
*
|
||||
* The flattened rangetable entries are appended to glob->finalrtable, and
|
||||
* plan dependencies are appended to glob->relationOids (for relations)
|
||||
* The flattened rangetable entries are appended to glob->finalrtable,
|
||||
* and we also append rowmarks entries to glob->finalrowmarks.
|
||||
* Plan dependencies are appended to glob->relationOids (for relations)
|
||||
* and glob->invalItems (for everything else).
|
||||
*
|
||||
* Notice that we modify Plan nodes in-place, but use expression_tree_mutator
|
||||
@ -180,7 +182,8 @@ static bool extract_query_dependencies_walker(Node *node,
|
||||
* it's not so safe to assume that for expression tree nodes.
|
||||
*/
|
||||
Plan *
|
||||
set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable)
|
||||
set_plan_references(PlannerGlobal *glob, Plan *plan,
|
||||
List *rtable, List *rowmarks)
|
||||
{
|
||||
int rtoffset = list_length(glob->finalrtable);
|
||||
ListCell *lc;
|
||||
@ -230,6 +233,26 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable)
|
||||
newrte->relid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust RT indexes of RowMarkClauses and add to final rowmarks list
|
||||
*/
|
||||
foreach(lc, rowmarks)
|
||||
{
|
||||
RowMarkClause *rc = (RowMarkClause *) lfirst(lc);
|
||||
RowMarkClause *newrc;
|
||||
|
||||
/* flat copy to duplicate all the scalar fields */
|
||||
newrc = (RowMarkClause *) palloc(sizeof(RowMarkClause));
|
||||
memcpy(newrc, rc, sizeof(RowMarkClause));
|
||||
|
||||
/* adjust indexes */
|
||||
newrc->rti += rtoffset;
|
||||
newrc->prti += rtoffset;
|
||||
/* rowmarkId must NOT be adjusted */
|
||||
|
||||
glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
|
||||
}
|
||||
|
||||
/* Now fix the Plan tree */
|
||||
return set_plan_refs(glob, plan, rtoffset);
|
||||
}
|
||||
@ -396,6 +419,27 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
|
||||
*/
|
||||
Assert(plan->qual == NIL);
|
||||
break;
|
||||
case T_LockRows:
|
||||
{
|
||||
LockRows *splan = (LockRows *) plan;
|
||||
|
||||
/*
|
||||
* Like the plan types above, LockRows doesn't evaluate its
|
||||
* tlist or quals. But we have to fix up the RT indexes
|
||||
* in its rowmarks.
|
||||
*/
|
||||
set_dummy_tlist_references(plan, rtoffset);
|
||||
Assert(splan->plan.qual == NIL);
|
||||
|
||||
foreach(l, splan->rowMarks)
|
||||
{
|
||||
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
||||
|
||||
rc->rti += rtoffset;
|
||||
rc->prti += rtoffset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_Limit:
|
||||
{
|
||||
Limit *splan = (Limit *) plan;
|
||||
@ -553,10 +597,12 @@ set_subqueryscan_references(PlannerGlobal *glob,
|
||||
Plan *result;
|
||||
|
||||
/* First, recursively process the subplan */
|
||||
plan->subplan = set_plan_references(glob, plan->subplan, plan->subrtable);
|
||||
plan->subplan = set_plan_references(glob, plan->subplan,
|
||||
plan->subrtable, plan->subrowmark);
|
||||
|
||||
/* subrtable is no longer needed in the plan tree */
|
||||
/* subrtable/subrowmark are no longer needed in the plan tree */
|
||||
plan->subrtable = NIL;
|
||||
plan->subrowmark = NIL;
|
||||
|
||||
if (trivial_subqueryscan(plan))
|
||||
{
|
||||
|
Reference in New Issue
Block a user