1
0
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:
Tom Lane
2007-10-24 18:37:09 +00:00
parent 9226ba817b
commit c29a9c37bf
6 changed files with 225 additions and 43 deletions

View File

@ -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 */
}