diff options
author | Tom Lane | 2007-10-24 18:37:09 +0000 |
---|---|---|
committer | Tom Lane | 2007-10-24 18:37:09 +0000 |
commit | c29a9c37bf6bdaaaa65ccbcd4c69c596691134e1 (patch) | |
tree | c7df7fd2c22d5007ff6901800714d93bc4ce8a4c /src/backend/executor/nodeTidscan.c | |
parent | 9226ba817b19999d51d39a0a2bde810160d0cf24 (diff) |
Fix UPDATE/DELETE WHERE CURRENT OF to support repeated update and update-
then-delete on the current cursor row. The basic fix is that nodeTidscan.c
has to apply heap_get_latest_tid() to the current-scan-TID obtained from the
cursor query; this ensures we get the latest row version to work with.
However, since that only works if the query plan is a TID scan, we also have
to hack the planner to make sure only that type of plan will be selected.
(Formerly, the planner might decide to apply a seqscan if the table is very
small. This change is probably a Good Thing anyway, since it's hard to see
how a seqscan could really win.) That means the execQual.c code to support
CurrentOfExpr as a regular expression type is dead code, so replace it with
just an elog(). Also, add regression tests covering these cases. Note
that the added tests expose the fact that re-fetching an updated row
misbehaves if the cursor used FOR UPDATE. That's an independent bug that
should be fixed later. Per report from Dharmendra Goyal.
Diffstat (limited to 'src/backend/executor/nodeTidscan.c')
-rw-r--r-- | src/backend/executor/nodeTidscan.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 31a9828b6a1..8c217a442be 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.55 2007/06/11 22:22:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.56 2007/10/24 18:37:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -68,6 +68,7 @@ TidListCreate(TidScanState *tidstate) tidList = (ItemPointerData *) palloc(numAllocTids * sizeof(ItemPointerData)); numTids = 0; + tidstate->tss_isCurrentOf = false; foreach(l, evalList) { @@ -165,6 +166,7 @@ TidListCreate(TidScanState *tidstate) numAllocTids * sizeof(ItemPointerData)); } tidList[numTids++] = cursor_tid; + tidstate->tss_isCurrentOf = true; } } else @@ -182,6 +184,9 @@ TidListCreate(TidScanState *tidstate) int lastTid; int i; + /* CurrentOfExpr could never appear OR'd with something else */ + Assert(!tidstate->tss_isCurrentOf); + qsort((void *) tidList, numTids, sizeof(ItemPointerData), itemptr_comparator); lastTid = 0; @@ -269,7 +274,8 @@ TidNext(TidScanState *node) /* * XXX shouldn't we check here to make sure tuple matches TID list? In - * runtime-key case this is not certain, is it? + * runtime-key case this is not certain, is it? However, in the + * WHERE CURRENT OF case it might not match anyway ... */ ExecStoreTuple(estate->es_evTuple[scanrelid - 1], @@ -319,6 +325,15 @@ TidNext(TidScanState *node) while (node->tss_TidPtr >= 0 && node->tss_TidPtr < numTids) { tuple->t_self = tidList[node->tss_TidPtr]; + + /* + * For WHERE CURRENT OF, the tuple retrieved from the cursor might + * since have been updated; if so, we should fetch the version that + * is current according to our snapshot. + */ + if (node->tss_isCurrentOf) + heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self); + if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL)) { /* |