diff options
-rw-r--r-- | contrib/pgrowlocks/pgrowlocks.c | 7 | ||||
-rw-r--r-- | src/backend/access/heap/heapam.c | 8 | ||||
-rw-r--r-- | src/backend/access/heap/tuptoaster.c | 4 | ||||
-rw-r--r-- | src/backend/access/transam/xact.c | 67 | ||||
-rw-r--r-- | src/backend/commands/async.c | 5 | ||||
-rw-r--r-- | src/backend/commands/copy.c | 6 | ||||
-rw-r--r-- | src/backend/commands/explain.c | 4 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 29 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 65 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 4 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 4 | ||||
-rw-r--r-- | src/backend/storage/ipc/procarray.c | 4 | ||||
-rw-r--r-- | src/backend/utils/cache/inval.c | 15 | ||||
-rw-r--r-- | src/backend/utils/time/tqual.c | 8 | ||||
-rw-r--r-- | src/include/access/xact.h | 4 | ||||
-rw-r--r-- | src/include/commands/trigger.h | 8 | ||||
-rw-r--r-- | src/include/executor/executor.h | 4 | ||||
-rw-r--r-- | src/include/nodes/execnodes.h | 5 | ||||
-rw-r--r-- | src/test/regress/expected/combocid.out | 178 | ||||
-rw-r--r-- | src/test/regress/sql/combocid.sql | 40 |
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); |