1 /*-------------------------------------------------------------------------
4 * top level transaction system support routines
6 * See src/backend/access/transam/README for more information.
8 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.192 2004/10/16 18:57:22 tgl Exp $
15 *-------------------------------------------------------------------------
23 #include "access/subtrans.h"
24 #include "access/xact.h"
25 #include "catalog/heap.h"
26 #include "catalog/index.h"
27 #include "catalog/namespace.h"
28 #include "commands/async.h"
29 #include "commands/tablecmds.h"
30 #include "commands/trigger.h"
31 #include "commands/user.h"
32 #include "executor/spi.h"
33 #include "libpq/be-fsstubs.h"
34 #include "miscadmin.h"
35 #include "storage/fd.h"
36 #include "storage/proc.h"
37 #include "storage/sinval.h"
38 #include "storage/smgr.h"
39 #include "utils/guc.h"
40 #include "utils/inval.h"
41 #include "utils/memutils.h"
42 #include "utils/portal.h"
43 #include "utils/relcache.h"
44 #include "utils/resowner.h"
49 * User-tweakable parameters
51 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
54 bool DefaultXactReadOnly = false;
57 int CommitDelay = 0; /* precommit delay in microseconds */
58 int CommitSiblings = 5; /* # concurrent xacts needed to sleep */
62 * transaction states - transaction state from server perspective
64 typedef enum TransState
74 * transaction block states - transaction state of client queries
76 * Note: the subtransaction states are used only for non-topmost
77 * transactions; the others appear only in the topmost transaction.
79 typedef enum TBlockState
81 /* not-in-transaction-block states */
82 TBLOCK_DEFAULT, /* idle */
83 TBLOCK_STARTED, /* running single-query transaction */
85 /* transaction block states */
86 TBLOCK_BEGIN, /* starting transaction block */
87 TBLOCK_INPROGRESS, /* live transaction */
88 TBLOCK_END, /* COMMIT received */
89 TBLOCK_ABORT, /* failed xact, awaiting ROLLBACK */
90 TBLOCK_ABORT_END, /* failed xact, ROLLBACK received */
91 TBLOCK_ABORT_PENDING, /* live xact, ROLLBACK received */
93 /* subtransaction states */
94 TBLOCK_SUBBEGIN, /* starting a subtransaction */
95 TBLOCK_SUBINPROGRESS, /* live subtransaction */
96 TBLOCK_SUBEND, /* RELEASE received */
97 TBLOCK_SUBABORT, /* failed subxact, awaiting ROLLBACK */
98 TBLOCK_SUBABORT_END, /* failed subxact, ROLLBACK received */
99 TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received */
100 TBLOCK_SUBRESTART, /* live subxact, ROLLBACK TO received */
101 TBLOCK_SUBABORT_RESTART /* failed subxact, ROLLBACK TO received */
105 * transaction state structure
107 typedef struct TransactionStateData
109 TransactionId transactionId; /* my XID, or Invalid if none */
110 SubTransactionId subTransactionId; /* my subxact ID */
111 char *name; /* savepoint name, if any */
112 int savepointLevel; /* savepoint level */
113 TransState state; /* low-level state */
114 TBlockState blockState; /* high-level state */
115 int nestingLevel; /* nest depth */
116 MemoryContext curTransactionContext; /* my xact-lifetime
118 ResourceOwner curTransactionOwner; /* my query resources */
119 List *childXids; /* subcommitted child XIDs */
120 AclId currentUser; /* subxact start current_user */
121 bool prevXactReadOnly; /* entry-time xact r/o state */
122 struct TransactionStateData *parent; /* back link to parent */
123 } TransactionStateData;
125 typedef TransactionStateData *TransactionState;
128 * childXids is currently implemented as an integer List, relying on the
129 * assumption that TransactionIds are no wider than int. We use these
130 * macros to provide some isolation in case that changes in the future.
132 #define lfirst_xid(lc) ((TransactionId) lfirst_int(lc))
133 #define lappend_xid(list, datum) lappend_int(list, (int) (datum))
136 * CurrentTransactionState always points to the current transaction state
137 * block. It will point to TopTransactionStateData when not in a
138 * transaction at all, or when in a top-level transaction.
140 static TransactionStateData TopTransactionStateData = {
141 0, /* transaction id */
142 0, /* subtransaction id */
143 NULL, /* savepoint name */
144 0, /* savepoint level */
145 TRANS_DEFAULT, /* transaction state */
146 TBLOCK_DEFAULT, /* transaction block state from the client
148 0, /* nesting level */
149 NULL, /* cur transaction context */
150 NULL, /* cur transaction resource owner */
151 NIL, /* subcommitted child Xids */
152 0, /* entry-time current userid */
153 false, /* entry-time xact r/o state */
154 NULL /* link to parent state block */
157 static TransactionState CurrentTransactionState = &TopTransactionStateData;
160 * The subtransaction ID and command ID assignment counters are global
161 * to a whole transaction, so we do not keep them in the state stack.
163 static SubTransactionId currentSubTransactionId;
164 static CommandId currentCommandId;
167 * These vars hold the value of now(), ie, the transaction start time.
168 * This does not change as we enter and exit subtransactions, so we don't
169 * keep it inside the TransactionState stack.
171 static AbsoluteTime xactStartTime; /* integer part */
172 static int xactStartTimeUsec; /* microsecond part */
176 * List of add-on start- and end-of-xact callbacks
178 typedef struct XactCallbackItem
180 struct XactCallbackItem *next;
181 XactCallback callback;
185 static XactCallbackItem *Xact_callbacks = NULL;
188 * List of add-on start- and end-of-subxact callbacks
190 typedef struct SubXactCallbackItem
192 struct SubXactCallbackItem *next;
193 SubXactCallback callback;
195 } SubXactCallbackItem;
197 static SubXactCallbackItem *SubXact_callbacks = NULL;
199 static void (*_RollbackFunc) (void *) = NULL;
200 static void *_RollbackData = NULL;
203 /* local function prototypes */
204 static void AssignSubTransactionId(TransactionState s);
205 static void AbortTransaction(void);
206 static void AtAbort_Memory(void);
207 static void AtCleanup_Memory(void);
208 static void AtAbort_ResourceOwner(void);
209 static void AtCommit_LocalCache(void);
210 static void AtCommit_Memory(void);
211 static void AtStart_Cache(void);
212 static void AtStart_Memory(void);
213 static void AtStart_ResourceOwner(void);
214 static void CallXactCallbacks(XactEvent event);
215 static void CallSubXactCallbacks(SubXactEvent event,
216 SubTransactionId mySubid,
217 SubTransactionId parentSubid);
218 static void CleanupTransaction(void);
219 static void CommitTransaction(void);
220 static void RecordTransactionAbort(void);
221 static void StartTransaction(void);
223 static void RecordSubTransactionCommit(void);
224 static void StartSubTransaction(void);
225 static void CommitSubTransaction(void);
226 static void AbortSubTransaction(void);
227 static void CleanupSubTransaction(void);
228 static void PushTransaction(void);
229 static void PopTransaction(void);
231 static void AtSubAbort_Memory(void);
232 static void AtSubCleanup_Memory(void);
233 static void AtSubAbort_ResourceOwner(void);
234 static void AtSubCommit_Memory(void);
235 static void AtSubStart_Memory(void);
236 static void AtSubStart_ResourceOwner(void);
238 static void ShowTransactionState(const char *str);
239 static void ShowTransactionStateRec(TransactionState state);
240 static const char *BlockStateAsString(TBlockState blockState);
241 static const char *TransStateAsString(TransState state);
244 /* ----------------------------------------------------------------
245 * transaction state accessors
246 * ----------------------------------------------------------------
252 * This returns true if we are currently running a query
253 * within an executing transaction.
256 IsTransactionState(void)
258 TransactionState s = CurrentTransactionState;
266 case TRANS_INPROGRESS:
275 * Shouldn't get here, but lint is not happy with this...
281 * IsAbortedTransactionBlockState
283 * This returns true if we are currently running a query
284 * within an aborted transaction block.
287 IsAbortedTransactionBlockState(void)
289 TransactionState s = CurrentTransactionState;
291 if (s->blockState == TBLOCK_ABORT ||
292 s->blockState == TBLOCK_SUBABORT)
300 * GetTopTransactionId
302 * Get the ID of the main transaction, even if we are currently inside
306 GetTopTransactionId(void)
308 return TopTransactionStateData.transactionId;
313 * GetCurrentTransactionId
315 * We do not assign XIDs to subtransactions until/unless this is called.
316 * When we do assign an XID to a subtransaction, recursively make sure
317 * its parent has one as well (this maintains the invariant that a child
318 * transaction has an XID following its parent's).
321 GetCurrentTransactionId(void)
323 TransactionState s = CurrentTransactionState;
325 if (!TransactionIdIsValid(s->transactionId))
326 AssignSubTransactionId(s);
328 return s->transactionId;
332 AssignSubTransactionId(TransactionState s)
334 ResourceOwner currentOwner;
336 Assert(s->parent != NULL);
337 Assert(s->state == TRANS_INPROGRESS);
338 if (!TransactionIdIsValid(s->parent->transactionId))
339 AssignSubTransactionId(s->parent);
342 * Generate a new Xid and record it in PG_PROC and pg_subtrans.
344 * NB: we must make the subtrans entry BEFORE the Xid appears anywhere
345 * in shared storage other than PG_PROC; because if there's no room for
346 * it in PG_PROC, the subtrans entry is needed to ensure that other
347 * backends see the Xid as "running". See GetNewTransactionId.
349 s->transactionId = GetNewTransactionId(true);
351 SubTransSetParent(s->transactionId, s->parent->transactionId);
354 * Acquire lock on the transaction XID. (We assume this cannot block.)
355 * We have to be sure that the lock is assigned to the transaction's
358 currentOwner = CurrentResourceOwner;
361 CurrentResourceOwner = s->curTransactionOwner;
363 XactLockTableInsert(s->transactionId);
367 /* Ensure CurrentResourceOwner is restored on error */
368 CurrentResourceOwner = currentOwner;
372 CurrentResourceOwner = currentOwner;
377 * GetCurrentTransactionIdIfAny
379 * Unlike GetCurrentTransactionId, this will return InvalidTransactionId
380 * if we are currently not in a transaction, or in a transaction or
381 * subtransaction that has not yet assigned itself an XID.
384 GetCurrentTransactionIdIfAny(void)
386 TransactionState s = CurrentTransactionState;
388 return s->transactionId;
393 * GetCurrentSubTransactionId
396 GetCurrentSubTransactionId(void)
398 TransactionState s = CurrentTransactionState;
400 return s->subTransactionId;
405 * GetCurrentCommandId
408 GetCurrentCommandId(void)
410 /* this is global to a transaction, not subtransaction-local */
411 return currentCommandId;
416 * GetCurrentTransactionStartTime
419 GetCurrentTransactionStartTime(void)
421 return xactStartTime;
426 * GetCurrentTransactionStartTimeUsec
429 GetCurrentTransactionStartTimeUsec(int *msec)
431 *msec = xactStartTimeUsec;
432 return xactStartTime;
437 * GetCurrentTransactionNestLevel
439 * Note: this will return zero when not inside any transaction, one when
440 * inside a top-level transaction, etc.
443 GetCurrentTransactionNestLevel(void)
445 TransactionState s = CurrentTransactionState;
447 return s->nestingLevel;
452 * TransactionIdIsCurrentTransactionId
454 * During bootstrap, we cheat and say "it's not my transaction ID" even though
455 * it is. Along with transam.c's cheat to say that the bootstrap XID is
456 * already committed, this causes the tqual.c routines to see previously
457 * inserted tuples as committed, which is what we need during bootstrap.
460 TransactionIdIsCurrentTransactionId(TransactionId xid)
466 Assert(xid == BootstrapTransactionId);
471 * We will return true for the Xid of the current subtransaction, any
472 * of its subcommitted children, any of its parents, or any of their
473 * previously subcommitted children. However, a transaction being
474 * aborted is no longer "current", even though it may still have an
475 * entry on the state stack.
477 for (s = CurrentTransactionState; s != NULL; s = s->parent)
481 if (s->state == TRANS_ABORT)
483 if (!TransactionIdIsValid(s->transactionId))
484 continue; /* it can't have any child XIDs either */
485 if (TransactionIdEquals(xid, s->transactionId))
487 foreach(cell, s->childXids)
489 if (TransactionIdEquals(xid, lfirst_xid(cell)))
499 * CommandCounterIncrement
502 CommandCounterIncrement(void)
504 currentCommandId += 1;
505 if (currentCommandId == FirstCommandId) /* check for overflow */
507 currentCommandId -= 1;
509 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
510 errmsg("cannot have more than 2^32-1 commands in a transaction")));
513 /* Propagate new command ID into static snapshots, if set */
514 if (SerializableSnapshot)
515 SerializableSnapshot->curcid = currentCommandId;
517 LatestSnapshot->curcid = currentCommandId;
520 * make cache changes visible to me.
522 AtCommit_LocalCache();
527 /* ----------------------------------------------------------------
528 * StartTransaction stuff
529 * ----------------------------------------------------------------
538 AcceptInvalidationMessages();
547 TransactionState s = CurrentTransactionState;
550 * We shouldn't have a transaction context already.
552 Assert(TopTransactionContext == NULL);
555 * Create a toplevel context for the transaction.
557 TopTransactionContext =
558 AllocSetContextCreate(TopMemoryContext,
559 "TopTransactionContext",
560 ALLOCSET_DEFAULT_MINSIZE,
561 ALLOCSET_DEFAULT_INITSIZE,
562 ALLOCSET_DEFAULT_MAXSIZE);
565 * In a top-level transaction, CurTransactionContext is the same as
566 * TopTransactionContext.
568 CurTransactionContext = TopTransactionContext;
569 s->curTransactionContext = CurTransactionContext;
571 /* Make the CurTransactionContext active. */
572 MemoryContextSwitchTo(CurTransactionContext);
576 * AtStart_ResourceOwner
579 AtStart_ResourceOwner(void)
581 TransactionState s = CurrentTransactionState;
584 * We shouldn't have a transaction resource owner already.
586 Assert(TopTransactionResourceOwner == NULL);
589 * Create a toplevel resource owner for the transaction.
591 s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
593 TopTransactionResourceOwner = s->curTransactionOwner;
594 CurTransactionResourceOwner = s->curTransactionOwner;
595 CurrentResourceOwner = s->curTransactionOwner;
598 /* ----------------------------------------------------------------
599 * StartSubTransaction stuff
600 * ----------------------------------------------------------------
607 AtSubStart_Memory(void)
609 TransactionState s = CurrentTransactionState;
611 Assert(CurTransactionContext != NULL);
614 * Create a CurTransactionContext, which will be used to hold data
615 * that survives subtransaction commit but disappears on
616 * subtransaction abort. We make it a child of the immediate parent's
617 * CurTransactionContext.
619 CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
620 "CurTransactionContext",
621 ALLOCSET_DEFAULT_MINSIZE,
622 ALLOCSET_DEFAULT_INITSIZE,
623 ALLOCSET_DEFAULT_MAXSIZE);
624 s->curTransactionContext = CurTransactionContext;
626 /* Make the CurTransactionContext active. */
627 MemoryContextSwitchTo(CurTransactionContext);
631 * AtSubStart_ResourceOwner
634 AtSubStart_ResourceOwner(void)
636 TransactionState s = CurrentTransactionState;
638 Assert(s->parent != NULL);
641 * Create a resource owner for the subtransaction. We make it a child
642 * of the immediate parent's resource owner.
644 s->curTransactionOwner =
645 ResourceOwnerCreate(s->parent->curTransactionOwner,
648 CurTransactionResourceOwner = s->curTransactionOwner;
649 CurrentResourceOwner = s->curTransactionOwner;
652 /* ----------------------------------------------------------------
653 * CommitTransaction stuff
654 * ----------------------------------------------------------------
658 * RecordTransactionCommit
661 RecordTransactionCommit(void)
666 TransactionId *children;
668 /* Get data needed for commit record */
669 nrels = smgrGetPendingDeletes(true, &rptr);
670 nchildren = xactGetCommittedChildren(&children);
673 * If we made neither any XLOG entries nor any temp-rel updates, and
674 * have no files to be deleted, we can omit recording the transaction
675 * commit at all. (This test includes the effects of subtransactions,
676 * so the presence of committed subxacts need not alone force a
679 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)
681 TransactionId xid = GetCurrentTransactionId();
685 /* Tell bufmgr and smgr to prepare for commit */
688 START_CRIT_SECTION();
691 * If our transaction made any transaction-controlled XLOG
692 * entries, we need to lock out checkpoint start between writing
693 * our XLOG record and updating pg_clog. Otherwise it is possible
694 * for the checkpoint to set REDO after the XLOG record but fail
695 * to flush the pg_clog update to disk, leading to loss of the
696 * transaction commit if we crash a little later. Slightly klugy
697 * fix for problem discovered 2004-08-10.
699 * (If it made no transaction-controlled XLOG entries, its XID
700 * appears nowhere in permanent storage, so no one else will ever
701 * care if it committed; so it doesn't matter if we lose the
704 * Note we only need a shared lock.
706 madeTCentries = (MyLastRecPtr.xrecoff != 0);
708 LWLockAcquire(CheckpointStartLock, LW_SHARED);
711 * We only need to log the commit in XLOG if the transaction made
712 * any transaction-controlled XLOG entries or will delete files.
714 if (madeTCentries || nrels > 0)
716 XLogRecData rdata[3];
718 xl_xact_commit xlrec;
720 xlrec.xtime = time(NULL);
722 xlrec.nsubxacts = nchildren;
723 rdata[0].buffer = InvalidBuffer;
724 rdata[0].data = (char *) (&xlrec);
725 rdata[0].len = MinSizeOfXactCommit;
726 /* dump rels to delete */
729 rdata[0].next = &(rdata[1]);
730 rdata[1].buffer = InvalidBuffer;
731 rdata[1].data = (char *) rptr;
732 rdata[1].len = nrels * sizeof(RelFileNode);
735 /* dump committed child Xids */
738 rdata[lastrdata].next = &(rdata[2]);
739 rdata[2].buffer = InvalidBuffer;
740 rdata[2].data = (char *) children;
741 rdata[2].len = nchildren * sizeof(TransactionId);
744 rdata[lastrdata].next = NULL;
746 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
750 /* Just flush through last record written by me */
751 recptr = ProcLastRecEnd;
755 * We must flush our XLOG entries to disk if we made any XLOG
756 * entries, whether in or out of transaction control. For
757 * example, if we reported a nextval() result to the client, this
758 * ensures that any XLOG record generated by nextval will hit the
759 * disk before we report the transaction committed.
761 * Note: if we generated a commit record above, MyXactMadeXLogEntry
762 * will certainly be set now.
764 if (MyXactMadeXLogEntry)
767 * Sleep before flush! So we can flush more than one commit
768 * records per single fsync. (The idea is some other backend
769 * may do the XLogFlush while we're sleeping. This needs work
770 * still, because on most Unixen, the minimum select() delay
771 * is 10msec or more, which is way too long.)
773 * We do not sleep if enableFsync is not turned on, nor if there
774 * are fewer than CommitSiblings other backends with active
777 if (CommitDelay > 0 && enableFsync &&
778 CountActiveBackends() >= CommitSiblings)
779 pg_usleep(CommitDelay);
785 * We must mark the transaction committed in clog if its XID
786 * appears either in permanent rels or in local temporary rels. We
787 * test this by seeing if we made transaction-controlled entries
788 * *OR* local-rel tuple updates. Note that if we made only the
789 * latter, we have not emitted an XLOG record for our commit, and
790 * so in the event of a crash the clog update might be lost. This
791 * is okay because no one else will ever care whether we
794 if (madeTCentries || MyXactMadeTempRelUpdate)
796 TransactionIdCommit(xid);
797 /* to avoid race conditions, the parent must commit first */
798 TransactionIdCommitTree(nchildren, children);
801 /* Unlock checkpoint lock if we acquired it */
803 LWLockRelease(CheckpointStartLock);
808 /* Break the chain of back-links in the XLOG records I output */
809 MyLastRecPtr.xrecoff = 0;
810 MyXactMadeXLogEntry = false;
811 MyXactMadeTempRelUpdate = false;
813 /* Show myself as out of the transaction in PGPROC array */
814 MyProc->logRec.xrecoff = 0;
816 /* And clean up local data */
825 * AtCommit_LocalCache
828 AtCommit_LocalCache(void)
831 * Make catalog changes visible to me for the next command.
833 CommandEndInvalidationMessages();
840 AtCommit_Memory(void)
843 * Now that we're "out" of a transaction, have the system allocate
844 * things in the top memory context instead of per-transaction
847 MemoryContextSwitchTo(TopMemoryContext);
850 * Release all transaction-local memory.
852 Assert(TopTransactionContext != NULL);
853 MemoryContextDelete(TopTransactionContext);
854 TopTransactionContext = NULL;
855 CurTransactionContext = NULL;
856 CurrentTransactionState->curTransactionContext = NULL;
859 /* ----------------------------------------------------------------
860 * CommitSubTransaction stuff
861 * ----------------------------------------------------------------
868 AtSubCommit_Memory(void)
870 TransactionState s = CurrentTransactionState;
872 Assert(s->parent != NULL);
874 /* Return to parent transaction level's memory context. */
875 CurTransactionContext = s->parent->curTransactionContext;
876 MemoryContextSwitchTo(CurTransactionContext);
879 * Ordinarily we cannot throw away the child's CurTransactionContext,
880 * since the data it contains will be needed at upper commit. However,
881 * if there isn't actually anything in it, we can throw it away. This
882 * avoids a small memory leak in the common case of "trivial" subxacts.
884 if (MemoryContextIsEmpty(s->curTransactionContext))
886 MemoryContextDelete(s->curTransactionContext);
887 s->curTransactionContext = NULL;
892 * AtSubCommit_childXids
894 * Pass my own XID and my child XIDs up to my parent as committed children.
897 AtSubCommit_childXids(void)
899 TransactionState s = CurrentTransactionState;
900 MemoryContext old_cxt;
902 Assert(s->parent != NULL);
905 * We keep the child-XID lists in TopTransactionContext; this avoids
906 * setting up child-transaction contexts for what might be just a few
907 * bytes of grandchild XIDs.
909 old_cxt = MemoryContextSwitchTo(TopTransactionContext);
911 s->parent->childXids = lappend_xid(s->parent->childXids,
914 if (s->childXids != NIL)
916 s->parent->childXids = list_concat(s->parent->childXids,
919 * list_concat doesn't free the list header for the second list;
920 * do so here to avoid memory leakage (kluge)
926 MemoryContextSwitchTo(old_cxt);
930 * RecordSubTransactionCommit
933 RecordSubTransactionCommit(void)
936 * We do not log the subcommit in XLOG; it doesn't matter until the
937 * top-level transaction commits.
939 * We must mark the subtransaction subcommitted in clog if its XID
940 * appears either in permanent rels or in local temporary rels. We
941 * test this by seeing if we made transaction-controlled entries *OR*
942 * local-rel tuple updates. (The test here actually covers the entire
943 * transaction tree so far, so it may mark subtransactions that don't
944 * really need it, but it's probably not worth being tenser. Note that
945 * if a prior subtransaction dirtied these variables, then
946 * RecordTransactionCommit will have to do the full pushup anyway...)
948 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
950 TransactionId xid = GetCurrentTransactionId();
952 /* XXX does this really need to be a critical section? */
953 START_CRIT_SECTION();
955 /* Record subtransaction subcommit */
956 TransactionIdSubCommit(xid);
962 /* ----------------------------------------------------------------
963 * AbortTransaction stuff
964 * ----------------------------------------------------------------
968 * RecordTransactionAbort
971 RecordTransactionAbort(void)
976 TransactionId *children;
978 /* Get data needed for abort record */
979 nrels = smgrGetPendingDeletes(false, &rptr);
980 nchildren = xactGetCommittedChildren(&children);
983 * If we made neither any transaction-controlled XLOG entries nor any
984 * temp-rel updates, and are not going to delete any files, we can
985 * omit recording the transaction abort at all. No one will ever care
986 * that it aborted. (These tests cover our whole transaction tree.)
988 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
990 TransactionId xid = GetCurrentTransactionId();
993 * Catch the scenario where we aborted partway through
994 * RecordTransactionCommit ...
996 if (TransactionIdDidCommit(xid))
997 elog(PANIC, "cannot abort transaction %u, it was already committed", xid);
999 START_CRIT_SECTION();
1002 * We only need to log the abort in XLOG if the transaction made
1003 * any transaction-controlled XLOG entries or will delete files.
1004 * (If it made no transaction-controlled XLOG entries, its XID
1005 * appears nowhere in permanent storage, so no one else will ever
1006 * care if it committed.)
1008 * We do not flush XLOG to disk unless deleting files, since the
1009 * default assumption after a crash would be that we aborted,
1010 * anyway. For the same reason, we don't need to worry about
1011 * interlocking against checkpoint start.
1013 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1015 XLogRecData rdata[3];
1017 xl_xact_abort xlrec;
1020 xlrec.xtime = time(NULL);
1021 xlrec.nrels = nrels;
1022 xlrec.nsubxacts = nchildren;
1023 rdata[0].buffer = InvalidBuffer;
1024 rdata[0].data = (char *) (&xlrec);
1025 rdata[0].len = MinSizeOfXactAbort;
1026 /* dump rels to delete */
1029 rdata[0].next = &(rdata[1]);
1030 rdata[1].buffer = InvalidBuffer;
1031 rdata[1].data = (char *) rptr;
1032 rdata[1].len = nrels * sizeof(RelFileNode);
1035 /* dump committed child Xids */
1038 rdata[lastrdata].next = &(rdata[2]);
1039 rdata[2].buffer = InvalidBuffer;
1040 rdata[2].data = (char *) children;
1041 rdata[2].len = nchildren * sizeof(TransactionId);
1044 rdata[lastrdata].next = NULL;
1046 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1048 /* Must flush if we are deleting files... */
1054 * Mark the transaction aborted in clog. This is not absolutely
1055 * necessary but we may as well do it while we are here.
1057 * The ordering here isn't critical but it seems best to mark the
1058 * parent first. This assures an atomic transition of all the
1059 * subtransactions to aborted state from the point of view of
1060 * concurrent TransactionIdDidAbort calls.
1062 TransactionIdAbort(xid);
1063 TransactionIdAbortTree(nchildren, children);
1068 /* Break the chain of back-links in the XLOG records I output */
1069 MyLastRecPtr.xrecoff = 0;
1070 MyXactMadeXLogEntry = false;
1071 MyXactMadeTempRelUpdate = false;
1073 /* Show myself as out of the transaction in PGPROC array */
1074 MyProc->logRec.xrecoff = 0;
1076 /* And clean up local data */
1087 AtAbort_Memory(void)
1090 * Make sure we are in a valid context (not a child of
1091 * TopTransactionContext...). Note that it is possible for this code
1092 * to be called when we aren't in a transaction at all; go directly to
1093 * TopMemoryContext in that case.
1095 if (TopTransactionContext != NULL)
1097 MemoryContextSwitchTo(TopTransactionContext);
1100 * We do not want to destroy the transaction's global state yet,
1101 * so we can't free any memory here.
1105 MemoryContextSwitchTo(TopMemoryContext);
1112 AtSubAbort_Memory(void)
1114 Assert(TopTransactionContext != NULL);
1116 MemoryContextSwitchTo(TopTransactionContext);
1121 * AtAbort_ResourceOwner
1124 AtAbort_ResourceOwner(void)
1127 * Make sure we have a valid ResourceOwner, if possible (else it
1128 * will be NULL, which is OK)
1130 CurrentResourceOwner = TopTransactionResourceOwner;
1134 * AtSubAbort_ResourceOwner
1137 AtSubAbort_ResourceOwner(void)
1139 TransactionState s = CurrentTransactionState;
1141 /* Make sure we have a valid ResourceOwner */
1142 CurrentResourceOwner = s->curTransactionOwner;
1147 * AtSubAbort_childXids
1150 AtSubAbort_childXids(void)
1152 TransactionState s = CurrentTransactionState;
1155 * We keep the child-XID lists in TopTransactionContext (see
1156 * AtSubCommit_childXids). This means we'd better free the list
1157 * explicitly at abort to avoid leakage.
1159 list_free(s->childXids);
1164 * RecordSubTransactionAbort
1167 RecordSubTransactionAbort(void)
1171 TransactionId xid = GetCurrentTransactionId();
1173 TransactionId *children;
1175 /* Get data needed for abort record */
1176 nrels = smgrGetPendingDeletes(false, &rptr);
1177 nchildren = xactGetCommittedChildren(&children);
1180 * If we made neither any transaction-controlled XLOG entries nor any
1181 * temp-rel updates, and are not going to delete any files, we can
1182 * omit recording the transaction abort at all. No one will ever care
1183 * that it aborted. (These tests cover our whole transaction tree,
1184 * and therefore may mark subxacts that don't really need it, but it's
1185 * probably not worth being tenser.)
1187 * In this case we needn't worry about marking subcommitted children as
1188 * aborted, because they didn't mark themselves as subcommitted in the
1189 * first place; see the optimization in RecordSubTransactionCommit.
1191 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
1193 START_CRIT_SECTION();
1196 * We only need to log the abort in XLOG if the transaction made
1197 * any transaction-controlled XLOG entries or will delete files.
1199 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1201 XLogRecData rdata[3];
1203 xl_xact_abort xlrec;
1206 xlrec.xtime = time(NULL);
1207 xlrec.nrels = nrels;
1208 xlrec.nsubxacts = nchildren;
1209 rdata[0].buffer = InvalidBuffer;
1210 rdata[0].data = (char *) (&xlrec);
1211 rdata[0].len = MinSizeOfXactAbort;
1212 /* dump rels to delete */
1215 rdata[0].next = &(rdata[1]);
1216 rdata[1].buffer = InvalidBuffer;
1217 rdata[1].data = (char *) rptr;
1218 rdata[1].len = nrels * sizeof(RelFileNode);
1221 /* dump committed child Xids */
1224 rdata[lastrdata].next = &(rdata[2]);
1225 rdata[2].buffer = InvalidBuffer;
1226 rdata[2].data = (char *) children;
1227 rdata[2].len = nchildren * sizeof(TransactionId);
1230 rdata[lastrdata].next = NULL;
1232 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1234 /* Must flush if we are deleting files... */
1240 * Mark the transaction aborted in clog. This is not absolutely
1241 * necessary but XactLockTableWait makes use of it to avoid waiting
1242 * for already-aborted subtransactions.
1244 TransactionIdAbort(xid);
1245 TransactionIdAbortTree(nchildren, children);
1251 * We can immediately remove failed XIDs from PGPROC's cache of
1252 * running child XIDs. It's easiest to do it here while we have the
1253 * child XID array at hand, even though in the main-transaction case
1254 * the equivalent work happens just after return from
1255 * RecordTransactionAbort.
1257 XidCacheRemoveRunningXids(xid, nchildren, children);
1259 /* And clean up local data */
1266 /* ----------------------------------------------------------------
1267 * CleanupTransaction stuff
1268 * ----------------------------------------------------------------
1275 AtCleanup_Memory(void)
1278 * Now that we're "out" of a transaction, have the system allocate
1279 * things in the top memory context instead of per-transaction
1282 MemoryContextSwitchTo(TopMemoryContext);
1284 Assert(CurrentTransactionState->parent == NULL);
1287 * Release all transaction-local memory.
1289 if (TopTransactionContext != NULL)
1290 MemoryContextDelete(TopTransactionContext);
1291 TopTransactionContext = NULL;
1292 CurTransactionContext = NULL;
1293 CurrentTransactionState->curTransactionContext = NULL;
1297 /* ----------------------------------------------------------------
1298 * CleanupSubTransaction stuff
1299 * ----------------------------------------------------------------
1303 * AtSubCleanup_Memory
1306 AtSubCleanup_Memory(void)
1308 TransactionState s = CurrentTransactionState;
1310 Assert(s->parent != NULL);
1312 /* Make sure we're not in an about-to-be-deleted context */
1313 MemoryContextSwitchTo(s->parent->curTransactionContext);
1314 CurTransactionContext = s->parent->curTransactionContext;
1317 * Delete the subxact local memory contexts. Its CurTransactionContext
1318 * can go too (note this also kills CurTransactionContexts from any
1319 * children of the subxact).
1321 if (s->curTransactionContext)
1322 MemoryContextDelete(s->curTransactionContext);
1323 s->curTransactionContext = NULL;
1326 /* ----------------------------------------------------------------
1327 * interface routines
1328 * ----------------------------------------------------------------
1335 StartTransaction(void)
1340 * Let's just make sure the state stack is empty
1342 s = &TopTransactionStateData;
1343 CurrentTransactionState = s;
1346 * check the current transaction state
1348 if (s->state != TRANS_DEFAULT)
1349 elog(WARNING, "StartTransaction while in %s state",
1350 TransStateAsString(s->state));
1353 * set the current transaction state information appropriately during
1356 s->state = TRANS_START;
1359 * Make sure we've freed any old snapshot, and reset xact state
1363 XactIsoLevel = DefaultXactIsoLevel;
1364 XactReadOnly = DefaultXactReadOnly;
1367 * reinitialize within-transaction counters
1369 s->subTransactionId = TopSubTransactionId;
1370 currentSubTransactionId = TopSubTransactionId;
1371 currentCommandId = FirstCommandId;
1374 * must initialize resource-management stuff first
1377 AtStart_ResourceOwner();
1380 * generate a new transaction id
1382 s->transactionId = GetNewTransactionId(false);
1384 XactLockTableInsert(s->transactionId);
1389 xactStartTime = GetCurrentAbsoluteTimeUsec(&(xactStartTimeUsec));
1392 * initialize current transaction state fields
1394 s->nestingLevel = 1;
1398 * You might expect to see "s->currentUser = GetUserId();" here, but
1399 * you won't because it doesn't work during startup; the userid isn't
1400 * set yet during a backend's first transaction start. We only use
1401 * the currentUser field in sub-transaction state structs.
1403 * prevXactReadOnly is also valid only in sub-transactions.
1407 * initialize other subsystems for new transaction
1411 AfterTriggerBeginXact();
1414 * done with start processing, set current transaction state to "in
1417 s->state = TRANS_INPROGRESS;
1419 ShowTransactionState("StartTransaction");
1426 CommitTransaction(void)
1428 TransactionState s = CurrentTransactionState;
1430 ShowTransactionState("CommitTransaction");
1433 * check the current transaction state
1435 if (s->state != TRANS_INPROGRESS)
1436 elog(WARNING, "CommitTransaction while in %s state",
1437 TransStateAsString(s->state));
1438 Assert(s->parent == NULL);
1441 * Tell the trigger manager that this transaction is about to be
1442 * committed. He'll invoke all trigger deferred until XACT before we
1443 * really start on committing the transaction.
1445 AfterTriggerEndXact();
1448 * Similarly, let ON COMMIT management do its thing before we start to
1451 PreCommit_on_commit_actions();
1453 /* Prevent cancel/die interrupt while cleaning up */
1457 * set the current transaction state information appropriately during
1458 * the abort processing
1460 s->state = TRANS_COMMIT;
1463 * Do pre-commit processing (most of this stuff requires database
1464 * access, and in fact could still cause an error...)
1469 /* close large objects before lower-level cleanup */
1470 AtEOXact_LargeObject(true);
1472 /* NOTIFY commit must come before lower-level cleanup */
1475 /* Update the flat password file if we changed pg_shadow or pg_group */
1476 /* This should be the last step before commit */
1477 AtEOXact_UpdatePasswordFile(true);
1480 * Here is where we really truly commit.
1482 RecordTransactionCommit();
1485 * Let others know about no transaction in progress by me. Note that
1486 * this must be done _before_ releasing locks we hold and _after_
1487 * RecordTransactionCommit.
1489 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
1490 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
1491 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
1492 * as running as well or it will see two tuple versions - one deleted
1493 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
1497 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1498 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1499 MyProc->xid = InvalidTransactionId;
1500 MyProc->xmin = InvalidTransactionId;
1502 /* Clear the subtransaction-XID cache too while holding the lock */
1503 MyProc->subxids.nxids = 0;
1504 MyProc->subxids.overflowed = false;
1506 LWLockRelease(SInvalLock);
1510 * This is all post-commit cleanup. Note that if an error is raised
1511 * here, it's too late to abort the transaction. This should be just
1512 * noncritical resource releasing.
1514 * The ordering of operations is not entirely random. The idea is:
1515 * release resources visible to other backends (eg, files, buffer
1516 * pins); then release locks; then release backend-local resources. We
1517 * want to release locks at the point where any backend waiting for us
1518 * will see our transaction as being fully cleaned up.
1520 * Resources that can be associated with individual queries are handled
1521 * by the ResourceOwner mechanism. The other calls here are for
1522 * backend-wide state.
1525 CallXactCallbacks(XACT_EVENT_COMMIT);
1527 ResourceOwnerRelease(TopTransactionResourceOwner,
1528 RESOURCE_RELEASE_BEFORE_LOCKS,
1531 /* Check we've released all buffer pins */
1532 AtEOXact_Buffers(true);
1535 * Make catalog changes visible to all backends. This has to happen
1536 * after relcache references are dropped (see comments for
1537 * AtEOXact_RelationCache), but before locks are released (if anyone
1538 * is waiting for lock on a relation we've modified, we want them to
1539 * know about the catalog change before they start using the
1542 AtEOXact_Inval(true);
1545 * Likewise, dropping of files deleted during the transaction is best done
1546 * after releasing relcache and buffer pins. (This is not strictly
1547 * necessary during commit, since such pins should have been released
1548 * already, but this ordering is definitely critical during abort.)
1550 smgrDoPendingDeletes(true);
1552 ResourceOwnerRelease(TopTransactionResourceOwner,
1553 RESOURCE_RELEASE_LOCKS,
1555 ResourceOwnerRelease(TopTransactionResourceOwner,
1556 RESOURCE_RELEASE_AFTER_LOCKS,
1559 AtEOXact_GUC(true, false);
1561 AtEOXact_on_commit_actions(true);
1562 AtEOXact_Namespace(true);
1563 /* smgrcommit already done */
1565 pgstat_count_xact_commit();
1567 CurrentResourceOwner = NULL;
1568 ResourceOwnerDelete(TopTransactionResourceOwner);
1569 s->curTransactionOwner = NULL;
1570 CurTransactionResourceOwner = NULL;
1571 TopTransactionResourceOwner = NULL;
1575 s->transactionId = InvalidTransactionId;
1576 s->subTransactionId = InvalidSubTransactionId;
1577 s->nestingLevel = 0;
1581 * done with commit processing, set current transaction state back to
1584 s->state = TRANS_DEFAULT;
1586 RESUME_INTERRUPTS();
1593 AbortTransaction(void)
1595 TransactionState s = CurrentTransactionState;
1597 /* Prevent cancel/die interrupt while cleaning up */
1601 * Release any LW locks we might be holding as quickly as possible.
1602 * (Regular locks, however, must be held till we finish aborting.)
1603 * Releasing LW locks is critical since we might try to grab them
1604 * again while cleaning up!
1608 /* Clean up buffer I/O and buffer context locks, too */
1613 * Also clean up any open wait for lock, since the lock manager will
1614 * choke if we try to wait for another lock before doing this.
1619 * check the current transaction state
1621 if (s->state != TRANS_INPROGRESS)
1622 elog(WARNING, "AbortTransaction while in %s state",
1623 TransStateAsString(s->state));
1624 Assert(s->parent == NULL);
1627 * set the current transaction state information appropriately during
1628 * the abort processing
1630 s->state = TRANS_ABORT;
1632 /* Make sure we have a valid memory context and resource owner */
1634 AtAbort_ResourceOwner();
1637 * Reset user id which might have been changed transiently. We cannot
1638 * use s->currentUser, but must get the session userid from
1641 * (Note: it is not necessary to restore session authorization here
1642 * because that can only be changed via GUC, and GUC will take care of
1643 * rolling it back if need be. However, an error within a SECURITY
1644 * DEFINER function could send control here with the wrong current
1647 SetUserId(GetSessionUserId());
1650 * do abort processing
1652 AfterTriggerAbortXact();
1654 AtEOXact_LargeObject(false); /* 'false' means it's abort */
1656 AtEOXact_UpdatePasswordFile(false);
1658 /* Advertise the fact that we aborted in pg_clog. */
1659 RecordTransactionAbort();
1662 * Let others know about no transaction in progress by me. Note that
1663 * this must be done _before_ releasing locks we hold and _after_
1664 * RecordTransactionAbort.
1668 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1669 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1670 MyProc->xid = InvalidTransactionId;
1671 MyProc->xmin = InvalidTransactionId;
1673 /* Clear the subtransaction-XID cache too while holding the lock */
1674 MyProc->subxids.nxids = 0;
1675 MyProc->subxids.overflowed = false;
1677 LWLockRelease(SInvalLock);
1681 * Post-abort cleanup. See notes in CommitTransaction() concerning
1685 CallXactCallbacks(XACT_EVENT_ABORT);
1687 ResourceOwnerRelease(TopTransactionResourceOwner,
1688 RESOURCE_RELEASE_BEFORE_LOCKS,
1690 AtEOXact_Buffers(false);
1691 AtEOXact_Inval(false);
1692 smgrDoPendingDeletes(false);
1693 ResourceOwnerRelease(TopTransactionResourceOwner,
1694 RESOURCE_RELEASE_LOCKS,
1696 ResourceOwnerRelease(TopTransactionResourceOwner,
1697 RESOURCE_RELEASE_AFTER_LOCKS,
1700 AtEOXact_GUC(false, false);
1701 AtEOXact_SPI(false);
1702 AtEOXact_on_commit_actions(false);
1703 AtEOXact_Namespace(false);
1706 pgstat_count_xact_rollback();
1709 * State remains TRANS_ABORT until CleanupTransaction().
1711 RESUME_INTERRUPTS();
1715 * CleanupTransaction
1718 CleanupTransaction(void)
1720 TransactionState s = CurrentTransactionState;
1723 * State should still be TRANS_ABORT from AbortTransaction().
1725 if (s->state != TRANS_ABORT)
1726 elog(FATAL, "CleanupTransaction: unexpected state %s",
1727 TransStateAsString(s->state));
1730 * do abort cleanup processing
1732 AtCleanup_Portals(); /* now safe to release portal memory */
1734 CurrentResourceOwner = NULL; /* and resource owner */
1735 if (TopTransactionResourceOwner)
1736 ResourceOwnerDelete(TopTransactionResourceOwner);
1737 s->curTransactionOwner = NULL;
1738 CurTransactionResourceOwner = NULL;
1739 TopTransactionResourceOwner = NULL;
1741 AtCleanup_Memory(); /* and transaction memory */
1743 s->transactionId = InvalidTransactionId;
1744 s->subTransactionId = InvalidSubTransactionId;
1745 s->nestingLevel = 0;
1749 * done with abort processing, set current transaction state back to
1752 s->state = TRANS_DEFAULT;
1756 * StartTransactionCommand
1759 StartTransactionCommand(void)
1761 TransactionState s = CurrentTransactionState;
1763 switch (s->blockState)
1766 * if we aren't in a transaction block, we just do our usual
1767 * start transaction.
1769 case TBLOCK_DEFAULT:
1771 s->blockState = TBLOCK_STARTED;
1775 * We are somewhere in a transaction block or subtransaction
1776 * and about to start a new command. For now we do nothing,
1777 * but someday we may do command-local resource initialization.
1778 * (Note that any needed CommandCounterIncrement was done by
1779 * the previous CommitTransactionCommand.)
1781 case TBLOCK_INPROGRESS:
1782 case TBLOCK_SUBINPROGRESS:
1786 * Here we are in a failed transaction block (one of
1787 * the commands caused an abort) so we do nothing but remain in
1788 * the abort state. Eventually we will get a ROLLBACK command
1789 * which will get us out of this state. (It is up to other
1790 * code to ensure that no commands other than ROLLBACK will be
1791 * processed in these states.)
1794 case TBLOCK_SUBABORT:
1797 /* These cases are invalid. */
1798 case TBLOCK_STARTED:
1800 case TBLOCK_SUBBEGIN:
1803 case TBLOCK_ABORT_END:
1804 case TBLOCK_SUBABORT_END:
1805 case TBLOCK_ABORT_PENDING:
1806 case TBLOCK_SUBABORT_PENDING:
1807 case TBLOCK_SUBRESTART:
1808 case TBLOCK_SUBABORT_RESTART:
1809 elog(ERROR, "StartTransactionCommand: unexpected state %s",
1810 BlockStateAsString(s->blockState));
1815 * We must switch to CurTransactionContext before returning. This is
1816 * already done if we called StartTransaction, otherwise not.
1818 Assert(CurTransactionContext != NULL);
1819 MemoryContextSwitchTo(CurTransactionContext);
1823 * CommitTransactionCommand
1826 CommitTransactionCommand(void)
1828 TransactionState s = CurrentTransactionState;
1830 switch (s->blockState)
1833 * This shouldn't happen, because it means the previous
1834 * StartTransactionCommand didn't set the STARTED state
1837 case TBLOCK_DEFAULT:
1838 elog(FATAL, "CommitTransactionCommand: unexpected state %s",
1839 BlockStateAsString(s->blockState));
1843 * If we aren't in a transaction block, just do our usual
1844 * transaction commit, and return to the idle state.
1846 case TBLOCK_STARTED:
1847 CommitTransaction();
1848 s->blockState = TBLOCK_DEFAULT;
1852 * We are completing a "BEGIN TRANSACTION" command, so we
1853 * change to the "transaction block in progress" state and
1854 * return. (We assume the BEGIN did nothing to the database,
1855 * so we need no CommandCounterIncrement.)
1858 s->blockState = TBLOCK_INPROGRESS;
1862 * This is the case when we have finished executing a command
1863 * someplace within a transaction block. We increment the
1864 * command counter and return.
1866 case TBLOCK_INPROGRESS:
1867 case TBLOCK_SUBINPROGRESS:
1868 CommandCounterIncrement();
1872 * We are completing a "COMMIT" command. Do it and return to
1876 CommitTransaction();
1877 s->blockState = TBLOCK_DEFAULT;
1881 * Here we are in the middle of a transaction block but one of
1882 * the commands caused an abort so we do nothing but remain in
1883 * the abort state. Eventually we will get a ROLLBACK comand.
1886 case TBLOCK_SUBABORT:
1890 * Here we were in an aborted transaction block and we just
1891 * got the ROLLBACK command from the user, so clean up the
1892 * already-aborted transaction and return to the idle state.
1894 case TBLOCK_ABORT_END:
1895 CleanupTransaction();
1896 s->blockState = TBLOCK_DEFAULT;
1900 * Here we were in a perfectly good transaction block but the
1901 * user told us to ROLLBACK anyway. We have to abort the
1902 * transaction and then clean up.
1904 case TBLOCK_ABORT_PENDING:
1906 CleanupTransaction();
1907 s->blockState = TBLOCK_DEFAULT;
1911 * We were just issued a SAVEPOINT inside a transaction block.
1912 * Start a subtransaction. (DefineSavepoint already did
1913 * PushTransaction, so as to have someplace to put the
1916 case TBLOCK_SUBBEGIN:
1917 StartSubTransaction();
1918 s->blockState = TBLOCK_SUBINPROGRESS;
1922 * We were issued a COMMIT or RELEASE command, so we end the
1923 * current subtransaction and return to the parent transaction.
1924 * The parent might be ended too, so repeat till we are all the
1925 * way out or find an INPROGRESS transaction.
1930 CommitSubTransaction();
1931 s = CurrentTransactionState; /* changed by pop */
1932 } while (s->blockState == TBLOCK_SUBEND);
1933 /* If we had a COMMIT command, finish off the main xact too */
1934 if (s->blockState == TBLOCK_END)
1936 Assert(s->parent == NULL);
1937 CommitTransaction();
1938 s->blockState = TBLOCK_DEFAULT;
1942 Assert(s->blockState == TBLOCK_INPROGRESS ||
1943 s->blockState == TBLOCK_SUBINPROGRESS);
1948 * The current already-failed subtransaction is ending due to a
1949 * ROLLBACK or ROLLBACK TO command, so pop it and recursively
1950 * examine the parent (which could be in any of several states).
1952 case TBLOCK_SUBABORT_END:
1953 CleanupSubTransaction();
1954 CommitTransactionCommand();
1958 * As above, but it's not dead yet, so abort first.
1960 case TBLOCK_SUBABORT_PENDING:
1961 AbortSubTransaction();
1962 CleanupSubTransaction();
1963 CommitTransactionCommand();
1967 * The current subtransaction is the target of a ROLLBACK TO
1968 * command. Abort and pop it, then start a new subtransaction
1969 * with the same name.
1971 case TBLOCK_SUBRESTART:
1976 /* save name and keep Cleanup from freeing it */
1979 savepointLevel = s->savepointLevel;
1981 AbortSubTransaction();
1982 CleanupSubTransaction();
1984 DefineSavepoint(NULL);
1985 s = CurrentTransactionState; /* changed by push */
1987 s->savepointLevel = savepointLevel;
1989 /* This is the same as TBLOCK_SUBBEGIN case */
1990 AssertState(s->blockState == TBLOCK_SUBBEGIN);
1991 StartSubTransaction();
1992 s->blockState = TBLOCK_SUBINPROGRESS;
1997 * Same as above, but the subtransaction had already failed,
1998 * so we don't need AbortSubTransaction.
2000 case TBLOCK_SUBABORT_RESTART:
2005 /* save name and keep Cleanup from freeing it */
2008 savepointLevel = s->savepointLevel;
2010 CleanupSubTransaction();
2012 DefineSavepoint(NULL);
2013 s = CurrentTransactionState; /* changed by push */
2015 s->savepointLevel = savepointLevel;
2017 /* This is the same as TBLOCK_SUBBEGIN case */
2018 AssertState(s->blockState == TBLOCK_SUBBEGIN);
2019 StartSubTransaction();
2020 s->blockState = TBLOCK_SUBINPROGRESS;
2027 * AbortCurrentTransaction
2030 AbortCurrentTransaction(void)
2032 TransactionState s = CurrentTransactionState;
2034 switch (s->blockState)
2037 * we aren't in a transaction, so we do nothing.
2039 case TBLOCK_DEFAULT:
2043 * if we aren't in a transaction block, we just do the basic
2044 * abort & cleanup transaction.
2046 case TBLOCK_STARTED:
2048 CleanupTransaction();
2049 s->blockState = TBLOCK_DEFAULT;
2053 * If we are in TBLOCK_BEGIN it means something screwed up
2054 * right after reading "BEGIN TRANSACTION". We assume that
2055 * the user will interpret the error as meaning the BEGIN
2056 * failed to get him into a transaction block, so we should
2057 * abort and return to idle state.
2061 CleanupTransaction();
2062 s->blockState = TBLOCK_DEFAULT;
2066 * We are somewhere in a transaction block and we've gotten a
2067 * failure, so we abort the transaction and set up the persistent
2068 * ABORT state. We will stay in ABORT until we get a ROLLBACK.
2070 case TBLOCK_INPROGRESS:
2072 s->blockState = TBLOCK_ABORT;
2073 /* CleanupTransaction happens when we exit TBLOCK_ABORT_END */
2077 * Here, we failed while trying to COMMIT. Clean up the
2078 * transaction and return to idle state (we do not want to
2079 * stay in the transaction).
2083 CleanupTransaction();
2084 s->blockState = TBLOCK_DEFAULT;
2088 * Here, we are already in an aborted transaction state and
2089 * are waiting for a ROLLBACK, but for some reason we failed
2090 * again! So we just remain in the abort state.
2093 case TBLOCK_SUBABORT:
2097 * We are in a failed transaction and we got the ROLLBACK command.
2098 * We have already aborted, we just need to cleanup and go to
2101 case TBLOCK_ABORT_END:
2102 CleanupTransaction();
2103 s->blockState = TBLOCK_DEFAULT;
2107 * We are in a live transaction and we got a ROLLBACK command.
2108 * Abort, cleanup, go to idle state.
2110 case TBLOCK_ABORT_PENDING:
2112 CleanupTransaction();
2113 s->blockState = TBLOCK_DEFAULT;
2117 * We got an error inside a subtransaction. Abort just the
2118 * subtransaction, and go to the persistent SUBABORT state
2119 * until we get ROLLBACK.
2121 case TBLOCK_SUBINPROGRESS:
2122 AbortSubTransaction();
2123 s->blockState = TBLOCK_SUBABORT;
2127 * If we failed while trying to create a subtransaction, clean up
2128 * the broken subtransaction and abort the parent. The same
2129 * applies if we get a failure while ending a subtransaction.
2131 case TBLOCK_SUBBEGIN:
2133 case TBLOCK_SUBABORT_PENDING:
2134 case TBLOCK_SUBRESTART:
2135 AbortSubTransaction();
2136 CleanupSubTransaction();
2137 AbortCurrentTransaction();
2141 * Same as above, except the Abort() was already done.
2143 case TBLOCK_SUBABORT_END:
2144 case TBLOCK_SUBABORT_RESTART:
2145 CleanupSubTransaction();
2146 AbortCurrentTransaction();
2152 * PreventTransactionChain
2154 * This routine is to be called by statements that must not run inside
2155 * a transaction block, typically because they have non-rollback-able
2156 * side effects or do internal commits.
2158 * If we have already started a transaction block, issue an error; also issue
2159 * an error if we appear to be running inside a user-defined function (which
2160 * could issue more commands and possibly cause a failure after the statement
2161 * completes). Subtransactions are verboten too.
2163 * stmtNode: pointer to parameter block for statement; this is used in
2164 * a very klugy way to determine whether we are inside a function.
2165 * stmtType: statement type name for error messages.
2168 PreventTransactionChain(void *stmtNode, const char *stmtType)
2171 * xact block already started?
2173 if (IsTransactionBlock())
2175 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2176 /* translator: %s represents an SQL statement name */
2177 errmsg("%s cannot run inside a transaction block",
2183 if (IsSubTransaction())
2185 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2186 /* translator: %s represents an SQL statement name */
2187 errmsg("%s cannot run inside a subtransaction",
2191 * Are we inside a function call? If the statement's parameter block
2192 * was allocated in QueryContext, assume it is an interactive command.
2193 * Otherwise assume it is coming from a function.
2195 if (!MemoryContextContains(QueryContext, stmtNode))
2197 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2198 /* translator: %s represents an SQL statement name */
2199 errmsg("%s cannot be executed from a function", stmtType)));
2201 /* If we got past IsTransactionBlock test, should be in default state */
2202 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2203 CurrentTransactionState->blockState != TBLOCK_STARTED)
2204 elog(FATAL, "cannot prevent transaction chain");
2209 * RequireTransactionChain
2211 * This routine is to be called by statements that must run inside
2212 * a transaction block, because they have no effects that persist past
2213 * transaction end (and so calling them outside a transaction block
2214 * is presumably an error). DECLARE CURSOR is an example.
2216 * If we appear to be running inside a user-defined function, we do not
2217 * issue an error, since the function could issue more commands that make
2218 * use of the current statement's results. Likewise subtransactions.
2219 * Thus this is an inverse for PreventTransactionChain.
2221 * stmtNode: pointer to parameter block for statement; this is used in
2222 * a very klugy way to determine whether we are inside a function.
2223 * stmtType: statement type name for error messages.
2226 RequireTransactionChain(void *stmtNode, const char *stmtType)
2229 * xact block already started?
2231 if (IsTransactionBlock())
2237 if (IsSubTransaction())
2241 * Are we inside a function call? If the statement's parameter block
2242 * was allocated in QueryContext, assume it is an interactive command.
2243 * Otherwise assume it is coming from a function.
2245 if (!MemoryContextContains(QueryContext, stmtNode))
2248 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2249 /* translator: %s represents an SQL statement name */
2250 errmsg("%s may only be used in transaction blocks",
2255 * IsInTransactionChain
2257 * This routine is for statements that need to behave differently inside
2258 * a transaction block than when running as single commands. ANALYZE is
2259 * currently the only example.
2261 * stmtNode: pointer to parameter block for statement; this is used in
2262 * a very klugy way to determine whether we are inside a function.
2265 IsInTransactionChain(void *stmtNode)
2268 * Return true on same conditions that would make
2269 * PreventTransactionChain error out
2271 if (IsTransactionBlock())
2274 if (IsSubTransaction())
2277 if (!MemoryContextContains(QueryContext, stmtNode))
2280 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2281 CurrentTransactionState->blockState != TBLOCK_STARTED)
2289 * Register or deregister callback functions for start- and end-of-xact
2292 * These functions are intended for use by dynamically loaded modules.
2293 * For built-in modules we generally just hardwire the appropriate calls
2294 * (mainly because it's easier to control the order that way, where needed).
2296 * At transaction end, the callback occurs post-commit or post-abort, so the
2297 * callback functions can only do noncritical cleanup.
2300 RegisterXactCallback(XactCallback callback, void *arg)
2302 XactCallbackItem *item;
2304 item = (XactCallbackItem *)
2305 MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
2306 item->callback = callback;
2308 item->next = Xact_callbacks;
2309 Xact_callbacks = item;
2313 UnregisterXactCallback(XactCallback callback, void *arg)
2315 XactCallbackItem *item;
2316 XactCallbackItem *prev;
2319 for (item = Xact_callbacks; item; prev = item, item = item->next)
2321 if (item->callback == callback && item->arg == arg)
2324 prev->next = item->next;
2326 Xact_callbacks = item->next;
2334 CallXactCallbacks(XactEvent event)
2336 XactCallbackItem *item;
2338 for (item = Xact_callbacks; item; item = item->next)
2339 (*item->callback) (event, item->arg);
2344 * Register or deregister callback functions for start- and end-of-subxact
2347 * Pretty much same as above, but for subtransaction events.
2349 * At subtransaction end, the callback occurs post-subcommit or post-subabort,
2350 * so the callback functions can only do noncritical cleanup. At
2351 * subtransaction start, the callback is called when the subtransaction has
2352 * finished initializing.
2355 RegisterSubXactCallback(SubXactCallback callback, void *arg)
2357 SubXactCallbackItem *item;
2359 item = (SubXactCallbackItem *)
2360 MemoryContextAlloc(TopMemoryContext, sizeof(SubXactCallbackItem));
2361 item->callback = callback;
2363 item->next = SubXact_callbacks;
2364 SubXact_callbacks = item;
2368 UnregisterSubXactCallback(SubXactCallback callback, void *arg)
2370 SubXactCallbackItem *item;
2371 SubXactCallbackItem *prev;
2374 for (item = SubXact_callbacks; item; prev = item, item = item->next)
2376 if (item->callback == callback && item->arg == arg)
2379 prev->next = item->next;
2381 SubXact_callbacks = item->next;
2389 CallSubXactCallbacks(SubXactEvent event,
2390 SubTransactionId mySubid,
2391 SubTransactionId parentSubid)
2393 SubXactCallbackItem *item;
2395 for (item = SubXact_callbacks; item; item = item->next)
2396 (*item->callback) (event, mySubid, parentSubid, item->arg);
2400 /* ----------------------------------------------------------------
2401 * transaction block support
2402 * ----------------------------------------------------------------
2406 * BeginTransactionBlock
2407 * This executes a BEGIN command.
2410 BeginTransactionBlock(void)
2412 TransactionState s = CurrentTransactionState;
2414 switch (s->blockState)
2417 * We are not inside a transaction block, so allow one to
2420 case TBLOCK_STARTED:
2421 s->blockState = TBLOCK_BEGIN;
2425 * Already a transaction block in progress.
2427 case TBLOCK_INPROGRESS:
2428 case TBLOCK_SUBINPROGRESS:
2430 case TBLOCK_SUBABORT:
2432 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2433 errmsg("there is already a transaction in progress")));
2436 /* These cases are invalid. */
2437 case TBLOCK_DEFAULT:
2439 case TBLOCK_SUBBEGIN:
2442 case TBLOCK_ABORT_END:
2443 case TBLOCK_SUBABORT_END:
2444 case TBLOCK_ABORT_PENDING:
2445 case TBLOCK_SUBABORT_PENDING:
2446 case TBLOCK_SUBRESTART:
2447 case TBLOCK_SUBABORT_RESTART:
2448 elog(FATAL, "BeginTransactionBlock: unexpected state %s",
2449 BlockStateAsString(s->blockState));
2455 * EndTransactionBlock
2456 * This executes a COMMIT command.
2458 * Since COMMIT may actually do a ROLLBACK, the result indicates what
2459 * happened: TRUE for COMMIT, FALSE for ROLLBACK.
2461 * Note that we don't actually do anything here except change blockState.
2462 * The real work will be done in the upcoming CommitTransactionCommand().
2463 * We do it this way because it's not convenient to change memory context,
2464 * resource owner, etc while executing inside a Portal.
2467 EndTransactionBlock(void)
2469 TransactionState s = CurrentTransactionState;
2470 bool result = false;
2472 switch (s->blockState)
2475 * We are in a transaction block, so tell CommitTransactionCommand
2478 case TBLOCK_INPROGRESS:
2479 s->blockState = TBLOCK_END;
2484 * We are in a failed transaction block. Tell
2485 * CommitTransactionCommand it's time to exit the block.
2488 s->blockState = TBLOCK_ABORT_END;
2492 * We are in a live subtransaction block. Set up to subcommit
2493 * all open subtransactions and then commit the main transaction.
2495 case TBLOCK_SUBINPROGRESS:
2496 while (s->parent != NULL)
2498 if (s->blockState == TBLOCK_SUBINPROGRESS)
2499 s->blockState = TBLOCK_SUBEND;
2501 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2502 BlockStateAsString(s->blockState));
2505 if (s->blockState == TBLOCK_INPROGRESS)
2506 s->blockState = TBLOCK_END;
2508 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2509 BlockStateAsString(s->blockState));
2514 * Here we are inside an aborted subtransaction. Treat the
2515 * COMMIT as ROLLBACK: set up to abort everything and exit
2516 * the main transaction.
2518 case TBLOCK_SUBABORT:
2519 while (s->parent != NULL)
2521 if (s->blockState == TBLOCK_SUBINPROGRESS)
2522 s->blockState = TBLOCK_SUBABORT_PENDING;
2523 else if (s->blockState == TBLOCK_SUBABORT)
2524 s->blockState = TBLOCK_SUBABORT_END;
2526 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2527 BlockStateAsString(s->blockState));
2530 if (s->blockState == TBLOCK_INPROGRESS)
2531 s->blockState = TBLOCK_ABORT_PENDING;
2532 else if (s->blockState == TBLOCK_ABORT)
2533 s->blockState = TBLOCK_ABORT_END;
2535 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2536 BlockStateAsString(s->blockState));
2540 * here, the user issued COMMIT when not inside a transaction.
2541 * Issue a WARNING and go to abort state. The upcoming call
2542 * to CommitTransactionCommand() will then put us back into
2543 * the default state.
2545 case TBLOCK_STARTED:
2547 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2548 errmsg("there is no transaction in progress")));
2549 s->blockState = TBLOCK_ABORT_PENDING;
2552 /* These cases are invalid. */
2553 case TBLOCK_DEFAULT:
2555 case TBLOCK_SUBBEGIN:
2558 case TBLOCK_ABORT_END:
2559 case TBLOCK_SUBABORT_END:
2560 case TBLOCK_ABORT_PENDING:
2561 case TBLOCK_SUBABORT_PENDING:
2562 case TBLOCK_SUBRESTART:
2563 case TBLOCK_SUBABORT_RESTART:
2564 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2565 BlockStateAsString(s->blockState));
2573 * UserAbortTransactionBlock
2574 * This executes a ROLLBACK command.
2576 * As above, we don't actually do anything here except change blockState.
2579 UserAbortTransactionBlock(void)
2581 TransactionState s = CurrentTransactionState;
2583 switch (s->blockState)
2586 * We are inside a transaction block and we got a ROLLBACK
2587 * command from the user, so tell CommitTransactionCommand
2588 * to abort and exit the transaction block.
2590 case TBLOCK_INPROGRESS:
2591 s->blockState = TBLOCK_ABORT_PENDING;
2595 * We are inside a failed transaction block and we got a ROLLBACK
2596 * command from the user. Abort processing is already done,
2597 * so CommitTransactionCommand just has to cleanup and go back
2601 s->blockState = TBLOCK_ABORT_END;
2605 * We are inside a subtransaction. Mark everything
2606 * up to top level as exitable.
2608 case TBLOCK_SUBINPROGRESS:
2609 case TBLOCK_SUBABORT:
2610 while (s->parent != NULL)
2612 if (s->blockState == TBLOCK_SUBINPROGRESS)
2613 s->blockState = TBLOCK_SUBABORT_PENDING;
2614 else if (s->blockState == TBLOCK_SUBABORT)
2615 s->blockState = TBLOCK_SUBABORT_END;
2617 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2618 BlockStateAsString(s->blockState));
2621 if (s->blockState == TBLOCK_INPROGRESS)
2622 s->blockState = TBLOCK_ABORT_PENDING;
2623 else if (s->blockState == TBLOCK_ABORT)
2624 s->blockState = TBLOCK_ABORT_END;
2626 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2627 BlockStateAsString(s->blockState));
2631 * The user issued ABORT when not inside a transaction. Issue
2632 * a WARNING and go to abort state. The upcoming call to
2633 * CommitTransactionCommand() will then put us back into the
2636 case TBLOCK_STARTED:
2638 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2639 errmsg("there is no transaction in progress")));
2640 s->blockState = TBLOCK_ABORT_PENDING;
2643 /* These cases are invalid. */
2644 case TBLOCK_DEFAULT:
2646 case TBLOCK_SUBBEGIN:
2649 case TBLOCK_ABORT_END:
2650 case TBLOCK_SUBABORT_END:
2651 case TBLOCK_ABORT_PENDING:
2652 case TBLOCK_SUBABORT_PENDING:
2653 case TBLOCK_SUBRESTART:
2654 case TBLOCK_SUBABORT_RESTART:
2655 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2656 BlockStateAsString(s->blockState));
2663 * This executes a SAVEPOINT command.
2666 DefineSavepoint(char *name)
2668 TransactionState s = CurrentTransactionState;
2670 switch (s->blockState)
2672 case TBLOCK_INPROGRESS:
2673 case TBLOCK_SUBINPROGRESS:
2674 /* Normal subtransaction start */
2676 s = CurrentTransactionState; /* changed by push */
2679 * Savepoint names, like the TransactionState block itself,
2680 * live in TopTransactionContext.
2683 s->name = MemoryContextStrdup(TopTransactionContext, name);
2686 /* These cases are invalid. */
2687 case TBLOCK_DEFAULT:
2688 case TBLOCK_STARTED:
2690 case TBLOCK_SUBBEGIN:
2694 case TBLOCK_SUBABORT:
2695 case TBLOCK_ABORT_END:
2696 case TBLOCK_SUBABORT_END:
2697 case TBLOCK_ABORT_PENDING:
2698 case TBLOCK_SUBABORT_PENDING:
2699 case TBLOCK_SUBRESTART:
2700 case TBLOCK_SUBABORT_RESTART:
2701 elog(FATAL, "DefineSavepoint: unexpected state %s",
2702 BlockStateAsString(s->blockState));
2709 * This executes a RELEASE command.
2711 * As above, we don't actually do anything here except change blockState.
2714 ReleaseSavepoint(List *options)
2716 TransactionState s = CurrentTransactionState;
2717 TransactionState target,
2722 switch (s->blockState)
2725 * We can't rollback to a savepoint if there is no savepoint
2728 case TBLOCK_INPROGRESS:
2730 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2731 errmsg("no such savepoint")));
2735 * We are in a non-aborted subtransaction. This is the only
2738 case TBLOCK_SUBINPROGRESS:
2741 /* These cases are invalid. */
2742 case TBLOCK_DEFAULT:
2743 case TBLOCK_STARTED:
2745 case TBLOCK_SUBBEGIN:
2749 case TBLOCK_SUBABORT:
2750 case TBLOCK_ABORT_END:
2751 case TBLOCK_SUBABORT_END:
2752 case TBLOCK_ABORT_PENDING:
2753 case TBLOCK_SUBABORT_PENDING:
2754 case TBLOCK_SUBRESTART:
2755 case TBLOCK_SUBABORT_RESTART:
2756 elog(FATAL, "ReleaseSavepoint: unexpected state %s",
2757 BlockStateAsString(s->blockState));
2761 foreach(cell, options)
2763 DefElem *elem = lfirst(cell);
2765 if (strcmp(elem->defname, "savepoint_name") == 0)
2766 name = strVal(elem->arg);
2769 Assert(PointerIsValid(name));
2771 for (target = s; PointerIsValid(target); target = target->parent)
2773 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2777 if (!PointerIsValid(target))
2779 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2780 errmsg("no such savepoint")));
2782 /* disallow crossing savepoint level boundaries */
2783 if (target->savepointLevel != s->savepointLevel)
2785 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2786 errmsg("no such savepoint")));
2789 * Mark "commit pending" all subtransactions up to the target
2790 * subtransaction. The actual commits will happen when control gets
2791 * to CommitTransactionCommand.
2793 xact = CurrentTransactionState;
2796 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2797 xact->blockState = TBLOCK_SUBEND;
2800 xact = xact->parent;
2801 Assert(PointerIsValid(xact));
2806 * RollbackToSavepoint
2807 * This executes a ROLLBACK TO <savepoint> command.
2809 * As above, we don't actually do anything here except change blockState.
2812 RollbackToSavepoint(List *options)
2814 TransactionState s = CurrentTransactionState;
2815 TransactionState target,
2820 switch (s->blockState)
2823 * We can't rollback to a savepoint if there is no savepoint
2826 case TBLOCK_INPROGRESS:
2829 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2830 errmsg("no such savepoint")));
2834 * There is at least one savepoint, so proceed.
2836 case TBLOCK_SUBINPROGRESS:
2837 case TBLOCK_SUBABORT:
2840 /* These cases are invalid. */
2841 case TBLOCK_DEFAULT:
2842 case TBLOCK_STARTED:
2844 case TBLOCK_SUBBEGIN:
2847 case TBLOCK_ABORT_END:
2848 case TBLOCK_SUBABORT_END:
2849 case TBLOCK_ABORT_PENDING:
2850 case TBLOCK_SUBABORT_PENDING:
2851 case TBLOCK_SUBRESTART:
2852 case TBLOCK_SUBABORT_RESTART:
2853 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2854 BlockStateAsString(s->blockState));
2858 foreach(cell, options)
2860 DefElem *elem = lfirst(cell);
2862 if (strcmp(elem->defname, "savepoint_name") == 0)
2863 name = strVal(elem->arg);
2866 Assert(PointerIsValid(name));
2868 for (target = s; PointerIsValid(target); target = target->parent)
2870 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2874 if (!PointerIsValid(target))
2876 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2877 errmsg("no such savepoint")));
2879 /* disallow crossing savepoint level boundaries */
2880 if (target->savepointLevel != s->savepointLevel)
2882 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2883 errmsg("no such savepoint")));
2886 * Mark "abort pending" all subtransactions up to the target
2887 * subtransaction. The actual aborts will happen when control gets
2888 * to CommitTransactionCommand.
2890 xact = CurrentTransactionState;
2895 if (xact->blockState == TBLOCK_SUBINPROGRESS)
2896 xact->blockState = TBLOCK_SUBABORT_PENDING;
2897 else if (xact->blockState == TBLOCK_SUBABORT)
2898 xact->blockState = TBLOCK_SUBABORT_END;
2900 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2901 BlockStateAsString(xact->blockState));
2902 xact = xact->parent;
2903 Assert(PointerIsValid(xact));
2906 /* And mark the target as "restart pending" */
2907 if (xact->blockState == TBLOCK_SUBINPROGRESS)
2908 xact->blockState = TBLOCK_SUBRESTART;
2909 else if (xact->blockState == TBLOCK_SUBABORT)
2910 xact->blockState = TBLOCK_SUBABORT_RESTART;
2912 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2913 BlockStateAsString(xact->blockState));
2917 * BeginInternalSubTransaction
2918 * This is the same as DefineSavepoint except it allows TBLOCK_STARTED
2919 * state, and therefore it can safely be used in a function that might
2920 * be called when not inside a BEGIN block. Also, we automatically
2921 * cycle through CommitTransactionCommand/StartTransactionCommand
2922 * instead of expecting the caller to do it.
2925 BeginInternalSubTransaction(char *name)
2927 TransactionState s = CurrentTransactionState;
2929 switch (s->blockState)
2931 case TBLOCK_STARTED:
2932 case TBLOCK_INPROGRESS:
2933 case TBLOCK_SUBINPROGRESS:
2934 /* Normal subtransaction start */
2936 s = CurrentTransactionState; /* changed by push */
2939 * Savepoint names, like the TransactionState block itself,
2940 * live in TopTransactionContext.
2943 s->name = MemoryContextStrdup(TopTransactionContext, name);
2946 /* These cases are invalid. */
2947 case TBLOCK_DEFAULT:
2949 case TBLOCK_SUBBEGIN:
2953 case TBLOCK_SUBABORT:
2954 case TBLOCK_ABORT_END:
2955 case TBLOCK_SUBABORT_END:
2956 case TBLOCK_ABORT_PENDING:
2957 case TBLOCK_SUBABORT_PENDING:
2958 case TBLOCK_SUBRESTART:
2959 case TBLOCK_SUBABORT_RESTART:
2960 elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
2961 BlockStateAsString(s->blockState));
2965 CommitTransactionCommand();
2966 StartTransactionCommand();
2970 * ReleaseCurrentSubTransaction
2972 * RELEASE (ie, commit) the innermost subtransaction, regardless of its
2973 * savepoint name (if any).
2974 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2977 ReleaseCurrentSubTransaction(void)
2979 TransactionState s = CurrentTransactionState;
2981 if (s->blockState != TBLOCK_SUBINPROGRESS)
2982 elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
2983 BlockStateAsString(s->blockState));
2984 Assert(s->state == TRANS_INPROGRESS);
2985 MemoryContextSwitchTo(CurTransactionContext);
2986 CommitSubTransaction();
2987 s = CurrentTransactionState; /* changed by pop */
2988 Assert(s->state == TRANS_INPROGRESS);
2992 * RollbackAndReleaseCurrentSubTransaction
2994 * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
2995 * of its savepoint name (if any).
2996 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2999 RollbackAndReleaseCurrentSubTransaction(void)
3001 TransactionState s = CurrentTransactionState;
3003 switch (s->blockState)
3005 /* Must be in a subtransaction */
3006 case TBLOCK_SUBINPROGRESS:
3007 case TBLOCK_SUBABORT:
3010 /* These cases are invalid. */
3011 case TBLOCK_DEFAULT:
3012 case TBLOCK_STARTED:
3014 case TBLOCK_SUBBEGIN:
3015 case TBLOCK_INPROGRESS:
3019 case TBLOCK_ABORT_END:
3020 case TBLOCK_SUBABORT_END:
3021 case TBLOCK_ABORT_PENDING:
3022 case TBLOCK_SUBABORT_PENDING:
3023 case TBLOCK_SUBRESTART:
3024 case TBLOCK_SUBABORT_RESTART:
3025 elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
3026 BlockStateAsString(s->blockState));
3031 * Abort the current subtransaction, if needed.
3033 if (s->blockState == TBLOCK_SUBINPROGRESS)
3034 AbortSubTransaction();
3036 /* And clean it up, too */
3037 CleanupSubTransaction();
3039 s = CurrentTransactionState; /* changed by pop */
3040 AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
3041 s->blockState == TBLOCK_INPROGRESS ||
3042 s->blockState == TBLOCK_STARTED);
3046 * AbortOutOfAnyTransaction
3048 * This routine is provided for error recovery purposes. It aborts any
3049 * active transaction or transaction block, leaving the system in a known
3053 AbortOutOfAnyTransaction(void)
3055 TransactionState s = CurrentTransactionState;
3058 * Get out of any transaction or nested transaction
3062 switch (s->blockState)
3064 case TBLOCK_DEFAULT:
3065 /* Not in a transaction, do nothing */
3067 case TBLOCK_STARTED:
3069 case TBLOCK_INPROGRESS:
3071 case TBLOCK_ABORT_PENDING:
3072 /* In a transaction, so clean up */
3074 CleanupTransaction();
3075 s->blockState = TBLOCK_DEFAULT;
3078 case TBLOCK_ABORT_END:
3079 /* AbortTransaction already done, still need Cleanup */
3080 CleanupTransaction();
3081 s->blockState = TBLOCK_DEFAULT;
3085 * In a subtransaction, so clean it up and abort parent
3088 case TBLOCK_SUBBEGIN:
3089 case TBLOCK_SUBINPROGRESS:
3091 case TBLOCK_SUBABORT_PENDING:
3092 case TBLOCK_SUBRESTART:
3093 AbortSubTransaction();
3094 CleanupSubTransaction();
3095 s = CurrentTransactionState; /* changed by pop */
3098 case TBLOCK_SUBABORT:
3099 case TBLOCK_SUBABORT_END:
3100 case TBLOCK_SUBABORT_RESTART:
3101 /* As above, but AbortSubTransaction already done */
3102 CleanupSubTransaction();
3103 s = CurrentTransactionState; /* changed by pop */
3106 } while (s->blockState != TBLOCK_DEFAULT);
3108 /* Should be out of all subxacts now */
3109 Assert(s->parent == NULL);
3113 * IsTransactionBlock --- are we within a transaction block?
3116 IsTransactionBlock(void)
3118 TransactionState s = CurrentTransactionState;
3120 if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
3127 * IsTransactionOrTransactionBlock --- are we within either a transaction
3128 * or a transaction block? (The backend is only really "idle" when this
3131 * This should match up with IsTransactionBlock and IsTransactionState.
3134 IsTransactionOrTransactionBlock(void)
3136 TransactionState s = CurrentTransactionState;
3138 if (s->blockState == TBLOCK_DEFAULT)
3145 * TransactionBlockStatusCode - return status code to send in ReadyForQuery
3148 TransactionBlockStatusCode(void)
3150 TransactionState s = CurrentTransactionState;
3152 switch (s->blockState)
3154 case TBLOCK_DEFAULT:
3155 case TBLOCK_STARTED:
3156 return 'I'; /* idle --- not in transaction */
3158 case TBLOCK_SUBBEGIN:
3159 case TBLOCK_INPROGRESS:
3160 case TBLOCK_SUBINPROGRESS:
3163 return 'T'; /* in transaction */
3165 case TBLOCK_SUBABORT:
3166 case TBLOCK_ABORT_END:
3167 case TBLOCK_SUBABORT_END:
3168 case TBLOCK_ABORT_PENDING:
3169 case TBLOCK_SUBABORT_PENDING:
3170 case TBLOCK_SUBRESTART:
3171 case TBLOCK_SUBABORT_RESTART:
3172 return 'E'; /* in failed transaction */
3175 /* should never get here */
3176 elog(FATAL, "invalid transaction block state: %s",
3177 BlockStateAsString(s->blockState));
3178 return 0; /* keep compiler quiet */
3185 IsSubTransaction(void)
3187 TransactionState s = CurrentTransactionState;
3189 if (s->nestingLevel >= 2)
3196 * StartSubTransaction
3198 * If you're wondering why this is separate from PushTransaction: it's because
3199 * we can't conveniently do this stuff right inside DefineSavepoint. The
3200 * SAVEPOINT utility command will be executed inside a Portal, and if we
3201 * muck with CurrentMemoryContext or CurrentResourceOwner then exit from
3202 * the Portal will undo those settings. So we make DefineSavepoint just
3203 * push a dummy transaction block, and when control returns to the main
3204 * idle loop, CommitTransactionCommand will be called, and we'll come here
3205 * to finish starting the subtransaction.
3208 StartSubTransaction(void)
3210 TransactionState s = CurrentTransactionState;
3212 if (s->state != TRANS_DEFAULT)
3213 elog(WARNING, "StartSubTransaction while in %s state",
3214 TransStateAsString(s->state));
3216 s->state = TRANS_START;
3219 * Initialize subsystems for new subtransaction
3221 * must initialize resource-management stuff first
3223 AtSubStart_Memory();
3224 AtSubStart_ResourceOwner();
3226 AtSubStart_Notify();
3227 AfterTriggerBeginSubXact();
3229 s->state = TRANS_INPROGRESS;
3232 * Call start-of-subxact callbacks
3234 CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
3235 s->parent->subTransactionId);
3237 ShowTransactionState("StartSubTransaction");
3241 * CommitSubTransaction
3243 * The caller has to make sure to always reassign CurrentTransactionState
3244 * if it has a local pointer to it after calling this function.
3247 CommitSubTransaction(void)
3249 TransactionState s = CurrentTransactionState;
3251 ShowTransactionState("CommitSubTransaction");
3253 if (s->state != TRANS_INPROGRESS)
3254 elog(WARNING, "CommitSubTransaction while in %s state",
3255 TransStateAsString(s->state));
3257 /* Pre-commit processing goes here -- nothing to do at the moment */
3259 s->state = TRANS_COMMIT;
3261 /* Must CCI to ensure commands of subtransaction are seen as done */
3262 CommandCounterIncrement();
3264 /* Mark subtransaction as subcommitted */
3265 if (TransactionIdIsValid(s->transactionId))
3267 RecordSubTransactionCommit();
3268 AtSubCommit_childXids();
3271 /* Post-commit cleanup */
3272 AfterTriggerEndSubXact(true);
3273 AtSubCommit_Portals(s->subTransactionId,
3274 s->parent->subTransactionId,
3275 s->parent->curTransactionOwner);
3276 AtEOSubXact_LargeObject(true, s->subTransactionId,
3277 s->parent->subTransactionId);
3278 AtSubCommit_Notify();
3279 AtEOSubXact_UpdatePasswordFile(true, s->subTransactionId,
3280 s->parent->subTransactionId);
3282 CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
3283 s->parent->subTransactionId);
3285 ResourceOwnerRelease(s->curTransactionOwner,
3286 RESOURCE_RELEASE_BEFORE_LOCKS,
3288 AtEOSubXact_RelationCache(true, s->subTransactionId,
3289 s->parent->subTransactionId);
3290 AtEOSubXact_Inval(true);
3294 * The only lock we actually release here is the subtransaction XID lock.
3295 * The rest just get transferred to the parent resource owner.
3297 CurrentResourceOwner = s->curTransactionOwner;
3298 if (TransactionIdIsValid(s->transactionId))
3299 XactLockTableDelete(s->transactionId);
3301 ResourceOwnerRelease(s->curTransactionOwner,
3302 RESOURCE_RELEASE_LOCKS,
3304 ResourceOwnerRelease(s->curTransactionOwner,
3305 RESOURCE_RELEASE_AFTER_LOCKS,
3308 AtEOXact_GUC(true, true);
3309 AtEOSubXact_SPI(true, s->subTransactionId);
3310 AtEOSubXact_on_commit_actions(true, s->subTransactionId,
3311 s->parent->subTransactionId);
3312 AtEOSubXact_Namespace(true, s->subTransactionId,
3313 s->parent->subTransactionId);
3314 AtEOSubXact_Files(true, s->subTransactionId,
3315 s->parent->subTransactionId);
3318 * We need to restore the upper transaction's read-only state, in case
3319 * the upper is read-write while the child is read-only; GUC will
3320 * incorrectly think it should leave the child state in place.
3322 XactReadOnly = s->prevXactReadOnly;
3324 CurrentResourceOwner = s->parent->curTransactionOwner;
3325 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3326 ResourceOwnerDelete(s->curTransactionOwner);
3327 s->curTransactionOwner = NULL;
3329 AtSubCommit_Memory();
3331 s->state = TRANS_DEFAULT;
3337 * AbortSubTransaction
3340 AbortSubTransaction(void)
3342 TransactionState s = CurrentTransactionState;
3344 ShowTransactionState("AbortSubTransaction");
3346 if (s->state != TRANS_INPROGRESS)
3347 elog(WARNING, "AbortSubTransaction while in %s state",
3348 TransStateAsString(s->state));
3352 s->state = TRANS_ABORT;
3355 * Release any LW locks we might be holding as quickly as possible.
3356 * (Regular locks, however, must be held till we finish aborting.)
3357 * Releasing LW locks is critical since we might try to grab them
3358 * again while cleaning up!
3360 * FIXME This may be incorrect --- Are there some locks we should keep?
3361 * Buffer locks, for example? I don't think so but I'm not sure.
3371 * do abort processing
3373 AtSubAbort_Memory();
3374 AtSubAbort_ResourceOwner();
3377 * We can skip all this stuff if the subxact failed before creating
3378 * a ResourceOwner...
3380 if (s->curTransactionOwner)
3382 AfterTriggerEndSubXact(false);
3383 AtSubAbort_Portals(s->subTransactionId,
3384 s->parent->subTransactionId,
3385 s->parent->curTransactionOwner);
3386 AtEOSubXact_LargeObject(false, s->subTransactionId,
3387 s->parent->subTransactionId);
3388 AtSubAbort_Notify();
3389 AtEOSubXact_UpdatePasswordFile(false, s->subTransactionId,
3390 s->parent->subTransactionId);
3392 /* Advertise the fact that we aborted in pg_clog. */
3393 if (TransactionIdIsValid(s->transactionId))
3395 RecordSubTransactionAbort();
3396 AtSubAbort_childXids();
3399 /* Post-abort cleanup */
3400 CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
3401 s->parent->subTransactionId);
3403 ResourceOwnerRelease(s->curTransactionOwner,
3404 RESOURCE_RELEASE_BEFORE_LOCKS,
3406 AtEOSubXact_RelationCache(false, s->subTransactionId,
3407 s->parent->subTransactionId);
3408 AtEOSubXact_Inval(false);
3410 ResourceOwnerRelease(s->curTransactionOwner,
3411 RESOURCE_RELEASE_LOCKS,
3413 ResourceOwnerRelease(s->curTransactionOwner,
3414 RESOURCE_RELEASE_AFTER_LOCKS,
3417 AtEOXact_GUC(false, true);
3418 AtEOSubXact_SPI(false, s->subTransactionId);
3419 AtEOSubXact_on_commit_actions(false, s->subTransactionId,
3420 s->parent->subTransactionId);
3421 AtEOSubXact_Namespace(false, s->subTransactionId,
3422 s->parent->subTransactionId);
3423 AtEOSubXact_Files(false, s->subTransactionId,
3424 s->parent->subTransactionId);
3428 * Reset user id which might have been changed transiently. Here we
3429 * want to restore to the userid that was current at subxact entry.
3430 * (As in AbortTransaction, we need not worry about the session
3433 * Must do this after AtEOXact_GUC to handle the case where we entered
3434 * the subxact inside a SECURITY DEFINER function (hence current and
3435 * session userids were different) and then session auth was changed
3436 * inside the subxact. GUC will reset both current and session
3437 * userids to the entry-time session userid. This is right in every
3438 * other scenario so it seems simplest to let GUC do that and fix it
3441 SetUserId(s->currentUser);
3444 * Restore the upper transaction's read-only state, too. This should
3445 * be redundant with GUC's cleanup but we may as well do it for
3446 * consistency with the commit case.
3448 XactReadOnly = s->prevXactReadOnly;
3450 RESUME_INTERRUPTS();
3454 * CleanupSubTransaction
3456 * The caller has to make sure to always reassign CurrentTransactionState
3457 * if it has a local pointer to it after calling this function.
3460 CleanupSubTransaction(void)
3462 TransactionState s = CurrentTransactionState;
3464 ShowTransactionState("CleanupSubTransaction");
3466 if (s->state != TRANS_ABORT)
3467 elog(WARNING, "CleanupSubTransaction while in %s state",
3468 TransStateAsString(s->state));
3470 AtSubCleanup_Portals(s->subTransactionId);
3472 CurrentResourceOwner = s->parent->curTransactionOwner;
3473 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3474 if (s->curTransactionOwner)
3475 ResourceOwnerDelete(s->curTransactionOwner);
3476 s->curTransactionOwner = NULL;
3478 AtSubCleanup_Memory();
3480 s->state = TRANS_DEFAULT;
3487 * Create transaction state stack entry for a subtransaction
3489 * The caller has to make sure to always reassign CurrentTransactionState
3490 * if it has a local pointer to it after calling this function.
3493 PushTransaction(void)
3495 TransactionState p = CurrentTransactionState;
3500 * At present, GetUserId cannot fail, but let's not assume that. Get
3501 * the ID before entering the critical code sequence.
3503 currentUser = GetUserId();
3506 * We keep subtransaction state nodes in TopTransactionContext.
3508 s = (TransactionState)
3509 MemoryContextAllocZero(TopTransactionContext,
3510 sizeof(TransactionStateData));
3512 * Assign a subtransaction ID, watching out for counter wraparound.
3514 currentSubTransactionId += 1;
3515 if (currentSubTransactionId == InvalidSubTransactionId)
3517 currentSubTransactionId -= 1;
3520 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3521 errmsg("cannot have more than 2^32-1 subtransactions in a transaction")));
3524 * We can now stack a minimally valid subtransaction without fear of
3527 s->transactionId = InvalidTransactionId; /* until assigned */
3528 s->subTransactionId = currentSubTransactionId;
3530 s->nestingLevel = p->nestingLevel + 1;
3531 s->savepointLevel = p->savepointLevel;
3532 s->state = TRANS_DEFAULT;
3533 s->blockState = TBLOCK_SUBBEGIN;
3534 s->currentUser = currentUser;
3535 s->prevXactReadOnly = XactReadOnly;
3537 CurrentTransactionState = s;
3540 * AbortSubTransaction and CleanupSubTransaction have to be able to
3541 * cope with the subtransaction from here on out; in particular they
3542 * should not assume that it necessarily has a transaction context,
3543 * resource owner, or XID.
3549 * Pop back to parent transaction state
3551 * The caller has to make sure to always reassign CurrentTransactionState
3552 * if it has a local pointer to it after calling this function.
3555 PopTransaction(void)
3557 TransactionState s = CurrentTransactionState;
3559 if (s->state != TRANS_DEFAULT)
3560 elog(WARNING, "PopTransaction while in %s state",
3561 TransStateAsString(s->state));
3563 if (s->parent == NULL)
3564 elog(FATAL, "PopTransaction with no parent");
3566 CurrentTransactionState = s->parent;
3568 /* Let's just make sure CurTransactionContext is good */
3569 CurTransactionContext = s->parent->curTransactionContext;
3570 MemoryContextSwitchTo(CurTransactionContext);
3572 /* Ditto for ResourceOwner links */
3573 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3574 CurrentResourceOwner = s->parent->curTransactionOwner;
3576 /* Free the old child structure */
3583 * ShowTransactionState
3587 ShowTransactionState(const char *str)
3589 /* skip work if message will definitely not be printed */
3590 if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
3592 elog(DEBUG2, "%s", str);
3593 ShowTransactionStateRec(CurrentTransactionState);
3598 * ShowTransactionStateRec
3599 * Recursive subroutine for ShowTransactionState
3602 ShowTransactionStateRec(TransactionState s)
3605 ShowTransactionStateRec(s->parent);
3607 /* use ereport to suppress computation if msg will not be printed */
3609 (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u, nestlvl: %d, children: %s",
3610 PointerIsValid(s->name) ? s->name : "unnamed",
3611 BlockStateAsString(s->blockState),
3612 TransStateAsString(s->state),
3613 (unsigned int) s->transactionId,
3614 (unsigned int) s->subTransactionId,
3615 (unsigned int) currentCommandId,
3617 nodeToString(s->childXids))));
3621 * BlockStateAsString
3625 BlockStateAsString(TBlockState blockState)
3629 case TBLOCK_DEFAULT:
3631 case TBLOCK_STARTED:
3635 case TBLOCK_INPROGRESS:
3636 return "INPROGRESS";
3641 case TBLOCK_ABORT_END:
3643 case TBLOCK_ABORT_PENDING:
3644 return "ABORT PEND";
3645 case TBLOCK_SUBBEGIN:
3647 case TBLOCK_SUBINPROGRESS:
3648 return "SUB INPROGRS";
3651 case TBLOCK_SUBABORT:
3653 case TBLOCK_SUBABORT_END:
3654 return "SUB ABORT END";
3655 case TBLOCK_SUBABORT_PENDING:
3656 return "SUB ABRT PEND";
3657 case TBLOCK_SUBRESTART:
3658 return "SUB RESTART";
3659 case TBLOCK_SUBABORT_RESTART:
3660 return "SUB AB RESTRT";
3662 return "UNRECOGNIZED";
3666 * TransStateAsString
3670 TransStateAsString(TransState state)
3682 case TRANS_INPROGRESS:
3685 return "UNRECOGNIZED";
3689 * xactGetCommittedChildren
3691 * Gets the list of committed children of the current transaction. The return
3692 * value is the number of child transactions. *children is set to point to a
3693 * palloc'd array of TransactionIds. If there are no subxacts, *children is
3697 xactGetCommittedChildren(TransactionId **ptr)
3699 TransactionState s = CurrentTransactionState;
3701 TransactionId *children;
3704 nchildren = list_length(s->childXids);
3711 children = (TransactionId *) palloc(nchildren * sizeof(TransactionId));
3714 foreach(p, s->childXids)
3716 TransactionId child = lfirst_xid(p);
3718 *children++ = child;
3725 * XLOG support routines
3729 xact_redo(XLogRecPtr lsn, XLogRecord *record)
3731 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3733 if (info == XLOG_XACT_COMMIT)
3735 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
3736 TransactionId *sub_xids;
3737 TransactionId max_xid;
3740 TransactionIdCommit(record->xl_xid);
3742 /* Mark committed subtransactions as committed */
3743 sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
3744 TransactionIdCommitTree(xlrec->nsubxacts, sub_xids);
3746 /* Make sure nextXid is beyond any XID mentioned in the record */
3747 max_xid = record->xl_xid;
3748 for (i = 0; i < xlrec->nsubxacts; i++)
3750 if (TransactionIdPrecedes(max_xid, sub_xids[i]))
3751 max_xid = sub_xids[i];
3753 if (TransactionIdFollowsOrEquals(max_xid,
3754 ShmemVariableCache->nextXid))
3756 ShmemVariableCache->nextXid = max_xid;
3757 TransactionIdAdvance(ShmemVariableCache->nextXid);
3760 /* Make sure files supposed to be dropped are dropped */
3761 for (i = 0; i < xlrec->nrels; i++)
3763 XLogCloseRelation(xlrec->xnodes[i]);
3764 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3767 else if (info == XLOG_XACT_ABORT)
3769 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
3770 TransactionId *sub_xids;
3771 TransactionId max_xid;
3774 TransactionIdAbort(record->xl_xid);
3776 /* Mark subtransactions as aborted */
3777 sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
3778 TransactionIdAbortTree(xlrec->nsubxacts, sub_xids);
3780 /* Make sure nextXid is beyond any XID mentioned in the record */
3781 max_xid = record->xl_xid;
3782 for (i = 0; i < xlrec->nsubxacts; i++)
3784 if (TransactionIdPrecedes(max_xid, sub_xids[i]))
3785 max_xid = sub_xids[i];
3787 if (TransactionIdFollowsOrEquals(max_xid,
3788 ShmemVariableCache->nextXid))
3790 ShmemVariableCache->nextXid = max_xid;
3791 TransactionIdAdvance(ShmemVariableCache->nextXid);
3794 /* Make sure files supposed to be dropped are dropped */
3795 for (i = 0; i < xlrec->nrels; i++)
3797 XLogCloseRelation(xlrec->xnodes[i]);
3798 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3802 elog(PANIC, "xact_redo: unknown op code %u", info);
3806 xact_undo(XLogRecPtr lsn, XLogRecord *record)
3808 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3810 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
3811 elog(PANIC, "xact_undo: can't undo committed xaction");
3812 else if (info != XLOG_XACT_ABORT)
3813 elog(PANIC, "xact_redo: unknown op code %u", info);
3817 xact_desc(char *buf, uint8 xl_info, char *rec)
3819 uint8 info = xl_info & ~XLR_INFO_MASK;
3822 if (info == XLOG_XACT_COMMIT)
3824 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
3825 struct tm *tm = localtime(&xlrec->xtime);
3827 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
3828 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3829 tm->tm_hour, tm->tm_min, tm->tm_sec);
3830 if (xlrec->nrels > 0)
3832 sprintf(buf + strlen(buf), "; rels:");
3833 for (i = 0; i < xlrec->nrels; i++)
3835 RelFileNode rnode = xlrec->xnodes[i];
3837 sprintf(buf + strlen(buf), " %u/%u/%u",
3838 rnode.spcNode, rnode.dbNode, rnode.relNode);
3841 if (xlrec->nsubxacts > 0)
3843 TransactionId *xacts = (TransactionId *)
3844 &xlrec->xnodes[xlrec->nrels];
3846 sprintf(buf + strlen(buf), "; subxacts:");
3847 for (i = 0; i < xlrec->nsubxacts; i++)
3848 sprintf(buf + strlen(buf), " %u", xacts[i]);
3851 else if (info == XLOG_XACT_ABORT)
3853 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
3854 struct tm *tm = localtime(&xlrec->xtime);
3856 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
3857 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3858 tm->tm_hour, tm->tm_min, tm->tm_sec);
3859 if (xlrec->nrels > 0)
3861 sprintf(buf + strlen(buf), "; rels:");
3862 for (i = 0; i < xlrec->nrels; i++)
3864 RelFileNode rnode = xlrec->xnodes[i];
3866 sprintf(buf + strlen(buf), " %u/%u/%u",
3867 rnode.spcNode, rnode.dbNode, rnode.relNode);
3870 if (xlrec->nsubxacts > 0)
3872 TransactionId *xacts = (TransactionId *)
3873 &xlrec->xnodes[xlrec->nrels];
3875 sprintf(buf + strlen(buf), "; subxacts:");
3876 for (i = 0; i < xlrec->nsubxacts; i++)
3877 sprintf(buf + strlen(buf), " %u", xacts[i]);
3881 strcat(buf, "UNKNOWN");
3885 XactPushRollback(void (*func) (void *), void *data)
3888 if (_RollbackFunc != NULL)
3889 elog(PANIC, "XactPushRollback: already installed");
3892 _RollbackFunc = func;
3893 _RollbackData = data;
3897 XactPopRollback(void)
3899 _RollbackFunc = NULL;