summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/prep/preptlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/prep/preptlist.c')
-rw-r--r--src/backend/optimizer/prep/preptlist.c107
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;
+}