Commit 895a94de authored by Tom Lane's avatar Tom Lane

Avoid incrementing the CommandCounter when CommandCounterIncrement is called

but no database changes have been made since the last CommandCounterIncrement.
This should result in a significant improvement in the number of "commands"
that can typically be performed within a transaction before hitting the 2^32
CommandId size limit.  In particular this buys back (and more) the possible
adverse consequences of my previous patch to fix plan caching behavior.

The implementation requires tracking whether the current CommandCounter
value has been "used" to mark any tuples.  CommandCounter values stored into
snapshots are presumed not to be used for this purpose.  This requires some
small executor changes, since the executor used to conflate the curcid of
the snapshot it was using with the command ID to mark output tuples with.
Separating these concepts allows some small simplifications in executor APIs.

Something for the TODO list: look into having CommandCounterIncrement not do
AcceptInvalidationMessages.  It seems fairly bogus to be doing it there,
but exactly where to do it instead isn't clear, and I'm disinclined to mess
with asynchronous behavior during late beta.
parent f0f18c70
/* /*
* $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 * Copyright (c) 2005-2006 Tatsuo Ishii
* *
...@@ -117,8 +117,9 @@ pgrowlocks(PG_FUNCTION_ARGS) ...@@ -117,8 +117,9 @@ pgrowlocks(PG_FUNCTION_ARGS)
/* must hold a buffer lock to call HeapTupleSatisfiesUpdate */ /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
if (HeapTupleSatisfiesUpdate(tuple->t_data, GetCurrentCommandId(), scan->rs_cbuf) if (HeapTupleSatisfiesUpdate(tuple->t_data,
== HeapTupleBeingUpdated) GetCurrentCommandId(false),
scan->rs_cbuf) == HeapTupleBeingUpdated)
{ {
char **values; char **values;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -1891,7 +1891,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, ...@@ -1891,7 +1891,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
Oid Oid
simple_heap_insert(Relation relation, HeapTuple tup) 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) ...@@ -2174,7 +2174,7 @@ simple_heap_delete(Relation relation, ItemPointer tid)
result = heap_delete(relation, tid, result = heap_delete(relation, tid,
&update_ctid, &update_xmax, &update_ctid, &update_xmax,
GetCurrentCommandId(), InvalidSnapshot, GetCurrentCommandId(true), InvalidSnapshot,
true /* wait for commit */ ); true /* wait for commit */ );
switch (result) switch (result)
{ {
...@@ -2817,7 +2817,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup) ...@@ -2817,7 +2817,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
result = heap_update(relation, otid, tup, result = heap_update(relation, otid, tup,
&update_ctid, &update_xmax, &update_ctid, &update_xmax,
GetCurrentCommandId(), InvalidSnapshot, GetCurrentCommandId(true), InvalidSnapshot,
true /* wait for commit */ ); true /* wait for commit */ );
switch (result) switch (result)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -1086,7 +1086,7 @@ toast_save_datum(Relation rel, Datum value, ...@@ -1086,7 +1086,7 @@ toast_save_datum(Relation rel, Datum value,
TupleDesc toasttupDesc; TupleDesc toasttupDesc;
Datum t_values[3]; Datum t_values[3];
bool t_isnull[3]; bool t_isnull[3];
CommandId mycid = GetCurrentCommandId(); CommandId mycid = GetCurrentCommandId(true);
struct varlena *result; struct varlena *result;
struct varatt_external toast_pointer; struct varatt_external toast_pointer;
struct struct
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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; ...@@ -161,6 +161,7 @@ static TransactionState CurrentTransactionState = &TopTransactionStateData;
*/ */
static SubTransactionId currentSubTransactionId; static SubTransactionId currentSubTransactionId;
static CommandId currentCommandId; static CommandId currentCommandId;
static bool currentCommandIdUsed;
/* /*
* xactStartTimestamp is the value of transaction_timestamp(). * xactStartTimestamp is the value of transaction_timestamp().
...@@ -435,11 +436,18 @@ GetCurrentSubTransactionId(void) ...@@ -435,11 +436,18 @@ GetCurrentSubTransactionId(void)
/* /*
* GetCurrentCommandId * 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 CommandId
GetCurrentCommandId(void) GetCurrentCommandId(bool used)
{ {
/* this is global to a transaction, not subtransaction-local */ /* this is global to a transaction, not subtransaction-local */
if (used)
currentCommandIdUsed = true;
return currentCommandId; return currentCommandId;
} }
...@@ -566,25 +574,50 @@ TransactionIdIsCurrentTransactionId(TransactionId xid) ...@@ -566,25 +574,50 @@ TransactionIdIsCurrentTransactionId(TransactionId xid)
void void
CommandCounterIncrement(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; currentCommandId += 1;
ereport(ERROR, if (currentCommandId == FirstCommandId) /* check for overflow */
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), {
currentCommandId -= 1;
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("cannot have more than 2^32-1 commands in a transaction"))); errmsg("cannot have more than 2^32-1 commands in a transaction")));
} }
currentCommandIdUsed = false;
/* Propagate new command ID into static snapshots, if set */ /* Propagate new command ID into static snapshots, if set */
if (SerializableSnapshot) if (SerializableSnapshot)
SerializableSnapshot->curcid = currentCommandId; SerializableSnapshot->curcid = currentCommandId;
if (LatestSnapshot) if (LatestSnapshot)
LatestSnapshot->curcid = currentCommandId; 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(); AtStart_Cache();
} }
...@@ -1416,6 +1449,7 @@ StartTransaction(void) ...@@ -1416,6 +1449,7 @@ StartTransaction(void)
s->subTransactionId = TopSubTransactionId; s->subTransactionId = TopSubTransactionId;
currentSubTransactionId = TopSubTransactionId; currentSubTransactionId = TopSubTransactionId;
currentCommandId = FirstCommandId; currentCommandId = FirstCommandId;
currentCommandIdUsed = false;
/* /*
* must initialize resource-management stuff first * must initialize resource-management stuff first
...@@ -4007,13 +4041,14 @@ ShowTransactionStateRec(TransactionState s) ...@@ -4007,13 +4041,14 @@ ShowTransactionStateRec(TransactionState s)
/* use ereport to suppress computation if msg will not be printed */ /* use ereport to suppress computation if msg will not be printed */
ereport(DEBUG3, 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", PointerIsValid(s->name) ? s->name : "unnamed",
BlockStateAsString(s->blockState), BlockStateAsString(s->blockState),
TransStateAsString(s->state), TransStateAsString(s->state),
(unsigned int) s->transactionId, (unsigned int) s->transactionId,
(unsigned int) s->subTransactionId, (unsigned int) s->subTransactionId,
(unsigned int) currentCommandId, (unsigned int) currentCommandId,
currentCommandIdUsed ? " (used)" : "",
s->nestingLevel, s->nestingLevel,
nodeToString(s->childXids)))); nodeToString(s->childXids))));
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -562,7 +562,8 @@ AtCommit_Notify(void)
*/ */
result = heap_update(lRel, &lTuple->t_self, rTuple, result = heap_update(lRel, &lTuple->t_self, rTuple,
&update_ctid, &update_xmax, &update_ctid, &update_xmax,
GetCurrentCommandId(), InvalidSnapshot, GetCurrentCommandId(true),
InvalidSnapshot,
false /* no wait for commit */ ); false /* no wait for commit */ );
switch (result) switch (result)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1033,7 +1033,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
* which COPY can be invoked, I think it's OK, because the active * which COPY can be invoked, I think it's OK, because the active
* snapshot shouldn't be shared with anything else anyway.) * snapshot shouldn't be shared with anything else anyway.)
*/ */
ActiveSnapshot->curcid = GetCurrentCommandId(); ActiveSnapshot->curcid = GetCurrentCommandId(false);
/* Create dest receiver for COPY OUT */ /* Create dest receiver for COPY OUT */
dest = CreateDestReceiver(DestCopyOut, NULL); dest = CreateDestReceiver(DestCopyOut, NULL);
...@@ -1637,7 +1637,7 @@ CopyFrom(CopyState cstate) ...@@ -1637,7 +1637,7 @@ CopyFrom(CopyState cstate)
ExprContext *econtext; /* used for ExecEvalExpr for default atts */ ExprContext *econtext; /* used for ExecEvalExpr for default atts */
MemoryContext oldcontext = CurrentMemoryContext; MemoryContext oldcontext = CurrentMemoryContext;
ErrorContextCallback errcontext; ErrorContextCallback errcontext;
CommandId mycid = GetCurrentCommandId(); CommandId mycid = GetCurrentCommandId(true);
bool use_wal = true; /* by default, use WAL logging */ bool use_wal = true; /* by default, use WAL logging */
bool use_fsm = true; /* by default, use FSM for free space */ bool use_fsm = true; /* by default, use FSM for free space */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * 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, ...@@ -233,7 +233,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
* EXPLAIN can be invoked, I think it's OK, because the active snapshot * EXPLAIN can be invoked, I think it's OK, because the active snapshot
* shouldn't be shared with anything else anyway.) * shouldn't be shared with anything else anyway.)
*/ */
ActiveSnapshot->curcid = GetCurrentCommandId(); ActiveSnapshot->curcid = GetCurrentCommandId(false);
/* Create a QueryDesc requesting no output */ /* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(plannedstmt, queryDesc = CreateQueryDesc(plannedstmt,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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); ...@@ -51,7 +51,6 @@ static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
static HeapTuple GetTupleForTrigger(EState *estate, static HeapTuple GetTupleForTrigger(EState *estate,
ResultRelInfo *relinfo, ResultRelInfo *relinfo,
ItemPointer tid, ItemPointer tid,
CommandId cid,
TupleTableSlot **newSlot); TupleTableSlot **newSlot);
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
int tgindx, int tgindx,
...@@ -1801,8 +1800,7 @@ ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo) ...@@ -1801,8 +1800,7 @@ ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
bool bool
ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid, ItemPointer tupleid)
CommandId cid)
{ {
TriggerDesc *trigdesc = relinfo->ri_TrigDesc; TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE]; int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
...@@ -1814,7 +1812,7 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ...@@ -1814,7 +1812,7 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *newSlot; TupleTableSlot *newSlot;
int i; int i;
trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, cid, &newSlot); trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL) if (trigtuple == NULL)
return false; return false;
...@@ -1871,9 +1869,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ...@@ -1871,9 +1869,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0) if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
{ {
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo, HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
tupleid, tupleid, NULL);
(CommandId) 0,
NULL);
AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE, AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
true, trigtuple, NULL); true, trigtuple, NULL);
...@@ -1952,8 +1948,7 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo) ...@@ -1952,8 +1948,7 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
HeapTuple HeapTuple
ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid, HeapTuple newtuple, ItemPointer tupleid, HeapTuple newtuple)
CommandId cid)
{ {
TriggerDesc *trigdesc = relinfo->ri_TrigDesc; TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE]; int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
...@@ -1965,7 +1960,7 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ...@@ -1965,7 +1960,7 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *newSlot; TupleTableSlot *newSlot;
int i; int i;
trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, cid, &newSlot); trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL) if (trigtuple == NULL)
return NULL; return NULL;
...@@ -2025,9 +2020,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ...@@ -2025,9 +2020,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0) if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
{ {
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo, HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
tupleid, tupleid, NULL);
(CommandId) 0,
NULL);
AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE, AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
true, trigtuple, newtuple); true, trigtuple, newtuple);
...@@ -2038,7 +2031,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ...@@ -2038,7 +2031,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
static HeapTuple static HeapTuple
GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo, GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
ItemPointer tid, CommandId cid, ItemPointer tid,
TupleTableSlot **newSlot) TupleTableSlot **newSlot)
{ {
Relation relation = relinfo->ri_RelationDesc; Relation relation = relinfo->ri_RelationDesc;
...@@ -2060,7 +2053,8 @@ GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo, ...@@ -2060,7 +2053,8 @@ GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
ltrmark:; ltrmark:;
tuple.t_self = *tid; tuple.t_self = *tid;
test = heap_lock_tuple(relation, &tuple, &buffer, test = heap_lock_tuple(relation, &tuple, &buffer,
&update_ctid, &update_xmax, cid, &update_ctid, &update_xmax,
estate->es_output_cid,
LockTupleExclusive, false); LockTupleExclusive, false);
switch (test) switch (test)
{ {
...@@ -2086,8 +2080,7 @@ ltrmark:; ...@@ -2086,8 +2080,7 @@ ltrmark:;
epqslot = EvalPlanQual(estate, epqslot = EvalPlanQual(estate,
relinfo->ri_RangeTableIndex, relinfo->ri_RangeTableIndex,
&update_ctid, &update_ctid,
update_xmax, update_xmax);
cid);
if (!TupIsNull(epqslot)) if (!TupIsNull(epqslot))
{ {
*tid = update_ctid; *tid = update_ctid;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -160,6 +160,30 @@ ExecutorStart(QueryDesc *queryDesc, int eflags) ...@@ -160,6 +160,30 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
estate->es_param_exec_vals = (ParamExecData *) estate->es_param_exec_vals = (ParamExecData *)
palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData)); 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 * Copy other important information into the EState
*/ */
...@@ -1285,7 +1309,7 @@ lnext: ; ...@@ -1285,7 +1309,7 @@ lnext: ;
test = heap_lock_tuple(erm->relation, &tuple, &buffer, test = heap_lock_tuple(erm->relation, &tuple, &buffer,
&update_ctid, &update_xmax, &update_ctid, &update_xmax,
estate->es_snapshot->curcid, estate->es_output_cid,
lockmode, erm->noWait); lockmode, erm->noWait);
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
switch (test) switch (test)
...@@ -1309,8 +1333,7 @@ lnext: ; ...@@ -1309,8 +1333,7 @@ lnext: ;
newSlot = EvalPlanQual(estate, newSlot = EvalPlanQual(estate,
erm->rti, erm->rti,
&update_ctid, &update_ctid,
update_xmax, update_xmax);
estate->es_snapshot->curcid);
if (!TupIsNull(newSlot)) if (!TupIsNull(newSlot))
{ {
slot = planSlot = newSlot; slot = planSlot = newSlot;
...@@ -1503,7 +1526,7 @@ ExecInsert(TupleTableSlot *slot, ...@@ -1503,7 +1526,7 @@ ExecInsert(TupleTableSlot *slot,
* t_self field. * t_self field.
*/ */
newId = heap_insert(resultRelationDesc, tuple, newId = heap_insert(resultRelationDesc, tuple,
estate->es_snapshot->curcid, estate->es_output_cid,
true, true); true, true);
IncrAppended(); IncrAppended();
...@@ -1557,8 +1580,7 @@ ExecDelete(ItemPointer tupleid, ...@@ -1557,8 +1580,7 @@ ExecDelete(ItemPointer tupleid,
{ {
bool dodelete; bool dodelete;
dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid, dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid);
estate->es_snapshot->curcid);
if (!dodelete) /* "do nothing" */ if (!dodelete) /* "do nothing" */
return; return;
...@@ -1575,7 +1597,7 @@ ExecDelete(ItemPointer tupleid, ...@@ -1575,7 +1597,7 @@ ExecDelete(ItemPointer tupleid,
ldelete:; ldelete:;
result = heap_delete(resultRelationDesc, tupleid, result = heap_delete(resultRelationDesc, tupleid,
&update_ctid, &update_xmax, &update_ctid, &update_xmax,
estate->es_snapshot->curcid, estate->es_output_cid,
estate->es_crosscheck_snapshot, estate->es_crosscheck_snapshot,
true /* wait for commit */ ); true /* wait for commit */ );
switch (result) switch (result)
...@@ -1599,8 +1621,7 @@ ldelete:; ...@@ -1599,8 +1621,7 @@ ldelete:;
epqslot = EvalPlanQual(estate, epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex, resultRelInfo->ri_RangeTableIndex,
&update_ctid, &update_ctid,
update_xmax, update_xmax);
estate->es_snapshot->curcid);
if (!TupIsNull(epqslot)) if (!TupIsNull(epqslot))
{ {
*tupleid = update_ctid; *tupleid = update_ctid;
...@@ -1708,8 +1729,7 @@ ExecUpdate(TupleTableSlot *slot, ...@@ -1708,8 +1729,7 @@ ExecUpdate(TupleTableSlot *slot,
HeapTuple newtuple; HeapTuple newtuple;
newtuple = ExecBRUpdateTriggers(estate, resultRelInfo, newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
tupleid, tuple, tupleid, tuple);
estate->es_snapshot->curcid);
if (newtuple == NULL) /* "do nothing" */ if (newtuple == NULL) /* "do nothing" */
return; return;
...@@ -1755,7 +1775,7 @@ lreplace:; ...@@ -1755,7 +1775,7 @@ lreplace:;
*/ */
result = heap_update(resultRelationDesc, tupleid, tuple, result = heap_update(resultRelationDesc, tupleid, tuple,
&update_ctid, &update_xmax, &update_ctid, &update_xmax,
estate->es_snapshot->curcid, estate->es_output_cid,
estate->es_crosscheck_snapshot, estate->es_crosscheck_snapshot,
true /* wait for commit */ ); true /* wait for commit */ );
switch (result) switch (result)
...@@ -1779,8 +1799,7 @@ lreplace:; ...@@ -1779,8 +1799,7 @@ lreplace:;
epqslot = EvalPlanQual(estate, epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex, resultRelInfo->ri_RangeTableIndex,
&update_ctid, &update_ctid,
update_xmax, update_xmax);
estate->es_snapshot->curcid);
if (!TupIsNull(epqslot)) if (!TupIsNull(epqslot))
{ {
*tupleid = update_ctid; *tupleid = update_ctid;
...@@ -1973,7 +1992,6 @@ ExecProcessReturning(ProjectionInfo *projectReturning, ...@@ -1973,7 +1992,6 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
* rti - rangetable index of table containing tuple * rti - rangetable index of table containing tuple
* *tid - t_ctid from the outdated tuple (ie, next updated version) * *tid - t_ctid from the outdated tuple (ie, next updated version)
* priorXmax - t_xmax from the outdated tuple * 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 * *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) * latest version of the tuple (note this may be changed even on failure)
...@@ -1983,7 +2001,7 @@ ExecProcessReturning(ProjectionInfo *projectReturning, ...@@ -1983,7 +2001,7 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
*/ */
TupleTableSlot * TupleTableSlot *
EvalPlanQual(EState *estate, Index rti, EvalPlanQual(EState *estate, Index rti,
ItemPointer tid, TransactionId priorXmax, CommandId curCid) ItemPointer tid, TransactionId priorXmax)
{ {
evalPlanQual *epq; evalPlanQual *epq;
EState *epqstate; EState *epqstate;
...@@ -2063,17 +2081,17 @@ EvalPlanQual(EState *estate, Index rti, ...@@ -2063,17 +2081,17 @@ EvalPlanQual(EState *estate, Index rti,
/* /*
* If tuple was inserted by our own transaction, we have to check * If tuple was inserted by our own transaction, we have to check
* cmin against curCid: cmin >= curCid means our command cannot * cmin against es_output_cid: cmin >= current CID means our
* see the tuple, so we should ignore it. Without this we are * command cannot see the tuple, so we should ignore it. Without
* open to the "Halloween problem" of indefinitely re-updating the * this we are open to the "Halloween problem" of indefinitely
* same tuple. (We need not check cmax because * re-updating the same tuple. (We need not check cmax because
* HeapTupleSatisfiesDirty will consider a tuple deleted by our * HeapTupleSatisfiesDirty will consider a tuple deleted by our
* transaction dead, regardless of cmax.) We just checked that * transaction dead, regardless of cmax.) We just checked that
* priorXmax == xmin, so we can test that variable instead of * priorXmax == xmin, so we can test that variable instead of
* doing HeapTupleHeaderGetXmin again. * doing HeapTupleHeaderGetXmin again.
*/ */
if (TransactionIdIsCurrentTransactionId(priorXmax) && if (TransactionIdIsCurrentTransactionId(priorXmax) &&
HeapTupleHeaderGetCmin(tuple.t_data) >= curCid) HeapTupleHeaderGetCmin(tuple.t_data) >= estate->es_output_cid)
{ {
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
return NULL; return NULL;
...@@ -2360,6 +2378,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq) ...@@ -2360,6 +2378,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
epqstate->es_snapshot = estate->es_snapshot; epqstate->es_snapshot = estate->es_snapshot;
epqstate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot; epqstate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
epqstate->es_range_table = estate->es_range_table; 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_result_relations = estate->es_result_relations;
epqstate->es_num_result_relations = estate->es_num_result_relations; epqstate->es_num_result_relations = estate->es_num_result_relations;
epqstate->es_result_relation_info = estate->es_result_relation_info; epqstate->es_result_relation_info = estate->es_result_relation_info;
...@@ -2718,7 +2737,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self) ...@@ -2718,7 +2737,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self)
heap_insert(estate->es_into_relation_descriptor, heap_insert(estate->es_into_relation_descriptor,
tuple, tuple,
estate->es_snapshot->curcid, estate->es_output_cid,
estate->es_into_relation_use_wal, estate->es_into_relation_use_wal,
false); /* never any point in using FSM */ false); /* never any point in using FSM */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -178,6 +178,8 @@ CreateExecutorState(void)
estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */ estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
estate->es_range_table = NIL; estate->es_range_table = NIL;
estate->es_output_cid = (CommandId) 0;
estate->es_result_relations = NULL; estate->es_result_relations = NULL;
estate->es_num_result_relations = 0; estate->es_num_result_relations = 0;
estate->es_result_relation_info = NULL; estate->es_result_relation_info = NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -1593,7 +1593,7 @@ _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
*/ */
ActiveSnapshot = CopySnapshot(snapshot); ActiveSnapshot = CopySnapshot(snapshot);
if (!read_only) if (!read_only)
ActiveSnapshot->curcid = GetCurrentCommandId(); ActiveSnapshot->curcid = GetCurrentCommandId(false);
} }
if (IsA(stmt, PlannedStmt) && if (IsA(stmt, PlannedStmt) &&
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -814,7 +814,7 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
snapshot->xcnt = count; snapshot->xcnt = count;
snapshot->subxcnt = subcount; snapshot->subxcnt = subcount;
snapshot->curcid = GetCurrentCommandId(); snapshot->curcid = GetCurrentCommandId(false);
return snapshot; return snapshot;
} }
......
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -402,6 +402,14 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId) ...@@ -402,6 +402,14 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId)
AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
dbId, 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 * 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. * relcache init file, mark that we need to zap that file at commit.
...@@ -420,6 +428,11 @@ RegisterSmgrInvalidation(RelFileNode rnode) ...@@ -420,6 +428,11 @@ RegisterSmgrInvalidation(RelFileNode rnode)
{ {
AddSmgrInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, AddSmgrInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
rnode); rnode);
/*
* As above, just in case there is not an associated catalog change.
*/
(void) GetCurrentCommandId(true);
} }
/* /*
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -382,7 +382,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
} }
else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple))) else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
{ {
if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId()) if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId(false))
return false; /* inserted after scan started */ return false; /* inserted after scan started */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
...@@ -401,7 +401,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) ...@@ -401,7 +401,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
return true; return true;
} }
if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId()) if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
return true; /* deleted after scan started */ return true; /* deleted after scan started */
else else
return false; /* deleted before scan started */ return false; /* deleted before scan started */
...@@ -443,7 +443,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) ...@@ -443,7 +443,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
{ {
if (tuple->t_infomask & HEAP_IS_LOCKED) if (tuple->t_infomask & HEAP_IS_LOCKED)
return true; return true;
if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId()) if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
return true; /* deleted after scan started */ return true; /* deleted after scan started */
else else
return false; /* deleted before scan started */ return false; /* deleted before scan started */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -143,7 +143,7 @@ extern TransactionId GetTopTransactionIdIfAny(void);
extern TransactionId GetCurrentTransactionId(void); extern TransactionId GetCurrentTransactionId(void);
extern TransactionId GetCurrentTransactionIdIfAny(void); extern TransactionId GetCurrentTransactionIdIfAny(void);
extern SubTransactionId GetCurrentSubTransactionId(void); extern SubTransactionId GetCurrentSubTransactionId(void);
extern CommandId GetCurrentCommandId(void); extern CommandId GetCurrentCommandId(bool used);
extern TimestampTz GetCurrentTransactionStartTimestamp(void); extern TimestampTz GetCurrentTransactionStartTimestamp(void);
extern TimestampTz GetCurrentStatementStartTimestamp(void); extern TimestampTz GetCurrentStatementStartTimestamp(void);
extern TimestampTz GetCurrentTransactionStopTimestamp(void); extern TimestampTz GetCurrentTransactionStopTimestamp(void);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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, ...@@ -124,8 +124,7 @@ extern void ExecASDeleteTriggers(EState *estate,
ResultRelInfo *relinfo); ResultRelInfo *relinfo);
extern bool ExecBRDeleteTriggers(EState *estate, extern bool ExecBRDeleteTriggers(EState *estate,
ResultRelInfo *relinfo, ResultRelInfo *relinfo,
ItemPointer tupleid, ItemPointer tupleid);
CommandId cid);
extern void ExecARDeleteTriggers(EState *estate, extern void ExecARDeleteTriggers(EState *estate,
ResultRelInfo *relinfo, ResultRelInfo *relinfo,
ItemPointer tupleid); ItemPointer tupleid);
...@@ -136,8 +135,7 @@ extern void ExecASUpdateTriggers(EState *estate, ...@@ -136,8 +135,7 @@ extern void ExecASUpdateTriggers(EState *estate,
extern HeapTuple ExecBRUpdateTriggers(EState *estate, extern HeapTuple ExecBRUpdateTriggers(EState *estate,
ResultRelInfo *relinfo, ResultRelInfo *relinfo,
ItemPointer tupleid, ItemPointer tupleid,
HeapTuple newtuple, HeapTuple newtuple);
CommandId cid);
extern void ExecARUpdateTriggers(EState *estate, extern void ExecARUpdateTriggers(EState *estate,
ResultRelInfo *relinfo, ResultRelInfo *relinfo,
ItemPointer tupleid, ItemPointer tupleid,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -143,7 +143,7 @@ extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
extern void ExecConstraints(ResultRelInfo *resultRelInfo, extern void ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate); TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
ItemPointer tid, TransactionId priorXmax, CommandId curCid); ItemPointer tid, TransactionId priorXmax);
extern PlanState *ExecGetActivePlanTree(QueryDesc *queryDesc); extern PlanState *ExecGetActivePlanTree(QueryDesc *queryDesc);
extern DestReceiver *CreateIntoRelDestReceiver(void); extern DestReceiver *CreateIntoRelDestReceiver(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -311,6 +311,9 @@ typedef struct EState
Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */ Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */
List *es_range_table; /* List of RangeTblEntry */ 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: */ /* Info about target table for insert/update/delete queries: */
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */ ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
int es_num_result_relations; /* length of array */ int es_num_result_relations; /* length of array */
......
...@@ -4,66 +4,16 @@ ...@@ -4,66 +4,16 @@
CREATE TEMP TABLE combocidtest (foobar int); CREATE TEMP TABLE combocidtest (foobar int);
BEGIN; BEGIN;
-- a few dummy ops to push up the CommandId counter -- a few dummy ops to push up the CommandId counter
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
?column? INSERT INTO combocidtest SELECT 1 LIMIT 0;
---------- INSERT INTO combocidtest SELECT 1 LIMIT 0;
1 INSERT INTO combocidtest SELECT 1 LIMIT 0;
(1 row) INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
?column? INSERT INTO combocidtest SELECT 1 LIMIT 0;
---------- INSERT INTO combocidtest SELECT 1 LIMIT 0;
1 INSERT INTO combocidtest SELECT 1 LIMIT 0;
(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 VALUES (1); INSERT INTO combocidtest VALUES (1);
INSERT INTO combocidtest VALUES (2); INSERT INTO combocidtest VALUES (2);
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
...@@ -79,8 +29,8 @@ UPDATE combocidtest SET foobar = foobar + 10; ...@@ -79,8 +29,8 @@ UPDATE combocidtest SET foobar = foobar + 10;
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,3) | 13 | 11 (0,3) | 12 | 11
(0,4) | 13 | 12 (0,4) | 12 | 12
(2 rows) (2 rows)
ROLLBACK TO s1; ROLLBACK TO s1;
...@@ -109,8 +59,8 @@ DELETE FROM combocidtest; ...@@ -109,8 +59,8 @@ DELETE FROM combocidtest;
FETCH ALL FROM c; FETCH ALL FROM c;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,1) | 2 | 1 (0,1) | 1 | 1
(0,2) | 2 | 2 (0,2) | 1 | 2
(0,5) | 0 | 333 (0,5) | 0 | 333
(3 rows) (3 rows)
...@@ -118,79 +68,29 @@ ROLLBACK; ...@@ -118,79 +68,29 @@ ROLLBACK;
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,1) | 2 | 1 (0,1) | 1 | 1
(0,2) | 2 | 2 (0,2) | 1 | 2
(2 rows) (2 rows)
-- check behavior with locked tuples -- check behavior with locked tuples
BEGIN; BEGIN;
-- a few dummy ops to push up the CommandId counter -- a few dummy ops to push up the CommandId counter
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
?column? INSERT INTO combocidtest SELECT 1 LIMIT 0;
---------- INSERT INTO combocidtest SELECT 1 LIMIT 0;
1 INSERT INTO combocidtest SELECT 1 LIMIT 0;
(1 row) INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
?column? INSERT INTO combocidtest SELECT 1 LIMIT 0;
---------- INSERT INTO combocidtest SELECT 1 LIMIT 0;
1 INSERT INTO combocidtest SELECT 1 LIMIT 0;
(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 VALUES (444); INSERT INTO combocidtest VALUES (444);
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,1) | 2 | 1 (0,1) | 1 | 1
(0,2) | 2 | 2 (0,2) | 1 | 2
(0,6) | 10 | 444 (0,6) | 10 | 444
(3 rows) (3 rows)
...@@ -199,16 +99,16 @@ SAVEPOINT s1; ...@@ -199,16 +99,16 @@ SAVEPOINT s1;
SELECT ctid,cmin,* FROM combocidtest FOR UPDATE; SELECT ctid,cmin,* FROM combocidtest FOR UPDATE;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,1) | 2 | 1 (0,1) | 1 | 1
(0,2) | 2 | 2 (0,2) | 1 | 2
(0,6) | 10 | 444 (0,6) | 10 | 444
(3 rows) (3 rows)
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,1) | 2 | 1 (0,1) | 1 | 1
(0,2) | 2 | 2 (0,2) | 1 | 2
(0,6) | 10 | 444 (0,6) | 10 | 444
(3 rows) (3 rows)
...@@ -217,17 +117,17 @@ UPDATE combocidtest SET foobar = foobar + 10; ...@@ -217,17 +117,17 @@ UPDATE combocidtest SET foobar = foobar + 10;
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,7) | 14 | 11 (0,7) | 12 | 11
(0,8) | 14 | 12 (0,8) | 12 | 12
(0,9) | 14 | 454 (0,9) | 12 | 454
(3 rows) (3 rows)
ROLLBACK TO s1; ROLLBACK TO s1;
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,1) | 14 | 1 (0,1) | 12 | 1
(0,2) | 14 | 2 (0,2) | 12 | 2
(0,6) | 0 | 444 (0,6) | 0 | 444
(3 rows) (3 rows)
...@@ -235,8 +135,8 @@ COMMIT; ...@@ -235,8 +135,8 @@ COMMIT;
SELECT ctid,cmin,* FROM combocidtest; SELECT ctid,cmin,* FROM combocidtest;
ctid | cmin | foobar ctid | cmin | foobar
-------+------+-------- -------+------+--------
(0,1) | 14 | 1 (0,1) | 12 | 1
(0,2) | 14 | 2 (0,2) | 12 | 2
(0,6) | 0 | 444 (0,6) | 0 | 444
(3 rows) (3 rows)
...@@ -6,16 +6,16 @@ CREATE TEMP TABLE combocidtest (foobar int); ...@@ -6,16 +6,16 @@ CREATE TEMP TABLE combocidtest (foobar int);
BEGIN; BEGIN;
-- a few dummy ops to push up the CommandId counter -- a few dummy ops to push up the CommandId counter
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest VALUES (1); INSERT INTO combocidtest VALUES (1);
INSERT INTO combocidtest VALUES (2); INSERT INTO combocidtest VALUES (2);
...@@ -58,16 +58,16 @@ SELECT ctid,cmin,* FROM combocidtest; ...@@ -58,16 +58,16 @@ SELECT ctid,cmin,* FROM combocidtest;
BEGIN; BEGIN;
-- a few dummy ops to push up the CommandId counter -- a few dummy ops to push up the CommandId counter
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
SELECT 1; INSERT INTO combocidtest SELECT 1 LIMIT 0;
INSERT INTO combocidtest VALUES (444); INSERT INTO combocidtest VALUES (444);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment