]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/execMain.c
Repair "Halloween problem" in EvalPlanQual: a tuple that's been inserted by
[postgresql] / src / backend / executor / execMain.c
index 1f70b2704adf1b2071e0e611bb8e5faa42f72873..a0f9cfedd3f17d7f042e73382d3c01f886ba8d34 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.264 2006/01/11 08:43:12 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.265 2006/01/12 21:48:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1213,7 +1213,8 @@ lnext:    ;
                                                                newSlot = EvalPlanQual(estate,
                                                                                                           erm->rti,
                                                                                                           &update_ctid,
-                                                                                                          update_xmax);
+                                                                                                          update_xmax,
+                                                                                                          estate->es_snapshot->curcid);
                                                                if (!TupIsNull(newSlot))
                                                                {
                                                                        slot = newSlot;
@@ -1521,7 +1522,8 @@ ldelete:;
                                epqslot = EvalPlanQual(estate,
                                                                           resultRelInfo->ri_RangeTableIndex,
                                                                           &update_ctid,
-                                                                          update_xmax);
+                                                                          update_xmax,
+                                                                          estate->es_snapshot->curcid);
                                if (!TupIsNull(epqslot))
                                {
                                        *tupleid = update_ctid;
@@ -1673,7 +1675,8 @@ lreplace:;
                                epqslot = EvalPlanQual(estate,
                                                                           resultRelInfo->ri_RangeTableIndex,
                                                                           &update_ctid,
-                                                                          update_xmax);
+                                                                          update_xmax,
+                                                                          estate->es_snapshot->curcid);
                                if (!TupIsNull(epqslot))
                                {
                                        *tupleid = update_ctid;
@@ -1820,6 +1823,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)
@@ -1829,7 +1833,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
  */
 TupleTableSlot *
 EvalPlanQual(EState *estate, Index rti,
-                        ItemPointer tid, TransactionId priorXmax)
+                        ItemPointer tid, TransactionId priorXmax, CommandId curCid)
 {
        evalPlanQual *epq;
        EState     *epqstate;
@@ -1905,6 +1909,24 @@ EvalPlanQual(EState *estate, Index rti,
                                continue;               /* loop back to repeat heap_fetch */
                        }
 
+                       /*
+                        * 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.
                         */