*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.154 2003/08/04 02:39:57 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.155 2003/09/15 23:33:38 tgl Exp $
*
*
* INTERFACE ROUTINES
*
* NB: do not call this directly unless you are prepared to deal with
* concurrent-update conditions. Use simple_heap_delete instead.
+ *
+ * Normal, successful return value is HeapTupleMayBeUpdated, which
+ * actually means we did delete it. Failure return codes are
+ * HeapTupleSelfUpdated, HeapTupleUpdated, or HeapTupleBeingUpdated
+ * (the last only possible if wait == false).
*/
int
heap_delete(Relation relation, ItemPointer tid,
- ItemPointer ctid, CommandId cid)
+ ItemPointer ctid, CommandId cid, bool wait)
{
ItemId lp;
HeapTupleData tp;
ReleaseBuffer(buffer);
elog(ERROR, "attempted to delete invisible tuple");
}
- else if (result == HeapTupleBeingUpdated)
+ else if (result == HeapTupleBeingUpdated && wait)
{
TransactionId xwait = HeapTupleHeaderGetXmax(tp.t_data);
}
if (result != HeapTupleMayBeUpdated)
{
- Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
+ Assert(result == HeapTupleSelfUpdated ||
+ result == HeapTupleUpdated ||
+ result == HeapTupleBeingUpdated);
*ctid = tp.t_data->t_ctid;
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
ItemPointerData ctid;
int result;
- result = heap_delete(relation, tid, &ctid, GetCurrentCommandId());
+ result = heap_delete(relation, tid,
+ &ctid,
+ GetCurrentCommandId(),
+ true /* wait for commit */);
switch (result)
{
case HeapTupleSelfUpdated:
*
* NB: do not call this directly unless you are prepared to deal with
* concurrent-update conditions. Use simple_heap_update instead.
+ *
+ * Normal, successful return value is HeapTupleMayBeUpdated, which
+ * actually means we *did* update it. Failure return codes are
+ * HeapTupleSelfUpdated, HeapTupleUpdated, or HeapTupleBeingUpdated
+ * (the last only possible if wait == false).
*/
int
heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
- ItemPointer ctid, CommandId cid)
+ ItemPointer ctid, CommandId cid, bool wait)
{
ItemId lp;
HeapTupleData oldtup;
ReleaseBuffer(buffer);
elog(ERROR, "attempted to update invisible tuple");
}
- else if (result == HeapTupleBeingUpdated)
+ else if (result == HeapTupleBeingUpdated && wait)
{
TransactionId xwait = HeapTupleHeaderGetXmax(oldtup.t_data);
}
if (result != HeapTupleMayBeUpdated)
{
- Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
+ Assert(result == HeapTupleSelfUpdated ||
+ result == HeapTupleUpdated ||
+ result == HeapTupleBeingUpdated);
*ctid = oldtup.t_data->t_ctid;
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
ItemPointerData ctid;
int result;
- result = heap_update(relation, otid, tup, &ctid, GetCurrentCommandId());
+ result = heap_update(relation, otid, tup,
+ &ctid,
+ GetCurrentCommandId(),
+ true /* wait for commit */);
switch (result)
{
case HeapTupleSelfUpdated:
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.99 2003/09/15 00:26:31 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.100 2003/09/15 23:33:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
else if (listener->notification == 0)
{
+ ItemPointerData ctid;
+ int result;
+
rTuple = heap_modifytuple(lTuple, lRel,
value, nulls, repl);
- simple_heap_update(lRel, &lTuple->t_self, rTuple);
+ /*
+ * We cannot use simple_heap_update here because the tuple
+ * could have been modified by an uncommitted transaction;
+ * specifically, since UNLISTEN releases exclusive lock on
+ * the table before commit, the other guy could already have
+ * tried to unlisten. There are no other cases where we
+ * should be able to see an uncommitted update or delete.
+ * Therefore, our response to a HeapTupleBeingUpdated result
+ * is just to ignore it. We do *not* wait for the other
+ * guy to commit --- that would risk deadlock, and we don't
+ * want to block while holding the table lock anyway for
+ * performance reasons. We also ignore HeapTupleUpdated,
+ * which could occur if the other guy commits between our
+ * heap_getnext and heap_update calls.
+ */
+ result = heap_update(lRel, &lTuple->t_self, rTuple,
+ &ctid,
+ GetCurrentCommandId(),
+ false /* no wait for commit */);
+ switch (result)
+ {
+ case HeapTupleSelfUpdated:
+ /* Tuple was already updated in current command? */
+ elog(ERROR, "tuple already updated by self");
+ break;
+
+ case HeapTupleMayBeUpdated:
+ /* done successfully */
#ifdef NOT_USED /* currently there are no indexes */
- CatalogUpdateIndexes(lRel, rTuple);
+ CatalogUpdateIndexes(lRel, rTuple);
#endif
+ break;
+
+ case HeapTupleBeingUpdated:
+ /* ignore uncommitted tuples */
+ break;
+
+ case HeapTupleUpdated:
+ /* ignore just-committed tuples */
+ break;
+
+ default:
+ elog(ERROR, "unrecognized heap_update status: %u",
+ result);
+ break;
+ }
}
}
}
relname, (int) sourcePID);
NotifyMyFrontEnd(relname, sourcePID);
- /* Rewrite the tuple with 0 in notification column */
+ /*
+ * Rewrite the tuple with 0 in notification column.
+ *
+ * simple_heap_update is safe here because no one else would
+ * have tried to UNLISTEN us, so there can be no uncommitted
+ * changes.
+ */
rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl);
simple_heap_update(lRel, &lTuple->t_self, rTuple);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.216 2003/08/08 21:41:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.217 2003/09/15 23:33:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
ldelete:;
result = heap_delete(resultRelationDesc, tupleid,
&ctid,
- estate->es_snapshot->curcid);
+ estate->es_snapshot->curcid,
+ true /* wait for commit */);
switch (result)
{
case HeapTupleSelfUpdated:
*/
result = heap_update(resultRelationDesc, tupleid, tuple,
&ctid,
- estate->es_snapshot->curcid);
+ estate->es_snapshot->curcid,
+ true /* wait for commit */);
switch (result)
{
case HeapTupleSelfUpdated:
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: heapam.h,v 1.83 2003/08/04 02:40:10 momjian Exp $
+ * $Id: heapam.h,v 1.84 2003/09/15 23:33:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid);
extern int heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid,
- CommandId cid);
+ CommandId cid, bool wait);
extern int heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
- ItemPointer ctid, CommandId cid);
+ ItemPointer ctid, CommandId cid, bool wait);
extern int heap_mark4update(Relation relation, HeapTuple tup,
Buffer *userbuf, CommandId cid);