diff options
Diffstat (limited to 'src/backend/optimizer')
| -rw-r--r-- | src/backend/optimizer/path/allpaths.c | 7 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 35 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 54 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 58 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/subselect.c | 17 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/preptlist.c | 27 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 7 | ||||
| -rw-r--r-- | src/backend/optimizer/util/relnode.c | 4 |
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; |
