aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-11-15 19:43:47 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-11-15 19:43:47 +0000
commit0656ed3daa29b00c7c41ad44b407a7165f83d453 (patch)
tree2167bd78fa501c3ffed1d0de842ded643c32500b /src/backend/executor
parent07c179a82b39ffbc172175382717706d90c714cd (diff)
downloadpostgresql-0656ed3daa29b00c7c41ad44b407a7165f83d453.tar.gz
postgresql-0656ed3daa29b00c7c41ad44b407a7165f83d453.zip
Make SELECT FOR UPDATE/SHARE work on inheritance trees, by having the plan
return the tableoid as well as the ctid for any FOR UPDATE targets that have child tables. All child tables are listed in the ExecRowMark list, but the executor just skips the ones that didn't produce the current row. Curiously, this longstanding restriction doesn't seem to have been documented anywhere; so no doc changes.
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c57
1 files changed, 49 insertions, 8 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 350381ad4b5..634ca69b4d1 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.315 2008/11/06 20:51:14 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.316 2008/11/15 19:43:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -590,18 +590,25 @@ InitPlan(QueryDesc *queryDesc, int eflags)
foreach(l, plannedstmt->rowMarks)
{
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
- Oid relid = getrelid(rc->rti, rangeTable);
+ Oid relid;
Relation relation;
ExecRowMark *erm;
+ /* ignore "parent" rowmarks; they are irrelevant at runtime */
+ if (rc->isParent)
+ continue;
+
+ relid = getrelid(rc->rti, rangeTable);
relation = heap_open(relid, RowShareLock);
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
erm->relation = relation;
erm->rti = rc->rti;
+ erm->prti = rc->prti;
erm->forUpdate = rc->forUpdate;
erm->noWait = rc->noWait;
- /* We'll set up ctidAttno below */
+ /* We'll locate the junk attrs below */
erm->ctidAttNo = InvalidAttrNumber;
+ erm->toidAttNo = InvalidAttrNumber;
estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
}
@@ -822,17 +829,29 @@ InitPlan(QueryDesc *queryDesc, int eflags)
elog(ERROR, "could not find junk ctid column");
}
- /* For SELECT FOR UPDATE/SHARE, find the ctid attrs now */
+ /* For SELECT FOR UPDATE/SHARE, find the junk attrs now */
foreach(l, estate->es_rowMarks)
{
ExecRowMark *erm = (ExecRowMark *) lfirst(l);
char resname[32];
- snprintf(resname, sizeof(resname), "ctid%u", erm->rti);
+ /* always need the ctid */
+ snprintf(resname, sizeof(resname), "ctid%u",
+ erm->prti);
erm->ctidAttNo = ExecFindJunkAttribute(j, resname);
if (!AttributeNumberIsValid(erm->ctidAttNo))
elog(ERROR, "could not find junk \"%s\" column",
resname);
+ /* if child relation, need tableoid too */
+ if (erm->rti != erm->prti)
+ {
+ snprintf(resname, sizeof(resname), "tableoid%u",
+ erm->prti);
+ erm->toidAttNo = ExecFindJunkAttribute(j, resname);
+ if (!AttributeNumberIsValid(erm->toidAttNo))
+ elog(ERROR, "could not find junk \"%s\" column",
+ resname);
+ }
}
}
}
@@ -1383,13 +1402,33 @@ lnext: ;
LockTupleMode lockmode;
HTSU_Result test;
+ /* if child rel, must check whether it produced this row */
+ if (erm->rti != erm->prti)
+ {
+ Oid tableoid;
+
+ datum = ExecGetJunkAttribute(slot,
+ erm->toidAttNo,
+ &isNull);
+ /* shouldn't ever get a null result... */
+ if (isNull)
+ elog(ERROR, "tableoid is NULL");
+ tableoid = DatumGetObjectId(datum);
+
+ if (tableoid != RelationGetRelid(erm->relation))
+ {
+ /* this child is inactive right now */
+ continue;
+ }
+ }
+
+ /* okay, fetch the tuple by ctid */
datum = ExecGetJunkAttribute(slot,
erm->ctidAttNo,
&isNull);
/* shouldn't ever get a null result... */
if (isNull)
elog(ERROR, "ctid is NULL");
-
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
if (erm->forUpdate)
@@ -2122,9 +2161,11 @@ EvalPlanQual(EState *estate, Index rti,
relation = NULL;
foreach(l, estate->es_rowMarks)
{
- if (((ExecRowMark *) lfirst(l))->rti == rti)
+ ExecRowMark *erm = lfirst(l);
+
+ if (erm->rti == rti)
{
- relation = ((ExecRowMark *) lfirst(l))->relation;
+ relation = erm->relation;
break;
}
}