mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
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.
This commit is contained in:
@ -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))
|
||||
{
|
||||
/*
|
||||
|
Reference in New Issue
Block a user