aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/pgrowlocks/pgrowlocks.c7
-rw-r--r--src/backend/access/heap/heapam.c8
-rw-r--r--src/backend/access/heap/tuptoaster.c4
-rw-r--r--src/backend/access/transam/xact.c67
-rw-r--r--src/backend/commands/async.c5
-rw-r--r--src/backend/commands/copy.c6
-rw-r--r--src/backend/commands/explain.c4
-rw-r--r--src/backend/commands/trigger.c29
-rw-r--r--src/backend/executor/execMain.c65
-rw-r--r--src/backend/executor/execUtils.c4
-rw-r--r--src/backend/executor/spi.c4
-rw-r--r--src/backend/storage/ipc/procarray.c4
-rw-r--r--src/backend/utils/cache/inval.c15
-rw-r--r--src/backend/utils/time/tqual.c8
-rw-r--r--src/include/access/xact.h4
-rw-r--r--src/include/commands/trigger.h8
-rw-r--r--src/include/executor/executor.h4
-rw-r--r--src/include/nodes/execnodes.h5
-rw-r--r--src/test/regress/expected/combocid.out178
-rw-r--r--src/test/regress/sql/combocid.sql40
20 files changed, 217 insertions, 252 deletions
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index aaa132fbc47..fb19983bf86 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -1,5 +1,5 @@
/*
- * $PostgreSQL: pgsql/contrib/pgrowlocks/pgrowlocks.c,v 1.7 2007/08/28 22:59:30 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/pgrowlocks/pgrowlocks.c,v 1.8 2007/11/30 21:22:53 tgl Exp $
*
* Copyright (c) 2005-2006 Tatsuo Ishii
*
@@ -117,8 +117,9 @@ pgrowlocks(PG_FUNCTION_ARGS)
/* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
- if (HeapTupleSatisfiesUpdate(tuple->t_data, GetCurrentCommandId(), scan->rs_cbuf)
- == HeapTupleBeingUpdated)
+ if (HeapTupleSatisfiesUpdate(tuple->t_data,
+ GetCurrentCommandId(false),
+ scan->rs_cbuf) == HeapTupleBeingUpdated)
{
char **values;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 20027592b50..1a4fc92f1c2 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.245 2007/11/15 21:14:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.246 2007/11/30 21:22:53 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1891,7 +1891,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
Oid
simple_heap_insert(Relation relation, HeapTuple tup)
{
- return heap_insert(relation, tup, GetCurrentCommandId(), true, true);
+ return heap_insert(relation, tup, GetCurrentCommandId(true), true, true);
}
/*
@@ -2174,7 +2174,7 @@ simple_heap_delete(Relation relation, ItemPointer tid)
result = heap_delete(relation, tid,
&update_ctid, &update_xmax,
- GetCurrentCommandId(), InvalidSnapshot,
+ GetCurrentCommandId(true), InvalidSnapshot,
true /* wait for commit */ );
switch (result)
{
@@ -2817,7 +2817,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
result = heap_update(relation, otid, tup,
&update_ctid, &update_xmax,
- GetCurrentCommandId(), InvalidSnapshot,
+ GetCurrentCommandId(true), InvalidSnapshot,
true /* wait for commit */ );
switch (result)
{
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index 0a8873f9945..f26fa9f4a6b 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.79 2007/11/15 21:14:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.80 2007/11/30 21:22:53 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1086,7 +1086,7 @@ toast_save_datum(Relation rel, Datum value,
TupleDesc toasttupDesc;
Datum t_values[3];
bool t_isnull[3];
- CommandId mycid = GetCurrentCommandId();
+ CommandId mycid = GetCurrentCommandId(true);
struct varlena *result;
struct varatt_external toast_pointer;
struct
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 04804c38711..ce0dd812819 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.253 2007/11/15 21:14:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.254 2007/11/30 21:22:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -161,6 +161,7 @@ static TransactionState CurrentTransactionState = &TopTransactionStateData;
*/
static SubTransactionId currentSubTransactionId;
static CommandId currentCommandId;
+static bool currentCommandIdUsed;
/*
* xactStartTimestamp is the value of transaction_timestamp().
@@ -435,11 +436,18 @@ GetCurrentSubTransactionId(void)
/*
* GetCurrentCommandId
+ *
+ * "used" must be TRUE if the caller intends to use the command ID to mark
+ * inserted/updated/deleted tuples. FALSE means the ID is being fetched
+ * for read-only purposes (ie, as a snapshot validity cutoff). See
+ * CommandCounterIncrement() for discussion.
*/
CommandId
-GetCurrentCommandId(void)
+GetCurrentCommandId(bool used)
{
/* this is global to a transaction, not subtransaction-local */
+ if (used)
+ currentCommandIdUsed = true;
return currentCommandId;
}
@@ -566,25 +574,50 @@ TransactionIdIsCurrentTransactionId(TransactionId xid)
void
CommandCounterIncrement(void)
{
- currentCommandId += 1;
- if (currentCommandId == FirstCommandId) /* check for overflow */
+ /*
+ * If the current value of the command counter hasn't been "used" to
+ * mark tuples, we need not increment it, since there's no need to
+ * distinguish a read-only command from others. This helps postpone
+ * command counter overflow, and keeps no-op CommandCounterIncrement
+ * operations cheap.
+ */
+ if (currentCommandIdUsed)
{
- currentCommandId -= 1;
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ currentCommandId += 1;
+ if (currentCommandId == FirstCommandId) /* check for overflow */
+ {
+ currentCommandId -= 1;
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("cannot have more than 2^32-1 commands in a transaction")));
- }
+ }
+ currentCommandIdUsed = false;
- /* Propagate new command ID into static snapshots, if set */
- if (SerializableSnapshot)
- SerializableSnapshot->curcid = currentCommandId;
- if (LatestSnapshot)
- LatestSnapshot->curcid = currentCommandId;
+ /* Propagate new command ID into static snapshots, if set */
+ if (SerializableSnapshot)
+ SerializableSnapshot->curcid = currentCommandId;
+ if (LatestSnapshot)
+ LatestSnapshot->curcid = currentCommandId;
+
+ /*
+ * Make any catalog changes done by the just-completed command
+ * visible in the local syscache. We obviously don't need to do
+ * this after a read-only command. (But see hacks in inval.c
+ * to make real sure we don't think a command that queued inval
+ * messages was read-only.)
+ */
+ AtCommit_LocalCache();
+ }
/*
- * make cache changes visible to me.
+ * Make any other backends' catalog changes visible to me.
+ *
+ * XXX this is probably in the wrong place: CommandCounterIncrement
+ * should be purely a local operation, most likely. However fooling
+ * with this will affect asynchronous cross-backend interactions,
+ * which doesn't seem like a wise thing to do in late beta, so save
+ * improving this for another day - tgl 2007-11-30
*/
- AtCommit_LocalCache();
AtStart_Cache();
}
@@ -1416,6 +1449,7 @@ StartTransaction(void)
s->subTransactionId = TopSubTransactionId;
currentSubTransactionId = TopSubTransactionId;
currentCommandId = FirstCommandId;
+ currentCommandIdUsed = false;
/*
* must initialize resource-management stuff first
@@ -4007,13 +4041,14 @@ ShowTransactionStateRec(TransactionState s)
/* use ereport to suppress computation if msg will not be printed */
ereport(DEBUG3,
- (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u, nestlvl: %d, children: %s",
+ (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u%s, nestlvl: %d, children: %s",
PointerIsValid(s->name) ? s->name : "unnamed",
BlockStateAsString(s->blockState),
TransStateAsString(s->state),
(unsigned int) s->transactionId,
(unsigned int) s->subTransactionId,
(unsigned int) currentCommandId,
+ currentCommandIdUsed ? " (used)" : "",
s->nestingLevel,
nodeToString(s->childXids))));
}
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 55b99f8c922..c32dd2b19fc 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.136 2007/04/12 06:53:46 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.137 2007/11/30 21:22:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -562,7 +562,8 @@ AtCommit_Notify(void)
*/
result = heap_update(lRel, &lTuple->t_self, rTuple,
&update_ctid, &update_xmax,
- GetCurrentCommandId(), InvalidSnapshot,
+ GetCurrentCommandId(true),
+ InvalidSnapshot,
false /* no wait for commit */ );
switch (result)
{
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index ef7e04ca286..c68d828fea0 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.288 2007/11/15 21:14:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.289 2007/11/30 21:22:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1033,7 +1033,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
* which COPY can be invoked, I think it's OK, because the active
* snapshot shouldn't be shared with anything else anyway.)
*/
- ActiveSnapshot->curcid = GetCurrentCommandId();
+ ActiveSnapshot->curcid = GetCurrentCommandId(false);
/* Create dest receiver for COPY OUT */
dest = CreateDestReceiver(DestCopyOut, NULL);
@@ -1637,7 +1637,7 @@ CopyFrom(CopyState cstate)
ExprContext *econtext; /* used for ExecEvalExpr for default atts */
MemoryContext oldcontext = CurrentMemoryContext;
ErrorContextCallback errcontext;
- CommandId mycid = GetCurrentCommandId();
+ CommandId mycid = GetCurrentCommandId(true);
bool use_wal = true; /* by default, use WAL logging */
bool use_fsm = true; /* by default, use FSM for free space */
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index a9aa2cb3e13..f77f8cdc5ec 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.167 2007/11/15 22:25:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.168 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -233,7 +233,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
* EXPLAIN can be invoked, I think it's OK, because the active snapshot
* shouldn't be shared with anything else anyway.)
*/
- ActiveSnapshot->curcid = GetCurrentCommandId();
+ ActiveSnapshot->curcid = GetCurrentCommandId(false);
/* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(plannedstmt,
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 7dc19505342..1b66bd22ba8 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.224 2007/11/16 01:51:22 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.225 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -51,7 +51,6 @@ static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
static HeapTuple GetTupleForTrigger(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tid,
- CommandId cid,
TupleTableSlot **newSlot);
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
int tgindx,
@@ -1801,8 +1800,7 @@ ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
bool
ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
- ItemPointer tupleid,
- CommandId cid)
+ ItemPointer tupleid)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
@@ -1814,7 +1812,7 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *newSlot;
int i;
- trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, cid, &newSlot);
+ trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL)
return false;
@@ -1871,9 +1869,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
- tupleid,
- (CommandId) 0,
- NULL);
+ tupleid, NULL);
AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
true, trigtuple, NULL);
@@ -1952,8 +1948,7 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
HeapTuple
ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
- ItemPointer tupleid, HeapTuple newtuple,
- CommandId cid)
+ ItemPointer tupleid, HeapTuple newtuple)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
@@ -1965,7 +1960,7 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *newSlot;
int i;
- trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, cid, &newSlot);
+ trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL)
return NULL;
@@ -2025,9 +2020,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
- tupleid,
- (CommandId) 0,
- NULL);
+ tupleid, NULL);
AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
true, trigtuple, newtuple);
@@ -2038,7 +2031,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
static HeapTuple
GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
- ItemPointer tid, CommandId cid,
+ ItemPointer tid,
TupleTableSlot **newSlot)
{
Relation relation = relinfo->ri_RelationDesc;
@@ -2060,7 +2053,8 @@ GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
ltrmark:;
tuple.t_self = *tid;
test = heap_lock_tuple(relation, &tuple, &buffer,
- &update_ctid, &update_xmax, cid,
+ &update_ctid, &update_xmax,
+ estate->es_output_cid,
LockTupleExclusive, false);
switch (test)
{
@@ -2086,8 +2080,7 @@ ltrmark:;
epqslot = EvalPlanQual(estate,
relinfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax,
- cid);
+ update_xmax);
if (!TupIsNull(epqslot))
{
*tid = update_ctid;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 4b6ad47adb0..5886234a1e8 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.300 2007/11/15 22:25:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.301 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -161,6 +161,30 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData));
/*
+ * If non-read-only query, set the command ID to mark output tuples with
+ */
+ switch (queryDesc->operation)
+ {
+ case CMD_SELECT:
+ /* SELECT INTO and SELECT FOR UPDATE/SHARE need to mark tuples */
+ if (queryDesc->plannedstmt->intoClause != NULL ||
+ queryDesc->plannedstmt->rowMarks != NIL)
+ estate->es_output_cid = GetCurrentCommandId(true);
+ break;
+
+ case CMD_INSERT:
+ case CMD_DELETE:
+ case CMD_UPDATE:
+ estate->es_output_cid = GetCurrentCommandId(true);
+ break;
+
+ default:
+ elog(ERROR, "unrecognized operation code: %d",
+ (int) queryDesc->operation);
+ break;
+ }
+
+ /*
* Copy other important information into the EState
*/
estate->es_snapshot = queryDesc->snapshot;
@@ -1285,7 +1309,7 @@ lnext: ;
test = heap_lock_tuple(erm->relation, &tuple, &buffer,
&update_ctid, &update_xmax,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
lockmode, erm->noWait);
ReleaseBuffer(buffer);
switch (test)
@@ -1309,8 +1333,7 @@ lnext: ;
newSlot = EvalPlanQual(estate,
erm->rti,
&update_ctid,
- update_xmax,
- estate->es_snapshot->curcid);
+ update_xmax);
if (!TupIsNull(newSlot))
{
slot = planSlot = newSlot;
@@ -1503,7 +1526,7 @@ ExecInsert(TupleTableSlot *slot,
* t_self field.
*/
newId = heap_insert(resultRelationDesc, tuple,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
true, true);
IncrAppended();
@@ -1557,8 +1580,7 @@ ExecDelete(ItemPointer tupleid,
{
bool dodelete;
- dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid,
- estate->es_snapshot->curcid);
+ dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid);
if (!dodelete) /* "do nothing" */
return;
@@ -1575,7 +1597,7 @@ ExecDelete(ItemPointer tupleid,
ldelete:;
result = heap_delete(resultRelationDesc, tupleid,
&update_ctid, &update_xmax,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
estate->es_crosscheck_snapshot,
true /* wait for commit */ );
switch (result)
@@ -1599,8 +1621,7 @@ ldelete:;
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax,
- estate->es_snapshot->curcid);
+ update_xmax);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
@@ -1708,8 +1729,7 @@ ExecUpdate(TupleTableSlot *slot,
HeapTuple newtuple;
newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
- tupleid, tuple,
- estate->es_snapshot->curcid);
+ tupleid, tuple);
if (newtuple == NULL) /* "do nothing" */
return;
@@ -1755,7 +1775,7 @@ lreplace:;
*/
result = heap_update(resultRelationDesc, tupleid, tuple,
&update_ctid, &update_xmax,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
estate->es_crosscheck_snapshot,
true /* wait for commit */ );
switch (result)
@@ -1779,8 +1799,7 @@ lreplace:;
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax,
- estate->es_snapshot->curcid);
+ update_xmax);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
@@ -1973,7 +1992,6 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
* 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)
@@ -1983,7 +2001,7 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
*/
TupleTableSlot *
EvalPlanQual(EState *estate, Index rti,
- ItemPointer tid, TransactionId priorXmax, CommandId curCid)
+ ItemPointer tid, TransactionId priorXmax)
{
evalPlanQual *epq;
EState *epqstate;
@@ -2063,17 +2081,17 @@ 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
+ * cmin against es_output_cid: cmin >= current CID 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)
+ HeapTupleHeaderGetCmin(tuple.t_data) >= estate->es_output_cid)
{
ReleaseBuffer(buffer);
return NULL;
@@ -2360,6 +2378,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
epqstate->es_snapshot = estate->es_snapshot;
epqstate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
epqstate->es_range_table = estate->es_range_table;
+ epqstate->es_output_cid = estate->es_output_cid;
epqstate->es_result_relations = estate->es_result_relations;
epqstate->es_num_result_relations = estate->es_num_result_relations;
epqstate->es_result_relation_info = estate->es_result_relation_info;
@@ -2718,7 +2737,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self)
heap_insert(estate->es_into_relation_descriptor,
tuple,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
estate->es_into_relation_use_wal,
false); /* never any point in using FSM */
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 230d5c919f2..12ddc910f47 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.152 2007/11/15 21:14:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.153 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -178,6 +178,8 @@ CreateExecutorState(void)
estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
estate->es_range_table = NIL;
+ estate->es_output_cid = (CommandId) 0;
+
estate->es_result_relations = NULL;
estate->es_num_result_relations = 0;
estate->es_result_relation_info = NULL;
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index a5601ecdfca..e08e91cb0a0 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.185 2007/11/30 18:38:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.186 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1593,7 +1593,7 @@ _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
*/
ActiveSnapshot = CopySnapshot(snapshot);
if (!read_only)
- ActiveSnapshot->curcid = GetCurrentCommandId();
+ ActiveSnapshot->curcid = GetCurrentCommandId(false);
}
if (IsA(stmt, PlannedStmt) &&
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index d7c8d706fd9..156f947604e 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -23,7 +23,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.37 2007/11/15 21:14:38 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.38 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -814,7 +814,7 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
snapshot->xcnt = count;
snapshot->subxcnt = subcount;
- snapshot->curcid = GetCurrentCommandId();
+ snapshot->curcid = GetCurrentCommandId(false);
return snapshot;
}
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 844dbc2be06..803727f0840 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -80,7 +80,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.81 2007/11/15 21:14:39 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.82 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -403,6 +403,14 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId)
dbId, relId);
/*
+ * Most of the time, relcache invalidation is associated with system
+ * catalog updates, but there are a few cases where it isn't. Quick
+ * hack to ensure that the next CommandCounterIncrement() will think
+ * that we need to do CommandEndInvalidationMessages().
+ */
+ (void) GetCurrentCommandId(true);
+
+ /*
* If the relation being invalidated is one of those cached in the
* relcache init file, mark that we need to zap that file at commit.
*/
@@ -420,6 +428,11 @@ RegisterSmgrInvalidation(RelFileNode rnode)
{
AddSmgrInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
rnode);
+
+ /*
+ * As above, just in case there is not an associated catalog change.
+ */
+ (void) GetCurrentCommandId(true);
}
/*
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index 4c128e4446b..dad379573c2 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -31,7 +31,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.107 2007/11/15 21:14:41 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.108 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -382,7 +382,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
}
else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
{
- if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId())
+ if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId(false))
return false; /* inserted after scan started */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
@@ -401,7 +401,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
return true;
}
- if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
+ if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
return true; /* deleted after scan started */
else
return false; /* deleted before scan started */
@@ -443,7 +443,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
{
if (tuple->t_infomask & HEAP_IS_LOCKED)
return true;
- if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
+ if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
return true; /* deleted after scan started */
else
return false; /* deleted before scan started */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 8a311dda3ba..9a6fa607a0e 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.91 2007/11/15 21:14:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.92 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -143,7 +143,7 @@ extern TransactionId GetTopTransactionIdIfAny(void);
extern TransactionId GetCurrentTransactionId(void);
extern TransactionId GetCurrentTransactionIdIfAny(void);
extern SubTransactionId GetCurrentSubTransactionId(void);
-extern CommandId GetCurrentCommandId(void);
+extern CommandId GetCurrentCommandId(bool used);
extern TimestampTz GetCurrentTransactionStartTimestamp(void);
extern TimestampTz GetCurrentStatementStartTimestamp(void);
extern TimestampTz GetCurrentTransactionStopTimestamp(void);
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 69ad97b4ec8..5a1d50edf94 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.63 2007/11/15 21:14:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.64 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -124,8 +124,7 @@ extern void ExecASDeleteTriggers(EState *estate,
ResultRelInfo *relinfo);
extern bool ExecBRDeleteTriggers(EState *estate,
ResultRelInfo *relinfo,
- ItemPointer tupleid,
- CommandId cid);
+ ItemPointer tupleid);
extern void ExecARDeleteTriggers(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tupleid);
@@ -136,8 +135,7 @@ extern void ExecASUpdateTriggers(EState *estate,
extern HeapTuple ExecBRUpdateTriggers(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
- HeapTuple newtuple,
- CommandId cid);
+ HeapTuple newtuple);
extern void ExecARUpdateTriggers(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 08b97e3adfc..78a0a2560a3 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.144 2007/11/15 22:25:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.145 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -143,7 +143,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, CommandId curCid);
+ ItemPointer tid, TransactionId priorXmax);
extern PlanState *ExecGetActivePlanTree(QueryDesc *queryDesc);
extern DestReceiver *CreateIntoRelDestReceiver(void);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index ca0e9c8fa78..a140a7533d4 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.181 2007/11/15 22:25:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.182 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -311,6 +311,9 @@ typedef struct EState
Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */
List *es_range_table; /* List of RangeTblEntry */
+ /* If query can insert/delete tuples, the command ID to mark them with */
+ CommandId es_output_cid;
+
/* Info about target table for insert/update/delete queries: */
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
int es_num_result_relations; /* length of array */
diff --git a/src/test/regress/expected/combocid.out b/src/test/regress/expected/combocid.out
index 14e45fe4893..b63894c2837 100644
--- a/src/test/regress/expected/combocid.out
+++ b/src/test/regress/expected/combocid.out
@@ -4,66 +4,16 @@
CREATE TEMP TABLE combocidtest (foobar int);
BEGIN;
-- a few dummy ops to push up the CommandId counter
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest VALUES (1);
INSERT INTO combocidtest VALUES (2);
SELECT ctid,cmin,* FROM combocidtest;
@@ -79,8 +29,8 @@ UPDATE combocidtest SET foobar = foobar + 10;
SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar
-------+------+--------
- (0,3) | 13 | 11
- (0,4) | 13 | 12
+ (0,3) | 12 | 11
+ (0,4) | 12 | 12
(2 rows)
ROLLBACK TO s1;
@@ -109,8 +59,8 @@ DELETE FROM combocidtest;
FETCH ALL FROM c;
ctid | cmin | foobar
-------+------+--------
- (0,1) | 2 | 1
- (0,2) | 2 | 2
+ (0,1) | 1 | 1
+ (0,2) | 1 | 2
(0,5) | 0 | 333
(3 rows)
@@ -118,79 +68,29 @@ ROLLBACK;
SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar
-------+------+--------
- (0,1) | 2 | 1
- (0,2) | 2 | 2
+ (0,1) | 1 | 1
+ (0,2) | 1 | 2
(2 rows)
-- check behavior with locked tuples
BEGIN;
-- a few dummy ops to push up the CommandId counter
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest VALUES (444);
SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar
-------+------+--------
- (0,1) | 2 | 1
- (0,2) | 2 | 2
+ (0,1) | 1 | 1
+ (0,2) | 1 | 2
(0,6) | 10 | 444
(3 rows)
@@ -199,16 +99,16 @@ SAVEPOINT s1;
SELECT ctid,cmin,* FROM combocidtest FOR UPDATE;
ctid | cmin | foobar
-------+------+--------
- (0,1) | 2 | 1
- (0,2) | 2 | 2
+ (0,1) | 1 | 1
+ (0,2) | 1 | 2
(0,6) | 10 | 444
(3 rows)
SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar
-------+------+--------
- (0,1) | 2 | 1
- (0,2) | 2 | 2
+ (0,1) | 1 | 1
+ (0,2) | 1 | 2
(0,6) | 10 | 444
(3 rows)
@@ -217,17 +117,17 @@ UPDATE combocidtest SET foobar = foobar + 10;
SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar
-------+------+--------
- (0,7) | 14 | 11
- (0,8) | 14 | 12
- (0,9) | 14 | 454
+ (0,7) | 12 | 11
+ (0,8) | 12 | 12
+ (0,9) | 12 | 454
(3 rows)
ROLLBACK TO s1;
SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar
-------+------+--------
- (0,1) | 14 | 1
- (0,2) | 14 | 2
+ (0,1) | 12 | 1
+ (0,2) | 12 | 2
(0,6) | 0 | 444
(3 rows)
@@ -235,8 +135,8 @@ COMMIT;
SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar
-------+------+--------
- (0,1) | 14 | 1
- (0,2) | 14 | 2
+ (0,1) | 12 | 1
+ (0,2) | 12 | 2
(0,6) | 0 | 444
(3 rows)
diff --git a/src/test/regress/sql/combocid.sql b/src/test/regress/sql/combocid.sql
index 3f30839b1f6..f24ac6b01a1 100644
--- a/src/test/regress/sql/combocid.sql
+++ b/src/test/regress/sql/combocid.sql
@@ -6,16 +6,16 @@ CREATE TEMP TABLE combocidtest (foobar int);
BEGIN;
-- a few dummy ops to push up the CommandId counter
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest VALUES (1);
INSERT INTO combocidtest VALUES (2);
@@ -58,16 +58,16 @@ SELECT ctid,cmin,* FROM combocidtest;
BEGIN;
-- a few dummy ops to push up the CommandId counter
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
-SELECT 1;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
+INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest VALUES (444);