diff options
Diffstat (limited to 'src/backend/optimizer/prep/preptlist.c')
| -rw-r--r-- | src/backend/optimizer/prep/preptlist.c | 107 |
1 files changed, 69 insertions, 38 deletions
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 0e6010aefa..d17671462c 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -9,14 +9,15 @@ * relation in the correct order. For both UPDATE and DELETE queries, * we need a junk targetlist entry holding the CTID attribute --- the * executor relies on this to find the tuple to be replaced/deleted. - * We may also need junk tlist entries for Vars used in the RETURNING list. + * We may also need junk tlist entries for Vars used in the RETURNING list + * and row ID information needed for EvalPlanQual checking. * * * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.97 2009/10/12 18:10:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.98 2009/10/26 02:26:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,7 +32,6 @@ #include "optimizer/subselect.h" #include "optimizer/tlist.h" #include "optimizer/var.h" -#include "parser/analyze.h" #include "parser/parsetree.h" #include "parser/parse_coerce.h" #include "utils/rel.h" @@ -54,6 +54,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) int result_relation = parse->resultRelation; List *range_table = parse->rtable; CmdType command_type = parse->commandType; + ListCell *lc; /* * Sanity check: if there is a result relation, it'd better be a real @@ -108,51 +109,47 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) } /* - * Add TID targets for rels selected FOR UPDATE/SHARE. The executor uses - * the TID to know which rows to lock, much as for UPDATE or DELETE. + * Add necessary junk columns for rowmarked rels. These values are + * needed for locking of rels selected FOR UPDATE/SHARE, and to do + * EvalPlanQual rechecking. While we are at it, store these junk attnos + * in the PlanRowMark list so that we don't have to redetermine them + * at runtime. */ - if (parse->rowMarks) + foreach(lc, root->rowMarks) { - ListCell *l; - - /* - * We've got trouble if the FOR UPDATE/SHARE appears inside grouping, - * since grouping renders a reference to individual tuple CTIDs - * invalid. This is also checked at parse time, but that's - * insufficient because of rule substitution, query pullup, etc. - */ - CheckSelectLocking(parse); + PlanRowMark *rc = (PlanRowMark *) lfirst(lc); + Var *var; + char resname[32]; + TargetEntry *tle; - foreach(l, parse->rowMarks) + /* child rels should just use the same junk attrs as their parents */ + if (rc->rti != rc->prti) { - RowMarkClause *rc = (RowMarkClause *) lfirst(l); - Var *var; - 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); + PlanRowMark *prc = get_plan_rowmark(root->rowMarks, rc->prti); + + /* parent should have appeared earlier in list */ + if (prc == NULL || prc->toidAttNo == InvalidAttrNumber) + elog(ERROR, "parent PlanRowMark not processed yet"); + rc->ctidAttNo = prc->ctidAttNo; + rc->toidAttNo = prc->toidAttNo; + continue; + } - /* always need the ctid */ + if (rc->markType != ROW_MARK_COPY) + { + /* It's a regular table, so fetch its TID */ var = makeVar(rc->rti, SelfItemPointerAttributeNumber, TIDOID, -1, 0); - - snprintf(resname, sizeof(resname), - "ctid%u", rc->rowmarkId); - + snprintf(resname, sizeof(resname), "ctid%u", rc->rti); tle = makeTargetEntry((Expr *) var, list_length(tlist) + 1, pstrdup(resname), true); - tlist = lappend(tlist, tle); + rc->ctidAttNo = tle->resno; /* if parent of inheritance tree, need the tableoid too */ if (rc->isParent) @@ -162,18 +159,31 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) OIDOID, -1, 0); - - snprintf(resname, sizeof(resname), - "tableoid%u", rc->rowmarkId); - + snprintf(resname, sizeof(resname), "tableoid%u", rc->rti); tle = makeTargetEntry((Expr *) var, list_length(tlist) + 1, pstrdup(resname), true); - tlist = lappend(tlist, tle); + rc->toidAttNo = tle->resno; } } + else + { + /* Not a table, so we need the whole row as a junk var */ + var = makeVar(rc->rti, + InvalidAttrNumber, + RECORDOID, + -1, + 0); + snprintf(resname, sizeof(resname), "wholerow%u", rc->rti); + tle = makeTargetEntry((Expr *) var, + list_length(tlist) + 1, + pstrdup(resname), + true); + tlist = lappend(tlist, tle); + rc->wholeAttNo = tle->resno; + } } /* @@ -394,3 +404,24 @@ expand_targetlist(List *tlist, int command_type, return new_tlist; } + + +/* + * Locate PlanRowMark for given RT index, or return NULL if none + * + * This probably ought to be elsewhere, but there's no very good place + */ +PlanRowMark * +get_plan_rowmark(List *rowmarks, Index rtindex) +{ + ListCell *l; + + foreach(l, rowmarks) + { + PlanRowMark *rc = (PlanRowMark *) lfirst(l); + + if (rc->rti == rtindex) + return rc; + } + return NULL; +} |
