aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-01-12 21:49:19 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-01-12 21:49:19 +0000
commite26b09618b98358d951eb37e48df2ab6f8cb5489 (patch)
tree1590c06dce692cb37a6e4b6bb7c125156427dab2
parent01e2a15adac9e437ac16fd0a6aef427f4eb78aad (diff)
downloadpostgresql-e26b09618b98358d951eb37e48df2ab6f8cb5489.tar.gz
postgresql-e26b09618b98358d951eb37e48df2ab6f8cb5489.zip
Repair "Halloween problem" in EvalPlanQual: a tuple that's been inserted by
our own command (or more generally, xmin = our xact and cmin >= current command ID) should not be seen as good. Else we may try to update rows we already updated. This error was inserted last August while fixing the even bigger problem that the old coding wouldn't see *any* tuples inserted by our own transaction as good. Per report from Euler Taveira de Oliveira.
-rw-r--r--src/backend/commands/trigger.c5
-rw-r--r--src/backend/executor/execMain.c32
-rw-r--r--src/include/executor/executor.h4
3 files changed, 32 insertions, 9 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index ec998aa7b9f..a6b75f06d58 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.177.4.2 2005/08/25 19:44:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.177.4.3 2006/01/12 21:49:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1603,7 +1603,8 @@ ltrmark:;
epqslot = EvalPlanQual(estate,
relinfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax);
+ update_xmax,
+ cid);
if (!TupIsNull(epqslot))
{
*tid = update_ctid;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index a825c281618..3a86d311629 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.241.4.1 2005/08/25 19:45:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.241.4.2 2006/01/12 21:49:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1159,7 +1159,8 @@ lnext: ;
newSlot = EvalPlanQual(estate,
erm->rti,
&update_ctid,
- update_xmax);
+ update_xmax,
+ estate->es_snapshot->curcid);
if (!TupIsNull(newSlot))
{
slot = newSlot;
@@ -1470,7 +1471,8 @@ ldelete:;
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax);
+ update_xmax,
+ estate->es_snapshot->curcid);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
@@ -1615,7 +1617,8 @@ lreplace:;
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax);
+ update_xmax,
+ estate->es_snapshot->curcid);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
@@ -1770,6 +1773,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
* rti - rangetable index of table containing tuple
* *tid - t_ctid from the outdated tuple (ie, next updated version)
* priorXmax - t_xmax from the outdated tuple
+ * curCid - command ID of current command of my transaction
*
* *tid is also an output parameter: it's modified to hold the TID of the
* latest version of the tuple (note this may be changed even on failure)
@@ -1779,7 +1783,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
*/
TupleTableSlot *
EvalPlanQual(EState *estate, Index rti,
- ItemPointer tid, TransactionId priorXmax)
+ ItemPointer tid, TransactionId priorXmax, CommandId curCid)
{
evalPlanQual *epq;
EState *epqstate;
@@ -1856,6 +1860,24 @@ EvalPlanQual(EState *estate, Index rti,
}
/*
+ * If tuple was inserted by our own transaction, we have to check
+ * cmin against curCid: cmin >= curCid means our command cannot
+ * see the tuple, so we should ignore it. Without this we are
+ * open to the "Halloween problem" of indefinitely re-updating
+ * the same tuple. (We need not check cmax because
+ * HeapTupleSatisfiesDirty will consider a tuple deleted by
+ * our transaction dead, regardless of cmax.) We just checked
+ * that priorXmax == xmin, so we can test that variable instead
+ * of doing HeapTupleHeaderGetXmin again.
+ */
+ if (TransactionIdIsCurrentTransactionId(priorXmax) &&
+ HeapTupleHeaderGetCmin(tuple.t_data) >= curCid)
+ {
+ ReleaseBuffer(buffer);
+ return NULL;
+ }
+
+ /*
* We got tuple - now copy it for use by recheck query.
*/
copyTuple = heap_copytuple(&tuple);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 6c7eff0d46d..77f7310d5ea 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.115.4.1 2005/08/25 19:45:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.115.4.2 2006/01/12 21:49:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -109,7 +109,7 @@ extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
- ItemPointer tid, TransactionId priorXmax);
+ ItemPointer tid, TransactionId priorXmax, CommandId curCid);
/*
* prototypes from functions in execProcnode.c