diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-11-15 19:43:47 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-11-15 19:43:47 +0000 |
commit | 0656ed3daa29b00c7c41ad44b407a7165f83d453 (patch) | |
tree | 2167bd78fa501c3ffed1d0de842ded643c32500b /src/backend/executor | |
parent | 07c179a82b39ffbc172175382717706d90c714cd (diff) | |
download | postgresql-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.c | 57 |
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; } } |