Index: backend/access/index/indexam.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/access/index/indexam.c,v retrieving revision 1.66 diff -c -r1.66 indexam.c *** backend/access/index/indexam.c 2003/03/24 21:42:33 1.66 --- backend/access/index/indexam.c 2003/04/17 22:51:31 *************** *** 528,534 **** LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE); sv_infomask = heapTuple->t_data->t_infomask; ! if (HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin) == HEAPTUPLE_DEAD) scan->kill_prior_tuple = true; --- 528,534 ---- LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE); sv_infomask = heapTuple->t_data->t_infomask; ! if (HeapTupleSatisfiesVacuum(heapTuple->t_data, GetRecentGlobalXmin()) == HEAPTUPLE_DEAD) scan->kill_prior_tuple = true; Index: backend/access/nbtree/nbtinsert.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/access/nbtree/nbtinsert.c,v retrieving revision 1.99 diff -c -r1.99 nbtinsert.c *** backend/access/nbtree/nbtinsert.c 2003/02/23 06:17:13 1.99 --- backend/access/nbtree/nbtinsert.c 2003/04/17 22:51:34 *************** *** 212,224 **** { cbti = (BTItem) PageGetItem(page, curitemid); htup.t_self = cbti->bti_itup.t_tid; ! if (heap_fetch(heapRel, SnapshotDirty, &htup, &hbuffer, true, NULL)) { /* it is a duplicate */ TransactionId xwait = ! (TransactionIdIsValid(SnapshotDirty->xmin)) ? ! SnapshotDirty->xmin : SnapshotDirty->xmax; ReleaseBuffer(hbuffer); --- 212,224 ---- { cbti = (BTItem) PageGetItem(page, curitemid); htup.t_self = cbti->bti_itup.t_tid; ! if (heap_fetch(heapRel, GetSnapshotDirty(), &htup, &hbuffer, true, NULL)) { /* it is a duplicate */ TransactionId xwait = ! (TransactionIdIsValid(GetXminSnapshotDirty())) ? ! GetXminSnapshotDirty() : GetXmaxSnapshotDirty(); ReleaseBuffer(hbuffer); *************** *** 252,258 **** LockBuffer(hbuffer, BUFFER_LOCK_SHARE); sv_infomask = htup.t_data->t_infomask; if (HeapTupleSatisfiesVacuum(htup.t_data, ! RecentGlobalXmin) == HEAPTUPLE_DEAD) { curitemid->lp_flags |= LP_DELETE; --- 252,258 ---- LockBuffer(hbuffer, BUFFER_LOCK_SHARE); sv_infomask = htup.t_data->t_infomask; if (HeapTupleSatisfiesVacuum(htup.t_data, ! GetRecentGlobalXmin()) == HEAPTUPLE_DEAD) { curitemid->lp_flags |= LP_DELETE; Index: backend/access/nbtree/nbtpage.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/access/nbtree/nbtpage.c,v retrieving revision 1.64 diff -c -r1.64 nbtpage.c *** backend/access/nbtree/nbtpage.c 2003/03/04 21:51:20 1.64 --- backend/access/nbtree/nbtpage.c 2003/04/17 22:51:36 *************** *** 539,545 **** */ opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (P_ISDELETED(opaque) && ! TransactionIdPrecedesOrEquals(opaque->btpo.xact, RecentXmin)) return true; return false; } --- 539,545 ---- */ opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (P_ISDELETED(opaque) && ! TransactionIdPrecedesOrEquals(opaque->btpo.xact, GetRecentXmin())) return true; return false; } Index: backend/access/transam/xact.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/access/transam/xact.c,v retrieving revision 1.145 diff -c -r1.145 xact.c *** backend/access/transam/xact.c 2003/03/27 16:51:27 1.145 --- backend/access/transam/xact.c 2003/04/17 22:51:46 *************** *** 87,93 **** * * Support for transaction blocks is provided via the functions: * ! * StartTransactionBlock * CommitTransactionBlock * AbortTransactionBlock * --- 87,93 ---- * * Support for transaction blocks is provided via the functions: * ! * BeginTransactionBlock * CommitTransactionBlock * AbortTransactionBlock * *************** *** 108,114 **** * * / StartTransactionCommand(); * 1) / ProcessUtility(); << begin ! * \ StartTransactionBlock(); * \ CommitTransactionCommand(); * * / StartTransactionCommand(); --- 108,114 ---- * * / StartTransactionCommand(); * 1) / ProcessUtility(); << begin ! * \ BeginTransactionBlock(); * \ CommitTransactionCommand(); * * / StartTransactionCommand(); *************** *** 127,133 **** * The point of this example is to demonstrate the need for * StartTransactionCommand() and CommitTransactionCommand() to * be state smart -- they should do nothing in between the calls ! * to StartTransactionBlock() and EndTransactionBlock() and * outside these calls they need to do normal start/commit * processing. * --- 127,133 ---- * The point of this example is to demonstrate the need for * StartTransactionCommand() and CommitTransactionCommand() to * be state smart -- they should do nothing in between the calls ! * to BeginTransactionBlock() and EndTransactionBlock() and * outside these calls they need to do normal start/commit * processing. * *************** *** 188,216 **** static void RecordTransactionAbort(void); static void StartTransaction(void); ! /* ! * global variables holding the current transaction state. ! */ ! static TransactionStateData CurrentTransactionStateData = { ! 0, /* transaction id */ ! FirstCommandId, /* command id */ ! 0, /* scan command id */ ! 0x0, /* start time */ ! TRANS_DEFAULT, /* transaction state */ ! TBLOCK_DEFAULT /* transaction block state from ! the client perspective */ ! }; ! ! TransactionState CurrentTransactionState = &CurrentTransactionStateData; /* * User-tweakable parameters */ int DefaultXactIsoLevel = XACT_READ_COMMITTED; - int XactIsoLevel; bool DefaultXactReadOnly = false; ! bool XactReadOnly; bool autocommit = true; --- 188,202 ---- static void RecordTransactionAbort(void); static void StartTransaction(void); ! void ShowTransactionState(void); /* * User-tweakable parameters */ int DefaultXactIsoLevel = XACT_READ_COMMITTED; bool DefaultXactReadOnly = false; ! bool XactReadOnly = false; bool autocommit = true; *************** *** 218,265 **** int CommitSiblings = 5; /* number of concurrent xacts needed to * sleep */ - static bool suppressChain = false; static void (*_RollbackFunc) (void *) = NULL; static void *_RollbackData = NULL; /* ---------------------------------------------------------------- * transaction state accessors * ---------------------------------------------------------------- */ - #ifdef NOT_USED - - /* -------------------------------- - * TransactionFlushEnabled() - * SetTransactionFlushEnabled() - * - * These are used to test and set the "TransactionFlushState" - * variable. If this variable is true (the default), then - * the system will flush all dirty buffers to disk at the end - * of each transaction. If false then we are assuming the - * buffer pool resides in stable main memory, in which case we - * only do writes as necessary. - * -------------------------------- - */ - static int TransactionFlushState = 1; - - int - TransactionFlushEnabled(void) - { - return TransactionFlushState; - } - - void - SetTransactionFlushEnabled(bool state) - { - TransactionFlushState = (state == true); - } - #endif - - /* * IsTransactionState * --- 204,238 ---- int CommitSiblings = 5; /* number of concurrent xacts needed to * sleep */ static bool suppressChain = false; static void (*_RollbackFunc) (void *) = NULL; static void *_RollbackData = NULL; + /* + * global variables holding the current transaction state. + */ + static TransactionStateData CurrentTransactionStateData = { + 0, /* transaction id */ + FirstCommandId, /* command id */ + 0, /* scan command id */ + 0x0, /* start time */ + TRANS_DEFAULT, /* transaction state */ + TBLOCK_DEFAULT, /* transaction block state from + the client perspective */ + NULL, /* toplevel memory context */ + NULL, /* per-statement memory context */ + 0, /* isolation level */ + NULL /* parent TransactionState */ + }; + + TransactionState CurrentTransactionState = &CurrentTransactionStateData; /* ---------------------------------------------------------------- * transaction state accessors * ---------------------------------------------------------------- */ /* * IsTransactionState * *************** *** 358,364 **** --- 331,361 ---- return s->startTime; } + /* + * GetTopTransactionContext + */ + MemoryContext + GetTopTransactionContext(void) + { + TransactionState s = CurrentTransactionState; + + Assert (s->topTransactionContext != NULL); + return s->topTransactionContext; + } + + /* + * GetTransactionCommandContext + */ + MemoryContext + GetTransactionCommandContext(void) + { + TransactionState s = CurrentTransactionState; + Assert(s->transactionCommandContext != NULL); + return s->transactionCommandContext; + } + + /* * TransactionIdIsCurrentTransactionId * *************** *** 390,396 **** { TransactionState s = CurrentTransactionState; ! return (cid == s->commandId) ? true : false; } --- 387,393 ---- { TransactionState s = CurrentTransactionState; ! return (cid == s->commandId); } *************** *** 407,416 **** elog(ERROR, "You may only have 2^32-1 commands per transaction"); /* Propagate new command ID into query snapshots, if set */ ! if (QuerySnapshot) ! QuerySnapshot->curcid = s->commandId; ! if (SerializableSnapshot) ! SerializableSnapshot->curcid = s->commandId; /* * make cache changes visible to me. AtCommit_LocalCache() instead of --- 404,413 ---- elog(ERROR, "You may only have 2^32-1 commands per transaction"); /* Propagate new command ID into query snapshots, if set */ ! if (IsValidQuerySnapshot()) ! SetQuerySnapshotCurCid(s->commandId); ! if (IsValidSerializableSnapshot()) ! SetSerializableSnapshotCurCid(s->commandId); /* * make cache changes visible to me. AtCommit_LocalCache() instead of *************** *** 455,471 **** static void AtStart_Memory(void) { /* * We shouldn't have any transaction contexts already. */ ! Assert(TopTransactionContext == NULL); ! Assert(TransactionCommandContext == NULL); /* * Create a toplevel context for the transaction. */ ! TopTransactionContext = ! AllocSetContextCreate(TopMemoryContext, "TopTransactionContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, --- 452,469 ---- static void AtStart_Memory(void) { + TransactionState s = CurrentTransactionState; /* * We shouldn't have any transaction contexts already. */ ! Assert(s->topTransactionContext == NULL); ! Assert(s->transactionCommandContext == NULL); /* * Create a toplevel context for the transaction. */ ! s->topTransactionContext = ! AllocSetContextCreate(ToplevelTransactionContext, "TopTransactionContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, *************** *** 474,486 **** /* * Create a statement-level context and make it active. */ ! TransactionCommandContext = ! AllocSetContextCreate(TopTransactionContext, "TransactionCommandContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); ! MemoryContextSwitchTo(TransactionCommandContext); } --- 472,484 ---- /* * Create a statement-level context and make it active. */ ! s->transactionCommandContext = ! AllocSetContextCreate(s->topTransactionContext, "TransactionCommandContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); ! MemoryContextSwitchTo(s->transactionCommandContext); } *************** *** 646,651 **** --- 644,650 ---- static void AtCommit_Memory(void) { + TransactionState s = CurrentTransactionState; /* * Now that we're "out" of a transaction, have the system allocate * things in the top memory context instead of per-transaction *************** *** 656,665 **** /* * Release all transaction-local memory. */ ! Assert(TopTransactionContext != NULL); ! MemoryContextDelete(TopTransactionContext); ! TopTransactionContext = NULL; ! TransactionCommandContext = NULL; } /* ---------------------------------------------------------------- --- 655,664 ---- /* * Release all transaction-local memory. */ ! Assert(s->topTransactionContext != NULL); ! MemoryContextDelete(s->topTransactionContext); ! s->topTransactionContext = NULL; ! s->transactionCommandContext = NULL; } /* ---------------------------------------------------------------- *************** *** 767,787 **** static void AtAbort_Memory(void) { /* * Make sure we are in a valid context (not a child of * TransactionCommandContext...). Note that it is possible for this * code to be called when we aren't in a transaction at all; go * directly to TopMemoryContext in that case. */ ! if (TransactionCommandContext != NULL) { ! MemoryContextSwitchTo(TransactionCommandContext); /* * We do not want to destroy transaction contexts yet, but it * should be OK to delete any command-local memory. */ ! MemoryContextResetAndDeleteChildren(TransactionCommandContext); } else MemoryContextSwitchTo(TopMemoryContext); --- 766,787 ---- static void AtAbort_Memory(void) { + TransactionState s = CurrentTransactionState; /* * Make sure we are in a valid context (not a child of * TransactionCommandContext...). Note that it is possible for this * code to be called when we aren't in a transaction at all; go * directly to TopMemoryContext in that case. */ ! if (s->transactionCommandContext != NULL) { ! MemoryContextSwitchTo(s->transactionCommandContext); /* * We do not want to destroy transaction contexts yet, but it * should be OK to delete any command-local memory. */ ! MemoryContextResetAndDeleteChildren(s->transactionCommandContext); } else MemoryContextSwitchTo(TopMemoryContext); *************** *** 799,804 **** --- 799,805 ---- static void AtCleanup_Memory(void) { + TransactionState s = CurrentTransactionState; /* * Now that we're "out" of a transaction, have the system allocate * things in the top memory context instead of per-transaction *************** *** 809,818 **** /* * Release all transaction-local memory. */ ! if (TopTransactionContext != NULL) ! MemoryContextDelete(TopTransactionContext); ! TopTransactionContext = NULL; ! TransactionCommandContext = NULL; } --- 810,819 ---- /* * Release all transaction-local memory. */ ! if (s->topTransactionContext != NULL) ! MemoryContextDelete(s->topTransactionContext); ! s->topTransactionContext = NULL; ! s->transactionCommandContext = NULL; } *************** *** 829,836 **** { TransactionState s = CurrentTransactionState; ! FreeXactSnapshot(); ! XactIsoLevel = DefaultXactIsoLevel; XactReadOnly = DefaultXactReadOnly; /* --- 830,841 ---- { TransactionState s = CurrentTransactionState; ! /* ! * XXX Maybe inherit values from parent xact? In that ! * case, we should leave the value alone here as it has been set in ! * PushCurrentTransaction. ! */ ! s->xactIsoLevel = DefaultXactIsoLevel; XactReadOnly = DefaultXactReadOnly; /* *************** *** 872,883 **** --- 877,895 ---- AtStart_Cache(); AtStart_Locks(); + AtStart_Snapshot(); + /* * Tell the trigger manager to we're starting a transaction */ DeferredTriggerBeginXact(); /* + * Initialize the smgr pending deletes stuff + */ + smgrCreatePendingDeletes(); + + /* * done with start processing, set current transaction state to "in * progress" */ *************** *** 993,998 **** --- 1005,1011 ---- AtEOXact_CatCache(true); AtEOXact_Files(); pgstat_count_xact_commit(); + AtEOXact_Snapshot(); AtCommit_Memory(); /* *************** *** 1087,1092 **** --- 1100,1106 ---- smgrDoPendingDeletes(false); AtAbort_Cache(); AtEOXact_Buffers(false); + AtEOXact_Snapshot(); smgrabort(); AtAbort_Locks(); *************** *** 1223,1230 **** * We must switch to TransactionCommandContext before returning. This * is already done if we called StartTransaction, otherwise not. */ ! Assert(TransactionCommandContext != NULL); ! MemoryContextSwitchTo(TransactionCommandContext); } /* --- 1237,1245 ---- * We must switch to TransactionCommandContext before returning. This * is already done if we called StartTransaction, otherwise not. */ ! Assert(s->transactionCommandContext != NULL); ! MemoryContextSwitchTo(s->transactionCommandContext); ! ShowTransactionState(); } /* *************** *** 1266,1272 **** Assert(s->blockState == TBLOCK_INPROGRESS); /* This code must match the TBLOCK_INPROGRESS case below: */ CommandCounterIncrement(); ! MemoryContextResetAndDeleteChildren(TransactionCommandContext); } break; --- 1281,1287 ---- Assert(s->blockState == TBLOCK_INPROGRESS); /* This code must match the TBLOCK_INPROGRESS case below: */ CommandCounterIncrement(); ! MemoryContextResetAndDeleteChildren(s->transactionCommandContext); } break; *************** *** 1281,1286 **** --- 1296,1314 ---- break; /* + * This is the case where we were already in a transaction and + * we get a "BEGIN TRANSACTION" command. Note that we first + * change the block state of the parent transaction, then + * start a subtransaction, and set its block state too. + */ + case TBLOCK_BEGINSUB: + s->blockState = TBLOCK_INPROGRESS; + PushCurrentTransaction(); + StartTransaction(); + s->blockState = TBLOCK_INPROGRESS; + break; + + /* * This is the case when we have finished executing a command * someplace within a transaction block. We increment the * command counter and return. Someday we may free resources *************** *** 1291,1297 **** */ case TBLOCK_INPROGRESS: CommandCounterIncrement(); ! MemoryContextResetAndDeleteChildren(TransactionCommandContext); break; /* --- 1319,1325 ---- */ case TBLOCK_INPROGRESS: CommandCounterIncrement(); ! MemoryContextResetAndDeleteChildren(s->transactionCommandContext); break; /* *************** *** 1301,1307 **** */ case TBLOCK_END: CommitTransaction(); ! s->blockState = TBLOCK_DEFAULT; break; /* --- 1329,1342 ---- */ case TBLOCK_END: CommitTransaction(); ! /* This code must match the TBLOCK_ENDABORT case below */ ! if (!IsCurrentTransactionToplevel()) ! PopTransaction(); ! else ! { ! s->blockState = TBLOCK_DEFAULT; ! s->parent = NULL; ! } break; /* *************** *** 1320,1328 **** */ case TBLOCK_ENDABORT: CleanupTransaction(); ! s->blockState = TBLOCK_DEFAULT; break; } } /* --- 1355,1370 ---- */ case TBLOCK_ENDABORT: CleanupTransaction(); ! if (!IsCurrentTransactionToplevel()) ! PopTransaction(); ! else ! { ! s->blockState = TBLOCK_DEFAULT; ! s->parent = NULL; ! } break; } + ShowTransactionState(); } /* *************** *** 1380,1385 **** --- 1422,1428 ---- s->blockState = TBLOCK_DEFAULT; AbortTransaction(); CleanupTransaction(); + PopTransaction(); break; /* *************** *** 1399,1404 **** --- 1442,1448 ---- */ case TBLOCK_ENDABORT: CleanupTransaction(); + PopTransaction(); s->blockState = TBLOCK_DEFAULT; break; } *************** *** 1512,1517 **** --- 1556,1567 ---- { TransactionState s = CurrentTransactionState; + if (s->blockState == TBLOCK_INPROGRESS) + { + s->blockState = TBLOCK_BEGINSUB; + return; + } + /* * check the current transaction state */ *************** *** 1585,1627 **** } /* - * AbortTransactionBlock - */ - #ifdef NOT_USED - static void - AbortTransactionBlock(void) - { - TransactionState s = CurrentTransactionState; - - /* - * check the current transaction state - */ - if (s->blockState == TBLOCK_INPROGRESS) - { - /* - * here we were inside a transaction block something screwed up - * inside the system so we enter the abort state, do the abort - * processing and then return. We remain in the abort state until - * we see an END TRANSACTION command. - */ - s->blockState = TBLOCK_ABORT; - AbortTransaction(); - return; - } - - /* - * here, the user issued ABORT when not inside a transaction. Issue a - * WARNING and go to abort state. The upcoming call to - * CommitTransactionCommand() will then put us back into the default - * state. - */ - elog(WARNING, "ROLLBACK: no transaction in progress"); - AbortTransaction(); - s->blockState = TBLOCK_ENDABORT; - } - #endif - - /* * UserAbortTransactionBlock */ void --- 1635,1640 ---- *************** *** 1718,1723 **** --- 1731,1830 ---- return false; } + /* + * PushCurrentTransaction + */ + void PushCurrentTransaction(void) + { + MemoryContext old_cxt; + TransactionState parent; + TransactionState s = CurrentTransactionState; + + /* Make sure the transaction state node is in a long-lived context */ + old_cxt = MemoryContextSwitchTo(ToplevelTransactionContext); + parent = (TransactionState)palloc(sizeof(TransactionStateData)); + memcpy(parent, s, sizeof(TransactionStateData)); + + s->commandId = FirstCommandId; + s->startTime = 0; + s->startTimeUsec = 0x0; + s->state = TRANS_DEFAULT; + s->blockState = TBLOCK_DEFAULT; + s->topTransactionContext = NULL; + s->transactionCommandContext = NULL; + /* + * Inherit setting from the parent transaction. + */ + s->xactIsoLevel = parent->xactIsoLevel; + s->parent = parent; + + s->transactionIdData = GetNewTransactionId(); + XactLockTableInsert(s->transactionIdData); + + MemoryContextSwitchTo(old_cxt); + } + + /* + * PopTransaction + */ + void PopTransaction(void) + { + TransactionState s = CurrentTransactionState; + TransactionState p; + Assert(s->parent != NULL); + + s->commandId = s->parent->commandId; + s->startTime = s->parent->startTime; + s->startTimeUsec = s->parent->startTimeUsec; + s->state = s->parent->state; + s->blockState = s->parent->blockState; + s->topTransactionContext = s->parent->topTransactionContext; + s->transactionCommandContext = s->parent->transactionCommandContext; + s->transactionIdData = s->parent->transactionIdData; + p = s->parent; + s->parent = p->parent; + pfree(p); + } + + /* + * ShowTransactionState + */ + void ShowTransactionState(void) + { + TransactionState s = CurrentTransactionState; + elog(DEBUG2, "blockState: %u, state: %u, parent: %u", s->blockState, + s->state, (unsigned int)s->parent); + } + + /* + * IsCurrentTransactionToplevel + */ + bool IsCurrentTransactionToplevel(void) + { + TransactionState s = CurrentTransactionState; + elog(DEBUG2, "IsToplevel: it is %stoplevel", (s->parent==NULL?"":"not ")); + return (s->parent == NULL); + } + + /* + * GetXactIsoLevel + */ + int + GetXactIsoLevel(void) + { + TransactionState s = CurrentTransactionState; + return s->xactIsoLevel; + } + + /* + * SetXactIsoLevel + */ + void + SetXactIsoLevel(int isoLevel) + { + TransactionState s = CurrentTransactionState; + s->xactIsoLevel = isoLevel; + } /* * XLOG support routines Index: backend/bootstrap/bootparse.y =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/bootstrap/bootparse.y,v retrieving revision 1.55 diff -c -r1.55 bootparse.y *** backend/bootstrap/bootparse.y 2002/11/11 22:19:21 1.55 --- backend/bootstrap/bootparse.y 2003/04/17 22:51:46 *************** *** 259,265 **** ; Boot_BuildIndsStmt: ! XBUILD INDICES { build_indices(); } ; --- 259,270 ---- ; Boot_BuildIndsStmt: ! XBUILD INDICES ! { ! do_start(); ! build_indices(); ! do_end(); ! } ; Index: backend/commands/async.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/async.c,v retrieving revision 1.92 diff -c -r1.92 async.c *** backend/commands/async.c 2003/02/18 02:53:29 1.92 --- backend/commands/async.c 2003/04/17 22:51:47 *************** *** 78,83 **** --- 78,84 ---- #include #include "access/heapam.h" + #include "access/xact.h" #include "catalog/catname.h" #include "catalog/pg_listener.h" #include "commands/async.h" *************** *** 161,167 **** */ MemoryContext oldcontext; ! oldcontext = MemoryContextSwitchTo(TopTransactionContext); pendingNotifies = lcons(pstrdup(relname), pendingNotifies); --- 162,168 ---- */ MemoryContext oldcontext; ! oldcontext = MemoryContextSwitchTo(GetTopTransactionContext()); pendingNotifies = lcons(pstrdup(relname), pendingNotifies); Index: backend/commands/trigger.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/trigger.c,v retrieving revision 1.147 diff -c -r1.147 trigger.c *** backend/commands/trigger.c 2003/03/31 20:47:51 1.147 --- backend/commands/trigger.c 2003/04/17 22:51:51 *************** *** 1540,1546 **** case HeapTupleUpdated: ReleaseBuffer(buffer); ! if (XactIsoLevel == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); else if (!(ItemPointerEquals(&(tuple.t_self), tid))) { --- 1540,1546 ---- case HeapTupleUpdated: ReleaseBuffer(buffer); ! if (GetXactIsoLevel() == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); else if (!(ItemPointerEquals(&(tuple.t_self), tid))) { *************** *** 1601,1625 **** * ---------- */ - /* - * Internal data to the deferred trigger mechanism is held over - * statements/commands in a context which is created at transaction - * start and destroyed at transaction end. - */ - - static MemoryContext deftrig_cxt = NULL; - - /* ---------- - * Global data that tells which triggers are actually in - * state IMMEDIATE or DEFERRED. - * ---------- - */ - static bool deftrig_all_isset = false; - static bool deftrig_all_isdeferred = false; - static List *deftrig_trigstates; - /* ---------- * The list of pending deferred trigger events during the current transaction. * * deftrig_events is the head, deftrig_event_tail is the last entry. --- 1601,1622 ---- * ---------- */ + typedef struct DeferredTriggerStackData { + /* Internal data is held in a per-transaction memory context */ + MemoryContext deftrig_cxt; + /* ALL DEFERRED or ALL IMMEDIATE */ + bool deftrig_all_isset; + bool deftrig_all_isdeferred; + /* Per trigger state */ + List *deftrig_trigstates; + /* List of pending deferred triggers. Previous comment below */ + DeferredTriggerEvent deftrig_events; + DeferredTriggerEvent deftrig_event_tail; + struct DeferredTriggerStackData *parent; + } DeferredTriggerStackData; /* ---------- + * deftrig_events, deftrig_event_tail: * The list of pending deferred trigger events during the current transaction. * * deftrig_events is the head, deftrig_event_tail is the last entry. *************** *** 1631,1639 **** * large... * ---------- */ - static DeferredTriggerEvent deftrig_events; - static DeferredTriggerEvent deftrig_event_tail; /* ---------- * deferredTriggerCheckState() --- 1628,1636 ---- * large... * ---------- */ + typedef DeferredTriggerStackData *DeferredTriggerStack; + static DeferredTriggerStack ts; /* ---------- * deferredTriggerCheckState() *************** *** 1659,1665 **** /* * Lookup if we know an individual state for this trigger */ ! foreach(sl, deftrig_trigstates) { trigstate = (DeferredTriggerStatus) lfirst(sl); if (trigstate->dts_tgoid == tgoid) --- 1656,1662 ---- /* * Lookup if we know an individual state for this trigger */ ! foreach(sl, ts->deftrig_trigstates) { trigstate = (DeferredTriggerStatus) lfirst(sl); if (trigstate->dts_tgoid == tgoid) *************** *** 1670,1690 **** * No individual state known - so if the user issued a SET CONSTRAINT * ALL ..., we return that instead of the triggers default state. */ ! if (deftrig_all_isset) ! return deftrig_all_isdeferred; /* * No ALL state known either, remember the default state as the * current and return that. */ ! oldcxt = MemoryContextSwitchTo(deftrig_cxt); trigstate = (DeferredTriggerStatus) palloc(sizeof(DeferredTriggerStatusData)); trigstate->dts_tgoid = tgoid; trigstate->dts_tgisdeferred = ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0); ! deftrig_trigstates = lappend(deftrig_trigstates, trigstate); MemoryContextSwitchTo(oldcxt); --- 1667,1687 ---- * No individual state known - so if the user issued a SET CONSTRAINT * ALL ..., we return that instead of the triggers default state. */ ! if (ts->deftrig_all_isset) ! return ts->deftrig_all_isdeferred; /* * No ALL state known either, remember the default state as the * current and return that. */ ! oldcxt = MemoryContextSwitchTo(ts->deftrig_cxt); trigstate = (DeferredTriggerStatus) palloc(sizeof(DeferredTriggerStatusData)); trigstate->dts_tgoid = tgoid; trigstate->dts_tgisdeferred = ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0); ! ts->deftrig_trigstates = lappend(ts->deftrig_trigstates, trigstate); MemoryContextSwitchTo(oldcxt); *************** *** 1707,1722 **** * "lappend". This avoids O(N^2) behavior for large numbers of events. */ event->dte_next = NULL; ! if (deftrig_event_tail == NULL) { /* first list entry */ ! deftrig_events = event; ! deftrig_event_tail = event; } else { ! deftrig_event_tail->dte_next = event; ! deftrig_event_tail = event; } } --- 1704,1719 ---- * "lappend". This avoids O(N^2) behavior for large numbers of events. */ event->dte_next = NULL; ! if (ts->deftrig_event_tail == NULL) { /* first list entry */ ! ts->deftrig_events = event; ! ts->deftrig_event_tail = event; } else { ! ts->deftrig_event_tail->dte_next = event; ! ts->deftrig_event_tail = event; } } *************** *** 1822,1828 **** * Might have been a referential integrity constraint trigger. Reset * the snapshot overriding flag. */ ! ReferentialIntegritySnapshotOverride = false; /* * Release buffers --- 1819,1825 ---- * Might have been a referential integrity constraint trigger. Reset * the snapshot overriding flag. */ ! SetReferentialIntegritySnapshotOverride(false); /* * Release buffers *************** *** 1874,1880 **** ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); ! event = deftrig_events; while (event != NULL) { bool still_deferred_ones = false; --- 1871,1877 ---- ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); ! event = ts->deftrig_events; while (event != NULL) { bool still_deferred_ones = false; *************** *** 1974,1980 **** if (prev_event) prev_event->dte_next = next_event; else ! deftrig_events = next_event; pfree(event); } else --- 1971,1977 ---- if (prev_event) prev_event->dte_next = next_event; else ! ts->deftrig_events = next_event; pfree(event); } else *************** *** 1991,1997 **** } /* Update list tail pointer in case we just deleted tail event */ ! deftrig_event_tail = prev_event; /* Release working resources */ if (rel) --- 1988,1994 ---- } /* Update list tail pointer in case we just deleted tail event */ ! ts->deftrig_event_tail = prev_event; /* Release working resources */ if (rel) *************** *** 2014,2021 **** void DeferredTriggerInit(void) { ! /* Nothing to do */ ! ; } --- 2011,2017 ---- void DeferredTriggerInit(void) { ! ts = NULL; } *************** *** 2029,2057 **** void DeferredTriggerBeginXact(void) { ! if (deftrig_cxt != NULL) ! elog(ERROR, ! "DeferredTriggerBeginXact() called while inside transaction"); /* * Create the per transaction memory context */ ! deftrig_cxt = AllocSetContextCreate(TopTransactionContext, "DeferredTriggerXact", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); - deftrig_all_isset = false; - /* * If unspecified, constraints default to IMMEDIATE, per SQL */ ! deftrig_all_isdeferred = false; ! deftrig_trigstates = NIL; ! deftrig_events = NULL; ! deftrig_event_tail = NULL; } --- 2025,2058 ---- void DeferredTriggerBeginXact(void) { ! DeferredTriggerStack tts; ! MemoryContext old_cxt; + old_cxt = MemoryContextSwitchTo(GetTopTransactionContext()); + tts = (DeferredTriggerStack) palloc(sizeof(DeferredTriggerStackData)); + /* * Create the per transaction memory context */ ! tts->deftrig_cxt = AllocSetContextCreate(GetTopTransactionContext(), "DeferredTriggerXact", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * If unspecified, constraints default to IMMEDIATE, per SQL */ ! tts->deftrig_all_isdeferred = false; ! tts->deftrig_all_isset = false; ! tts->deftrig_trigstates = NIL; ! tts->deftrig_events = NULL; ! tts->deftrig_event_tail = NULL; ! tts->parent = ts; ! ts = tts; ! ! MemoryContextSwitchTo(old_cxt); } *************** *** 2068,2074 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; deferredTriggerInvokeEvents(true); --- 2069,2075 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; deferredTriggerInvokeEvents(true); *************** *** 2088,2100 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; deferredTriggerInvokeEvents(false); ! MemoryContextDelete(deftrig_cxt); ! deftrig_cxt = NULL; } --- 2089,2104 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; deferredTriggerInvokeEvents(false); ! /* ! * The stack item will be freed when the TopTransactionContext ! * is erased, so there's no need to do it manually. ! */ ! ts = ts->parent; } *************** *** 2112,2122 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; ! MemoryContextDelete(deftrig_cxt); ! deftrig_cxt = NULL; } --- 2116,2129 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; ! /* ! * The stack item will be freed when the TopTransactionContext ! * is erased, so there's no need to do it manually. ! */ ! ts = ts->parent; } *************** *** 2134,2140 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; /* --- 2141,2147 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; /* *************** *** 2146,2152 **** * Drop all per-transaction information about individual trigger * states. */ ! l = deftrig_trigstates; while (l != NIL) { List *next = lnext(l); --- 2153,2159 ---- * Drop all per-transaction information about individual trigger * states. */ ! l = ts->deftrig_trigstates; while (l != NIL) { List *next = lnext(l); *************** *** 2155,2167 **** pfree(l); l = next; } ! deftrig_trigstates = NIL; /* * Set the per-transaction ALL state to known. */ ! deftrig_all_isset = true; ! deftrig_all_isdeferred = stmt->deferred; } else { --- 2162,2174 ---- pfree(l); l = next; } ! ts->deftrig_trigstates = NIL; /* * Set the per-transaction ALL state to known. */ ! ts->deftrig_all_isset = true; ! ts->deftrig_all_isdeferred = stmt->deferred; } else { *************** *** 2243,2254 **** * Inside of a transaction block set the trigger states of * individual triggers on transaction level. */ ! oldcxt = MemoryContextSwitchTo(deftrig_cxt); foreach(l, loid) { found = false; ! foreach(ls, deftrig_trigstates) { state = (DeferredTriggerStatus) lfirst(ls); if (state->dts_tgoid == lfirsto(l)) --- 2250,2261 ---- * Inside of a transaction block set the trigger states of * individual triggers on transaction level. */ ! oldcxt = MemoryContextSwitchTo(ts->deftrig_cxt); foreach(l, loid) { found = false; ! foreach(ls, ts->deftrig_trigstates) { state = (DeferredTriggerStatus) lfirst(ls); if (state->dts_tgoid == lfirsto(l)) *************** *** 2265,2272 **** state->dts_tgoid = lfirsto(l); state->dts_tgisdeferred = stmt->deferred; ! deftrig_trigstates = ! lappend(deftrig_trigstates, state); } } --- 2272,2279 ---- state->dts_tgoid = lfirsto(l); state->dts_tgisdeferred = stmt->deferred; ! ts->deftrig_trigstates = ! lappend(ts->deftrig_trigstates, state); } } *************** *** 2310,2316 **** ItemPointerData oldctid; ItemPointerData newctid; ! if (deftrig_cxt == NULL) elog(ERROR, "DeferredTriggerSaveEvent() called outside of transaction"); --- 2317,2323 ---- ItemPointerData oldctid; ItemPointerData newctid; ! if (ts == NULL) elog(ERROR, "DeferredTriggerSaveEvent() called outside of transaction"); *************** *** 2360,2366 **** /* * Create a new event */ ! oldcxt = MemoryContextSwitchTo(deftrig_cxt); new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + n_enabled_triggers * sizeof(DeferredTriggerEventItem); --- 2367,2373 ---- /* * Create a new event */ ! oldcxt = MemoryContextSwitchTo(ts->deftrig_cxt); new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + n_enabled_triggers * sizeof(DeferredTriggerEventItem); Index: backend/commands/variable.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/variable.c,v retrieving revision 1.73 diff -c -r1.73 variable.c *** backend/commands/variable.c 2003/02/01 18:31:28 1.73 --- backend/commands/variable.c 2003/04/17 22:51:51 *************** *** 416,438 **** const char * assign_XactIsoLevel(const char *value, bool doit, bool interactive) { ! if (doit && interactive && SerializableSnapshot != NULL) elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query"); if (strcmp(value, "serializable") == 0) { if (doit) ! XactIsoLevel = XACT_SERIALIZABLE; } else if (strcmp(value, "read committed") == 0) { if (doit) ! XactIsoLevel = XACT_READ_COMMITTED; } else if (strcmp(value, "default") == 0) { if (doit) ! XactIsoLevel = DefaultXactIsoLevel; } else return NULL; --- 416,438 ---- const char * assign_XactIsoLevel(const char *value, bool doit, bool interactive) { ! if (doit && interactive && IsValidSerializableSnapshot()) elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query"); if (strcmp(value, "serializable") == 0) { if (doit) ! SetXactIsoLevel(XACT_SERIALIZABLE); } else if (strcmp(value, "read committed") == 0) { if (doit) ! SetXactIsoLevel(XACT_READ_COMMITTED); } else if (strcmp(value, "default") == 0) { if (doit) ! SetXactIsoLevel(DefaultXactIsoLevel); } else return NULL; *************** *** 443,449 **** const char * show_XactIsoLevel(void) { ! if (XactIsoLevel == XACT_SERIALIZABLE) return "SERIALIZABLE"; else return "READ COMMITTED"; --- 443,449 ---- const char * show_XactIsoLevel(void) { ! if (GetXactIsoLevel() == XACT_SERIALIZABLE) return "SERIALIZABLE"; else return "READ COMMITTED"; Index: backend/executor/execMain.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/execMain.c,v retrieving revision 1.205 diff -c -r1.205 execMain.c *** backend/executor/execMain.c 2003/03/27 16:51:27 1.205 --- backend/executor/execMain.c 2003/04/17 22:51:55 *************** *** 1106,1112 **** break; case HeapTupleUpdated: ! if (XactIsoLevel == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); if (!(ItemPointerEquals(&(tuple.t_self), (ItemPointer) DatumGetPointer(datum)))) --- 1106,1112 ---- break; case HeapTupleUpdated: ! if (GetXactIsoLevel() == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); if (!(ItemPointerEquals(&(tuple.t_self), (ItemPointer) DatumGetPointer(datum)))) *************** *** 1400,1406 **** break; case HeapTupleUpdated: ! if (XactIsoLevel == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); else if (!(ItemPointerEquals(tupleid, &ctid))) { --- 1400,1406 ---- break; case HeapTupleUpdated: ! if (GetXactIsoLevel() == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); else if (!(ItemPointerEquals(tupleid, &ctid))) { *************** *** 1535,1541 **** break; case HeapTupleUpdated: ! if (XactIsoLevel == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); else if (!(ItemPointerEquals(tupleid, &ctid))) { --- 1535,1541 ---- break; case HeapTupleUpdated: ! if (GetXactIsoLevel() == XACT_SERIALIZABLE) elog(ERROR, "Can't serialize access due to concurrent update"); else if (!(ItemPointerEquals(tupleid, &ctid))) { *************** *** 1732,1742 **** { Buffer buffer; ! if (heap_fetch(relation, SnapshotDirty, &tuple, &buffer, false, NULL)) { ! TransactionId xwait = SnapshotDirty->xmax; ! if (TransactionIdIsValid(SnapshotDirty->xmin)) elog(ERROR, "EvalPlanQual: t_xmin is uncommitted ?!"); /* --- 1732,1742 ---- { Buffer buffer; ! if (heap_fetch(relation, GetSnapshotDirty(), &tuple, &buffer, false, NULL)) { ! TransactionId xwait = GetXmaxSnapshotDirty(); ! if (TransactionIdIsValid(GetXminSnapshotDirty())) elog(ERROR, "EvalPlanQual: t_xmin is uncommitted ?!"); /* *************** *** 1763,1773 **** * Note that it's possible to get invalid SnapshotDirty->tid if * tuple updated by this transaction. Have we to check this ? */ ! if (ItemPointerIsValid(&(SnapshotDirty->tid)) && ! !(ItemPointerEquals(&(tuple.t_self), &(SnapshotDirty->tid)))) { /* updated, so look at the updated copy */ ! tuple.t_self = SnapshotDirty->tid; continue; } --- 1763,1774 ---- * Note that it's possible to get invalid SnapshotDirty->tid if * tuple updated by this transaction. Have we to check this ? */ ! if (ItemPointerIsValid(GetTidSnapshotDirty()) && ! !(ItemPointerEquals(&(tuple.t_self), GetTidSnapshotDirty()))) { /* updated, so look at the updated copy */ ! ItemPointer tid = GetTidSnapshotDirty(); ! tuple.t_self = *tid; continue; } Index: backend/executor/execQual.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/execQual.c,v retrieving revision 1.128 diff -c -r1.128 execQual.c *** backend/executor/execQual.c 2003/04/08 23:20:00 1.128 --- backend/executor/execQual.c 2003/04/17 22:51:59 *************** *** 35,40 **** --- 35,41 ---- #include "postgres.h" #include "access/heapam.h" + #include "access/xact.h" #include "catalog/pg_type.h" #include "commands/typecmds.h" #include "executor/execdebug.h" *************** *** 391,397 **** TupleTableSlot *tempSlot; HeapTuple tup; ! oldContext = MemoryContextSwitchTo(TransactionCommandContext); tempSlot = MakeTupleTableSlot(); tup = heap_copytuple(heapTuple); ExecStoreTuple(tup, tempSlot, InvalidBuffer, true); --- 392,398 ---- TupleTableSlot *tempSlot; HeapTuple tup; ! oldContext = MemoryContextSwitchTo(GetTransactionCommandContext()); tempSlot = MakeTupleTableSlot(); tup = heap_copytuple(heapTuple); ExecStoreTuple(tup, tempSlot, InvalidBuffer, true); Index: backend/executor/spi.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/spi.c,v retrieving revision 1.89 diff -c -r1.89 spi.c *** backend/executor/spi.c 2003/03/27 16:51:28 1.89 --- backend/executor/spi.c 2003/04/17 22:52:02 *************** *** 15,20 **** --- 15,21 ---- #include "postgres.h" #include "access/printtup.h" + #include "access/xact.h" #include "catalog/heap.h" #include "commands/portalcmds.h" #include "executor/spi_priv.h" *************** *** 92,103 **** _SPI_current->tuptable = NULL; /* Create memory contexts for this procedure */ ! _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext, "SPI Proc", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); ! _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext, "SPI Exec", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, --- 93,104 ---- _SPI_current->tuptable = NULL; /* Create memory contexts for this procedure */ ! _SPI_current->procCxt = AllocSetContextCreate(GetTopTransactionContext(), "SPI Proc", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); ! _SPI_current->execCxt = AllocSetContextCreate(GetTopTransactionContext(), "SPI Exec", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, Index: backend/optimizer/geqo/geqo_eval.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/geqo/geqo_eval.c,v retrieving revision 1.61 diff -c -r1.61 geqo_eval.c *** backend/optimizer/geqo/geqo_eval.c 2003/01/20 18:54:49 1.61 --- backend/optimizer/geqo/geqo_eval.c 2003/04/17 22:52:02 *************** *** 25,30 **** --- 25,31 ---- #include #include + #include "access/xact.h" #include "optimizer/geqo.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" *************** *** 68,74 **** * make the temp context a child of TransactionCommandContext, so that * it will be freed even if we abort via elog(ERROR). */ ! mycontext = AllocSetContextCreate(TransactionCommandContext, "GEQO", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, --- 69,75 ---- * make the temp context a child of TransactionCommandContext, so that * it will be freed even if we abort via elog(ERROR). */ ! mycontext = AllocSetContextCreate(GetTransactionCommandContext(), "GEQO", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, Index: backend/postmaster/pgstat.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/pgstat.c,v retrieving revision 1.32 diff -c -r1.32 pgstat.c *** backend/postmaster/pgstat.c 2003/03/20 03:34:56 1.32 --- backend/postmaster/pgstat.c 2003/04/17 22:52:06 *************** *** 2081,2087 **** } else { ! use_mcxt = TopTransactionContext; mcxt_flags = HASH_CONTEXT; } --- 2081,2087 ---- } else { ! use_mcxt = GetTopTransactionContext(); mcxt_flags = HASH_CONTEXT; } Index: backend/postmaster/postmaster.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v retrieving revision 1.310 diff -c -r1.310 postmaster.c *** backend/postmaster/postmaster.c 2003/04/06 22:45:22 1.310 --- backend/postmaster/postmaster.c 2003/04/17 22:52:11 *************** *** 413,418 **** --- 413,427 ---- ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(PostmasterContext); + /* + * Create a toplevel transaction context. + */ + ToplevelTransactionContext = AllocSetContextCreate(TopMemoryContext, + "ToplevelTransaction", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + IgnoreSystemIndexes(false); /* Index: backend/storage/ipc/sinval.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/storage/ipc/sinval.c,v retrieving revision 1.54 diff -c -r1.54 sinval.c *** backend/storage/ipc/sinval.c 2003/02/23 23:20:52 1.54 --- backend/storage/ipc/sinval.c 2003/04/17 22:52:12 *************** *** 307,313 **** Snapshot GetSnapshotData(bool serializable) { ! Snapshot snapshot = (Snapshot) malloc(sizeof(SnapshotData)); SISeg *segP = shmInvalBuffer; ProcState *stateP = segP->procState; TransactionId xmin; --- 307,313 ---- Snapshot GetSnapshotData(bool serializable) { ! Snapshot snapshot = (Snapshot) palloc(sizeof(SnapshotData)); SISeg *segP = shmInvalBuffer; ProcState *stateP = segP->procState; TransactionId xmin; *************** *** 316,333 **** int index; int count = 0; - if (snapshot == NULL) - elog(ERROR, "Memory exhausted in GetSnapshotData"); - /* * Allocating space for MaxBackends xids is usually overkill; * lastBackend would be sufficient. But it seems better to do the ! * malloc while not holding the lock, so we can't look at lastBackend. */ snapshot->xip = (TransactionId *) ! malloc(MaxBackends * sizeof(TransactionId)); ! if (snapshot->xip == NULL) ! elog(ERROR, "Memory exhausted in GetSnapshotData"); globalxmin = xmin = GetCurrentTransactionId(); --- 316,328 ---- int index; int count = 0; /* * Allocating space for MaxBackends xids is usually overkill; * lastBackend would be sufficient. But it seems better to do the ! * palloc while not holding the lock, so we can't look at lastBackend. */ snapshot->xip = (TransactionId *) ! palloc(MaxBackends * sizeof(TransactionId)); globalxmin = xmin = GetCurrentTransactionId(); *************** *** 421,428 **** globalxmin = xmin; /* Update globals for use by VACUUM */ ! RecentGlobalXmin = globalxmin; ! RecentXmin = xmin; snapshot->xmin = xmin; snapshot->xmax = xmax; --- 416,423 ---- globalxmin = xmin; /* Update globals for use by VACUUM */ ! SetRecentGlobalXmin(globalxmin); ! SetRecentXmin(xmin); snapshot->xmin = xmin; snapshot->xmax = xmax; Index: backend/storage/lmgr/lwlock.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/storage/lmgr/lwlock.c,v retrieving revision 1.14 diff -c -r1.14 lwlock.c *** backend/storage/lmgr/lwlock.c 2002/09/25 20:31:40 1.14 --- backend/storage/lmgr/lwlock.c 2003/04/17 22:52:13 *************** *** 22,27 **** --- 22,28 ---- #include "postgres.h" #include "access/clog.h" + #include "access/xact.h" #include "storage/lwlock.h" #include "storage/proc.h" #include "storage/spin.h" *************** *** 58,65 **** #define MAX_SIMUL_LWLOCKS 100 static int num_held_lwlocks = 0; - static LWLockId held_lwlocks[MAX_SIMUL_LWLOCKS]; #ifdef LOCK_DEBUG bool Trace_lwlocks = false; --- 59,72 ---- #define MAX_SIMUL_LWLOCKS 100 static int num_held_lwlocks = 0; + typedef struct held_lock + { + LWLockId lockId; + TransactionId transactionId; + } held_lock; + + static held_lock held_lwlocks[MAX_SIMUL_LWLOCKS]; #ifdef LOCK_DEBUG bool Trace_lwlocks = false; *************** *** 326,332 **** /* Add lock to list of locks held by this backend */ Assert(num_held_lwlocks < MAX_SIMUL_LWLOCKS); ! held_lwlocks[num_held_lwlocks++] = lockid; /* * Fix the process wait semaphore's count for any absorbed wakeups. --- 333,340 ---- /* Add lock to list of locks held by this backend */ Assert(num_held_lwlocks < MAX_SIMUL_LWLOCKS); ! held_lwlocks[num_held_lwlocks].lockId = lockid; ! held_lwlocks[num_held_lwlocks++].transactionId = GetCurrentTransactionId(); /* * Fix the process wait semaphore's count for any absorbed wakeups. *************** *** 395,401 **** { /* Add lock to list of locks held by this backend */ Assert(num_held_lwlocks < MAX_SIMUL_LWLOCKS); ! held_lwlocks[num_held_lwlocks++] = lockid; } return !mustwait; --- 403,410 ---- { /* Add lock to list of locks held by this backend */ Assert(num_held_lwlocks < MAX_SIMUL_LWLOCKS); ! held_lwlocks[num_held_lwlocks].lockId = lockid; ! held_lwlocks[num_held_lwlocks++].transactionId = GetCurrentTransactionId(); } return !mustwait; *************** *** 420,433 **** */ for (i = num_held_lwlocks; --i >= 0;) { ! if (lockid == held_lwlocks[i]) break; } if (i < 0) elog(ERROR, "LWLockRelease: lock %d is not held", (int) lockid); num_held_lwlocks--; for (; i < num_held_lwlocks; i++) ! held_lwlocks[i] = held_lwlocks[i + 1]; /* Acquire mutex. Time spent holding mutex should be short! */ SpinLockAcquire_NoHoldoff(&lock->mutex); --- 429,445 ---- */ for (i = num_held_lwlocks; --i >= 0;) { ! if (lockid == held_lwlocks[i].lockId) break; } if (i < 0) elog(ERROR, "LWLockRelease: lock %d is not held", (int) lockid); num_held_lwlocks--; for (; i < num_held_lwlocks; i++) ! { ! held_lwlocks[i].lockId = held_lwlocks[i + 1].lockId; ! held_lwlocks[i].transactionId = held_lwlocks[i + 1].transactionId; ! } /* Acquire mutex. Time spent holding mutex should be short! */ SpinLockAcquire_NoHoldoff(&lock->mutex); *************** *** 512,521 **** void LWLockReleaseAll(void) { ! while (num_held_lwlocks > 0) { ! HOLD_INTERRUPTS(); /* match the upcoming RESUME_INTERRUPTS */ ! LWLockRelease(held_lwlocks[num_held_lwlocks - 1]); } } --- 524,539 ---- void LWLockReleaseAll(void) { ! TransactionId xid = GetCurrentTransactionId(); ! int i; ! ! for (i=0; i < num_held_lwlocks; i++) { ! if (held_lwlocks[i].transactionId == xid) ! { ! HOLD_INTERRUPTS(); /* match the upcoming RESUME_INTERRUPTS */ ! LWLockRelease(held_lwlocks[i].lockId); ! } } } Index: backend/storage/smgr/smgr.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/storage/smgr/smgr.c,v retrieving revision 1.62 diff -c -r1.62 smgr.c *** backend/storage/smgr/smgr.c 2003/03/04 21:51:21 1.62 --- backend/storage/smgr/smgr.c 2003/04/17 22:52:14 *************** *** 17,22 **** --- 17,23 ---- */ #include "postgres.h" + #include "access/xact.h" #include "storage/bufmgr.h" #include "storage/freespace.h" #include "storage/ipc.h" *************** *** 97,105 **** * executed immediately, but is just entered in the list. When and if * the transaction commits, we can delete the physical file. * ! * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear ! * unbetimes. It'd probably be OK to keep it in TopTransactionContext, ! * but I'm being paranoid. */ typedef struct PendingRelDelete --- 98,105 ---- * executed immediately, but is just entered in the list. When and if * the transaction commits, we can delete the physical file. * ! * The list is kept in TopTransactionContext. When a transaction ends, ! * all the memory is released when the TopTransactionContext is reset. */ typedef struct PendingRelDelete *************** *** 111,117 **** struct PendingRelDelete *next; /* linked-list link */ } PendingRelDelete; ! static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */ /* --- 111,124 ---- struct PendingRelDelete *next; /* linked-list link */ } PendingRelDelete; ! typedef struct PendingRelDeleteStack ! { ! PendingRelDelete *pendingDelete; ! struct PendingRelDeleteStack *parent; ! } PendingRelDeleteStack; ! ! /* top of the stack */ ! static PendingRelDeleteStack *pendingDeletes = NULL; /* *************** *** 175,187 **** /* Add the relation to the list of stuff to delete at abort */ pending = (PendingRelDelete *) ! MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); pending->relnode = reln->rd_node; pending->which = which; pending->isTemp = reln->rd_istemp; pending->atCommit = false; /* delete if abort */ ! pending->next = pendingDeletes; ! pendingDeletes = pending; return fd; } --- 182,195 ---- /* Add the relation to the list of stuff to delete at abort */ pending = (PendingRelDelete *) ! MemoryContextAlloc(GetTopTransactionContext(), ! sizeof(PendingRelDelete)); pending->relnode = reln->rd_node; pending->which = which; pending->isTemp = reln->rd_istemp; pending->atCommit = false; /* delete if abort */ ! pending->next = pendingDeletes->pendingDelete; ! pendingDeletes->pendingDelete = pending; return fd; } *************** *** 203,215 **** /* Add the relation to the list of stuff to delete at commit */ pending = (PendingRelDelete *) ! MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); pending->relnode = reln->rd_node; pending->which = which; pending->isTemp = reln->rd_istemp; pending->atCommit = true; /* delete if commit */ ! pending->next = pendingDeletes; ! pendingDeletes = pending; /* * NOTE: if the relation was created in this transaction, it will now --- 211,224 ---- /* Add the relation to the list of stuff to delete at commit */ pending = (PendingRelDelete *) ! MemoryContextAlloc(GetTopTransactionContext(), ! sizeof(PendingRelDelete)); pending->relnode = reln->rd_node; pending->which = which; pending->isTemp = reln->rd_istemp; pending->atCommit = true; /* delete if commit */ ! pending->next = pendingDeletes->pendingDelete; ! pendingDeletes->pendingDelete = pending; /* * NOTE: if the relation was created in this transaction, it will now *************** *** 422,437 **** } /* * smgrDoPendingDeletes() -- take care of relation deletes at end of xact. */ int smgrDoPendingDeletes(bool isCommit) { ! while (pendingDeletes != NULL) ! { ! PendingRelDelete *pending = pendingDeletes; ! pendingDeletes = pending->next; if (pending->atCommit == isCommit) { /* --- 431,470 ---- } /* + * Create the pending deletes stack item. + */ + void + smgrCreatePendingDeletes(void) + { + MemoryContext old_cxt; + PendingRelDeleteStack *ps; + + old_cxt = MemoryContextSwitchTo(GetTopTransactionContext()); + ps = (PendingRelDeleteStack *) palloc(sizeof(PendingRelDeleteStack)); + MemoryContextSwitchTo(old_cxt); + + ps->parent = pendingDeletes; + ps->pendingDelete = NULL; + + pendingDeletes = ps; + } + + + /* * smgrDoPendingDeletes() -- take care of relation deletes at end of xact. */ int smgrDoPendingDeletes(bool isCommit) { ! PendingRelDelete *pending; ! ! if (pendingDeletes == NULL) ! return SM_SUCCESS; ! ! pending = pendingDeletes->pendingDelete; ! while (pending != NULL) ! { if (pending->atCommit == isCommit) { /* *************** *** 459,467 **** elog(WARNING, "cannot unlink %u/%u: %m", pending->relnode.tblNode, pending->relnode.relNode); } ! pfree(pending); } return SM_SUCCESS; } --- 492,501 ---- elog(WARNING, "cannot unlink %u/%u: %m", pending->relnode.tblNode, pending->relnode.relNode); } ! pending = pending->next; } + pendingDeletes = pendingDeletes->parent; return SM_SUCCESS; } Index: backend/utils/adt/ri_triggers.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ri_triggers.c,v retrieving revision 1.49 diff -c -r1.49 ri_triggers.c *** backend/utils/adt/ri_triggers.c 2003/04/07 20:30:38 1.49 --- backend/utils/adt/ri_triggers.c 2003/04/17 22:52:20 *************** *** 193,199 **** int i; int match_type; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 193,199 ---- int i; int match_type; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 654,660 **** int i; int match_type; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 654,660 ---- int i; int match_type; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 848,854 **** int i; int match_type; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 848,854 ---- int i; int match_type; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 1049,1055 **** void *qplan; int i; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 1049,1055 ---- void *qplan; int i; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 1228,1234 **** int i; int j; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 1228,1234 ---- int i; int j; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 1432,1438 **** void *qplan; int i; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 1432,1438 ---- void *qplan; int i; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 1617,1623 **** void *qplan; int i; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 1617,1623 ---- void *qplan; int i; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 1805,1811 **** void *qplan; int i; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 1805,1811 ---- void *qplan; int i; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 1993,1999 **** int match_type; bool use_cached_query; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 1993,1999 ---- int match_type; bool use_cached_query; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 2226,2232 **** RI_QueryKey qkey; void *qplan; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 2226,2232 ---- RI_QueryKey qkey; void *qplan; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and *************** *** 2451,2457 **** void *qplan; int match_type; ! ReferentialIntegritySnapshotOverride = true; /* * Check that this is a valid trigger call on the right time and --- 2451,2457 ---- void *qplan; int match_type; ! SetReferentialIntegritySnapshotOverride(true); /* * Check that this is a valid trigger call on the right time and Index: backend/utils/cache/inval.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/cache/inval.c,v retrieving revision 1.55 diff -c -r1.55 inval.c *** backend/utils/cache/inval.c 2002/09/04 20:31:29 1.55 --- backend/utils/cache/inval.c 2003/04/17 22:52:21 *************** *** 80,85 **** --- 80,86 ---- */ #include "postgres.h" + #include "access/xact.h" #include "catalog/catalog.h" #include "miscadmin.h" #include "storage/sinval.h" *************** *** 174,180 **** /* First time through; create initial chunk */ #define FIRSTCHUNKSIZE 16 chunk = (InvalidationChunk *) ! MemoryContextAlloc(TopTransactionContext, sizeof(InvalidationChunk) + (FIRSTCHUNKSIZE - 1) *sizeof(SharedInvalidationMessage)); chunk->nitems = 0; --- 175,181 ---- /* First time through; create initial chunk */ #define FIRSTCHUNKSIZE 16 chunk = (InvalidationChunk *) ! MemoryContextAlloc(GetTopTransactionContext(), sizeof(InvalidationChunk) + (FIRSTCHUNKSIZE - 1) *sizeof(SharedInvalidationMessage)); chunk->nitems = 0; *************** *** 188,194 **** int chunksize = 2 * chunk->maxitems; chunk = (InvalidationChunk *) ! MemoryContextAlloc(TopTransactionContext, sizeof(InvalidationChunk) + (chunksize - 1) *sizeof(SharedInvalidationMessage)); chunk->nitems = 0; --- 189,195 ---- int chunksize = 2 * chunk->maxitems; chunk = (InvalidationChunk *) ! MemoryContextAlloc(GetTopTransactionContext(), sizeof(InvalidationChunk) + (chunksize - 1) *sizeof(SharedInvalidationMessage)); chunk->nitems = 0; Index: backend/utils/mmgr/README =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/mmgr/README,v retrieving revision 1.3 diff -c -r1.3 README *** backend/utils/mmgr/README 2001/02/15 21:38:26 1.3 --- backend/utils/mmgr/README 2003/04/17 22:52:23 *************** *** 70,76 **** We could even consider getting rid of CurrentMemoryContext entirely, instead requiring the target memory context for allocation to be specified explicitly. But I think that would be too much notational overhead --- ! we'd have to pass an apppropriate memory context to called routines in many places. For example, the copyObject routines would need to be passed a context, as would function execution routines that return a pass-by-reference datatype. And what of routines that temporarily --- 70,76 ---- We could even consider getting rid of CurrentMemoryContext entirely, instead requiring the target memory context for allocation to be specified explicitly. But I think that would be too much notational overhead --- ! we'd have to pass an appropriate memory context to called routines in many places. For example, the copyObject routines would need to be passed a context, as would function execution routines that return a pass-by-reference datatype. And what of routines that temporarily Index: backend/utils/mmgr/mcxt.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/mmgr/mcxt.c,v retrieving revision 1.39 diff -c -r1.39 mcxt.c *** backend/utils/mmgr/mcxt.c 2003/03/27 16:51:29 1.39 --- backend/utils/mmgr/mcxt.c 2003/04/17 22:52:24 *************** *** 44,51 **** MemoryContext PostmasterContext = NULL; MemoryContext CacheMemoryContext = NULL; MemoryContext QueryContext = NULL; ! MemoryContext TopTransactionContext = NULL; ! MemoryContext TransactionCommandContext = NULL; /***************************************************************************** --- 44,50 ---- MemoryContext PostmasterContext = NULL; MemoryContext CacheMemoryContext = NULL; MemoryContext QueryContext = NULL; ! MemoryContext ToplevelTransactionContext = NULL; /***************************************************************************** Index: backend/utils/time/tqual.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/time/tqual.c,v retrieving revision 1.62 diff -c -r1.62 tqual.c *** backend/utils/time/tqual.c 2003/02/23 23:20:52 1.62 --- backend/utils/time/tqual.c 2003/04/17 22:52:26 *************** *** 26,45 **** #include "storage/sinval.h" #include "utils/tqual.h" ! static SnapshotData SnapshotDirtyData; ! Snapshot SnapshotDirty = &SnapshotDirtyData; ! Snapshot QuerySnapshot = NULL; ! Snapshot SerializableSnapshot = NULL; - /* These are updated by GetSnapshotData: */ - TransactionId RecentXmin = InvalidTransactionId; - TransactionId RecentGlobalXmin = InvalidTransactionId; - - bool ReferentialIntegritySnapshotOverride = false; - - /* * HeapTupleSatisfiesItself * True iff heap tuple is valid "for itself". --- 26,45 ---- #include "storage/sinval.h" #include "utils/tqual.h" + typedef struct SnapshotStackData { + SnapshotData SnapshotDirtyData; + Snapshot QuerySnapshot; + Snapshot SerializableSnapshot; + TransactionId RecentXmin; + TransactionId RecentGlobalXmin; + bool ReferentialIntegritySnapshotOverride; + struct SnapshotStackData *parent; + } SnapshotStackData; ! typedef SnapshotStackData *SnapshotStack; ! static SnapshotStack snapshotStack = NULL; /* * HeapTupleSatisfiesItself * True iff heap tuple is valid "for itself". *************** *** 501,509 **** bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple) { ! SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId; ! ItemPointerSetInvalid(&(SnapshotDirty->tid)); if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) --- 501,512 ---- bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple) { ! ItemPointer tid = &(snapshotStack->SnapshotDirtyData.tid); + snapshotStack->SnapshotDirtyData.xmin = + snapshotStack->SnapshotDirtyData.xmax = InvalidTransactionId; + ItemPointerSetInvalid(tid); + if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) *************** *** 557,563 **** tuple->t_infomask |= HEAP_XMIN_INVALID; return false; } ! SnapshotDirty->xmin = HeapTupleHeaderGetXmin(tuple); /* XXX shouldn't we fall through to look at xmax? */ return true; /* in insertion by other */ } --- 560,566 ---- tuple->t_infomask |= HEAP_XMIN_INVALID; return false; } ! snapshotStack->SnapshotDirtyData.xmin = HeapTupleHeaderGetXmin(tuple); /* XXX shouldn't we fall through to look at xmax? */ return true; /* in insertion by other */ } *************** *** 574,580 **** { if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) return true; ! SnapshotDirty->tid = tuple->t_ctid; return false; /* updated by other */ } --- 577,583 ---- { if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) return true; ! snapshotStack->SnapshotDirtyData.tid = tuple->t_ctid; return false; /* updated by other */ } *************** *** 593,599 **** return true; } /* running xact */ ! SnapshotDirty->xmax = HeapTupleHeaderGetXmax(tuple); return true; /* in updation by other */ } --- 596,602 ---- return true; } /* running xact */ ! snapshotStack->SnapshotDirtyData.xmax = HeapTupleHeaderGetXmax(tuple); return true; /* in updation by other */ } *************** *** 603,609 **** if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) return true; ! SnapshotDirty->tid = tuple->t_ctid; return false; /* updated by other */ } --- 606,612 ---- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) return true; ! snapshotStack->SnapshotDirtyData.tid = tuple->t_ctid; return false; /* updated by other */ } *************** *** 632,638 **** HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) { /* XXX this is horribly ugly: */ ! if (ReferentialIntegritySnapshotOverride) return HeapTupleSatisfiesNow(tuple); if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) --- 635,641 ---- HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) { /* XXX this is horribly ugly: */ ! if (snapshotStack->ReferentialIntegritySnapshotOverride) return HeapTupleSatisfiesNow(tuple); if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) *************** *** 935,965 **** void SetQuerySnapshot(void) { /* Initialize snapshot overriding to false */ ! ReferentialIntegritySnapshotOverride = false; /* 1st call in xaction? */ ! if (SerializableSnapshot == NULL) { ! SerializableSnapshot = GetSnapshotData(true); ! QuerySnapshot = SerializableSnapshot; ! Assert(QuerySnapshot != NULL); return; } ! if (QuerySnapshot != SerializableSnapshot) { ! free(QuerySnapshot->xip); ! free(QuerySnapshot); ! QuerySnapshot = NULL; } ! if (XactIsoLevel == XACT_SERIALIZABLE) ! QuerySnapshot = SerializableSnapshot; else ! QuerySnapshot = GetSnapshotData(false); ! Assert(QuerySnapshot != NULL); } /* --- 938,979 ---- void SetQuerySnapshot(void) { + MemoryContext old_cxt; + /* Initialize snapshot overriding to false */ ! snapshotStack->ReferentialIntegritySnapshotOverride = false; + /* + * Switch to TopTransactionContext so the Snapshot are palloc'ed + * there. + */ + old_cxt = MemoryContextSwitchTo(GetTopTransactionContext()); + /* 1st call in xaction? */ ! if (snapshotStack->SerializableSnapshot == NULL) { ! snapshotStack->SerializableSnapshot = GetSnapshotData(true); ! snapshotStack->QuerySnapshot = snapshotStack->SerializableSnapshot; ! Assert(snapshotStack->QuerySnapshot != NULL); ! MemoryContextSwitchTo(old_cxt); return; } ! if (snapshotStack->QuerySnapshot != snapshotStack->SerializableSnapshot) { ! pfree(snapshotStack->QuerySnapshot->xip); ! pfree(snapshotStack->QuerySnapshot); ! snapshotStack->QuerySnapshot = NULL; } ! if (GetXactIsoLevel() == XACT_SERIALIZABLE) ! snapshotStack->QuerySnapshot = snapshotStack->SerializableSnapshot; else ! snapshotStack->QuerySnapshot = GetSnapshotData(false); ! ! MemoryContextSwitchTo(old_cxt); ! Assert(snapshotStack->QuerySnapshot != NULL); } /* *************** *** 978,993 **** { Snapshot snapshot; ! if (QuerySnapshot == NULL) /* should be set beforehand */ elog(ERROR, "CopyQuerySnapshot: no snapshot has been set"); snapshot = (Snapshot) palloc(sizeof(SnapshotData)); ! memcpy(snapshot, QuerySnapshot, sizeof(SnapshotData)); if (snapshot->xcnt > 0) { snapshot->xip = (TransactionId *) palloc(snapshot->xcnt * sizeof(TransactionId)); ! memcpy(snapshot->xip, QuerySnapshot->xip, snapshot->xcnt * sizeof(TransactionId)); } else --- 992,1007 ---- { Snapshot snapshot; ! if (snapshotStack->QuerySnapshot == NULL) /* should be set beforehand */ elog(ERROR, "CopyQuerySnapshot: no snapshot has been set"); snapshot = (Snapshot) palloc(sizeof(SnapshotData)); ! memcpy(snapshot, snapshotStack->QuerySnapshot, sizeof(SnapshotData)); if (snapshot->xcnt > 0) { snapshot->xip = (TransactionId *) palloc(snapshot->xcnt * sizeof(TransactionId)); ! memcpy(snapshot->xip, snapshotStack->QuerySnapshot->xip, snapshot->xcnt * sizeof(TransactionId)); } else *************** *** 997,1021 **** } /* ! * FreeXactSnapshot ! * Free snapshot(s) at end of transaction. */ void ! FreeXactSnapshot(void) { ! if (QuerySnapshot != NULL && QuerySnapshot != SerializableSnapshot) ! { ! free(QuerySnapshot->xip); ! free(QuerySnapshot); ! } ! QuerySnapshot = NULL; ! if (SerializableSnapshot != NULL) ! { ! free(SerializableSnapshot->xip); ! free(SerializableSnapshot); ! } ! SerializableSnapshot = NULL; } --- 1011,1141 ---- } /* ! * Add a SnapshotStack item */ void ! AtStart_Snapshot(void) { ! SnapshotStack ssitem; ! MemoryContext old_cxt; ! old_cxt = MemoryContextSwitchTo(GetTopTransactionContext()); ! ssitem = (SnapshotStack) palloc(sizeof(SnapshotStackData)); ! ssitem->parent = snapshotStack; ! ssitem->SerializableSnapshot = NULL; ! ssitem->QuerySnapshot = NULL; ! ssitem->RecentXmin = InvalidTransactionId; ! ssitem->RecentGlobalXmin = InvalidTransactionId; ! snapshotStack = ssitem; ! MemoryContextSwitchTo(old_cxt); ! } ! /* ! * Pops the SnapshotStack item ! */ ! void ! AtEOXact_Snapshot(void) ! { ! Assert(snapshotStack != NULL); ! snapshotStack = snapshotStack->parent; ! ! /* ! * The leftover stack item will be deleted when the transaction ! * memory context is reset or deleted. ! */ ! ! } ! ! TransactionId ! GetRecentXmin(void) ! { ! return snapshotStack->RecentXmin; ! } ! ! void ! SetRecentXmin(TransactionId recentXmin) ! { ! snapshotStack->RecentXmin = recentXmin; ! } ! ! TransactionId ! GetRecentGlobalXmin(void) ! { ! return snapshotStack->RecentGlobalXmin; ! } ! ! void ! SetRecentGlobalXmin(TransactionId recentGlobalXmin) ! { ! snapshotStack->RecentGlobalXmin = recentGlobalXmin; ! } ! ! void ! SetReferentialIntegritySnapshotOverride(bool override) ! { ! Assert(snapshotStack != NULL); ! snapshotStack->ReferentialIntegritySnapshotOverride = override; ! } ! ! Snapshot ! GetSnapshotDirty(void) ! { ! Assert(snapshotStack != NULL); ! return &(snapshotStack->SnapshotDirtyData); ! } ! ! void ! SetQuerySnapshotCurCid(CommandId curcid) ! { ! Assert(IsValidQuerySnapshot()); ! snapshotStack->QuerySnapshot->curcid = curcid; ! } ! ! bool ! IsValidQuerySnapshot(void) ! { ! Assert (snapshotStack != NULL); ! return (snapshotStack->QuerySnapshot != NULL); ! } ! ! void ! SetSerializableSnapshotCurCid(CommandId curcid) ! { ! Assert(IsValidSerializableSnapshot()); ! snapshotStack->SerializableSnapshot->curcid = curcid; ! } ! ! bool ! IsValidSerializableSnapshot(void) ! { ! Assert(snapshotStack != NULL); ! return (snapshotStack->SerializableSnapshot != NULL); ! } ! ! bool ! IsSnapshotDirty(Snapshot snapshot) ! { ! Assert(snapshotStack != NULL); ! return (snapshot == &(snapshotStack->SnapshotDirtyData)); ! } ! ! TransactionId ! GetXminSnapshotDirty(void) ! { ! Assert(snapshotStack != NULL); ! return snapshotStack->SnapshotDirtyData.xmin; ! } ! TransactionId ! GetXmaxSnapshotDirty(void) ! { ! Assert(snapshotStack != NULL); ! return snapshotStack->SnapshotDirtyData.xmax; ! } ! ! ItemPointer ! GetTidSnapshotDirty(void) ! { ! Assert(snapshotStack != NULL); ! return &(snapshotStack->SnapshotDirtyData.tid); } Index: include/access/xact.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/access/xact.h,v retrieving revision 1.49 diff -c -r1.49 xact.h *** include/access/xact.h 2003/01/10 22:03:30 1.49 --- include/access/xact.h 2003/04/17 22:52:27 *************** *** 28,34 **** #define XACT_SERIALIZABLE 3 extern int DefaultXactIsoLevel; - extern int XactIsoLevel; extern bool DefaultXactReadOnly; extern bool XactReadOnly; --- 28,33 ---- *************** *** 39,50 **** */ typedef struct TransactionStateData { ! TransactionId transactionIdData; ! CommandId commandId; ! AbsoluteTime startTime; ! int startTimeUsec; ! int state; ! int blockState; } TransactionStateData; typedef TransactionStateData *TransactionState; --- 38,53 ---- */ typedef struct TransactionStateData { ! TransactionId transactionIdData; ! CommandId commandId; ! AbsoluteTime startTime; ! int startTimeUsec; ! int state; ! int blockState; ! MemoryContext topTransactionContext; ! MemoryContext transactionCommandContext; ! int xactIsoLevel; ! struct TransactionStateData *parent; } TransactionStateData; typedef TransactionStateData *TransactionState; *************** *** 66,75 **** */ #define TBLOCK_DEFAULT 0 #define TBLOCK_BEGIN 1 ! #define TBLOCK_INPROGRESS 2 ! #define TBLOCK_END 3 ! #define TBLOCK_ABORT 4 ! #define TBLOCK_ENDABORT 5 /* * XLOG allows to store some information in high 4 bits of log --- 69,79 ---- */ #define TBLOCK_DEFAULT 0 #define TBLOCK_BEGIN 1 ! #define TBLOCK_BEGINSUB 2 ! #define TBLOCK_INPROGRESS 3 ! #define TBLOCK_END 4 ! #define TBLOCK_ABORT 5 ! #define TBLOCK_ENDABORT 6 /* * XLOG allows to store some information in high 4 bits of log *************** *** 106,111 **** --- 110,117 ---- extern CommandId GetCurrentCommandId(void); extern AbsoluteTime GetCurrentTransactionStartTime(void); extern AbsoluteTime GetCurrentTransactionStartTimeUsec(int *usec); + extern MemoryContext GetTopTransactionContext(void); + extern MemoryContext GetTransactionCommandContext(void); extern bool TransactionIdIsCurrentTransactionId(TransactionId xid); extern bool CommandIdIsCurrentCommandId(CommandId cid); extern void CommandCounterIncrement(void); *************** *** 119,124 **** --- 125,136 ---- extern void AbortOutOfAnyTransaction(void); extern void PreventTransactionChain(void *stmtNode, const char *stmtType); extern void RequireTransactionChain(void *stmtNode, const char *stmtType); + extern void PushCurrentTransaction(void); + extern void PopTransaction(void); + extern bool IsCurrentTransactionToplevel(void); + + extern int GetXactIsoLevel(void); + extern void SetXactIsoLevel(int xactIsoLevel); extern void RecordTransactionCommit(void); Index: include/storage/smgr.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/storage/smgr.h,v retrieving revision 1.36 diff -c -r1.36 smgr.h *** include/storage/smgr.h 2002/08/06 02:36:35 1.36 --- include/storage/smgr.h 2003/04/17 22:52:28 *************** *** 41,46 **** --- 41,47 ---- extern BlockNumber smgrnblocks(int16 which, Relation reln); extern BlockNumber smgrtruncate(int16 which, Relation reln, BlockNumber nblocks); + extern void smgrCreatePendingDeletes(void); extern int smgrDoPendingDeletes(bool isCommit); extern int smgrcommit(void); extern int smgrabort(void); Index: include/utils/memutils.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/utils/memutils.h,v retrieving revision 1.50 diff -c -r1.50 memutils.h *** include/utils/memutils.h 2002/12/16 16:22:46 1.50 --- include/utils/memutils.h 2003/04/17 22:52:28 *************** *** 69,76 **** extern DLLIMPORT MemoryContext PostmasterContext; extern DLLIMPORT MemoryContext CacheMemoryContext; extern DLLIMPORT MemoryContext QueryContext; ! extern DLLIMPORT MemoryContext TopTransactionContext; ! extern DLLIMPORT MemoryContext TransactionCommandContext; /* --- 69,75 ---- extern DLLIMPORT MemoryContext PostmasterContext; extern DLLIMPORT MemoryContext CacheMemoryContext; extern DLLIMPORT MemoryContext QueryContext; ! extern DLLIMPORT MemoryContext ToplevelTransactionContext; /* Index: include/utils/tqual.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/utils/tqual.h,v retrieving revision 1.44 diff -c -r1.44 tqual.h *** include/utils/tqual.h 2003/02/23 23:20:52 1.44 --- include/utils/tqual.h 2003/04/17 22:52:29 *************** *** 37,56 **** #define SnapshotAny ((Snapshot) 0x2) #define SnapshotToast ((Snapshot) 0x3) - extern DLLIMPORT Snapshot SnapshotDirty; - extern DLLIMPORT Snapshot QuerySnapshot; - extern DLLIMPORT Snapshot SerializableSnapshot; - - extern TransactionId RecentXmin; - extern TransactionId RecentGlobalXmin; - - extern bool ReferentialIntegritySnapshotOverride; - #define IsSnapshotNow(snapshot) ((Snapshot) (snapshot) == SnapshotNow) #define IsSnapshotSelf(snapshot) ((Snapshot) (snapshot) == SnapshotSelf) #define IsSnapshotAny(snapshot) ((Snapshot) (snapshot) == SnapshotAny) #define IsSnapshotToast(snapshot) ((Snapshot) (snapshot) == SnapshotToast) - #define IsSnapshotDirty(snapshot) ((Snapshot) (snapshot) == SnapshotDirty) /* --- 37,46 ---- *************** *** 117,121 **** --- 107,129 ---- extern void SetQuerySnapshot(void); extern Snapshot CopyQuerySnapshot(void); extern void FreeXactSnapshot(void); + + extern void AtStart_Snapshot(void); + extern void AtEOXact_Snapshot(void); + + extern TransactionId GetRecentXmin(void); + extern void SetRecentXmin(TransactionId recentXmin); + extern TransactionId GetRecentGlobalXmin(void); + extern void SetRecentGlobalXmin(TransactionId recentGlobalXmin); + extern void SetReferentialIntegritySnapshotOverride(bool override); + extern Snapshot GetSnapshotDirty(void); + extern void SetQuerySnapshotCurCid(CommandId curcid); + extern bool IsValidQuerySnapshot(void); + extern void SetSerializableSnapshotCurCid(CommandId curcid); + extern bool IsValidSerializableSnapshot(void); + extern bool IsSnapshotDirty(Snapshot snapshot); + extern TransactionId GetXminSnapshotDirty(void); + extern TransactionId GetXmaxSnapshotDirty(void); + extern ItemPointer GetTidSnapshotDirty(void); #endif /* TQUAL_H */