mirror of
https://github.com/postgres/postgres.git
synced 2025-06-11 20:28:21 +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/execQual.c,v 1.222 2007/09/06 17:31:58 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.223 2007/10/24 18:37:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -3694,45 +3694,17 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEvalCurrentOfExpr
|
||||
*
|
||||
* Normally, the planner will convert CURRENT OF into a TidScan qualification,
|
||||
* but we have plain execQual support in case it doesn't.
|
||||
* The planner must convert CURRENT OF into a TidScan qualification.
|
||||
* So, we have to be able to do ExecInitExpr on a CurrentOfExpr,
|
||||
* but we shouldn't ever actually execute it.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone)
|
||||
{
|
||||
CurrentOfExpr *cexpr = (CurrentOfExpr *) exprstate->expr;
|
||||
bool result;
|
||||
bool lisnull;
|
||||
Oid tableoid;
|
||||
ItemPointer tuple_tid;
|
||||
ItemPointerData cursor_tid;
|
||||
|
||||
if (isDone)
|
||||
*isDone = ExprSingleResult;
|
||||
*isNull = false;
|
||||
|
||||
Assert(cexpr->cvarno != INNER);
|
||||
Assert(cexpr->cvarno != OUTER);
|
||||
Assert(!TupIsNull(econtext->ecxt_scantuple));
|
||||
/* Use slot_getattr to catch any possible mistakes */
|
||||
tableoid = DatumGetObjectId(slot_getattr(econtext->ecxt_scantuple,
|
||||
TableOidAttributeNumber,
|
||||
&lisnull));
|
||||
Assert(!lisnull);
|
||||
tuple_tid = (ItemPointer)
|
||||
DatumGetPointer(slot_getattr(econtext->ecxt_scantuple,
|
||||
SelfItemPointerAttributeNumber,
|
||||
&lisnull));
|
||||
Assert(!lisnull);
|
||||
|
||||
if (execCurrentOf(cexpr, econtext, tableoid, &cursor_tid))
|
||||
result = ItemPointerEquals(&cursor_tid, tuple_tid);
|
||||
else
|
||||
result = false;
|
||||
|
||||
return BoolGetDatum(result);
|
||||
elog(ERROR, "CURRENT OF cannot be executed");
|
||||
return 0; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user