From: | Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> |
---|---|
To: | Euler Taveira de Oliveira <eulerto(at)yahoo(dot)com(dot)br> |
Cc: | pgsql-bugs(at)postgresql(dot)org |
Subject: | Re: BUG #2166: attempted to update invisible tuple |
Date: | 2006-01-12 21:51:30 |
Message-ID: | 18756.1137102690@sss.pgh.pa.us |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-bugs |
I wrote:
> It looks to me like the correct test requires passing in the current
> command ID so we can check the tuple's cmax against it.
Er, cmin not cmax. Here's the patch against 8.1 if you need it.
regards, tom lane
Index: src/backend/commands/trigger.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/trigger.c,v
retrieving revision 1.195.2.1
diff -c -r1.195.2.1 trigger.c
*** src/backend/commands/trigger.c 22 Nov 2005 18:23:07 -0000 1.195.2.1
--- src/backend/commands/trigger.c 12 Jan 2006 21:10:09 -0000
***************
*** 1736,1742 ****
epqslot = EvalPlanQual(estate,
relinfo->ri_RangeTableIndex,
&update_ctid,
! update_xmax);
if (!TupIsNull(epqslot))
{
*tid = update_ctid;
--- 1736,1743 ----
epqslot = EvalPlanQual(estate,
relinfo->ri_RangeTableIndex,
&update_ctid,
! update_xmax,
! cid);
if (!TupIsNull(epqslot))
{
*tid = update_ctid;
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.256.2.4
diff -c -r1.256.2.4 execMain.c
*** src/backend/executor/execMain.c 22 Nov 2005 18:23:08 -0000 1.256.2.4
--- src/backend/executor/execMain.c 12 Jan 2006 21:10:09 -0000
***************
*** 1219,1225 ****
newSlot = EvalPlanQual(estate,
erm->rti,
&update_ctid,
! update_xmax);
if (!TupIsNull(newSlot))
{
slot = newSlot;
--- 1219,1226 ----
newSlot = EvalPlanQual(estate,
erm->rti,
&update_ctid,
! update_xmax,
! estate->es_snapshot->curcid);
if (!TupIsNull(newSlot))
{
slot = newSlot;
***************
*** 1527,1533 ****
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
! update_xmax);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
--- 1528,1535 ----
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
! update_xmax,
! estate->es_snapshot->curcid);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
***************
*** 1679,1685 ****
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
! update_xmax);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
--- 1681,1688 ----
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
! update_xmax,
! estate->es_snapshot->curcid);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
***************
*** 1826,1831 ****
--- 1829,1835 ----
* 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)
***************
*** 1835,1841 ****
*/
TupleTableSlot *
EvalPlanQual(EState *estate, Index rti,
! ItemPointer tid, TransactionId priorXmax)
{
evalPlanQual *epq;
EState *epqstate;
--- 1839,1845 ----
*/
TupleTableSlot *
EvalPlanQual(EState *estate, Index rti,
! ItemPointer tid, TransactionId priorXmax, CommandId curCid)
{
evalPlanQual *epq;
EState *epqstate;
***************
*** 1912,1917 ****
--- 1916,1939 ----
}
/*
+ * 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);
Index: src/include/executor/executor.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/executor/executor.h,v
retrieving revision 1.120.2.1
diff -c -r1.120.2.1 executor.h
*** src/include/executor/executor.h 23 Nov 2005 20:28:05 -0000 1.120.2.1
--- src/include/executor/executor.h 12 Jan 2006 21:10:10 -0000
***************
*** 98,104 ****
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
! ItemPointer tid, TransactionId priorXmax);
/*
* prototypes from functions in execProcnode.c
--- 98,104 ----
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
! ItemPointer tid, TransactionId priorXmax, CommandId curCid);
/*
* prototypes from functions in execProcnode.c
From | Date | Subject | |
---|---|---|---|
Next Message | Sunil Basu | 2006-01-13 04:39:34 | BUG #2167: Performance degradation |
Previous Message | Tom Lane | 2006-01-12 19:54:24 | Re: BUG #2166: attempted to update invisible tuple |