summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/allpaths.c7
-rw-r--r--src/backend/optimizer/plan/createplan.c35
-rw-r--r--src/backend/optimizer/plan/planner.c54
-rw-r--r--src/backend/optimizer/plan/setrefs.c58
-rw-r--r--src/backend/optimizer/plan/subselect.c17
-rw-r--r--src/backend/optimizer/prep/preptlist.c27
-rw-r--r--src/backend/optimizer/prep/prepunion.c7
-rw-r--r--src/backend/optimizer/util/relnode.c4
8 files changed, 166 insertions, 43 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 5b7f0ff0e3..f6fffec902 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.186 2009/09/17 20:49:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.187 2009/10/12 18:10:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -632,6 +632,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
false, tuple_fraction,
&subroot);
rel->subrtable = subroot->parse->rtable;
+ rel->subrowmark = subroot->parse->rowMarks;
/* Copy number of output rows from subplan */
rel->tuples = rel->subplan->plan_rows;
@@ -971,10 +972,10 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
* since that could change the set of rows returned.
*
* 2. If the subquery contains any window functions, we can't push quals
- * into it, because that would change the results.
+ * into it, because that could change the results.
*
* 3. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push
- * quals into it, because that would change the results.
+ * quals into it, because that could change the results.
*
* 4. For subqueries using UNION/UNION ALL/INTERSECT/INTERSECT ALL, we can
* push quals into each component query, but the quals can only reference
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index b29b076591..1452bdd035 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.264 2009/10/10 01:43:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.265 2009/10/12 18:10:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1336,7 +1336,8 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
scan_clauses,
scan_relid,
best_path->parent->subplan,
- best_path->parent->subrtable);
+ best_path->parent->subrtable,
+ best_path->parent->subrowmark);
copy_path_costsize(&scan_plan->scan.plan, best_path);
@@ -2508,7 +2509,8 @@ make_subqueryscan(List *qptlist,
List *qpqual,
Index scanrelid,
Plan *subplan,
- List *subrtable)
+ List *subrtable,
+ List *subrowmark)
{
SubqueryScan *node = makeNode(SubqueryScan);
Plan *plan = &node->scan.plan;
@@ -2528,6 +2530,7 @@ make_subqueryscan(List *qptlist,
node->scan.scanrelid = scanrelid;
node->subplan = subplan;
node->subrtable = subrtable;
+ node->subrowmark = subrowmark;
return node;
}
@@ -3591,6 +3594,31 @@ make_setop(SetOpCmd cmd, SetOpStrategy strategy, Plan *lefttree,
}
/*
+ * make_lockrows
+ * Build a LockRows plan node
+ */
+LockRows *
+make_lockrows(Plan *lefttree, List *rowMarks)
+{
+ LockRows *node = makeNode(LockRows);
+ Plan *plan = &node->plan;
+
+ copy_plan_costsize(plan, lefttree);
+
+ /* charge cpu_tuple_cost to reflect locking costs (underestimate?) */
+ plan->total_cost += cpu_tuple_cost * plan->plan_rows;
+
+ plan->targetlist = lefttree->targetlist;
+ plan->qual = NIL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+
+ node->rowMarks = rowMarks;
+
+ return node;
+}
+
+/*
* Note: offset_est and count_est are passed in to save having to repeat
* work already done to estimate the values of the limitOffset and limitCount
* expressions. Their values are as returned by preprocess_limit (0 means
@@ -3792,6 +3820,7 @@ is_projection_capable_plan(Plan *plan)
case T_Sort:
case T_Unique:
case T_SetOp:
+ case T_LockRows:
case T_Limit:
case T_ModifyTable:
case T_Append:
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 4b06c823b6..c17fe5f63f 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.258 2009/10/10 01:43:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.259 2009/10/12 18:10:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -132,7 +132,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *root;
Plan *top_plan;
ListCell *lp,
- *lr;
+ *lrt,
+ *lrm;
/* Cursor options may come from caller or from DECLARE CURSOR stmt */
if (parse->utilityStmt &&
@@ -151,11 +152,14 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
glob->paramlist = NIL;
glob->subplans = NIL;
glob->subrtables = NIL;
+ glob->subrowmarks = NIL;
glob->rewindPlanIDs = NULL;
glob->finalrtable = NIL;
+ glob->finalrowmarks = NIL;
glob->relationOids = NIL;
glob->invalItems = NIL;
glob->lastPHId = 0;
+ glob->lastRowmarkId = 0;
glob->transientPlan = false;
/* Determine what fraction of the plan is likely to be scanned */
@@ -202,15 +206,25 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
/* final cleanup of the plan */
Assert(glob->finalrtable == NIL);
- top_plan = set_plan_references(glob, top_plan, root->parse->rtable);
+ Assert(glob->finalrowmarks == NIL);
+ top_plan = set_plan_references(glob, top_plan,
+ root->parse->rtable,
+ root->parse->rowMarks);
/* ... and the subplans (both regular subplans and initplans) */
Assert(list_length(glob->subplans) == list_length(glob->subrtables));
- forboth(lp, glob->subplans, lr, glob->subrtables)
+ Assert(list_length(glob->subplans) == list_length(glob->subrowmarks));
+ lrt = list_head(glob->subrtables);
+ lrm = list_head(glob->subrowmarks);
+ foreach(lp, glob->subplans)
{
Plan *subplan = (Plan *) lfirst(lp);
- List *subrtable = (List *) lfirst(lr);
+ List *subrtable = (List *) lfirst(lrt);
+ List *subrowmark = (List *) lfirst(lrm);
- lfirst(lp) = set_plan_references(glob, subplan, subrtable);
+ lfirst(lp) = set_plan_references(glob, subplan,
+ subrtable, subrowmark);
+ lrt = lnext(lrt);
+ lrm = lnext(lrm);
}
/* build the PlannedStmt result */
@@ -227,7 +241,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->intoClause = parse->intoClause;
result->subplans = glob->subplans;
result->rewindPlanIDs = glob->rewindPlanIDs;
- result->rowMarks = parse->rowMarks;
+ result->rowMarks = glob->finalrowmarks;
result->relationOids = glob->relationOids;
result->invalItems = glob->invalItems;
result->nParamExec = list_length(glob->paramlist);
@@ -350,6 +364,21 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
}
/*
+ * Assign unique IDs (unique within this planner run) to RowMarkClauses.
+ * We can't identify them just by RT index because that will change
+ * during final rtable flattening, and we don't want to have to go back
+ * and change the resnames assigned to junk CTID tlist entries at that
+ * point. Do it now before expanding inheritance sets, because child
+ * relations should inherit their parents' rowmarkId.
+ */
+ foreach(l, parse->rowMarks)
+ {
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+
+ rc->rowmarkId = ++(root->glob->lastRowmarkId);
+ }
+
+ /*
* Expand any rangetable entries that are inheritance sets into "append
* relations". This can add entries to the rangetable, but they must be
* plain base relations not joins, so it's OK (and marginally more
@@ -1588,7 +1617,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
}
/*
- * Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node.
+ * If there is a LIMIT/OFFSET clause, add the LIMIT node.
*/
if (parse->limitCount || parse->limitOffset)
{
@@ -1599,6 +1628,15 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
count_est);
}
+ /*
+ * Finally, if there is a FOR UPDATE/SHARE clause, add the LockRows node.
+ */
+ if (parse->rowMarks)
+ {
+ result_plan = (Plan *) make_lockrows(result_plan,
+ parse->rowMarks);
+ }
+
/* Compute result-relations list if needed */
if (parse->resultRelation)
root->resultRelations = list_make1_int(parse->resultRelation);
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 9b10b381ac..20d40841ef 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -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))
{
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 6a813106d1..7b0dd75e7f 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.154 2009/10/10 01:43:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.155 2009/10/12 18:10:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,7 +53,8 @@ typedef struct finalize_primnode_context
} finalize_primnode_context;
-static Node *build_subplan(PlannerInfo *root, Plan *plan, List *rtable,
+static Node *build_subplan(PlannerInfo *root, Plan *plan,
+ List *rtable, List *rowmarks,
SubLinkType subLinkType, Node *testexpr,
bool adjust_testexpr, bool unknownEqFalse);
static List *generate_subquery_params(PlannerInfo *root, List *tlist,
@@ -333,7 +334,8 @@ make_subplan(PlannerInfo *root, Query *orig_subquery, SubLinkType subLinkType,
&subroot);
/* And convert to SubPlan or InitPlan format. */
- result = build_subplan(root, plan, subroot->parse->rtable,
+ result = build_subplan(root, plan,
+ subroot->parse->rtable, subroot->parse->rowMarks,
subLinkType, testexpr, true, isTopQual);
/*
@@ -375,6 +377,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery, SubLinkType subLinkType,
/* OK, convert to SubPlan format. */
hashplan = (SubPlan *) build_subplan(root, plan,
subroot->parse->rtable,
+ subroot->parse->rowMarks,
ANY_SUBLINK, newtestexpr,
false, true);
/* Check we got what we expected */
@@ -402,7 +405,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery, SubLinkType subLinkType,
* as explained in the comments for make_subplan.
*/
static Node *
-build_subplan(PlannerInfo *root, Plan *plan, List *rtable,
+build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks,
SubLinkType subLinkType, Node *testexpr,
bool adjust_testexpr, bool unknownEqFalse)
{
@@ -585,6 +588,7 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable,
*/
root->glob->subplans = lappend(root->glob->subplans, plan);
root->glob->subrtables = lappend(root->glob->subrtables, rtable);
+ root->glob->subrowmarks = lappend(root->glob->subrowmarks, rowmarks);
splan->plan_id = list_length(root->glob->subplans);
if (isInitPlan)
@@ -944,6 +948,8 @@ SS_process_ctes(PlannerInfo *root)
root->glob->subplans = lappend(root->glob->subplans, plan);
root->glob->subrtables = lappend(root->glob->subrtables,
subroot->parse->rtable);
+ root->glob->subrowmarks = lappend(root->glob->subrowmarks,
+ subroot->parse->rowMarks);
splan->plan_id = list_length(root->glob->subplans);
root->init_plans = lappend(root->init_plans, splan);
@@ -2035,6 +2041,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params)
case T_Unique:
case T_SetOp:
case T_Group:
+ case T_LockRows:
break;
default:
@@ -2191,6 +2198,8 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
plan);
root->glob->subrtables = lappend(root->glob->subrtables,
root->parse->rtable);
+ root->glob->subrowmarks = lappend(root->glob->subrowmarks,
+ root->parse->rowMarks);
/*
* Create a SubPlan node and add it to the outer list of InitPlans. Note
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 73a158e5d8..0e6010aefa 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -16,7 +16,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.96 2009/04/19 19:46:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.97 2009/10/12 18:10:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -123,25 +123,20 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
*/
CheckSelectLocking(parse);
- /*
- * Currently the executor only supports FOR UPDATE/SHARE at top level
- */
- if (root->query_level > 1)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed in subqueries")));
-
foreach(l, parse->rowMarks)
{
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
Var *var;
- char *resname;
+ char resname[32];
TargetEntry *tle;
/* ignore child rels */
if (rc->rti != rc->prti)
continue;
+ /* we should have an ID for the RowMarkClause */
+ Assert(rc->rowmarkId != 0);
+
/* always need the ctid */
var = makeVar(rc->rti,
SelfItemPointerAttributeNumber,
@@ -149,12 +144,12 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
-1,
0);
- resname = (char *) palloc(32);
- snprintf(resname, 32, "ctid%u", rc->rti);
+ snprintf(resname, sizeof(resname),
+ "ctid%u", rc->rowmarkId);
tle = makeTargetEntry((Expr *) var,
list_length(tlist) + 1,
- resname,
+ pstrdup(resname),
true);
tlist = lappend(tlist, tle);
@@ -168,12 +163,12 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
-1,
0);
- resname = (char *) palloc(32);
- snprintf(resname, 32, "tableoid%u", rc->rti);
+ snprintf(resname, sizeof(resname),
+ "tableoid%u", rc->rowmarkId);
tle = makeTargetEntry((Expr *) var,
list_length(tlist) + 1,
- resname,
+ pstrdup(resname),
true);
tlist = lappend(tlist, tle);
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 7e6e1fbdcb..2f43e32738 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.175 2009/10/10 01:43:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.176 2009/10/12 18:10:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -247,7 +247,8 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
NIL,
rtr->rtindex,
subplan,
- subroot->parse->rtable);
+ subroot->parse->rtable,
+ subroot->parse->rowMarks);
/*
* We don't bother to determine the subquery's output ordering since
@@ -1281,6 +1282,8 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrc->rti = childRTindex;
newrc->prti = rti;
+ /* children use the same rowmarkId as their parent */
+ newrc->rowmarkId = oldrc->rowmarkId;
newrc->forUpdate = oldrc->forUpdate;
newrc->noWait = oldrc->noWait;
newrc->isParent = false;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 4ca3eeaaf2..5850594933 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.94 2009/06/11 14:48:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.95 2009/10/12 18:10:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -84,6 +84,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->tuples = 0;
rel->subplan = NULL;
rel->subrtable = NIL;
+ rel->subrowmark = NIL;
rel->baserestrictinfo = NIL;
rel->baserestrictcost.startup = 0;
rel->baserestrictcost.per_tuple = 0;
@@ -337,6 +338,7 @@ build_join_rel(PlannerInfo *root,
joinrel->tuples = 0;
joinrel->subplan = NULL;
joinrel->subrtable = NIL;
+ joinrel->subrowmark = NIL;
joinrel->baserestrictinfo = NIL;
joinrel->baserestrictcost.startup = 0;
joinrel->baserestrictcost.per_tuple = 0;