1 /*-------------------------------------------------------------------------
4 * top level transaction system support routines
6 * See src/backend/access/transam/README for more information.
8 * Portions Copyright (c) 1996-2005, 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.197 2005/02/20 21:46:48 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 "executor/spi.h"
32 #include "libpq/be-fsstubs.h"
33 #include "miscadmin.h"
34 #include "storage/fd.h"
35 #include "storage/proc.h"
36 #include "storage/sinval.h"
37 #include "storage/smgr.h"
38 #include "utils/flatfiles.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
455 TransactionIdIsCurrentTransactionId(TransactionId xid)
460 * We always say that BootstrapTransactionId is "not my transaction ID"
461 * even when it is (ie, during bootstrap). Along with the fact that
462 * transam.c always treats BootstrapTransactionId as already committed,
463 * this causes the tqual.c routines to see all tuples as committed,
464 * which is what we need during bootstrap. (Bootstrap mode only inserts
465 * tuples, it never updates or deletes them, so all tuples can be presumed
468 if (xid == BootstrapTransactionId)
472 * We will return true for the Xid of the current subtransaction, any
473 * of its subcommitted children, any of its parents, or any of their
474 * previously subcommitted children. However, a transaction being
475 * aborted is no longer "current", even though it may still have an
476 * entry on the state stack.
478 for (s = CurrentTransactionState; s != NULL; s = s->parent)
482 if (s->state == TRANS_ABORT)
484 if (!TransactionIdIsValid(s->transactionId))
485 continue; /* it can't have any child XIDs either */
486 if (TransactionIdEquals(xid, s->transactionId))
488 foreach(cell, s->childXids)
490 if (TransactionIdEquals(xid, lfirst_xid(cell)))
500 * CommandCounterIncrement
503 CommandCounterIncrement(void)
505 currentCommandId += 1;
506 if (currentCommandId == FirstCommandId) /* check for overflow */
508 currentCommandId -= 1;
510 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
511 errmsg("cannot have more than 2^32-1 commands in a transaction")));
514 /* Propagate new command ID into static snapshots, if set */
515 if (SerializableSnapshot)
516 SerializableSnapshot->curcid = currentCommandId;
518 LatestSnapshot->curcid = currentCommandId;
521 * make cache changes visible to me.
523 AtCommit_LocalCache();
528 /* ----------------------------------------------------------------
529 * StartTransaction stuff
530 * ----------------------------------------------------------------
539 AcceptInvalidationMessages();
548 TransactionState s = CurrentTransactionState;
551 * We shouldn't have a transaction context already.
553 Assert(TopTransactionContext == NULL);
556 * Create a toplevel context for the transaction.
558 TopTransactionContext =
559 AllocSetContextCreate(TopMemoryContext,
560 "TopTransactionContext",
561 ALLOCSET_DEFAULT_MINSIZE,
562 ALLOCSET_DEFAULT_INITSIZE,
563 ALLOCSET_DEFAULT_MAXSIZE);
566 * In a top-level transaction, CurTransactionContext is the same as
567 * TopTransactionContext.
569 CurTransactionContext = TopTransactionContext;
570 s->curTransactionContext = CurTransactionContext;
572 /* Make the CurTransactionContext active. */
573 MemoryContextSwitchTo(CurTransactionContext);
577 * AtStart_ResourceOwner
580 AtStart_ResourceOwner(void)
582 TransactionState s = CurrentTransactionState;
585 * We shouldn't have a transaction resource owner already.
587 Assert(TopTransactionResourceOwner == NULL);
590 * Create a toplevel resource owner for the transaction.
592 s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
594 TopTransactionResourceOwner = s->curTransactionOwner;
595 CurTransactionResourceOwner = s->curTransactionOwner;
596 CurrentResourceOwner = s->curTransactionOwner;
599 /* ----------------------------------------------------------------
600 * StartSubTransaction stuff
601 * ----------------------------------------------------------------
608 AtSubStart_Memory(void)
610 TransactionState s = CurrentTransactionState;
612 Assert(CurTransactionContext != NULL);
615 * Create a CurTransactionContext, which will be used to hold data
616 * that survives subtransaction commit but disappears on
617 * subtransaction abort. We make it a child of the immediate parent's
618 * CurTransactionContext.
620 CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
621 "CurTransactionContext",
622 ALLOCSET_DEFAULT_MINSIZE,
623 ALLOCSET_DEFAULT_INITSIZE,
624 ALLOCSET_DEFAULT_MAXSIZE);
625 s->curTransactionContext = CurTransactionContext;
627 /* Make the CurTransactionContext active. */
628 MemoryContextSwitchTo(CurTransactionContext);
632 * AtSubStart_ResourceOwner
635 AtSubStart_ResourceOwner(void)
637 TransactionState s = CurrentTransactionState;
639 Assert(s->parent != NULL);
642 * Create a resource owner for the subtransaction. We make it a child
643 * of the immediate parent's resource owner.
645 s->curTransactionOwner =
646 ResourceOwnerCreate(s->parent->curTransactionOwner,
649 CurTransactionResourceOwner = s->curTransactionOwner;
650 CurrentResourceOwner = s->curTransactionOwner;
653 /* ----------------------------------------------------------------
654 * CommitTransaction stuff
655 * ----------------------------------------------------------------
659 * RecordTransactionCommit
662 RecordTransactionCommit(void)
667 TransactionId *children;
669 /* Get data needed for commit record */
670 nrels = smgrGetPendingDeletes(true, &rptr);
671 nchildren = xactGetCommittedChildren(&children);
674 * If we made neither any XLOG entries nor any temp-rel updates, and
675 * have no files to be deleted, we can omit recording the transaction
676 * commit at all. (This test includes the effects of subtransactions,
677 * so the presence of committed subxacts need not alone force a
680 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)
682 TransactionId xid = GetCurrentTransactionId();
686 /* Tell bufmgr and smgr to prepare for commit */
689 START_CRIT_SECTION();
692 * If our transaction made any transaction-controlled XLOG
693 * entries, we need to lock out checkpoint start between writing
694 * our XLOG record and updating pg_clog. Otherwise it is possible
695 * for the checkpoint to set REDO after the XLOG record but fail
696 * to flush the pg_clog update to disk, leading to loss of the
697 * transaction commit if we crash a little later. Slightly klugy
698 * fix for problem discovered 2004-08-10.
700 * (If it made no transaction-controlled XLOG entries, its XID
701 * appears nowhere in permanent storage, so no one else will ever
702 * care if it committed; so it doesn't matter if we lose the
705 * Note we only need a shared lock.
707 madeTCentries = (MyLastRecPtr.xrecoff != 0);
709 LWLockAcquire(CheckpointStartLock, LW_SHARED);
712 * We only need to log the commit in XLOG if the transaction made
713 * any transaction-controlled XLOG entries or will delete files.
715 if (madeTCentries || nrels > 0)
717 XLogRecData rdata[3];
719 xl_xact_commit xlrec;
721 xlrec.xtime = time(NULL);
723 xlrec.nsubxacts = nchildren;
724 rdata[0].buffer = InvalidBuffer;
725 rdata[0].data = (char *) (&xlrec);
726 rdata[0].len = MinSizeOfXactCommit;
727 /* dump rels to delete */
730 rdata[0].next = &(rdata[1]);
731 rdata[1].buffer = InvalidBuffer;
732 rdata[1].data = (char *) rptr;
733 rdata[1].len = nrels * sizeof(RelFileNode);
736 /* dump committed child Xids */
739 rdata[lastrdata].next = &(rdata[2]);
740 rdata[2].buffer = InvalidBuffer;
741 rdata[2].data = (char *) children;
742 rdata[2].len = nchildren * sizeof(TransactionId);
745 rdata[lastrdata].next = NULL;
747 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
751 /* Just flush through last record written by me */
752 recptr = ProcLastRecEnd;
756 * We must flush our XLOG entries to disk if we made any XLOG
757 * entries, whether in or out of transaction control. For
758 * example, if we reported a nextval() result to the client, this
759 * ensures that any XLOG record generated by nextval will hit the
760 * disk before we report the transaction committed.
762 * Note: if we generated a commit record above, MyXactMadeXLogEntry
763 * will certainly be set now.
765 if (MyXactMadeXLogEntry)
768 * Sleep before flush! So we can flush more than one commit
769 * records per single fsync. (The idea is some other backend
770 * may do the XLogFlush while we're sleeping. This needs work
771 * still, because on most Unixen, the minimum select() delay
772 * is 10msec or more, which is way too long.)
774 * We do not sleep if enableFsync is not turned on, nor if there
775 * are fewer than CommitSiblings other backends with active
778 if (CommitDelay > 0 && enableFsync &&
779 CountActiveBackends() >= CommitSiblings)
780 pg_usleep(CommitDelay);
786 * We must mark the transaction committed in clog if its XID
787 * appears either in permanent rels or in local temporary rels. We
788 * test this by seeing if we made transaction-controlled entries
789 * *OR* local-rel tuple updates. Note that if we made only the
790 * latter, we have not emitted an XLOG record for our commit, and
791 * so in the event of a crash the clog update might be lost. This
792 * is okay because no one else will ever care whether we
795 if (madeTCentries || MyXactMadeTempRelUpdate)
797 TransactionIdCommit(xid);
798 /* to avoid race conditions, the parent must commit first */
799 TransactionIdCommitTree(nchildren, children);
802 /* Unlock checkpoint lock if we acquired it */
804 LWLockRelease(CheckpointStartLock);
809 /* Break the chain of back-links in the XLOG records I output */
810 MyLastRecPtr.xrecoff = 0;
811 MyXactMadeXLogEntry = false;
812 MyXactMadeTempRelUpdate = false;
814 /* Show myself as out of the transaction in PGPROC array */
815 MyProc->logRec.xrecoff = 0;
817 /* And clean up local data */
826 * AtCommit_LocalCache
829 AtCommit_LocalCache(void)
832 * Make catalog changes visible to me for the next command.
834 CommandEndInvalidationMessages();
841 AtCommit_Memory(void)
844 * Now that we're "out" of a transaction, have the system allocate
845 * things in the top memory context instead of per-transaction
848 MemoryContextSwitchTo(TopMemoryContext);
851 * Release all transaction-local memory.
853 Assert(TopTransactionContext != NULL);
854 MemoryContextDelete(TopTransactionContext);
855 TopTransactionContext = NULL;
856 CurTransactionContext = NULL;
857 CurrentTransactionState->curTransactionContext = NULL;
860 /* ----------------------------------------------------------------
861 * CommitSubTransaction stuff
862 * ----------------------------------------------------------------
869 AtSubCommit_Memory(void)
871 TransactionState s = CurrentTransactionState;
873 Assert(s->parent != NULL);
875 /* Return to parent transaction level's memory context. */
876 CurTransactionContext = s->parent->curTransactionContext;
877 MemoryContextSwitchTo(CurTransactionContext);
880 * Ordinarily we cannot throw away the child's CurTransactionContext,
881 * since the data it contains will be needed at upper commit. However,
882 * if there isn't actually anything in it, we can throw it away. This
883 * avoids a small memory leak in the common case of "trivial" subxacts.
885 if (MemoryContextIsEmpty(s->curTransactionContext))
887 MemoryContextDelete(s->curTransactionContext);
888 s->curTransactionContext = NULL;
893 * AtSubCommit_childXids
895 * Pass my own XID and my child XIDs up to my parent as committed children.
898 AtSubCommit_childXids(void)
900 TransactionState s = CurrentTransactionState;
901 MemoryContext old_cxt;
903 Assert(s->parent != NULL);
906 * We keep the child-XID lists in TopTransactionContext; this avoids
907 * setting up child-transaction contexts for what might be just a few
908 * bytes of grandchild XIDs.
910 old_cxt = MemoryContextSwitchTo(TopTransactionContext);
912 s->parent->childXids = lappend_xid(s->parent->childXids,
915 if (s->childXids != NIL)
917 s->parent->childXids = list_concat(s->parent->childXids,
920 * list_concat doesn't free the list header for the second list;
921 * do so here to avoid memory leakage (kluge)
927 MemoryContextSwitchTo(old_cxt);
931 * RecordSubTransactionCommit
934 RecordSubTransactionCommit(void)
937 * We do not log the subcommit in XLOG; it doesn't matter until the
938 * top-level transaction commits.
940 * We must mark the subtransaction subcommitted in clog if its XID
941 * appears either in permanent rels or in local temporary rels. We
942 * test this by seeing if we made transaction-controlled entries *OR*
943 * local-rel tuple updates. (The test here actually covers the entire
944 * transaction tree so far, so it may mark subtransactions that don't
945 * really need it, but it's probably not worth being tenser. Note that
946 * if a prior subtransaction dirtied these variables, then
947 * RecordTransactionCommit will have to do the full pushup anyway...)
949 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
951 TransactionId xid = GetCurrentTransactionId();
953 /* XXX does this really need to be a critical section? */
954 START_CRIT_SECTION();
956 /* Record subtransaction subcommit */
957 TransactionIdSubCommit(xid);
963 /* ----------------------------------------------------------------
964 * AbortTransaction stuff
965 * ----------------------------------------------------------------
969 * RecordTransactionAbort
972 RecordTransactionAbort(void)
977 TransactionId *children;
979 /* Get data needed for abort record */
980 nrels = smgrGetPendingDeletes(false, &rptr);
981 nchildren = xactGetCommittedChildren(&children);
984 * If we made neither any transaction-controlled XLOG entries nor any
985 * temp-rel updates, and are not going to delete any files, we can
986 * omit recording the transaction abort at all. No one will ever care
987 * that it aborted. (These tests cover our whole transaction tree.)
989 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
991 TransactionId xid = GetCurrentTransactionId();
994 * Catch the scenario where we aborted partway through
995 * RecordTransactionCommit ...
997 if (TransactionIdDidCommit(xid))
998 elog(PANIC, "cannot abort transaction %u, it was already committed", xid);
1000 START_CRIT_SECTION();
1003 * We only need to log the abort in XLOG if the transaction made
1004 * any transaction-controlled XLOG entries or will delete files.
1005 * (If it made no transaction-controlled XLOG entries, its XID
1006 * appears nowhere in permanent storage, so no one else will ever
1007 * care if it committed.)
1009 * We do not flush XLOG to disk unless deleting files, since the
1010 * default assumption after a crash would be that we aborted,
1011 * anyway. For the same reason, we don't need to worry about
1012 * interlocking against checkpoint start.
1014 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1016 XLogRecData rdata[3];
1018 xl_xact_abort xlrec;
1021 xlrec.xtime = time(NULL);
1022 xlrec.nrels = nrels;
1023 xlrec.nsubxacts = nchildren;
1024 rdata[0].buffer = InvalidBuffer;
1025 rdata[0].data = (char *) (&xlrec);
1026 rdata[0].len = MinSizeOfXactAbort;
1027 /* dump rels to delete */
1030 rdata[0].next = &(rdata[1]);
1031 rdata[1].buffer = InvalidBuffer;
1032 rdata[1].data = (char *) rptr;
1033 rdata[1].len = nrels * sizeof(RelFileNode);
1036 /* dump committed child Xids */
1039 rdata[lastrdata].next = &(rdata[2]);
1040 rdata[2].buffer = InvalidBuffer;
1041 rdata[2].data = (char *) children;
1042 rdata[2].len = nchildren * sizeof(TransactionId);
1045 rdata[lastrdata].next = NULL;
1047 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1049 /* Must flush if we are deleting files... */
1055 * Mark the transaction aborted in clog. This is not absolutely
1056 * necessary but we may as well do it while we are here.
1058 * The ordering here isn't critical but it seems best to mark the
1059 * parent first. This assures an atomic transition of all the
1060 * subtransactions to aborted state from the point of view of
1061 * concurrent TransactionIdDidAbort calls.
1063 TransactionIdAbort(xid);
1064 TransactionIdAbortTree(nchildren, children);
1069 /* Break the chain of back-links in the XLOG records I output */
1070 MyLastRecPtr.xrecoff = 0;
1071 MyXactMadeXLogEntry = false;
1072 MyXactMadeTempRelUpdate = false;
1074 /* Show myself as out of the transaction in PGPROC array */
1075 MyProc->logRec.xrecoff = 0;
1077 /* And clean up local data */
1088 AtAbort_Memory(void)
1091 * Make sure we are in a valid context (not a child of
1092 * TopTransactionContext...). Note that it is possible for this code
1093 * to be called when we aren't in a transaction at all; go directly to
1094 * TopMemoryContext in that case.
1096 if (TopTransactionContext != NULL)
1098 MemoryContextSwitchTo(TopTransactionContext);
1101 * We do not want to destroy the transaction's global state yet,
1102 * so we can't free any memory here.
1106 MemoryContextSwitchTo(TopMemoryContext);
1113 AtSubAbort_Memory(void)
1115 Assert(TopTransactionContext != NULL);
1117 MemoryContextSwitchTo(TopTransactionContext);
1122 * AtAbort_ResourceOwner
1125 AtAbort_ResourceOwner(void)
1128 * Make sure we have a valid ResourceOwner, if possible (else it
1129 * will be NULL, which is OK)
1131 CurrentResourceOwner = TopTransactionResourceOwner;
1135 * AtSubAbort_ResourceOwner
1138 AtSubAbort_ResourceOwner(void)
1140 TransactionState s = CurrentTransactionState;
1142 /* Make sure we have a valid ResourceOwner */
1143 CurrentResourceOwner = s->curTransactionOwner;
1148 * AtSubAbort_childXids
1151 AtSubAbort_childXids(void)
1153 TransactionState s = CurrentTransactionState;
1156 * We keep the child-XID lists in TopTransactionContext (see
1157 * AtSubCommit_childXids). This means we'd better free the list
1158 * explicitly at abort to avoid leakage.
1160 list_free(s->childXids);
1165 * RecordSubTransactionAbort
1168 RecordSubTransactionAbort(void)
1172 TransactionId xid = GetCurrentTransactionId();
1174 TransactionId *children;
1176 /* Get data needed for abort record */
1177 nrels = smgrGetPendingDeletes(false, &rptr);
1178 nchildren = xactGetCommittedChildren(&children);
1181 * If we made neither any transaction-controlled XLOG entries nor any
1182 * temp-rel updates, and are not going to delete any files, we can
1183 * omit recording the transaction abort at all. No one will ever care
1184 * that it aborted. (These tests cover our whole transaction tree,
1185 * and therefore may mark subxacts that don't really need it, but it's
1186 * probably not worth being tenser.)
1188 * In this case we needn't worry about marking subcommitted children as
1189 * aborted, because they didn't mark themselves as subcommitted in the
1190 * first place; see the optimization in RecordSubTransactionCommit.
1192 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
1194 START_CRIT_SECTION();
1197 * We only need to log the abort in XLOG if the transaction made
1198 * any transaction-controlled XLOG entries or will delete files.
1200 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1202 XLogRecData rdata[3];
1204 xl_xact_abort xlrec;
1207 xlrec.xtime = time(NULL);
1208 xlrec.nrels = nrels;
1209 xlrec.nsubxacts = nchildren;
1210 rdata[0].buffer = InvalidBuffer;
1211 rdata[0].data = (char *) (&xlrec);
1212 rdata[0].len = MinSizeOfXactAbort;
1213 /* dump rels to delete */
1216 rdata[0].next = &(rdata[1]);
1217 rdata[1].buffer = InvalidBuffer;
1218 rdata[1].data = (char *) rptr;
1219 rdata[1].len = nrels * sizeof(RelFileNode);
1222 /* dump committed child Xids */
1225 rdata[lastrdata].next = &(rdata[2]);
1226 rdata[2].buffer = InvalidBuffer;
1227 rdata[2].data = (char *) children;
1228 rdata[2].len = nchildren * sizeof(TransactionId);
1231 rdata[lastrdata].next = NULL;
1233 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1235 /* Must flush if we are deleting files... */
1241 * Mark the transaction aborted in clog. This is not absolutely
1242 * necessary but XactLockTableWait makes use of it to avoid waiting
1243 * for already-aborted subtransactions.
1245 TransactionIdAbort(xid);
1246 TransactionIdAbortTree(nchildren, children);
1252 * We can immediately remove failed XIDs from PGPROC's cache of
1253 * running child XIDs. It's easiest to do it here while we have the
1254 * child XID array at hand, even though in the main-transaction case
1255 * the equivalent work happens just after return from
1256 * RecordTransactionAbort.
1258 XidCacheRemoveRunningXids(xid, nchildren, children);
1260 /* And clean up local data */
1267 /* ----------------------------------------------------------------
1268 * CleanupTransaction stuff
1269 * ----------------------------------------------------------------
1276 AtCleanup_Memory(void)
1279 * Now that we're "out" of a transaction, have the system allocate
1280 * things in the top memory context instead of per-transaction
1283 MemoryContextSwitchTo(TopMemoryContext);
1285 Assert(CurrentTransactionState->parent == NULL);
1288 * Release all transaction-local memory.
1290 if (TopTransactionContext != NULL)
1291 MemoryContextDelete(TopTransactionContext);
1292 TopTransactionContext = NULL;
1293 CurTransactionContext = NULL;
1294 CurrentTransactionState->curTransactionContext = NULL;
1298 /* ----------------------------------------------------------------
1299 * CleanupSubTransaction stuff
1300 * ----------------------------------------------------------------
1304 * AtSubCleanup_Memory
1307 AtSubCleanup_Memory(void)
1309 TransactionState s = CurrentTransactionState;
1311 Assert(s->parent != NULL);
1313 /* Make sure we're not in an about-to-be-deleted context */
1314 MemoryContextSwitchTo(s->parent->curTransactionContext);
1315 CurTransactionContext = s->parent->curTransactionContext;
1318 * Delete the subxact local memory contexts. Its CurTransactionContext
1319 * can go too (note this also kills CurTransactionContexts from any
1320 * children of the subxact).
1322 if (s->curTransactionContext)
1323 MemoryContextDelete(s->curTransactionContext);
1324 s->curTransactionContext = NULL;
1327 /* ----------------------------------------------------------------
1328 * interface routines
1329 * ----------------------------------------------------------------
1336 StartTransaction(void)
1341 * Let's just make sure the state stack is empty
1343 s = &TopTransactionStateData;
1344 CurrentTransactionState = s;
1347 * check the current transaction state
1349 if (s->state != TRANS_DEFAULT)
1350 elog(WARNING, "StartTransaction while in %s state",
1351 TransStateAsString(s->state));
1354 * set the current transaction state information appropriately during
1357 s->state = TRANS_START;
1358 s->transactionId = InvalidTransactionId; /* until assigned */
1361 * Make sure we've freed any old snapshot, and reset xact state
1365 XactIsoLevel = DefaultXactIsoLevel;
1366 XactReadOnly = DefaultXactReadOnly;
1369 * reinitialize within-transaction counters
1371 s->subTransactionId = TopSubTransactionId;
1372 currentSubTransactionId = TopSubTransactionId;
1373 currentCommandId = FirstCommandId;
1376 * must initialize resource-management stuff first
1379 AtStart_ResourceOwner();
1382 * generate a new transaction id
1384 s->transactionId = GetNewTransactionId(false);
1386 XactLockTableInsert(s->transactionId);
1391 xactStartTime = GetCurrentAbsoluteTimeUsec(&(xactStartTimeUsec));
1394 * initialize current transaction state fields
1396 s->nestingLevel = 1;
1400 * You might expect to see "s->currentUser = GetUserId();" here, but
1401 * you won't because it doesn't work during startup; the userid isn't
1402 * set yet during a backend's first transaction start. We only use
1403 * the currentUser field in sub-transaction state structs.
1405 * prevXactReadOnly is also valid only in sub-transactions.
1409 * initialize other subsystems for new transaction
1413 AfterTriggerBeginXact();
1416 * done with start processing, set current transaction state to "in
1419 s->state = TRANS_INPROGRESS;
1421 ShowTransactionState("StartTransaction");
1428 CommitTransaction(void)
1430 TransactionState s = CurrentTransactionState;
1432 ShowTransactionState("CommitTransaction");
1435 * check the current transaction state
1437 if (s->state != TRANS_INPROGRESS)
1438 elog(WARNING, "CommitTransaction while in %s state",
1439 TransStateAsString(s->state));
1440 Assert(s->parent == NULL);
1443 * Do pre-commit processing (most of this stuff requires database
1444 * access, and in fact could still cause an error...)
1448 * Tell the trigger manager that this transaction is about to be
1449 * committed. He'll invoke all trigger deferred until XACT before we
1450 * really start on committing the transaction.
1452 AfterTriggerEndXact();
1454 /* Close open cursors */
1458 * Let ON COMMIT management do its thing (must happen after closing
1459 * cursors, to avoid dangling-reference problems)
1461 PreCommit_on_commit_actions();
1463 /* close large objects before lower-level cleanup */
1464 AtEOXact_LargeObject(true);
1466 /* NOTIFY commit must come before lower-level cleanup */
1469 /* Update flat files if we changed pg_database, pg_shadow or pg_group */
1470 /* This should be the last step before commit */
1471 AtEOXact_UpdateFlatFiles(true);
1473 /* Prevent cancel/die interrupt while cleaning up */
1477 * set the current transaction state information appropriately during
1478 * the abort processing
1480 s->state = TRANS_COMMIT;
1483 * Here is where we really truly commit.
1485 RecordTransactionCommit();
1488 * Let others know about no transaction in progress by me. Note that
1489 * this must be done _before_ releasing locks we hold and _after_
1490 * RecordTransactionCommit.
1492 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
1493 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
1494 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
1495 * as running as well or it will see two tuple versions - one deleted
1496 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
1500 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1501 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1502 MyProc->xid = InvalidTransactionId;
1503 MyProc->xmin = InvalidTransactionId;
1505 /* Clear the subtransaction-XID cache too while holding the lock */
1506 MyProc->subxids.nxids = 0;
1507 MyProc->subxids.overflowed = false;
1509 LWLockRelease(SInvalLock);
1513 * This is all post-commit cleanup. Note that if an error is raised
1514 * here, it's too late to abort the transaction. This should be just
1515 * noncritical resource releasing.
1517 * The ordering of operations is not entirely random. The idea is:
1518 * release resources visible to other backends (eg, files, buffer
1519 * pins); then release locks; then release backend-local resources. We
1520 * want to release locks at the point where any backend waiting for us
1521 * will see our transaction as being fully cleaned up.
1523 * Resources that can be associated with individual queries are handled
1524 * by the ResourceOwner mechanism. The other calls here are for
1525 * backend-wide state.
1528 CallXactCallbacks(XACT_EVENT_COMMIT);
1530 ResourceOwnerRelease(TopTransactionResourceOwner,
1531 RESOURCE_RELEASE_BEFORE_LOCKS,
1534 /* Check we've released all buffer pins */
1535 AtEOXact_Buffers(true);
1538 * Make catalog changes visible to all backends. This has to happen
1539 * after relcache references are dropped (see comments for
1540 * AtEOXact_RelationCache), but before locks are released (if anyone
1541 * is waiting for lock on a relation we've modified, we want them to
1542 * know about the catalog change before they start using the
1545 AtEOXact_Inval(true);
1548 * Likewise, dropping of files deleted during the transaction is best done
1549 * after releasing relcache and buffer pins. (This is not strictly
1550 * necessary during commit, since such pins should have been released
1551 * already, but this ordering is definitely critical during abort.)
1553 smgrDoPendingDeletes(true);
1555 ResourceOwnerRelease(TopTransactionResourceOwner,
1556 RESOURCE_RELEASE_LOCKS,
1558 ResourceOwnerRelease(TopTransactionResourceOwner,
1559 RESOURCE_RELEASE_AFTER_LOCKS,
1562 AtEOXact_GUC(true, false);
1564 AtEOXact_on_commit_actions(true);
1565 AtEOXact_Namespace(true);
1566 /* smgrcommit already done */
1568 pgstat_count_xact_commit();
1570 CurrentResourceOwner = NULL;
1571 ResourceOwnerDelete(TopTransactionResourceOwner);
1572 s->curTransactionOwner = NULL;
1573 CurTransactionResourceOwner = NULL;
1574 TopTransactionResourceOwner = NULL;
1578 s->transactionId = InvalidTransactionId;
1579 s->subTransactionId = InvalidSubTransactionId;
1580 s->nestingLevel = 0;
1584 * done with commit processing, set current transaction state back to
1587 s->state = TRANS_DEFAULT;
1589 RESUME_INTERRUPTS();
1596 AbortTransaction(void)
1598 TransactionState s = CurrentTransactionState;
1600 /* Prevent cancel/die interrupt while cleaning up */
1604 * Release any LW locks we might be holding as quickly as possible.
1605 * (Regular locks, however, must be held till we finish aborting.)
1606 * Releasing LW locks is critical since we might try to grab them
1607 * again while cleaning up!
1611 /* Clean up buffer I/O and buffer context locks, too */
1616 * Also clean up any open wait for lock, since the lock manager will
1617 * choke if we try to wait for another lock before doing this.
1622 * check the current transaction state
1624 if (s->state != TRANS_INPROGRESS)
1625 elog(WARNING, "AbortTransaction while in %s state",
1626 TransStateAsString(s->state));
1627 Assert(s->parent == NULL);
1630 * set the current transaction state information appropriately during
1631 * the abort processing
1633 s->state = TRANS_ABORT;
1635 /* Make sure we have a valid memory context and resource owner */
1637 AtAbort_ResourceOwner();
1640 * Reset user id which might have been changed transiently. We cannot
1641 * use s->currentUser, but must get the session userid from
1644 * (Note: it is not necessary to restore session authorization here
1645 * because that can only be changed via GUC, and GUC will take care of
1646 * rolling it back if need be. However, an error within a SECURITY
1647 * DEFINER function could send control here with the wrong current
1650 SetUserId(GetSessionUserId());
1653 * do abort processing
1655 AfterTriggerAbortXact();
1657 AtEOXact_LargeObject(false); /* 'false' means it's abort */
1659 AtEOXact_UpdateFlatFiles(false);
1662 * Advertise the fact that we aborted in pg_clog (assuming that we
1663 * got as far as assigning an XID to advertise).
1665 if (TransactionIdIsValid(s->transactionId))
1666 RecordTransactionAbort();
1669 * Let others know about no transaction in progress by me. Note that
1670 * this must be done _before_ releasing locks we hold and _after_
1671 * RecordTransactionAbort.
1675 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1676 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1677 MyProc->xid = InvalidTransactionId;
1678 MyProc->xmin = InvalidTransactionId;
1680 /* Clear the subtransaction-XID cache too while holding the lock */
1681 MyProc->subxids.nxids = 0;
1682 MyProc->subxids.overflowed = false;
1684 LWLockRelease(SInvalLock);
1688 * Post-abort cleanup. See notes in CommitTransaction() concerning
1692 CallXactCallbacks(XACT_EVENT_ABORT);
1694 ResourceOwnerRelease(TopTransactionResourceOwner,
1695 RESOURCE_RELEASE_BEFORE_LOCKS,
1697 AtEOXact_Buffers(false);
1698 AtEOXact_Inval(false);
1699 smgrDoPendingDeletes(false);
1700 ResourceOwnerRelease(TopTransactionResourceOwner,
1701 RESOURCE_RELEASE_LOCKS,
1703 ResourceOwnerRelease(TopTransactionResourceOwner,
1704 RESOURCE_RELEASE_AFTER_LOCKS,
1707 AtEOXact_GUC(false, false);
1708 AtEOXact_SPI(false);
1709 AtEOXact_on_commit_actions(false);
1710 AtEOXact_Namespace(false);
1713 pgstat_count_xact_rollback();
1716 * State remains TRANS_ABORT until CleanupTransaction().
1718 RESUME_INTERRUPTS();
1722 * CleanupTransaction
1725 CleanupTransaction(void)
1727 TransactionState s = CurrentTransactionState;
1730 * State should still be TRANS_ABORT from AbortTransaction().
1732 if (s->state != TRANS_ABORT)
1733 elog(FATAL, "CleanupTransaction: unexpected state %s",
1734 TransStateAsString(s->state));
1737 * do abort cleanup processing
1739 AtCleanup_Portals(); /* now safe to release portal memory */
1741 CurrentResourceOwner = NULL; /* and resource owner */
1742 if (TopTransactionResourceOwner)
1743 ResourceOwnerDelete(TopTransactionResourceOwner);
1744 s->curTransactionOwner = NULL;
1745 CurTransactionResourceOwner = NULL;
1746 TopTransactionResourceOwner = NULL;
1748 AtCleanup_Memory(); /* and transaction memory */
1750 s->transactionId = InvalidTransactionId;
1751 s->subTransactionId = InvalidSubTransactionId;
1752 s->nestingLevel = 0;
1756 * done with abort processing, set current transaction state back to
1759 s->state = TRANS_DEFAULT;
1763 * StartTransactionCommand
1766 StartTransactionCommand(void)
1768 TransactionState s = CurrentTransactionState;
1770 switch (s->blockState)
1773 * if we aren't in a transaction block, we just do our usual
1774 * start transaction.
1776 case TBLOCK_DEFAULT:
1778 s->blockState = TBLOCK_STARTED;
1782 * We are somewhere in a transaction block or subtransaction
1783 * and about to start a new command. For now we do nothing,
1784 * but someday we may do command-local resource initialization.
1785 * (Note that any needed CommandCounterIncrement was done by
1786 * the previous CommitTransactionCommand.)
1788 case TBLOCK_INPROGRESS:
1789 case TBLOCK_SUBINPROGRESS:
1793 * Here we are in a failed transaction block (one of
1794 * the commands caused an abort) so we do nothing but remain in
1795 * the abort state. Eventually we will get a ROLLBACK command
1796 * which will get us out of this state. (It is up to other
1797 * code to ensure that no commands other than ROLLBACK will be
1798 * processed in these states.)
1801 case TBLOCK_SUBABORT:
1804 /* These cases are invalid. */
1805 case TBLOCK_STARTED:
1807 case TBLOCK_SUBBEGIN:
1810 case TBLOCK_ABORT_END:
1811 case TBLOCK_SUBABORT_END:
1812 case TBLOCK_ABORT_PENDING:
1813 case TBLOCK_SUBABORT_PENDING:
1814 case TBLOCK_SUBRESTART:
1815 case TBLOCK_SUBABORT_RESTART:
1816 elog(ERROR, "StartTransactionCommand: unexpected state %s",
1817 BlockStateAsString(s->blockState));
1822 * We must switch to CurTransactionContext before returning. This is
1823 * already done if we called StartTransaction, otherwise not.
1825 Assert(CurTransactionContext != NULL);
1826 MemoryContextSwitchTo(CurTransactionContext);
1830 * CommitTransactionCommand
1833 CommitTransactionCommand(void)
1835 TransactionState s = CurrentTransactionState;
1837 switch (s->blockState)
1840 * This shouldn't happen, because it means the previous
1841 * StartTransactionCommand didn't set the STARTED state
1844 case TBLOCK_DEFAULT:
1845 elog(FATAL, "CommitTransactionCommand: unexpected state %s",
1846 BlockStateAsString(s->blockState));
1850 * If we aren't in a transaction block, just do our usual
1851 * transaction commit, and return to the idle state.
1853 case TBLOCK_STARTED:
1854 CommitTransaction();
1855 s->blockState = TBLOCK_DEFAULT;
1859 * We are completing a "BEGIN TRANSACTION" command, so we
1860 * change to the "transaction block in progress" state and
1861 * return. (We assume the BEGIN did nothing to the database,
1862 * so we need no CommandCounterIncrement.)
1865 s->blockState = TBLOCK_INPROGRESS;
1869 * This is the case when we have finished executing a command
1870 * someplace within a transaction block. We increment the
1871 * command counter and return.
1873 case TBLOCK_INPROGRESS:
1874 case TBLOCK_SUBINPROGRESS:
1875 CommandCounterIncrement();
1879 * We are completing a "COMMIT" command. Do it and return to
1883 CommitTransaction();
1884 s->blockState = TBLOCK_DEFAULT;
1888 * Here we are in the middle of a transaction block but one of
1889 * the commands caused an abort so we do nothing but remain in
1890 * the abort state. Eventually we will get a ROLLBACK comand.
1893 case TBLOCK_SUBABORT:
1897 * Here we were in an aborted transaction block and we just
1898 * got the ROLLBACK command from the user, so clean up the
1899 * already-aborted transaction and return to the idle state.
1901 case TBLOCK_ABORT_END:
1902 CleanupTransaction();
1903 s->blockState = TBLOCK_DEFAULT;
1907 * Here we were in a perfectly good transaction block but the
1908 * user told us to ROLLBACK anyway. We have to abort the
1909 * transaction and then clean up.
1911 case TBLOCK_ABORT_PENDING:
1913 CleanupTransaction();
1914 s->blockState = TBLOCK_DEFAULT;
1918 * We were just issued a SAVEPOINT inside a transaction block.
1919 * Start a subtransaction. (DefineSavepoint already did
1920 * PushTransaction, so as to have someplace to put the
1923 case TBLOCK_SUBBEGIN:
1924 StartSubTransaction();
1925 s->blockState = TBLOCK_SUBINPROGRESS;
1929 * We were issued a COMMIT or RELEASE command, so we end the
1930 * current subtransaction and return to the parent transaction.
1931 * The parent might be ended too, so repeat till we are all the
1932 * way out or find an INPROGRESS transaction.
1937 CommitSubTransaction();
1938 s = CurrentTransactionState; /* changed by pop */
1939 } while (s->blockState == TBLOCK_SUBEND);
1940 /* If we had a COMMIT command, finish off the main xact too */
1941 if (s->blockState == TBLOCK_END)
1943 Assert(s->parent == NULL);
1944 CommitTransaction();
1945 s->blockState = TBLOCK_DEFAULT;
1949 Assert(s->blockState == TBLOCK_INPROGRESS ||
1950 s->blockState == TBLOCK_SUBINPROGRESS);
1955 * The current already-failed subtransaction is ending due to a
1956 * ROLLBACK or ROLLBACK TO command, so pop it and recursively
1957 * examine the parent (which could be in any of several states).
1959 case TBLOCK_SUBABORT_END:
1960 CleanupSubTransaction();
1961 CommitTransactionCommand();
1965 * As above, but it's not dead yet, so abort first.
1967 case TBLOCK_SUBABORT_PENDING:
1968 AbortSubTransaction();
1969 CleanupSubTransaction();
1970 CommitTransactionCommand();
1974 * The current subtransaction is the target of a ROLLBACK TO
1975 * command. Abort and pop it, then start a new subtransaction
1976 * with the same name.
1978 case TBLOCK_SUBRESTART:
1983 /* save name and keep Cleanup from freeing it */
1986 savepointLevel = s->savepointLevel;
1988 AbortSubTransaction();
1989 CleanupSubTransaction();
1991 DefineSavepoint(NULL);
1992 s = CurrentTransactionState; /* changed by push */
1994 s->savepointLevel = savepointLevel;
1996 /* This is the same as TBLOCK_SUBBEGIN case */
1997 AssertState(s->blockState == TBLOCK_SUBBEGIN);
1998 StartSubTransaction();
1999 s->blockState = TBLOCK_SUBINPROGRESS;
2004 * Same as above, but the subtransaction had already failed,
2005 * so we don't need AbortSubTransaction.
2007 case TBLOCK_SUBABORT_RESTART:
2012 /* save name and keep Cleanup from freeing it */
2015 savepointLevel = s->savepointLevel;
2017 CleanupSubTransaction();
2019 DefineSavepoint(NULL);
2020 s = CurrentTransactionState; /* changed by push */
2022 s->savepointLevel = savepointLevel;
2024 /* This is the same as TBLOCK_SUBBEGIN case */
2025 AssertState(s->blockState == TBLOCK_SUBBEGIN);
2026 StartSubTransaction();
2027 s->blockState = TBLOCK_SUBINPROGRESS;
2034 * AbortCurrentTransaction
2037 AbortCurrentTransaction(void)
2039 TransactionState s = CurrentTransactionState;
2041 switch (s->blockState)
2043 case TBLOCK_DEFAULT:
2044 if (s->state == TRANS_DEFAULT)
2046 /* we are idle, so nothing to do */
2051 * We can get here after an error during transaction start
2052 * (state will be TRANS_START). Need to clean up the
2053 * incompletely started transaction. First, adjust the
2054 * low-level state to suppress warning message from
2057 if (s->state == TRANS_START)
2058 s->state = TRANS_INPROGRESS;
2060 CleanupTransaction();
2065 * if we aren't in a transaction block, we just do the basic
2066 * abort & cleanup transaction.
2068 case TBLOCK_STARTED:
2070 CleanupTransaction();
2071 s->blockState = TBLOCK_DEFAULT;
2075 * If we are in TBLOCK_BEGIN it means something screwed up
2076 * right after reading "BEGIN TRANSACTION". We assume that
2077 * the user will interpret the error as meaning the BEGIN
2078 * failed to get him into a transaction block, so we should
2079 * abort and return to idle state.
2083 CleanupTransaction();
2084 s->blockState = TBLOCK_DEFAULT;
2088 * We are somewhere in a transaction block and we've gotten a
2089 * failure, so we abort the transaction and set up the persistent
2090 * ABORT state. We will stay in ABORT until we get a ROLLBACK.
2092 case TBLOCK_INPROGRESS:
2094 s->blockState = TBLOCK_ABORT;
2095 /* CleanupTransaction happens when we exit TBLOCK_ABORT_END */
2099 * Here, we failed while trying to COMMIT. Clean up the
2100 * transaction and return to idle state (we do not want to
2101 * stay in the transaction).
2105 CleanupTransaction();
2106 s->blockState = TBLOCK_DEFAULT;
2110 * Here, we are already in an aborted transaction state and
2111 * are waiting for a ROLLBACK, but for some reason we failed
2112 * again! So we just remain in the abort state.
2115 case TBLOCK_SUBABORT:
2119 * We are in a failed transaction and we got the ROLLBACK command.
2120 * We have already aborted, we just need to cleanup and go to
2123 case TBLOCK_ABORT_END:
2124 CleanupTransaction();
2125 s->blockState = TBLOCK_DEFAULT;
2129 * We are in a live transaction and we got a ROLLBACK command.
2130 * Abort, cleanup, go to idle state.
2132 case TBLOCK_ABORT_PENDING:
2134 CleanupTransaction();
2135 s->blockState = TBLOCK_DEFAULT;
2139 * We got an error inside a subtransaction. Abort just the
2140 * subtransaction, and go to the persistent SUBABORT state
2141 * until we get ROLLBACK.
2143 case TBLOCK_SUBINPROGRESS:
2144 AbortSubTransaction();
2145 s->blockState = TBLOCK_SUBABORT;
2149 * If we failed while trying to create a subtransaction, clean up
2150 * the broken subtransaction and abort the parent. The same
2151 * applies if we get a failure while ending a subtransaction.
2153 case TBLOCK_SUBBEGIN:
2155 case TBLOCK_SUBABORT_PENDING:
2156 case TBLOCK_SUBRESTART:
2157 AbortSubTransaction();
2158 CleanupSubTransaction();
2159 AbortCurrentTransaction();
2163 * Same as above, except the Abort() was already done.
2165 case TBLOCK_SUBABORT_END:
2166 case TBLOCK_SUBABORT_RESTART:
2167 CleanupSubTransaction();
2168 AbortCurrentTransaction();
2174 * PreventTransactionChain
2176 * This routine is to be called by statements that must not run inside
2177 * a transaction block, typically because they have non-rollback-able
2178 * side effects or do internal commits.
2180 * If we have already started a transaction block, issue an error; also issue
2181 * an error if we appear to be running inside a user-defined function (which
2182 * could issue more commands and possibly cause a failure after the statement
2183 * completes). Subtransactions are verboten too.
2185 * stmtNode: pointer to parameter block for statement; this is used in
2186 * a very klugy way to determine whether we are inside a function.
2187 * stmtType: statement type name for error messages.
2190 PreventTransactionChain(void *stmtNode, const char *stmtType)
2193 * xact block already started?
2195 if (IsTransactionBlock())
2197 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2198 /* translator: %s represents an SQL statement name */
2199 errmsg("%s cannot run inside a transaction block",
2205 if (IsSubTransaction())
2207 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2208 /* translator: %s represents an SQL statement name */
2209 errmsg("%s cannot run inside a subtransaction",
2213 * Are we inside a function call? If the statement's parameter block
2214 * was allocated in QueryContext, assume it is an interactive command.
2215 * Otherwise assume it is coming from a function.
2217 if (!MemoryContextContains(QueryContext, stmtNode))
2219 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2220 /* translator: %s represents an SQL statement name */
2221 errmsg("%s cannot be executed from a function", stmtType)));
2223 /* If we got past IsTransactionBlock test, should be in default state */
2224 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2225 CurrentTransactionState->blockState != TBLOCK_STARTED)
2226 elog(FATAL, "cannot prevent transaction chain");
2231 * RequireTransactionChain
2233 * This routine is to be called by statements that must run inside
2234 * a transaction block, because they have no effects that persist past
2235 * transaction end (and so calling them outside a transaction block
2236 * is presumably an error). DECLARE CURSOR is an example.
2238 * If we appear to be running inside a user-defined function, we do not
2239 * issue an error, since the function could issue more commands that make
2240 * use of the current statement's results. Likewise subtransactions.
2241 * Thus this is an inverse for PreventTransactionChain.
2243 * stmtNode: pointer to parameter block for statement; this is used in
2244 * a very klugy way to determine whether we are inside a function.
2245 * stmtType: statement type name for error messages.
2248 RequireTransactionChain(void *stmtNode, const char *stmtType)
2251 * xact block already started?
2253 if (IsTransactionBlock())
2259 if (IsSubTransaction())
2263 * Are we inside a function call? If the statement's parameter block
2264 * was allocated in QueryContext, assume it is an interactive command.
2265 * Otherwise assume it is coming from a function.
2267 if (!MemoryContextContains(QueryContext, stmtNode))
2270 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2271 /* translator: %s represents an SQL statement name */
2272 errmsg("%s may only be used in transaction blocks",
2277 * IsInTransactionChain
2279 * This routine is for statements that need to behave differently inside
2280 * a transaction block than when running as single commands. ANALYZE is
2281 * currently the only example.
2283 * stmtNode: pointer to parameter block for statement; this is used in
2284 * a very klugy way to determine whether we are inside a function.
2287 IsInTransactionChain(void *stmtNode)
2290 * Return true on same conditions that would make
2291 * PreventTransactionChain error out
2293 if (IsTransactionBlock())
2296 if (IsSubTransaction())
2299 if (!MemoryContextContains(QueryContext, stmtNode))
2302 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2303 CurrentTransactionState->blockState != TBLOCK_STARTED)
2311 * Register or deregister callback functions for start- and end-of-xact
2314 * These functions are intended for use by dynamically loaded modules.
2315 * For built-in modules we generally just hardwire the appropriate calls
2316 * (mainly because it's easier to control the order that way, where needed).
2318 * At transaction end, the callback occurs post-commit or post-abort, so the
2319 * callback functions can only do noncritical cleanup.
2322 RegisterXactCallback(XactCallback callback, void *arg)
2324 XactCallbackItem *item;
2326 item = (XactCallbackItem *)
2327 MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
2328 item->callback = callback;
2330 item->next = Xact_callbacks;
2331 Xact_callbacks = item;
2335 UnregisterXactCallback(XactCallback callback, void *arg)
2337 XactCallbackItem *item;
2338 XactCallbackItem *prev;
2341 for (item = Xact_callbacks; item; prev = item, item = item->next)
2343 if (item->callback == callback && item->arg == arg)
2346 prev->next = item->next;
2348 Xact_callbacks = item->next;
2356 CallXactCallbacks(XactEvent event)
2358 XactCallbackItem *item;
2360 for (item = Xact_callbacks; item; item = item->next)
2361 (*item->callback) (event, item->arg);
2366 * Register or deregister callback functions for start- and end-of-subxact
2369 * Pretty much same as above, but for subtransaction events.
2371 * At subtransaction end, the callback occurs post-subcommit or post-subabort,
2372 * so the callback functions can only do noncritical cleanup. At
2373 * subtransaction start, the callback is called when the subtransaction has
2374 * finished initializing.
2377 RegisterSubXactCallback(SubXactCallback callback, void *arg)
2379 SubXactCallbackItem *item;
2381 item = (SubXactCallbackItem *)
2382 MemoryContextAlloc(TopMemoryContext, sizeof(SubXactCallbackItem));
2383 item->callback = callback;
2385 item->next = SubXact_callbacks;
2386 SubXact_callbacks = item;
2390 UnregisterSubXactCallback(SubXactCallback callback, void *arg)
2392 SubXactCallbackItem *item;
2393 SubXactCallbackItem *prev;
2396 for (item = SubXact_callbacks; item; prev = item, item = item->next)
2398 if (item->callback == callback && item->arg == arg)
2401 prev->next = item->next;
2403 SubXact_callbacks = item->next;
2411 CallSubXactCallbacks(SubXactEvent event,
2412 SubTransactionId mySubid,
2413 SubTransactionId parentSubid)
2415 SubXactCallbackItem *item;
2417 for (item = SubXact_callbacks; item; item = item->next)
2418 (*item->callback) (event, mySubid, parentSubid, item->arg);
2422 /* ----------------------------------------------------------------
2423 * transaction block support
2424 * ----------------------------------------------------------------
2428 * BeginTransactionBlock
2429 * This executes a BEGIN command.
2432 BeginTransactionBlock(void)
2434 TransactionState s = CurrentTransactionState;
2436 switch (s->blockState)
2439 * We are not inside a transaction block, so allow one to
2442 case TBLOCK_STARTED:
2443 s->blockState = TBLOCK_BEGIN;
2447 * Already a transaction block in progress.
2449 case TBLOCK_INPROGRESS:
2450 case TBLOCK_SUBINPROGRESS:
2452 case TBLOCK_SUBABORT:
2454 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2455 errmsg("there is already a transaction in progress")));
2458 /* These cases are invalid. */
2459 case TBLOCK_DEFAULT:
2461 case TBLOCK_SUBBEGIN:
2464 case TBLOCK_ABORT_END:
2465 case TBLOCK_SUBABORT_END:
2466 case TBLOCK_ABORT_PENDING:
2467 case TBLOCK_SUBABORT_PENDING:
2468 case TBLOCK_SUBRESTART:
2469 case TBLOCK_SUBABORT_RESTART:
2470 elog(FATAL, "BeginTransactionBlock: unexpected state %s",
2471 BlockStateAsString(s->blockState));
2477 * EndTransactionBlock
2478 * This executes a COMMIT command.
2480 * Since COMMIT may actually do a ROLLBACK, the result indicates what
2481 * happened: TRUE for COMMIT, FALSE for ROLLBACK.
2483 * Note that we don't actually do anything here except change blockState.
2484 * The real work will be done in the upcoming CommitTransactionCommand().
2485 * We do it this way because it's not convenient to change memory context,
2486 * resource owner, etc while executing inside a Portal.
2489 EndTransactionBlock(void)
2491 TransactionState s = CurrentTransactionState;
2492 bool result = false;
2494 switch (s->blockState)
2497 * We are in a transaction block, so tell CommitTransactionCommand
2500 case TBLOCK_INPROGRESS:
2501 s->blockState = TBLOCK_END;
2506 * We are in a failed transaction block. Tell
2507 * CommitTransactionCommand it's time to exit the block.
2510 s->blockState = TBLOCK_ABORT_END;
2514 * We are in a live subtransaction block. Set up to subcommit
2515 * all open subtransactions and then commit the main transaction.
2517 case TBLOCK_SUBINPROGRESS:
2518 while (s->parent != NULL)
2520 if (s->blockState == TBLOCK_SUBINPROGRESS)
2521 s->blockState = TBLOCK_SUBEND;
2523 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2524 BlockStateAsString(s->blockState));
2527 if (s->blockState == TBLOCK_INPROGRESS)
2528 s->blockState = TBLOCK_END;
2530 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2531 BlockStateAsString(s->blockState));
2536 * Here we are inside an aborted subtransaction. Treat the
2537 * COMMIT as ROLLBACK: set up to abort everything and exit
2538 * the main transaction.
2540 case TBLOCK_SUBABORT:
2541 while (s->parent != NULL)
2543 if (s->blockState == TBLOCK_SUBINPROGRESS)
2544 s->blockState = TBLOCK_SUBABORT_PENDING;
2545 else if (s->blockState == TBLOCK_SUBABORT)
2546 s->blockState = TBLOCK_SUBABORT_END;
2548 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2549 BlockStateAsString(s->blockState));
2552 if (s->blockState == TBLOCK_INPROGRESS)
2553 s->blockState = TBLOCK_ABORT_PENDING;
2554 else if (s->blockState == TBLOCK_ABORT)
2555 s->blockState = TBLOCK_ABORT_END;
2557 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2558 BlockStateAsString(s->blockState));
2562 * The user issued COMMIT when not inside a transaction. Issue a
2563 * WARNING, staying in TBLOCK_STARTED state. The upcoming call to
2564 * CommitTransactionCommand() will then close the transaction and
2565 * put us back into the default state.
2567 case TBLOCK_STARTED:
2569 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2570 errmsg("there is no transaction in progress")));
2574 /* These cases are invalid. */
2575 case TBLOCK_DEFAULT:
2577 case TBLOCK_SUBBEGIN:
2580 case TBLOCK_ABORT_END:
2581 case TBLOCK_SUBABORT_END:
2582 case TBLOCK_ABORT_PENDING:
2583 case TBLOCK_SUBABORT_PENDING:
2584 case TBLOCK_SUBRESTART:
2585 case TBLOCK_SUBABORT_RESTART:
2586 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2587 BlockStateAsString(s->blockState));
2595 * UserAbortTransactionBlock
2596 * This executes a ROLLBACK command.
2598 * As above, we don't actually do anything here except change blockState.
2601 UserAbortTransactionBlock(void)
2603 TransactionState s = CurrentTransactionState;
2605 switch (s->blockState)
2608 * We are inside a transaction block and we got a ROLLBACK
2609 * command from the user, so tell CommitTransactionCommand
2610 * to abort and exit the transaction block.
2612 case TBLOCK_INPROGRESS:
2613 s->blockState = TBLOCK_ABORT_PENDING;
2617 * We are inside a failed transaction block and we got a ROLLBACK
2618 * command from the user. Abort processing is already done,
2619 * so CommitTransactionCommand just has to cleanup and go back
2623 s->blockState = TBLOCK_ABORT_END;
2627 * We are inside a subtransaction. Mark everything
2628 * up to top level as exitable.
2630 case TBLOCK_SUBINPROGRESS:
2631 case TBLOCK_SUBABORT:
2632 while (s->parent != NULL)
2634 if (s->blockState == TBLOCK_SUBINPROGRESS)
2635 s->blockState = TBLOCK_SUBABORT_PENDING;
2636 else if (s->blockState == TBLOCK_SUBABORT)
2637 s->blockState = TBLOCK_SUBABORT_END;
2639 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2640 BlockStateAsString(s->blockState));
2643 if (s->blockState == TBLOCK_INPROGRESS)
2644 s->blockState = TBLOCK_ABORT_PENDING;
2645 else if (s->blockState == TBLOCK_ABORT)
2646 s->blockState = TBLOCK_ABORT_END;
2648 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2649 BlockStateAsString(s->blockState));
2653 * The user issued ABORT when not inside a transaction. Issue
2654 * a WARNING and go to abort state. The upcoming call to
2655 * CommitTransactionCommand() will then put us back into the
2658 case TBLOCK_STARTED:
2660 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2661 errmsg("there is no transaction in progress")));
2662 s->blockState = TBLOCK_ABORT_PENDING;
2665 /* These cases are invalid. */
2666 case TBLOCK_DEFAULT:
2668 case TBLOCK_SUBBEGIN:
2671 case TBLOCK_ABORT_END:
2672 case TBLOCK_SUBABORT_END:
2673 case TBLOCK_ABORT_PENDING:
2674 case TBLOCK_SUBABORT_PENDING:
2675 case TBLOCK_SUBRESTART:
2676 case TBLOCK_SUBABORT_RESTART:
2677 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2678 BlockStateAsString(s->blockState));
2685 * This executes a SAVEPOINT command.
2688 DefineSavepoint(char *name)
2690 TransactionState s = CurrentTransactionState;
2692 switch (s->blockState)
2694 case TBLOCK_INPROGRESS:
2695 case TBLOCK_SUBINPROGRESS:
2696 /* Normal subtransaction start */
2698 s = CurrentTransactionState; /* changed by push */
2701 * Savepoint names, like the TransactionState block itself,
2702 * live in TopTransactionContext.
2705 s->name = MemoryContextStrdup(TopTransactionContext, name);
2708 /* These cases are invalid. */
2709 case TBLOCK_DEFAULT:
2710 case TBLOCK_STARTED:
2712 case TBLOCK_SUBBEGIN:
2716 case TBLOCK_SUBABORT:
2717 case TBLOCK_ABORT_END:
2718 case TBLOCK_SUBABORT_END:
2719 case TBLOCK_ABORT_PENDING:
2720 case TBLOCK_SUBABORT_PENDING:
2721 case TBLOCK_SUBRESTART:
2722 case TBLOCK_SUBABORT_RESTART:
2723 elog(FATAL, "DefineSavepoint: unexpected state %s",
2724 BlockStateAsString(s->blockState));
2731 * This executes a RELEASE command.
2733 * As above, we don't actually do anything here except change blockState.
2736 ReleaseSavepoint(List *options)
2738 TransactionState s = CurrentTransactionState;
2739 TransactionState target,
2744 switch (s->blockState)
2747 * We can't rollback to a savepoint if there is no savepoint
2750 case TBLOCK_INPROGRESS:
2752 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2753 errmsg("no such savepoint")));
2757 * We are in a non-aborted subtransaction. This is the only
2760 case TBLOCK_SUBINPROGRESS:
2763 /* These cases are invalid. */
2764 case TBLOCK_DEFAULT:
2765 case TBLOCK_STARTED:
2767 case TBLOCK_SUBBEGIN:
2771 case TBLOCK_SUBABORT:
2772 case TBLOCK_ABORT_END:
2773 case TBLOCK_SUBABORT_END:
2774 case TBLOCK_ABORT_PENDING:
2775 case TBLOCK_SUBABORT_PENDING:
2776 case TBLOCK_SUBRESTART:
2777 case TBLOCK_SUBABORT_RESTART:
2778 elog(FATAL, "ReleaseSavepoint: unexpected state %s",
2779 BlockStateAsString(s->blockState));
2783 foreach(cell, options)
2785 DefElem *elem = lfirst(cell);
2787 if (strcmp(elem->defname, "savepoint_name") == 0)
2788 name = strVal(elem->arg);
2791 Assert(PointerIsValid(name));
2793 for (target = s; PointerIsValid(target); target = target->parent)
2795 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2799 if (!PointerIsValid(target))
2801 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2802 errmsg("no such savepoint")));
2804 /* disallow crossing savepoint level boundaries */
2805 if (target->savepointLevel != s->savepointLevel)
2807 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2808 errmsg("no such savepoint")));
2811 * Mark "commit pending" all subtransactions up to the target
2812 * subtransaction. The actual commits will happen when control gets
2813 * to CommitTransactionCommand.
2815 xact = CurrentTransactionState;
2818 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2819 xact->blockState = TBLOCK_SUBEND;
2822 xact = xact->parent;
2823 Assert(PointerIsValid(xact));
2828 * RollbackToSavepoint
2829 * This executes a ROLLBACK TO <savepoint> command.
2831 * As above, we don't actually do anything here except change blockState.
2834 RollbackToSavepoint(List *options)
2836 TransactionState s = CurrentTransactionState;
2837 TransactionState target,
2842 switch (s->blockState)
2845 * We can't rollback to a savepoint if there is no savepoint
2848 case TBLOCK_INPROGRESS:
2851 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2852 errmsg("no such savepoint")));
2856 * There is at least one savepoint, so proceed.
2858 case TBLOCK_SUBINPROGRESS:
2859 case TBLOCK_SUBABORT:
2862 /* These cases are invalid. */
2863 case TBLOCK_DEFAULT:
2864 case TBLOCK_STARTED:
2866 case TBLOCK_SUBBEGIN:
2869 case TBLOCK_ABORT_END:
2870 case TBLOCK_SUBABORT_END:
2871 case TBLOCK_ABORT_PENDING:
2872 case TBLOCK_SUBABORT_PENDING:
2873 case TBLOCK_SUBRESTART:
2874 case TBLOCK_SUBABORT_RESTART:
2875 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2876 BlockStateAsString(s->blockState));
2880 foreach(cell, options)
2882 DefElem *elem = lfirst(cell);
2884 if (strcmp(elem->defname, "savepoint_name") == 0)
2885 name = strVal(elem->arg);
2888 Assert(PointerIsValid(name));
2890 for (target = s; PointerIsValid(target); target = target->parent)
2892 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2896 if (!PointerIsValid(target))
2898 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2899 errmsg("no such savepoint")));
2901 /* disallow crossing savepoint level boundaries */
2902 if (target->savepointLevel != s->savepointLevel)
2904 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2905 errmsg("no such savepoint")));
2908 * Mark "abort pending" all subtransactions up to the target
2909 * subtransaction. The actual aborts will happen when control gets
2910 * to CommitTransactionCommand.
2912 xact = CurrentTransactionState;
2917 if (xact->blockState == TBLOCK_SUBINPROGRESS)
2918 xact->blockState = TBLOCK_SUBABORT_PENDING;
2919 else if (xact->blockState == TBLOCK_SUBABORT)
2920 xact->blockState = TBLOCK_SUBABORT_END;
2922 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2923 BlockStateAsString(xact->blockState));
2924 xact = xact->parent;
2925 Assert(PointerIsValid(xact));
2928 /* And mark the target as "restart pending" */
2929 if (xact->blockState == TBLOCK_SUBINPROGRESS)
2930 xact->blockState = TBLOCK_SUBRESTART;
2931 else if (xact->blockState == TBLOCK_SUBABORT)
2932 xact->blockState = TBLOCK_SUBABORT_RESTART;
2934 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2935 BlockStateAsString(xact->blockState));
2939 * BeginInternalSubTransaction
2940 * This is the same as DefineSavepoint except it allows TBLOCK_STARTED
2941 * state, and therefore it can safely be used in a function that might
2942 * be called when not inside a BEGIN block. Also, we automatically
2943 * cycle through CommitTransactionCommand/StartTransactionCommand
2944 * instead of expecting the caller to do it.
2947 BeginInternalSubTransaction(char *name)
2949 TransactionState s = CurrentTransactionState;
2951 switch (s->blockState)
2953 case TBLOCK_STARTED:
2954 case TBLOCK_INPROGRESS:
2955 case TBLOCK_SUBINPROGRESS:
2956 /* Normal subtransaction start */
2958 s = CurrentTransactionState; /* changed by push */
2961 * Savepoint names, like the TransactionState block itself,
2962 * live in TopTransactionContext.
2965 s->name = MemoryContextStrdup(TopTransactionContext, name);
2968 /* These cases are invalid. */
2969 case TBLOCK_DEFAULT:
2971 case TBLOCK_SUBBEGIN:
2975 case TBLOCK_SUBABORT:
2976 case TBLOCK_ABORT_END:
2977 case TBLOCK_SUBABORT_END:
2978 case TBLOCK_ABORT_PENDING:
2979 case TBLOCK_SUBABORT_PENDING:
2980 case TBLOCK_SUBRESTART:
2981 case TBLOCK_SUBABORT_RESTART:
2982 elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
2983 BlockStateAsString(s->blockState));
2987 CommitTransactionCommand();
2988 StartTransactionCommand();
2992 * ReleaseCurrentSubTransaction
2994 * RELEASE (ie, commit) the innermost subtransaction, regardless of its
2995 * savepoint name (if any).
2996 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2999 ReleaseCurrentSubTransaction(void)
3001 TransactionState s = CurrentTransactionState;
3003 if (s->blockState != TBLOCK_SUBINPROGRESS)
3004 elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
3005 BlockStateAsString(s->blockState));
3006 Assert(s->state == TRANS_INPROGRESS);
3007 MemoryContextSwitchTo(CurTransactionContext);
3008 CommitSubTransaction();
3009 s = CurrentTransactionState; /* changed by pop */
3010 Assert(s->state == TRANS_INPROGRESS);
3014 * RollbackAndReleaseCurrentSubTransaction
3016 * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
3017 * of its savepoint name (if any).
3018 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
3021 RollbackAndReleaseCurrentSubTransaction(void)
3023 TransactionState s = CurrentTransactionState;
3025 switch (s->blockState)
3027 /* Must be in a subtransaction */
3028 case TBLOCK_SUBINPROGRESS:
3029 case TBLOCK_SUBABORT:
3032 /* These cases are invalid. */
3033 case TBLOCK_DEFAULT:
3034 case TBLOCK_STARTED:
3036 case TBLOCK_SUBBEGIN:
3037 case TBLOCK_INPROGRESS:
3041 case TBLOCK_ABORT_END:
3042 case TBLOCK_SUBABORT_END:
3043 case TBLOCK_ABORT_PENDING:
3044 case TBLOCK_SUBABORT_PENDING:
3045 case TBLOCK_SUBRESTART:
3046 case TBLOCK_SUBABORT_RESTART:
3047 elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
3048 BlockStateAsString(s->blockState));
3053 * Abort the current subtransaction, if needed.
3055 if (s->blockState == TBLOCK_SUBINPROGRESS)
3056 AbortSubTransaction();
3058 /* And clean it up, too */
3059 CleanupSubTransaction();
3061 s = CurrentTransactionState; /* changed by pop */
3062 AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
3063 s->blockState == TBLOCK_INPROGRESS ||
3064 s->blockState == TBLOCK_STARTED);
3068 * AbortOutOfAnyTransaction
3070 * This routine is provided for error recovery purposes. It aborts any
3071 * active transaction or transaction block, leaving the system in a known
3075 AbortOutOfAnyTransaction(void)
3077 TransactionState s = CurrentTransactionState;
3080 * Get out of any transaction or nested transaction
3084 switch (s->blockState)
3086 case TBLOCK_DEFAULT:
3087 /* Not in a transaction, do nothing */
3089 case TBLOCK_STARTED:
3091 case TBLOCK_INPROGRESS:
3093 case TBLOCK_ABORT_PENDING:
3094 /* In a transaction, so clean up */
3096 CleanupTransaction();
3097 s->blockState = TBLOCK_DEFAULT;
3100 case TBLOCK_ABORT_END:
3101 /* AbortTransaction already done, still need Cleanup */
3102 CleanupTransaction();
3103 s->blockState = TBLOCK_DEFAULT;
3107 * In a subtransaction, so clean it up and abort parent
3110 case TBLOCK_SUBBEGIN:
3111 case TBLOCK_SUBINPROGRESS:
3113 case TBLOCK_SUBABORT_PENDING:
3114 case TBLOCK_SUBRESTART:
3115 AbortSubTransaction();
3116 CleanupSubTransaction();
3117 s = CurrentTransactionState; /* changed by pop */
3120 case TBLOCK_SUBABORT:
3121 case TBLOCK_SUBABORT_END:
3122 case TBLOCK_SUBABORT_RESTART:
3123 /* As above, but AbortSubTransaction already done */
3124 CleanupSubTransaction();
3125 s = CurrentTransactionState; /* changed by pop */
3128 } while (s->blockState != TBLOCK_DEFAULT);
3130 /* Should be out of all subxacts now */
3131 Assert(s->parent == NULL);
3135 * IsTransactionBlock --- are we within a transaction block?
3138 IsTransactionBlock(void)
3140 TransactionState s = CurrentTransactionState;
3142 if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
3149 * IsTransactionOrTransactionBlock --- are we within either a transaction
3150 * or a transaction block? (The backend is only really "idle" when this
3153 * This should match up with IsTransactionBlock and IsTransactionState.
3156 IsTransactionOrTransactionBlock(void)
3158 TransactionState s = CurrentTransactionState;
3160 if (s->blockState == TBLOCK_DEFAULT)
3167 * TransactionBlockStatusCode - return status code to send in ReadyForQuery
3170 TransactionBlockStatusCode(void)
3172 TransactionState s = CurrentTransactionState;
3174 switch (s->blockState)
3176 case TBLOCK_DEFAULT:
3177 case TBLOCK_STARTED:
3178 return 'I'; /* idle --- not in transaction */
3180 case TBLOCK_SUBBEGIN:
3181 case TBLOCK_INPROGRESS:
3182 case TBLOCK_SUBINPROGRESS:
3185 return 'T'; /* in transaction */
3187 case TBLOCK_SUBABORT:
3188 case TBLOCK_ABORT_END:
3189 case TBLOCK_SUBABORT_END:
3190 case TBLOCK_ABORT_PENDING:
3191 case TBLOCK_SUBABORT_PENDING:
3192 case TBLOCK_SUBRESTART:
3193 case TBLOCK_SUBABORT_RESTART:
3194 return 'E'; /* in failed transaction */
3197 /* should never get here */
3198 elog(FATAL, "invalid transaction block state: %s",
3199 BlockStateAsString(s->blockState));
3200 return 0; /* keep compiler quiet */
3207 IsSubTransaction(void)
3209 TransactionState s = CurrentTransactionState;
3211 if (s->nestingLevel >= 2)
3218 * StartSubTransaction
3220 * If you're wondering why this is separate from PushTransaction: it's because
3221 * we can't conveniently do this stuff right inside DefineSavepoint. The
3222 * SAVEPOINT utility command will be executed inside a Portal, and if we
3223 * muck with CurrentMemoryContext or CurrentResourceOwner then exit from
3224 * the Portal will undo those settings. So we make DefineSavepoint just
3225 * push a dummy transaction block, and when control returns to the main
3226 * idle loop, CommitTransactionCommand will be called, and we'll come here
3227 * to finish starting the subtransaction.
3230 StartSubTransaction(void)
3232 TransactionState s = CurrentTransactionState;
3234 if (s->state != TRANS_DEFAULT)
3235 elog(WARNING, "StartSubTransaction while in %s state",
3236 TransStateAsString(s->state));
3238 s->state = TRANS_START;
3241 * Initialize subsystems for new subtransaction
3243 * must initialize resource-management stuff first
3245 AtSubStart_Memory();
3246 AtSubStart_ResourceOwner();
3248 AtSubStart_Notify();
3249 AfterTriggerBeginSubXact();
3251 s->state = TRANS_INPROGRESS;
3254 * Call start-of-subxact callbacks
3256 CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
3257 s->parent->subTransactionId);
3259 ShowTransactionState("StartSubTransaction");
3263 * CommitSubTransaction
3265 * The caller has to make sure to always reassign CurrentTransactionState
3266 * if it has a local pointer to it after calling this function.
3269 CommitSubTransaction(void)
3271 TransactionState s = CurrentTransactionState;
3273 ShowTransactionState("CommitSubTransaction");
3275 if (s->state != TRANS_INPROGRESS)
3276 elog(WARNING, "CommitSubTransaction while in %s state",
3277 TransStateAsString(s->state));
3279 /* Pre-commit processing goes here -- nothing to do at the moment */
3281 s->state = TRANS_COMMIT;
3283 /* Must CCI to ensure commands of subtransaction are seen as done */
3284 CommandCounterIncrement();
3286 /* Mark subtransaction as subcommitted */
3287 if (TransactionIdIsValid(s->transactionId))
3289 RecordSubTransactionCommit();
3290 AtSubCommit_childXids();
3293 /* Post-commit cleanup */
3294 AfterTriggerEndSubXact(true);
3295 AtSubCommit_Portals(s->subTransactionId,
3296 s->parent->subTransactionId,
3297 s->parent->curTransactionOwner);
3298 AtEOSubXact_LargeObject(true, s->subTransactionId,
3299 s->parent->subTransactionId);
3300 AtSubCommit_Notify();
3301 AtEOSubXact_UpdateFlatFiles(true, s->subTransactionId,
3302 s->parent->subTransactionId);
3304 CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
3305 s->parent->subTransactionId);
3307 ResourceOwnerRelease(s->curTransactionOwner,
3308 RESOURCE_RELEASE_BEFORE_LOCKS,
3310 AtEOSubXact_RelationCache(true, s->subTransactionId,
3311 s->parent->subTransactionId);
3312 AtEOSubXact_Inval(true);
3316 * The only lock we actually release here is the subtransaction XID lock.
3317 * The rest just get transferred to the parent resource owner.
3319 CurrentResourceOwner = s->curTransactionOwner;
3320 if (TransactionIdIsValid(s->transactionId))
3321 XactLockTableDelete(s->transactionId);
3323 ResourceOwnerRelease(s->curTransactionOwner,
3324 RESOURCE_RELEASE_LOCKS,
3326 ResourceOwnerRelease(s->curTransactionOwner,
3327 RESOURCE_RELEASE_AFTER_LOCKS,
3330 AtEOXact_GUC(true, true);
3331 AtEOSubXact_SPI(true, s->subTransactionId);
3332 AtEOSubXact_on_commit_actions(true, s->subTransactionId,
3333 s->parent->subTransactionId);
3334 AtEOSubXact_Namespace(true, s->subTransactionId,
3335 s->parent->subTransactionId);
3336 AtEOSubXact_Files(true, s->subTransactionId,
3337 s->parent->subTransactionId);
3340 * We need to restore the upper transaction's read-only state, in case
3341 * the upper is read-write while the child is read-only; GUC will
3342 * incorrectly think it should leave the child state in place.
3344 XactReadOnly = s->prevXactReadOnly;
3346 CurrentResourceOwner = s->parent->curTransactionOwner;
3347 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3348 ResourceOwnerDelete(s->curTransactionOwner);
3349 s->curTransactionOwner = NULL;
3351 AtSubCommit_Memory();
3353 s->state = TRANS_DEFAULT;
3359 * AbortSubTransaction
3362 AbortSubTransaction(void)
3364 TransactionState s = CurrentTransactionState;
3366 ShowTransactionState("AbortSubTransaction");
3368 if (s->state != TRANS_INPROGRESS)
3369 elog(WARNING, "AbortSubTransaction while in %s state",
3370 TransStateAsString(s->state));
3374 s->state = TRANS_ABORT;
3377 * Release any LW locks we might be holding as quickly as possible.
3378 * (Regular locks, however, must be held till we finish aborting.)
3379 * Releasing LW locks is critical since we might try to grab them
3380 * again while cleaning up!
3382 * FIXME This may be incorrect --- Are there some locks we should keep?
3383 * Buffer locks, for example? I don't think so but I'm not sure.
3393 * do abort processing
3395 AtSubAbort_Memory();
3396 AtSubAbort_ResourceOwner();
3399 * We can skip all this stuff if the subxact failed before creating
3400 * a ResourceOwner...
3402 if (s->curTransactionOwner)
3404 AfterTriggerEndSubXact(false);
3405 AtSubAbort_Portals(s->subTransactionId,
3406 s->parent->subTransactionId,
3407 s->parent->curTransactionOwner);
3408 AtEOSubXact_LargeObject(false, s->subTransactionId,
3409 s->parent->subTransactionId);
3410 AtSubAbort_Notify();
3411 AtEOSubXact_UpdateFlatFiles(false, s->subTransactionId,
3412 s->parent->subTransactionId);
3414 /* Advertise the fact that we aborted in pg_clog. */
3415 if (TransactionIdIsValid(s->transactionId))
3417 RecordSubTransactionAbort();
3418 AtSubAbort_childXids();
3421 /* Post-abort cleanup */
3422 CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
3423 s->parent->subTransactionId);
3425 ResourceOwnerRelease(s->curTransactionOwner,
3426 RESOURCE_RELEASE_BEFORE_LOCKS,
3428 AtEOSubXact_RelationCache(false, s->subTransactionId,
3429 s->parent->subTransactionId);
3430 AtEOSubXact_Inval(false);
3432 ResourceOwnerRelease(s->curTransactionOwner,
3433 RESOURCE_RELEASE_LOCKS,
3435 ResourceOwnerRelease(s->curTransactionOwner,
3436 RESOURCE_RELEASE_AFTER_LOCKS,
3439 AtEOXact_GUC(false, true);
3440 AtEOSubXact_SPI(false, s->subTransactionId);
3441 AtEOSubXact_on_commit_actions(false, s->subTransactionId,
3442 s->parent->subTransactionId);
3443 AtEOSubXact_Namespace(false, s->subTransactionId,
3444 s->parent->subTransactionId);
3445 AtEOSubXact_Files(false, s->subTransactionId,
3446 s->parent->subTransactionId);
3450 * Reset user id which might have been changed transiently. Here we
3451 * want to restore to the userid that was current at subxact entry.
3452 * (As in AbortTransaction, we need not worry about the session
3455 * Must do this after AtEOXact_GUC to handle the case where we entered
3456 * the subxact inside a SECURITY DEFINER function (hence current and
3457 * session userids were different) and then session auth was changed
3458 * inside the subxact. GUC will reset both current and session
3459 * userids to the entry-time session userid. This is right in every
3460 * other scenario so it seems simplest to let GUC do that and fix it
3463 SetUserId(s->currentUser);
3466 * Restore the upper transaction's read-only state, too. This should
3467 * be redundant with GUC's cleanup but we may as well do it for
3468 * consistency with the commit case.
3470 XactReadOnly = s->prevXactReadOnly;
3472 RESUME_INTERRUPTS();
3476 * CleanupSubTransaction
3478 * The caller has to make sure to always reassign CurrentTransactionState
3479 * if it has a local pointer to it after calling this function.
3482 CleanupSubTransaction(void)
3484 TransactionState s = CurrentTransactionState;
3486 ShowTransactionState("CleanupSubTransaction");
3488 if (s->state != TRANS_ABORT)
3489 elog(WARNING, "CleanupSubTransaction while in %s state",
3490 TransStateAsString(s->state));
3492 AtSubCleanup_Portals(s->subTransactionId);
3494 CurrentResourceOwner = s->parent->curTransactionOwner;
3495 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3496 if (s->curTransactionOwner)
3497 ResourceOwnerDelete(s->curTransactionOwner);
3498 s->curTransactionOwner = NULL;
3500 AtSubCleanup_Memory();
3502 s->state = TRANS_DEFAULT;
3509 * Create transaction state stack entry for a subtransaction
3511 * The caller has to make sure to always reassign CurrentTransactionState
3512 * if it has a local pointer to it after calling this function.
3515 PushTransaction(void)
3517 TransactionState p = CurrentTransactionState;
3522 * At present, GetUserId cannot fail, but let's not assume that. Get
3523 * the ID before entering the critical code sequence.
3525 currentUser = GetUserId();
3528 * We keep subtransaction state nodes in TopTransactionContext.
3530 s = (TransactionState)
3531 MemoryContextAllocZero(TopTransactionContext,
3532 sizeof(TransactionStateData));
3534 * Assign a subtransaction ID, watching out for counter wraparound.
3536 currentSubTransactionId += 1;
3537 if (currentSubTransactionId == InvalidSubTransactionId)
3539 currentSubTransactionId -= 1;
3542 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3543 errmsg("cannot have more than 2^32-1 subtransactions in a transaction")));
3546 * We can now stack a minimally valid subtransaction without fear of
3549 s->transactionId = InvalidTransactionId; /* until assigned */
3550 s->subTransactionId = currentSubTransactionId;
3552 s->nestingLevel = p->nestingLevel + 1;
3553 s->savepointLevel = p->savepointLevel;
3554 s->state = TRANS_DEFAULT;
3555 s->blockState = TBLOCK_SUBBEGIN;
3556 s->currentUser = currentUser;
3557 s->prevXactReadOnly = XactReadOnly;
3559 CurrentTransactionState = s;
3562 * AbortSubTransaction and CleanupSubTransaction have to be able to
3563 * cope with the subtransaction from here on out; in particular they
3564 * should not assume that it necessarily has a transaction context,
3565 * resource owner, or XID.
3571 * Pop back to parent transaction state
3573 * The caller has to make sure to always reassign CurrentTransactionState
3574 * if it has a local pointer to it after calling this function.
3577 PopTransaction(void)
3579 TransactionState s = CurrentTransactionState;
3581 if (s->state != TRANS_DEFAULT)
3582 elog(WARNING, "PopTransaction while in %s state",
3583 TransStateAsString(s->state));
3585 if (s->parent == NULL)
3586 elog(FATAL, "PopTransaction with no parent");
3588 CurrentTransactionState = s->parent;
3590 /* Let's just make sure CurTransactionContext is good */
3591 CurTransactionContext = s->parent->curTransactionContext;
3592 MemoryContextSwitchTo(CurTransactionContext);
3594 /* Ditto for ResourceOwner links */
3595 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3596 CurrentResourceOwner = s->parent->curTransactionOwner;
3598 /* Free the old child structure */
3605 * ShowTransactionState
3609 ShowTransactionState(const char *str)
3611 /* skip work if message will definitely not be printed */
3612 if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
3614 elog(DEBUG2, "%s", str);
3615 ShowTransactionStateRec(CurrentTransactionState);
3620 * ShowTransactionStateRec
3621 * Recursive subroutine for ShowTransactionState
3624 ShowTransactionStateRec(TransactionState s)
3627 ShowTransactionStateRec(s->parent);
3629 /* use ereport to suppress computation if msg will not be printed */
3631 (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u, nestlvl: %d, children: %s",
3632 PointerIsValid(s->name) ? s->name : "unnamed",
3633 BlockStateAsString(s->blockState),
3634 TransStateAsString(s->state),
3635 (unsigned int) s->transactionId,
3636 (unsigned int) s->subTransactionId,
3637 (unsigned int) currentCommandId,
3639 nodeToString(s->childXids))));
3643 * BlockStateAsString
3647 BlockStateAsString(TBlockState blockState)
3651 case TBLOCK_DEFAULT:
3653 case TBLOCK_STARTED:
3657 case TBLOCK_INPROGRESS:
3658 return "INPROGRESS";
3663 case TBLOCK_ABORT_END:
3665 case TBLOCK_ABORT_PENDING:
3666 return "ABORT PEND";
3667 case TBLOCK_SUBBEGIN:
3669 case TBLOCK_SUBINPROGRESS:
3670 return "SUB INPROGRS";
3673 case TBLOCK_SUBABORT:
3675 case TBLOCK_SUBABORT_END:
3676 return "SUB ABORT END";
3677 case TBLOCK_SUBABORT_PENDING:
3678 return "SUB ABRT PEND";
3679 case TBLOCK_SUBRESTART:
3680 return "SUB RESTART";
3681 case TBLOCK_SUBABORT_RESTART:
3682 return "SUB AB RESTRT";
3684 return "UNRECOGNIZED";
3688 * TransStateAsString
3692 TransStateAsString(TransState state)
3704 case TRANS_INPROGRESS:
3707 return "UNRECOGNIZED";
3711 * xactGetCommittedChildren
3713 * Gets the list of committed children of the current transaction. The return
3714 * value is the number of child transactions. *children is set to point to a
3715 * palloc'd array of TransactionIds. If there are no subxacts, *children is
3719 xactGetCommittedChildren(TransactionId **ptr)
3721 TransactionState s = CurrentTransactionState;
3723 TransactionId *children;
3726 nchildren = list_length(s->childXids);
3733 children = (TransactionId *) palloc(nchildren * sizeof(TransactionId));
3736 foreach(p, s->childXids)
3738 TransactionId child = lfirst_xid(p);
3740 *children++ = child;
3747 * XLOG support routines
3751 xact_redo(XLogRecPtr lsn, XLogRecord *record)
3753 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3755 if (info == XLOG_XACT_COMMIT)
3757 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
3758 TransactionId *sub_xids;
3759 TransactionId max_xid;
3762 TransactionIdCommit(record->xl_xid);
3764 /* Mark committed subtransactions as committed */
3765 sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
3766 TransactionIdCommitTree(xlrec->nsubxacts, sub_xids);
3768 /* Make sure nextXid is beyond any XID mentioned in the record */
3769 max_xid = record->xl_xid;
3770 for (i = 0; i < xlrec->nsubxacts; i++)
3772 if (TransactionIdPrecedes(max_xid, sub_xids[i]))
3773 max_xid = sub_xids[i];
3775 if (TransactionIdFollowsOrEquals(max_xid,
3776 ShmemVariableCache->nextXid))
3778 ShmemVariableCache->nextXid = max_xid;
3779 TransactionIdAdvance(ShmemVariableCache->nextXid);
3782 /* Make sure files supposed to be dropped are dropped */
3783 for (i = 0; i < xlrec->nrels; i++)
3785 XLogCloseRelation(xlrec->xnodes[i]);
3786 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3789 else if (info == XLOG_XACT_ABORT)
3791 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
3792 TransactionId *sub_xids;
3793 TransactionId max_xid;
3796 TransactionIdAbort(record->xl_xid);
3798 /* Mark subtransactions as aborted */
3799 sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
3800 TransactionIdAbortTree(xlrec->nsubxacts, sub_xids);
3802 /* Make sure nextXid is beyond any XID mentioned in the record */
3803 max_xid = record->xl_xid;
3804 for (i = 0; i < xlrec->nsubxacts; i++)
3806 if (TransactionIdPrecedes(max_xid, sub_xids[i]))
3807 max_xid = sub_xids[i];
3809 if (TransactionIdFollowsOrEquals(max_xid,
3810 ShmemVariableCache->nextXid))
3812 ShmemVariableCache->nextXid = max_xid;
3813 TransactionIdAdvance(ShmemVariableCache->nextXid);
3816 /* Make sure files supposed to be dropped are dropped */
3817 for (i = 0; i < xlrec->nrels; i++)
3819 XLogCloseRelation(xlrec->xnodes[i]);
3820 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3824 elog(PANIC, "xact_redo: unknown op code %u", info);
3828 xact_undo(XLogRecPtr lsn, XLogRecord *record)
3830 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3832 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
3833 elog(PANIC, "xact_undo: can't undo committed xaction");
3834 else if (info != XLOG_XACT_ABORT)
3835 elog(PANIC, "xact_redo: unknown op code %u", info);
3839 xact_desc(char *buf, uint8 xl_info, char *rec)
3841 uint8 info = xl_info & ~XLR_INFO_MASK;
3844 if (info == XLOG_XACT_COMMIT)
3846 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
3847 struct tm *tm = localtime(&xlrec->xtime);
3849 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
3850 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3851 tm->tm_hour, tm->tm_min, tm->tm_sec);
3852 if (xlrec->nrels > 0)
3854 sprintf(buf + strlen(buf), "; rels:");
3855 for (i = 0; i < xlrec->nrels; i++)
3857 RelFileNode rnode = xlrec->xnodes[i];
3859 sprintf(buf + strlen(buf), " %u/%u/%u",
3860 rnode.spcNode, rnode.dbNode, rnode.relNode);
3863 if (xlrec->nsubxacts > 0)
3865 TransactionId *xacts = (TransactionId *)
3866 &xlrec->xnodes[xlrec->nrels];
3868 sprintf(buf + strlen(buf), "; subxacts:");
3869 for (i = 0; i < xlrec->nsubxacts; i++)
3870 sprintf(buf + strlen(buf), " %u", xacts[i]);
3873 else if (info == XLOG_XACT_ABORT)
3875 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
3876 struct tm *tm = localtime(&xlrec->xtime);
3878 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
3879 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3880 tm->tm_hour, tm->tm_min, tm->tm_sec);
3881 if (xlrec->nrels > 0)
3883 sprintf(buf + strlen(buf), "; rels:");
3884 for (i = 0; i < xlrec->nrels; i++)
3886 RelFileNode rnode = xlrec->xnodes[i];
3888 sprintf(buf + strlen(buf), " %u/%u/%u",
3889 rnode.spcNode, rnode.dbNode, rnode.relNode);
3892 if (xlrec->nsubxacts > 0)
3894 TransactionId *xacts = (TransactionId *)
3895 &xlrec->xnodes[xlrec->nrels];
3897 sprintf(buf + strlen(buf), "; subxacts:");
3898 for (i = 0; i < xlrec->nsubxacts; i++)
3899 sprintf(buf + strlen(buf), " %u", xacts[i]);
3903 strcat(buf, "UNKNOWN");
3907 XactPushRollback(void (*func) (void *), void *data)
3910 if (_RollbackFunc != NULL)
3911 elog(PANIC, "XactPushRollback: already installed");
3914 _RollbackFunc = func;
3915 _RollbackData = data;
3919 XactPopRollback(void)
3921 _RollbackFunc = NULL;