1 /*-------------------------------------------------------------------------
4 * top level transaction system support routines
6 * See src/backend/access/transam/README for more information.
8 * Portions Copyright (c) 1996-2003, 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.180 2004/08/28 20:31:43 tgl Exp $
15 *-------------------------------------------------------------------------
23 #include "access/subtrans.h"
24 #include "access/xact.h"
25 #include "catalog/heap.h"
26 #include "catalog/index.h"
27 #include "catalog/namespace.h"
28 #include "commands/async.h"
29 #include "commands/tablecmds.h"
30 #include "commands/trigger.h"
31 #include "commands/user.h"
32 #include "executor/spi.h"
33 #include "libpq/be-fsstubs.h"
34 #include "miscadmin.h"
35 #include "storage/fd.h"
36 #include "storage/proc.h"
37 #include "storage/sinval.h"
38 #include "storage/smgr.h"
39 #include "utils/guc.h"
40 #include "utils/inval.h"
41 #include "utils/memutils.h"
42 #include "utils/portal.h"
43 #include "utils/relcache.h"
44 #include "utils/resowner.h"
49 * transaction states - transaction state from server perspective
51 typedef enum TransState
61 * transaction block states - transaction state of client queries
63 typedef enum TBlockState
65 /* not-in-transaction-block states */
69 /* transaction block states */
76 /* subtransaction states */
81 TBLOCK_SUBABORT_PENDING,
82 TBLOCK_SUBENDABORT_ALL,
83 TBLOCK_SUBENDABORT_RELEASE,
88 * transaction state structure
90 typedef struct TransactionStateData
92 TransactionId transactionIdData; /* my XID */
93 char *name; /* savepoint name, if any */
94 int savepointLevel; /* savepoint level */
95 CommandId commandId; /* current CID */
96 TransState state; /* low-level state */
97 TBlockState blockState; /* high-level state */
98 int nestingLevel; /* nest depth */
99 MemoryContext curTransactionContext; /* my xact-lifetime context */
100 ResourceOwner curTransactionOwner; /* my query resources */
101 List *childXids; /* subcommitted child XIDs */
102 AclId currentUser; /* subxact start current_user */
103 bool prevXactReadOnly; /* entry-time xact r/o state */
104 struct TransactionStateData *parent; /* back link to parent */
105 } TransactionStateData;
107 typedef TransactionStateData *TransactionState;
110 * childXids is currently implemented as an integer List, relying on the
111 * assumption that TransactionIds are no wider than int. We use these
112 * macros to provide some isolation in case that changes in the future.
114 #define lfirst_xid(lc) ((TransactionId) lfirst_int(lc))
115 #define lappend_xid(list, datum) lappend_int(list, (int) (datum))
118 static void AbortTransaction(void);
119 static void AtAbort_Memory(void);
120 static void AtCleanup_Memory(void);
121 static void AtCommit_LocalCache(void);
122 static void AtCommit_Memory(void);
123 static void AtStart_Cache(void);
124 static void AtStart_Memory(void);
125 static void AtStart_ResourceOwner(void);
126 static void CallXactCallbacks(XactEvent event, TransactionId parentXid);
127 static void CleanupTransaction(void);
128 static void CommitTransaction(void);
129 static void RecordTransactionAbort(void);
130 static void StartTransaction(void);
132 static void RecordSubTransactionCommit(void);
133 static void StartSubTransaction(void);
134 static void CommitSubTransaction(void);
135 static void AbortSubTransaction(void);
136 static void CleanupSubTransaction(void);
137 static void StartAbortedSubTransaction(void);
138 static void PushTransaction(void);
139 static void PopTransaction(void);
140 static void CommitTransactionToLevel(int level);
141 static char *CleanupAbortedSubTransactions(bool returnName);
143 static void AtSubAbort_Memory(void);
144 static void AtSubCleanup_Memory(void);
145 static void AtSubCommit_Memory(void);
146 static void AtSubStart_Memory(void);
147 static void AtSubStart_ResourceOwner(void);
149 static void ShowTransactionState(const char *str);
150 static void ShowTransactionStateRec(TransactionState state);
151 static const char *BlockStateAsString(TBlockState blockState);
152 static const char *TransStateAsString(TransState state);
155 * CurrentTransactionState always points to the current transaction state
156 * block. It will point to TopTransactionStateData when not in a
157 * transaction at all, or when in a top-level transaction.
159 static TransactionStateData TopTransactionStateData = {
160 0, /* transaction id */
161 NULL, /* savepoint name */
162 0, /* savepoint level */
163 FirstCommandId, /* command id */
164 TRANS_DEFAULT, /* transaction state */
165 TBLOCK_DEFAULT, /* transaction block state from the client
167 0, /* nesting level */
168 NULL, /* cur transaction context */
169 NULL, /* cur transaction resource owner */
170 NIL, /* subcommitted child Xids */
171 0, /* entry-time current userid */
172 false, /* entry-time xact r/o state */
173 NULL /* link to parent state block */
176 static TransactionState CurrentTransactionState = &TopTransactionStateData;
179 * These vars hold the value of now(), ie, the transaction start time.
180 * This does not change as we enter and exit subtransactions, so we don't
181 * keep it inside the TransactionState stack.
183 static AbsoluteTime xactStartTime; /* integer part */
184 static int xactStartTimeUsec; /* microsecond part */
188 * User-tweakable parameters
190 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
193 bool DefaultXactReadOnly = false;
196 int CommitDelay = 0; /* precommit delay in microseconds */
197 int CommitSiblings = 5; /* number of concurrent xacts needed to
202 * List of add-on start- and end-of-xact callbacks
204 typedef struct XactCallbackItem
206 struct XactCallbackItem *next;
207 XactCallback callback;
211 static XactCallbackItem *Xact_callbacks = NULL;
213 static void (*_RollbackFunc) (void *) = NULL;
214 static void *_RollbackData = NULL;
217 /* ----------------------------------------------------------------
218 * transaction state accessors
219 * ----------------------------------------------------------------
225 * This returns true if we are currently running a query
226 * within an executing transaction.
229 IsTransactionState(void)
231 TransactionState s = CurrentTransactionState;
239 case TRANS_INPROGRESS:
248 * Shouldn't get here, but lint is not happy with this...
254 * IsAbortedTransactionBlockState
256 * This returns true if we are currently running a query
257 * within an aborted transaction block.
260 IsAbortedTransactionBlockState(void)
262 TransactionState s = CurrentTransactionState;
264 if (s->blockState == TBLOCK_ABORT ||
265 s->blockState == TBLOCK_SUBABORT)
273 * GetTopTransactionId
275 * Get the ID of the main transaction, even if we are currently inside
279 GetTopTransactionId(void)
281 return TopTransactionStateData.transactionIdData;
286 * GetCurrentTransactionId
289 GetCurrentTransactionId(void)
291 TransactionState s = CurrentTransactionState;
293 return s->transactionIdData;
298 * GetCurrentCommandId
301 GetCurrentCommandId(void)
303 TransactionState s = CurrentTransactionState;
310 * GetCurrentTransactionStartTime
313 GetCurrentTransactionStartTime(void)
315 return xactStartTime;
320 * GetCurrentTransactionStartTimeUsec
323 GetCurrentTransactionStartTimeUsec(int *msec)
325 *msec = xactStartTimeUsec;
326 return xactStartTime;
331 * GetCurrentTransactionNestLevel
333 * Note: this will return zero when not inside any transaction, one when
334 * inside a top-level transaction, etc.
337 GetCurrentTransactionNestLevel(void)
339 TransactionState s = CurrentTransactionState;
341 return s->nestingLevel;
346 * TransactionIdIsCurrentTransactionId
348 * During bootstrap, we cheat and say "it's not my transaction ID" even though
349 * it is. Along with transam.c's cheat to say that the bootstrap XID is
350 * already committed, this causes the tqual.c routines to see previously
351 * inserted tuples as committed, which is what we need during bootstrap.
354 TransactionIdIsCurrentTransactionId(TransactionId xid)
360 Assert(xid == BootstrapTransactionId);
365 * We will return true for the Xid of the current subtransaction,
366 * any of its subcommitted children, any of its parents, or any of
367 * their previously subcommitted children. However, a transaction
368 * being aborted is no longer "current", even though it may still
369 * have an entry on the state stack.
371 for (s = CurrentTransactionState; s != NULL; s = s->parent)
375 if (s->state == TRANS_ABORT)
377 if (TransactionIdEquals(xid, s->transactionIdData))
379 foreach(cell, s->childXids)
381 if (TransactionIdEquals(xid, lfirst_xid(cell)))
391 * CommandCounterIncrement
394 CommandCounterIncrement(void)
396 TransactionState s = CurrentTransactionState;
399 if (s->commandId == FirstCommandId) /* check for overflow */
401 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
402 errmsg("cannot have more than 2^32-1 commands in a transaction")));
404 /* Propagate new command ID into query snapshots, if set */
406 QuerySnapshot->curcid = s->commandId;
407 if (SerializableSnapshot)
408 SerializableSnapshot->curcid = s->commandId;
411 * make cache changes visible to me.
413 AtCommit_LocalCache();
418 /* ----------------------------------------------------------------
419 * StartTransaction stuff
420 * ----------------------------------------------------------------
429 AcceptInvalidationMessages();
438 TransactionState s = CurrentTransactionState;
441 * We shouldn't have a transaction context already.
443 Assert(TopTransactionContext == NULL);
446 * Create a toplevel context for the transaction.
448 TopTransactionContext =
449 AllocSetContextCreate(TopMemoryContext,
450 "TopTransactionContext",
451 ALLOCSET_DEFAULT_MINSIZE,
452 ALLOCSET_DEFAULT_INITSIZE,
453 ALLOCSET_DEFAULT_MAXSIZE);
456 * In a top-level transaction, CurTransactionContext is the same as
457 * TopTransactionContext.
459 CurTransactionContext = TopTransactionContext;
460 s->curTransactionContext = CurTransactionContext;
462 /* Make the CurTransactionContext active. */
463 MemoryContextSwitchTo(CurTransactionContext);
467 * AtStart_ResourceOwner
470 AtStart_ResourceOwner(void)
472 TransactionState s = CurrentTransactionState;
475 * We shouldn't have a transaction resource owner already.
477 Assert(TopTransactionResourceOwner == NULL);
480 * Create a toplevel resource owner for the transaction.
482 s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
484 TopTransactionResourceOwner = s->curTransactionOwner;
485 CurTransactionResourceOwner = s->curTransactionOwner;
486 CurrentResourceOwner = s->curTransactionOwner;
489 /* ----------------------------------------------------------------
490 * StartSubTransaction stuff
491 * ----------------------------------------------------------------
498 AtSubStart_Memory(void)
500 TransactionState s = CurrentTransactionState;
502 Assert(CurTransactionContext != NULL);
505 * Create a CurTransactionContext, which will be used to hold data that
506 * survives subtransaction commit but disappears on subtransaction abort.
507 * We make it a child of the immediate parent's CurTransactionContext.
509 CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
510 "CurTransactionContext",
511 ALLOCSET_DEFAULT_MINSIZE,
512 ALLOCSET_DEFAULT_INITSIZE,
513 ALLOCSET_DEFAULT_MAXSIZE);
514 s->curTransactionContext = CurTransactionContext;
516 /* Make the CurTransactionContext active. */
517 MemoryContextSwitchTo(CurTransactionContext);
521 * AtSubStart_ResourceOwner
524 AtSubStart_ResourceOwner(void)
526 TransactionState s = CurrentTransactionState;
528 Assert(s->parent != NULL);
531 * Create a resource owner for the subtransaction. We make it a
532 * child of the immediate parent's resource owner.
534 s->curTransactionOwner =
535 ResourceOwnerCreate(s->parent->curTransactionOwner,
538 CurTransactionResourceOwner = s->curTransactionOwner;
539 CurrentResourceOwner = s->curTransactionOwner;
542 /* ----------------------------------------------------------------
543 * CommitTransaction stuff
544 * ----------------------------------------------------------------
548 * RecordTransactionCommit
551 RecordTransactionCommit(void)
556 TransactionId *children;
558 /* Get data needed for commit record */
559 nrels = smgrGetPendingDeletes(true, &rptr);
560 nchildren = xactGetCommittedChildren(&children);
563 * If we made neither any XLOG entries nor any temp-rel updates,
564 * and have no files to be deleted, we can omit recording the transaction
565 * commit at all. (This test includes the effects of subtransactions,
566 * so the presence of committed subxacts need not alone force a write.)
568 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)
570 TransactionId xid = GetCurrentTransactionId();
574 /* Tell bufmgr and smgr to prepare for commit */
577 START_CRIT_SECTION();
580 * If our transaction made any transaction-controlled XLOG entries,
581 * we need to lock out checkpoint start between writing our XLOG
582 * record and updating pg_clog. Otherwise it is possible for the
583 * checkpoint to set REDO after the XLOG record but fail to flush the
584 * pg_clog update to disk, leading to loss of the transaction commit
585 * if we crash a little later. Slightly klugy fix for problem
586 * discovered 2004-08-10.
588 * (If it made no transaction-controlled XLOG entries, its XID
589 * appears nowhere in permanent storage, so no one else will ever care
590 * if it committed; so it doesn't matter if we lose the commit flag.)
592 * Note we only need a shared lock.
594 madeTCentries = (MyLastRecPtr.xrecoff != 0);
596 LWLockAcquire(CheckpointStartLock, LW_SHARED);
599 * We only need to log the commit in XLOG if the transaction made
600 * any transaction-controlled XLOG entries or will delete files.
602 if (madeTCentries || nrels > 0)
604 XLogRecData rdata[3];
606 xl_xact_commit xlrec;
608 xlrec.xtime = time(NULL);
610 xlrec.nsubxacts = nchildren;
611 rdata[0].buffer = InvalidBuffer;
612 rdata[0].data = (char *) (&xlrec);
613 rdata[0].len = MinSizeOfXactCommit;
614 /* dump rels to delete */
617 rdata[0].next = &(rdata[1]);
618 rdata[1].buffer = InvalidBuffer;
619 rdata[1].data = (char *) rptr;
620 rdata[1].len = nrels * sizeof(RelFileNode);
623 /* dump committed child Xids */
626 rdata[lastrdata].next = &(rdata[2]);
627 rdata[2].buffer = InvalidBuffer;
628 rdata[2].data = (char *) children;
629 rdata[2].len = nchildren * sizeof(TransactionId);
632 rdata[lastrdata].next = NULL;
634 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
638 /* Just flush through last record written by me */
639 recptr = ProcLastRecEnd;
643 * We must flush our XLOG entries to disk if we made any XLOG
644 * entries, whether in or out of transaction control. For
645 * example, if we reported a nextval() result to the client, this
646 * ensures that any XLOG record generated by nextval will hit the
647 * disk before we report the transaction committed.
649 * Note: if we generated a commit record above, MyXactMadeXLogEntry
650 * will certainly be set now.
652 if (MyXactMadeXLogEntry)
655 * Sleep before flush! So we can flush more than one commit
656 * records per single fsync. (The idea is some other backend
657 * may do the XLogFlush while we're sleeping. This needs work
658 * still, because on most Unixen, the minimum select() delay
659 * is 10msec or more, which is way too long.)
661 * We do not sleep if enableFsync is not turned on, nor if there
662 * are fewer than CommitSiblings other backends with active
665 if (CommitDelay > 0 && enableFsync &&
666 CountActiveBackends() >= CommitSiblings)
667 pg_usleep(CommitDelay);
673 * We must mark the transaction committed in clog if its XID
674 * appears either in permanent rels or in local temporary rels. We
675 * test this by seeing if we made transaction-controlled entries
676 * *OR* local-rel tuple updates. Note that if we made only the
677 * latter, we have not emitted an XLOG record for our commit, and
678 * so in the event of a crash the clog update might be lost. This
679 * is okay because no one else will ever care whether we
682 if (madeTCentries || MyXactMadeTempRelUpdate)
684 TransactionIdCommit(xid);
685 /* to avoid race conditions, the parent must commit first */
686 TransactionIdCommitTree(nchildren, children);
689 /* Unlock checkpoint lock if we acquired it */
691 LWLockRelease(CheckpointStartLock);
696 /* Break the chain of back-links in the XLOG records I output */
697 MyLastRecPtr.xrecoff = 0;
698 MyXactMadeXLogEntry = false;
699 MyXactMadeTempRelUpdate = false;
701 /* Show myself as out of the transaction in PGPROC array */
702 MyProc->logRec.xrecoff = 0;
704 /* And clean up local data */
713 * AtCommit_LocalCache
716 AtCommit_LocalCache(void)
719 * Make catalog changes visible to me for the next command.
721 CommandEndInvalidationMessages();
728 AtCommit_Memory(void)
731 * Now that we're "out" of a transaction, have the system allocate
732 * things in the top memory context instead of per-transaction
735 MemoryContextSwitchTo(TopMemoryContext);
738 * Release all transaction-local memory.
740 Assert(TopTransactionContext != NULL);
741 MemoryContextDelete(TopTransactionContext);
742 TopTransactionContext = NULL;
743 CurTransactionContext = NULL;
744 CurrentTransactionState->curTransactionContext = NULL;
747 /* ----------------------------------------------------------------
748 * CommitSubTransaction stuff
749 * ----------------------------------------------------------------
755 * We do not throw away the child's CurTransactionContext, since the data
756 * it contains will be needed at upper commit.
759 AtSubCommit_Memory(void)
761 TransactionState s = CurrentTransactionState;
763 Assert(s->parent != NULL);
765 /* Return to parent transaction level's memory context. */
766 CurTransactionContext = s->parent->curTransactionContext;
767 MemoryContextSwitchTo(CurTransactionContext);
771 * AtSubCommit_childXids
773 * Pass my own XID and my child XIDs up to my parent as committed children.
776 AtSubCommit_childXids(void)
778 TransactionState s = CurrentTransactionState;
779 MemoryContext old_cxt;
781 Assert(s->parent != NULL);
783 old_cxt = MemoryContextSwitchTo(s->parent->curTransactionContext);
785 s->parent->childXids = lappend_xid(s->parent->childXids,
786 s->transactionIdData);
788 s->parent->childXids = list_concat(s->parent->childXids, s->childXids);
789 s->childXids = NIL; /* ensure list not doubly referenced */
791 MemoryContextSwitchTo(old_cxt);
795 * RecordSubTransactionCommit
798 RecordSubTransactionCommit(void)
801 * We do not log the subcommit in XLOG; it doesn't matter until
802 * the top-level transaction commits.
804 * We must mark the subtransaction subcommitted in clog if its XID
805 * appears either in permanent rels or in local temporary rels. We
806 * test this by seeing if we made transaction-controlled entries
807 * *OR* local-rel tuple updates. (The test here actually covers the
808 * entire transaction tree so far, so it may mark subtransactions that
809 * don't really need it, but it's probably not worth being tenser.
810 * Note that if a prior subtransaction dirtied these variables, then
811 * RecordTransactionCommit will have to do the full pushup anyway...)
813 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
815 TransactionId xid = GetCurrentTransactionId();
817 /* XXX does this really need to be a critical section? */
818 START_CRIT_SECTION();
820 /* Record subtransaction subcommit */
821 TransactionIdSubCommit(xid);
827 /* ----------------------------------------------------------------
828 * AbortTransaction stuff
829 * ----------------------------------------------------------------
833 * RecordTransactionAbort
836 RecordTransactionAbort(void)
841 TransactionId *children;
843 /* Get data needed for abort record */
844 nrels = smgrGetPendingDeletes(false, &rptr);
845 nchildren = xactGetCommittedChildren(&children);
848 * If we made neither any transaction-controlled XLOG entries nor any
849 * temp-rel updates, and are not going to delete any files, we can omit
850 * recording the transaction abort at all. No one will ever care that
851 * it aborted. (These tests cover our whole transaction tree.)
853 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
855 TransactionId xid = GetCurrentTransactionId();
858 * Catch the scenario where we aborted partway through
859 * RecordTransactionCommit ...
861 if (TransactionIdDidCommit(xid))
862 elog(PANIC, "cannot abort transaction %u, it was already committed", xid);
864 START_CRIT_SECTION();
867 * We only need to log the abort in XLOG if the transaction made
868 * any transaction-controlled XLOG entries or will delete files.
869 * (If it made no transaction-controlled XLOG entries, its XID
870 * appears nowhere in permanent storage, so no one else will ever care
873 * We do not flush XLOG to disk unless deleting files, since the
874 * default assumption after a crash would be that we aborted, anyway.
875 * For the same reason, we don't need to worry about interlocking
876 * against checkpoint start.
878 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
880 XLogRecData rdata[3];
885 xlrec.xtime = time(NULL);
887 xlrec.nsubxacts = nchildren;
888 rdata[0].buffer = InvalidBuffer;
889 rdata[0].data = (char *) (&xlrec);
890 rdata[0].len = MinSizeOfXactAbort;
891 /* dump rels to delete */
894 rdata[0].next = &(rdata[1]);
895 rdata[1].buffer = InvalidBuffer;
896 rdata[1].data = (char *) rptr;
897 rdata[1].len = nrels * sizeof(RelFileNode);
900 /* dump committed child Xids */
903 rdata[lastrdata].next = &(rdata[2]);
904 rdata[2].buffer = InvalidBuffer;
905 rdata[2].data = (char *) children;
906 rdata[2].len = nchildren * sizeof(TransactionId);
909 rdata[lastrdata].next = NULL;
911 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
913 /* Must flush if we are deleting files... */
919 * Mark the transaction aborted in clog. This is not absolutely
920 * necessary but we may as well do it while we are here.
922 * The ordering here isn't critical but it seems best to mark the
923 * parent last. That reduces the chance that concurrent
924 * TransactionIdDidAbort calls will decide they need to do redundant
927 TransactionIdAbortTree(nchildren, children);
928 TransactionIdAbort(xid);
933 /* Break the chain of back-links in the XLOG records I output */
934 MyLastRecPtr.xrecoff = 0;
935 MyXactMadeXLogEntry = false;
936 MyXactMadeTempRelUpdate = false;
938 /* Show myself as out of the transaction in PGPROC array */
939 MyProc->logRec.xrecoff = 0;
941 /* And clean up local data */
955 * Make sure we are in a valid context (not a child of
956 * TopTransactionContext...). Note that it is possible for this code
957 * to be called when we aren't in a transaction at all; go directly to
958 * TopMemoryContext in that case.
960 if (TopTransactionContext != NULL)
962 MemoryContextSwitchTo(TopTransactionContext);
965 * We do not want to destroy the transaction's global state yet,
966 * so we can't free any memory here.
970 MemoryContextSwitchTo(TopMemoryContext);
978 AtSubAbort_Memory(void)
980 Assert(TopTransactionContext != NULL);
982 MemoryContextSwitchTo(TopTransactionContext);
986 * RecordSubTransactionAbort
989 RecordSubTransactionAbort(void)
993 TransactionId xid = GetCurrentTransactionId();
995 TransactionId *children;
997 /* Get data needed for abort record */
998 nrels = smgrGetPendingDeletes(false, &rptr);
999 nchildren = xactGetCommittedChildren(&children);
1002 * If we made neither any transaction-controlled XLOG entries nor any
1003 * temp-rel updates, and are not going to delete any files, we can omit
1004 * recording the transaction abort at all. No one will ever care that
1005 * it aborted. (These tests cover our whole transaction tree, and
1006 * therefore may mark subxacts that don't really need it, but it's
1007 * probably not worth being tenser.)
1009 * In this case we needn't worry about marking subcommitted children as
1010 * aborted, because they didn't mark themselves as subcommitted in the
1011 * first place; see the optimization in RecordSubTransactionCommit.
1013 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
1015 START_CRIT_SECTION();
1018 * We only need to log the abort in XLOG if the transaction made
1019 * any transaction-controlled XLOG entries or will delete files.
1021 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1023 XLogRecData rdata[3];
1025 xl_xact_abort xlrec;
1028 xlrec.xtime = time(NULL);
1029 xlrec.nrels = nrels;
1030 xlrec.nsubxacts = nchildren;
1031 rdata[0].buffer = InvalidBuffer;
1032 rdata[0].data = (char *) (&xlrec);
1033 rdata[0].len = MinSizeOfXactAbort;
1034 /* dump rels to delete */
1037 rdata[0].next = &(rdata[1]);
1038 rdata[1].buffer = InvalidBuffer;
1039 rdata[1].data = (char *) rptr;
1040 rdata[1].len = nrels * sizeof(RelFileNode);
1043 /* dump committed child Xids */
1046 rdata[lastrdata].next = &(rdata[2]);
1047 rdata[2].buffer = InvalidBuffer;
1048 rdata[2].data = (char *) children;
1049 rdata[2].len = nchildren * sizeof(TransactionId);
1052 rdata[lastrdata].next = NULL;
1054 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1056 /* Must flush if we are deleting files... */
1062 * Mark the transaction aborted in clog. This is not absolutely
1063 * necessary but we may as well do it while we are here.
1065 TransactionIdAbortTree(nchildren, children);
1066 TransactionIdAbort(xid);
1072 * We can immediately remove failed XIDs from PGPROC's cache of
1073 * running child XIDs. It's easiest to do it here while we have the
1074 * child XID array at hand, even though in the main-transaction
1075 * case the equivalent work happens just after return from
1076 * RecordTransactionAbort.
1078 XidCacheRemoveRunningXids(xid, nchildren, children);
1080 /* And clean up local data */
1087 /* ----------------------------------------------------------------
1088 * CleanupTransaction stuff
1089 * ----------------------------------------------------------------
1096 AtCleanup_Memory(void)
1099 * Now that we're "out" of a transaction, have the system allocate
1100 * things in the top memory context instead of per-transaction
1103 MemoryContextSwitchTo(TopMemoryContext);
1105 Assert(CurrentTransactionState->parent == NULL);
1108 * Release all transaction-local memory.
1110 if (TopTransactionContext != NULL)
1111 MemoryContextDelete(TopTransactionContext);
1112 TopTransactionContext = NULL;
1113 CurTransactionContext = NULL;
1114 CurrentTransactionState->curTransactionContext = NULL;
1118 /* ----------------------------------------------------------------
1119 * CleanupSubTransaction stuff
1120 * ----------------------------------------------------------------
1124 * AtSubCleanup_Memory
1127 AtSubCleanup_Memory(void)
1129 TransactionState s = CurrentTransactionState;
1131 Assert(s->parent != NULL);
1133 /* Make sure we're not in an about-to-be-deleted context */
1134 MemoryContextSwitchTo(s->parent->curTransactionContext);
1135 CurTransactionContext = s->parent->curTransactionContext;
1138 * Delete the subxact local memory contexts. Its CurTransactionContext
1139 * can go too (note this also kills CurTransactionContexts from any
1140 * children of the subxact).
1142 MemoryContextDelete(s->curTransactionContext);
1145 /* ----------------------------------------------------------------
1146 * interface routines
1147 * ----------------------------------------------------------------
1154 StartTransaction(void)
1156 TransactionState s = CurrentTransactionState;
1159 * check the current transaction state
1161 if (s->state != TRANS_DEFAULT)
1162 elog(WARNING, "StartTransaction while in %s state",
1163 TransStateAsString(s->state));
1166 * set the current transaction state information appropriately during
1169 s->state = TRANS_START;
1172 * Make sure we've freed any old snapshot, and reset xact state variables
1175 XactIsoLevel = DefaultXactIsoLevel;
1176 XactReadOnly = DefaultXactReadOnly;
1179 * must initialize resource-management stuff first
1182 AtStart_ResourceOwner();
1185 * generate a new transaction id
1187 s->transactionIdData = GetNewTransactionId(false);
1189 XactLockTableInsert(s->transactionIdData);
1194 xactStartTime = GetCurrentAbsoluteTimeUsec(&(xactStartTimeUsec));
1197 * initialize current transaction state fields
1199 s->commandId = FirstCommandId;
1200 s->nestingLevel = 1;
1204 * You might expect to see "s->currentUser = GetUserId();" here, but
1205 * you won't because it doesn't work during startup; the userid isn't
1206 * set yet during a backend's first transaction start. We only use
1207 * the currentUser field in sub-transaction state structs.
1209 * prevXactReadOnly is also valid only in sub-transactions.
1213 * initialize other subsystems for new transaction
1217 DeferredTriggerBeginXact();
1220 * done with start processing, set current transaction state to "in
1223 s->state = TRANS_INPROGRESS;
1225 ShowTransactionState("StartTransaction");
1232 CommitTransaction(void)
1234 TransactionState s = CurrentTransactionState;
1236 ShowTransactionState("CommitTransaction");
1239 * check the current transaction state
1241 if (s->state != TRANS_INPROGRESS)
1242 elog(WARNING, "CommitTransaction while in %s state",
1243 TransStateAsString(s->state));
1244 Assert(s->parent == NULL);
1247 * Tell the trigger manager that this transaction is about to be
1248 * committed. He'll invoke all trigger deferred until XACT before we
1249 * really start on committing the transaction.
1251 DeferredTriggerEndXact();
1254 * Similarly, let ON COMMIT management do its thing before we start to
1257 PreCommit_on_commit_actions();
1259 /* Prevent cancel/die interrupt while cleaning up */
1263 * set the current transaction state information appropriately during
1264 * the abort processing
1266 s->state = TRANS_COMMIT;
1269 * Do pre-commit processing (most of this stuff requires database
1270 * access, and in fact could still cause an error...)
1275 /* close large objects before lower-level cleanup */
1276 AtEOXact_LargeObject(true);
1278 /* NOTIFY commit must come before lower-level cleanup */
1281 /* Update the flat password file if we changed pg_shadow or pg_group */
1282 /* This should be the last step before commit */
1283 AtEOXact_UpdatePasswordFile(true);
1286 * Here is where we really truly commit.
1288 RecordTransactionCommit();
1291 * Let others know about no transaction in progress by me. Note that
1292 * this must be done _before_ releasing locks we hold and _after_
1293 * RecordTransactionCommit.
1295 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
1296 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
1297 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
1298 * as running as well or it will see two tuple versions - one deleted
1299 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
1303 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1304 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1305 MyProc->xid = InvalidTransactionId;
1306 MyProc->xmin = InvalidTransactionId;
1308 /* Clear the subtransaction-XID cache too while holding the lock */
1309 MyProc->subxids.nxids = 0;
1310 MyProc->subxids.overflowed = false;
1312 LWLockRelease(SInvalLock);
1316 * This is all post-commit cleanup. Note that if an error is raised
1317 * here, it's too late to abort the transaction. This should be just
1318 * noncritical resource releasing.
1320 * The ordering of operations is not entirely random. The idea is:
1321 * release resources visible to other backends (eg, files, buffer
1322 * pins); then release locks; then release backend-local resources. We
1323 * want to release locks at the point where any backend waiting for us
1324 * will see our transaction as being fully cleaned up.
1326 * Resources that can be associated with individual queries are
1327 * handled by the ResourceOwner mechanism. The other calls here
1328 * are for backend-wide state.
1331 smgrDoPendingDeletes(true);
1332 /* smgrcommit already done */
1334 CallXactCallbacks(XACT_EVENT_COMMIT, InvalidTransactionId);
1336 ResourceOwnerRelease(TopTransactionResourceOwner,
1337 RESOURCE_RELEASE_BEFORE_LOCKS,
1341 * Make catalog changes visible to all backends. This has to happen
1342 * after relcache references are dropped (see comments for
1343 * AtEOXact_RelationCache), but before locks are released (if anyone
1344 * is waiting for lock on a relation we've modified, we want them to
1345 * know about the catalog change before they start using the relation).
1347 AtEOXact_Inval(true);
1349 ResourceOwnerRelease(TopTransactionResourceOwner,
1350 RESOURCE_RELEASE_LOCKS,
1352 ResourceOwnerRelease(TopTransactionResourceOwner,
1353 RESOURCE_RELEASE_AFTER_LOCKS,
1356 AtEOXact_GUC(true, false);
1358 AtEOXact_on_commit_actions(true, s->transactionIdData);
1359 AtEOXact_Namespace(true);
1361 pgstat_count_xact_commit();
1363 CurrentResourceOwner = NULL;
1364 ResourceOwnerDelete(TopTransactionResourceOwner);
1365 s->curTransactionOwner = NULL;
1366 CurTransactionResourceOwner = NULL;
1367 TopTransactionResourceOwner = NULL;
1371 s->nestingLevel = 0;
1375 * done with commit processing, set current transaction state back to
1378 s->state = TRANS_DEFAULT;
1380 RESUME_INTERRUPTS();
1387 AbortTransaction(void)
1389 TransactionState s = CurrentTransactionState;
1391 /* Prevent cancel/die interrupt while cleaning up */
1395 * Release any LW locks we might be holding as quickly as possible.
1396 * (Regular locks, however, must be held till we finish aborting.)
1397 * Releasing LW locks is critical since we might try to grab them
1398 * again while cleaning up!
1402 /* Clean up buffer I/O and buffer context locks, too */
1407 * Also clean up any open wait for lock, since the lock manager will
1408 * choke if we try to wait for another lock before doing this.
1413 * check the current transaction state
1415 if (s->state != TRANS_INPROGRESS)
1416 elog(WARNING, "AbortTransaction while in %s state",
1417 TransStateAsString(s->state));
1418 Assert(s->parent == NULL);
1421 * set the current transaction state information appropriately during
1422 * the abort processing
1424 s->state = TRANS_ABORT;
1426 /* Make sure we are in a valid memory context */
1430 * Reset user id which might have been changed transiently. We cannot
1431 * use s->currentUser, but must get the session userid from miscinit.c.
1433 * (Note: it is not necessary to restore session authorization here
1434 * because that can only be changed via GUC, and GUC will take care of
1435 * rolling it back if need be. However, an error within a SECURITY
1436 * DEFINER function could send control here with the wrong current
1439 SetUserId(GetSessionUserId());
1442 * do abort processing
1444 DeferredTriggerAbortXact();
1446 AtEOXact_LargeObject(false); /* 'false' means it's abort */
1448 AtEOXact_UpdatePasswordFile(false);
1450 /* Advertise the fact that we aborted in pg_clog. */
1451 RecordTransactionAbort();
1454 * Let others know about no transaction in progress by me. Note that
1455 * this must be done _before_ releasing locks we hold and _after_
1456 * RecordTransactionAbort.
1460 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1461 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1462 MyProc->xid = InvalidTransactionId;
1463 MyProc->xmin = InvalidTransactionId;
1465 /* Clear the subtransaction-XID cache too while holding the lock */
1466 MyProc->subxids.nxids = 0;
1467 MyProc->subxids.overflowed = false;
1469 LWLockRelease(SInvalLock);
1473 * Post-abort cleanup. See notes in CommitTransaction() concerning
1477 smgrDoPendingDeletes(false);
1480 CallXactCallbacks(XACT_EVENT_ABORT, InvalidTransactionId);
1482 ResourceOwnerRelease(TopTransactionResourceOwner,
1483 RESOURCE_RELEASE_BEFORE_LOCKS,
1485 AtEOXact_Inval(false);
1486 ResourceOwnerRelease(TopTransactionResourceOwner,
1487 RESOURCE_RELEASE_LOCKS,
1489 ResourceOwnerRelease(TopTransactionResourceOwner,
1490 RESOURCE_RELEASE_AFTER_LOCKS,
1493 AtEOXact_GUC(false, false);
1494 AtEOXact_SPI(false);
1495 AtEOXact_on_commit_actions(false, s->transactionIdData);
1496 AtEOXact_Namespace(false);
1498 pgstat_count_xact_rollback();
1501 * State remains TRANS_ABORT until CleanupTransaction().
1503 RESUME_INTERRUPTS();
1507 * CleanupTransaction
1510 CleanupTransaction(void)
1512 TransactionState s = CurrentTransactionState;
1515 * State should still be TRANS_ABORT from AbortTransaction().
1517 if (s->state != TRANS_ABORT)
1518 elog(FATAL, "CleanupTransaction: unexpected state %s",
1519 TransStateAsString(s->state));
1522 * do abort cleanup processing
1524 AtCleanup_Portals(); /* now safe to release portal memory */
1526 CurrentResourceOwner = NULL; /* and resource owner */
1527 ResourceOwnerDelete(TopTransactionResourceOwner);
1528 s->curTransactionOwner = NULL;
1529 CurTransactionResourceOwner = NULL;
1530 TopTransactionResourceOwner = NULL;
1532 AtCleanup_Memory(); /* and transaction memory */
1534 s->nestingLevel = 0;
1538 * done with abort processing, set current transaction state back to
1541 s->state = TRANS_DEFAULT;
1545 * StartTransactionCommand
1548 StartTransactionCommand(void)
1550 TransactionState s = CurrentTransactionState;
1552 switch (s->blockState)
1555 * if we aren't in a transaction block, we just do our usual
1556 * start transaction.
1558 case TBLOCK_DEFAULT:
1560 s->blockState = TBLOCK_STARTED;
1564 * This is the case when we are somewhere in a transaction block
1565 * and about to start a new command. For now we do nothing
1566 * but someday we may do command-local resource initialization.
1568 case TBLOCK_INPROGRESS:
1569 case TBLOCK_SUBINPROGRESS:
1573 * Here we are in the middle of a transaction block but one of
1574 * the commands caused an abort so we do nothing but remain in
1575 * the abort state. Eventually we will get to the "END
1576 * TRANSACTION" which will set things straight.
1579 case TBLOCK_SUBABORT:
1582 /* These cases are invalid. */
1583 case TBLOCK_STARTED:
1585 case TBLOCK_SUBBEGIN:
1588 case TBLOCK_SUBENDABORT_ALL:
1589 case TBLOCK_SUBENDABORT:
1590 case TBLOCK_SUBABORT_PENDING:
1591 case TBLOCK_SUBENDABORT_RELEASE:
1592 case TBLOCK_ENDABORT:
1593 elog(FATAL, "StartTransactionCommand: unexpected state %s",
1594 BlockStateAsString(s->blockState));
1599 * We must switch to CurTransactionContext before returning. This is
1600 * already done if we called StartTransaction, otherwise not.
1602 Assert(CurTransactionContext != NULL);
1603 MemoryContextSwitchTo(CurTransactionContext);
1607 * CommitTransactionCommand
1610 CommitTransactionCommand(void)
1612 TransactionState s = CurrentTransactionState;
1614 switch (s->blockState)
1617 * This shouldn't happen, because it means the previous
1618 * StartTransactionCommand didn't set the STARTED state
1619 * appropriately, or we didn't manage previous pending
1622 case TBLOCK_DEFAULT:
1623 case TBLOCK_SUBABORT_PENDING:
1624 elog(FATAL, "CommitTransactionCommand: unexpected state %s",
1625 BlockStateAsString(s->blockState));
1629 * If we aren't in a transaction block, just do our usual
1630 * transaction commit.
1632 case TBLOCK_STARTED:
1633 CommitTransaction();
1634 s->blockState = TBLOCK_DEFAULT;
1638 * This is the case right after we get a "BEGIN TRANSACTION"
1639 * command, but the user hasn't done anything else yet, so we
1640 * change to the "transaction block in progress" state and
1644 s->blockState = TBLOCK_INPROGRESS;
1648 * This is the case when we have finished executing a command
1649 * someplace within a transaction block. We increment the
1650 * command counter and return.
1652 case TBLOCK_INPROGRESS:
1653 CommandCounterIncrement();
1657 * This is the case when we just got the "END TRANSACTION"
1658 * statement, so we commit the transaction and go back to the
1662 /* commit all open subtransactions */
1663 if (s->nestingLevel > 1)
1664 CommitTransactionToLevel(2);
1665 s = CurrentTransactionState;
1666 Assert(s->parent == NULL);
1667 /* and now the outer transaction */
1668 CommitTransaction();
1669 s->blockState = TBLOCK_DEFAULT;
1673 * Here we are in the middle of a transaction block but one of
1674 * the commands caused an abort so we do nothing but remain in
1675 * the abort state. Eventually we will get to the "END
1676 * TRANSACTION" which will set things straight.
1682 * Here we were in an aborted transaction block which just
1683 * processed the "END TRANSACTION" command from the user, so
1684 * clean up and return to the default state.
1686 case TBLOCK_ENDABORT:
1687 CleanupTransaction();
1688 s->blockState = TBLOCK_DEFAULT;
1692 * Ditto, but in a subtransaction. AbortOutOfAnyTransaction
1693 * will do the dirty work.
1695 case TBLOCK_SUBENDABORT_ALL:
1696 AbortOutOfAnyTransaction();
1697 s = CurrentTransactionState; /* changed by AbortOutOfAnyTransaction */
1698 /* AbortOutOfAnyTransaction sets the blockState */
1702 * We were just issued a SAVEPOINT inside a transaction block.
1703 * Start a subtransaction. (DefineSavepoint already
1704 * did PushTransaction, so as to have someplace to put the
1707 case TBLOCK_SUBBEGIN:
1708 StartSubTransaction();
1709 s->blockState = TBLOCK_SUBINPROGRESS;
1713 * Inside a subtransaction, increment the command counter.
1715 case TBLOCK_SUBINPROGRESS:
1716 CommandCounterIncrement();
1720 * We were issued a RELEASE command, so we end the current
1721 * subtransaction and return to the parent transaction.
1723 * Since RELEASE can exit multiple levels of subtransaction,
1724 * we must loop here until we get out of all SUBEND'ed levels.
1728 CommitSubTransaction();
1730 s = CurrentTransactionState; /* changed by pop */
1731 } while (s->blockState == TBLOCK_SUBEND);
1735 * If we are in an aborted subtransaction, do nothing.
1737 case TBLOCK_SUBABORT:
1741 * The current subtransaction is ending. Do the equivalent
1742 * of a ROLLBACK TO followed by a RELEASE command.
1744 case TBLOCK_SUBENDABORT_RELEASE:
1745 CleanupAbortedSubTransactions(false);
1749 * The current subtransaction is ending due to a ROLLBACK
1750 * TO command, so close all savepoints up to the target
1751 * level. When finished, recreate the savepoint.
1753 case TBLOCK_SUBENDABORT:
1755 char *name = CleanupAbortedSubTransactions(true);
1757 Assert(PointerIsValid(name));
1758 DefineSavepoint(name);
1759 s = CurrentTransactionState; /* changed by DefineSavepoint */
1762 /* This is the same as TBLOCK_SUBBEGIN case */
1763 AssertState(s->blockState == TBLOCK_SUBBEGIN);
1764 StartSubTransaction();
1765 s->blockState = TBLOCK_SUBINPROGRESS;
1772 * CleanupAbortedSubTransactions
1774 * Helper function for CommitTransactionCommand. Aborts and cleans up
1775 * dead subtransactions after a ROLLBACK TO command. Optionally returns
1776 * the name of the last dead subtransaction so it can be reused to redefine
1777 * the savepoint. (Caller is responsible for pfree'ing the result.)
1780 CleanupAbortedSubTransactions(bool returnName)
1782 TransactionState s = CurrentTransactionState;
1785 AssertState(PointerIsValid(s->parent));
1786 Assert(s->parent->blockState == TBLOCK_SUBINPROGRESS ||
1787 s->parent->blockState == TBLOCK_INPROGRESS ||
1788 s->parent->blockState == TBLOCK_STARTED ||
1789 s->parent->blockState == TBLOCK_SUBABORT_PENDING);
1792 * Abort everything up to the target level. The current
1793 * subtransaction only needs cleanup. If we need to save the name,
1794 * look for the last subtransaction in TBLOCK_SUBABORT_PENDING state.
1796 if (returnName && s->parent->blockState != TBLOCK_SUBABORT_PENDING)
1797 name = MemoryContextStrdup(TopMemoryContext, s->name);
1799 CleanupSubTransaction();
1801 s = CurrentTransactionState; /* changed by pop */
1803 while (s->blockState == TBLOCK_SUBABORT_PENDING)
1805 AbortSubTransaction();
1806 if (returnName && s->parent->blockState != TBLOCK_SUBABORT_PENDING)
1807 name = MemoryContextStrdup(TopMemoryContext, s->name);
1808 CleanupSubTransaction();
1810 s = CurrentTransactionState;
1813 AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
1814 s->blockState == TBLOCK_INPROGRESS ||
1815 s->blockState == TBLOCK_STARTED);
1821 * AbortCurrentTransaction
1824 AbortCurrentTransaction(void)
1826 TransactionState s = CurrentTransactionState;
1828 switch (s->blockState)
1831 * we aren't in a transaction, so we do nothing.
1833 case TBLOCK_DEFAULT:
1837 * if we aren't in a transaction block, we just do the basic
1838 * abort & cleanup transaction.
1840 case TBLOCK_STARTED:
1842 CleanupTransaction();
1843 s->blockState = TBLOCK_DEFAULT;
1847 * If we are in TBLOCK_BEGIN it means something screwed up
1848 * right after reading "BEGIN TRANSACTION" so we enter the
1849 * abort state. Eventually an "END TRANSACTION" will fix
1854 s->blockState = TBLOCK_ABORT;
1855 /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
1859 * This is the case when we are somewhere in a transaction block
1860 * and we've gotten a failure, so we abort the transaction and
1861 * set up the persistent ABORT state. We will stay in ABORT
1862 * until we get an "END TRANSACTION".
1864 case TBLOCK_INPROGRESS:
1866 s->blockState = TBLOCK_ABORT;
1867 /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
1871 * Here, the system was fouled up just after the user wanted
1872 * to end the transaction block so we abort the transaction
1873 * and return to the default state.
1877 CleanupTransaction();
1878 s->blockState = TBLOCK_DEFAULT;
1882 * Here, we are already in an aborted transaction state and
1883 * are waiting for an "END TRANSACTION" to come along and lo
1884 * and behold, we abort again! So we just remain in the abort
1888 case TBLOCK_SUBABORT:
1892 * Here we were in an aborted transaction block which just
1893 * processed the "END TRANSACTION" command but somehow aborted
1894 * again.. since we must have done the abort processing, we
1895 * clean up and return to the default state.
1897 case TBLOCK_ENDABORT:
1898 CleanupTransaction();
1899 s->blockState = TBLOCK_DEFAULT;
1903 * If we are just starting a subtransaction, put it
1906 case TBLOCK_SUBBEGIN:
1907 StartAbortedSubTransaction();
1908 s->blockState = TBLOCK_SUBABORT;
1911 case TBLOCK_SUBINPROGRESS:
1912 AbortSubTransaction();
1913 s->blockState = TBLOCK_SUBABORT;
1917 * If we are aborting an ending transaction,
1918 * we have to abort the parent transaction too.
1921 case TBLOCK_SUBABORT_PENDING:
1922 AbortSubTransaction();
1923 CleanupSubTransaction();
1925 s = CurrentTransactionState; /* changed by pop */
1926 Assert(s->blockState != TBLOCK_SUBEND &&
1927 s->blockState != TBLOCK_SUBENDABORT);
1928 AbortCurrentTransaction();
1932 * Same as above, except the Abort() was already done.
1934 case TBLOCK_SUBENDABORT:
1935 case TBLOCK_SUBENDABORT_RELEASE:
1936 CleanupSubTransaction();
1938 s = CurrentTransactionState; /* changed by pop */
1939 Assert(s->blockState != TBLOCK_SUBEND &&
1940 s->blockState != TBLOCK_SUBENDABORT);
1941 AbortCurrentTransaction();
1945 * We are already aborting the whole transaction tree.
1946 * Do nothing, CommitTransactionCommand will call
1947 * AbortOutOfAnyTransaction and set things straight.
1949 case TBLOCK_SUBENDABORT_ALL:
1955 * PreventTransactionChain
1957 * This routine is to be called by statements that must not run inside
1958 * a transaction block, typically because they have non-rollback-able
1959 * side effects or do internal commits.
1961 * If we have already started a transaction block, issue an error; also issue
1962 * an error if we appear to be running inside a user-defined function (which
1963 * could issue more commands and possibly cause a failure after the statement
1964 * completes). Subtransactions are verboten too.
1966 * stmtNode: pointer to parameter block for statement; this is used in
1967 * a very klugy way to determine whether we are inside a function.
1968 * stmtType: statement type name for error messages.
1971 PreventTransactionChain(void *stmtNode, const char *stmtType)
1974 * xact block already started?
1976 if (IsTransactionBlock())
1978 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1979 /* translator: %s represents an SQL statement name */
1980 errmsg("%s cannot run inside a transaction block",
1986 if (IsSubTransaction())
1988 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1989 /* translator: %s represents an SQL statement name */
1990 errmsg("%s cannot run inside a subtransaction",
1994 * Are we inside a function call? If the statement's parameter block
1995 * was allocated in QueryContext, assume it is an interactive command.
1996 * Otherwise assume it is coming from a function.
1998 if (!MemoryContextContains(QueryContext, stmtNode))
2000 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2001 /* translator: %s represents an SQL statement name */
2002 errmsg("%s cannot be executed from a function", stmtType)));
2004 /* If we got past IsTransactionBlock test, should be in default state */
2005 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2006 CurrentTransactionState->blockState != TBLOCK_STARTED)
2007 elog(FATAL, "cannot prevent transaction chain");
2012 * RequireTransactionChain
2014 * This routine is to be called by statements that must run inside
2015 * a transaction block, because they have no effects that persist past
2016 * transaction end (and so calling them outside a transaction block
2017 * is presumably an error). DECLARE CURSOR is an example.
2019 * If we appear to be running inside a user-defined function, we do not
2020 * issue an error, since the function could issue more commands that make
2021 * use of the current statement's results. Likewise subtransactions.
2022 * Thus this is an inverse for PreventTransactionChain.
2024 * stmtNode: pointer to parameter block for statement; this is used in
2025 * a very klugy way to determine whether we are inside a function.
2026 * stmtType: statement type name for error messages.
2029 RequireTransactionChain(void *stmtNode, const char *stmtType)
2032 * xact block already started?
2034 if (IsTransactionBlock())
2040 if (IsSubTransaction())
2044 * Are we inside a function call? If the statement's parameter block
2045 * was allocated in QueryContext, assume it is an interactive command.
2046 * Otherwise assume it is coming from a function.
2048 if (!MemoryContextContains(QueryContext, stmtNode))
2051 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2052 /* translator: %s represents an SQL statement name */
2053 errmsg("%s may only be used in transaction blocks",
2058 * IsInTransactionChain
2060 * This routine is for statements that need to behave differently inside
2061 * a transaction block than when running as single commands. ANALYZE is
2062 * currently the only example.
2064 * stmtNode: pointer to parameter block for statement; this is used in
2065 * a very klugy way to determine whether we are inside a function.
2068 IsInTransactionChain(void *stmtNode)
2071 * Return true on same conditions that would make PreventTransactionChain
2074 if (IsTransactionBlock())
2077 if (IsSubTransaction())
2080 if (!MemoryContextContains(QueryContext, stmtNode))
2083 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2084 CurrentTransactionState->blockState != TBLOCK_STARTED)
2092 * Register or deregister callback functions for start- and end-of-xact
2095 * These functions are intended for use by dynamically loaded modules.
2096 * For built-in modules we generally just hardwire the appropriate calls
2097 * (mainly because it's easier to control the order that way, where needed).
2099 * At transaction end, the callback occurs post-commit or post-abort, so the
2100 * callback functions can only do noncritical cleanup. At subtransaction
2101 * start, the callback is called when the subtransaction has finished
2105 RegisterXactCallback(XactCallback callback, void *arg)
2107 XactCallbackItem *item;
2109 item = (XactCallbackItem *)
2110 MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
2111 item->callback = callback;
2113 item->next = Xact_callbacks;
2114 Xact_callbacks = item;
2118 UnregisterXactCallback(XactCallback callback, void *arg)
2120 XactCallbackItem *item;
2121 XactCallbackItem *prev;
2124 for (item = Xact_callbacks; item; prev = item, item = item->next)
2126 if (item->callback == callback && item->arg == arg)
2129 prev->next = item->next;
2131 Xact_callbacks = item->next;
2139 CallXactCallbacks(XactEvent event, TransactionId parentXid)
2141 XactCallbackItem *item;
2143 for (item = Xact_callbacks; item; item = item->next)
2145 (*item->callback) (event, parentXid, item->arg);
2150 /* ----------------------------------------------------------------
2151 * transaction block support
2152 * ----------------------------------------------------------------
2156 * BeginTransactionBlock
2157 * This executes a BEGIN command.
2160 BeginTransactionBlock(void)
2162 TransactionState s = CurrentTransactionState;
2164 switch (s->blockState)
2167 * We are not inside a transaction block, so allow one
2170 case TBLOCK_STARTED:
2171 s->blockState = TBLOCK_BEGIN;
2175 * Already a transaction block in progress.
2177 case TBLOCK_INPROGRESS:
2178 case TBLOCK_SUBINPROGRESS:
2180 case TBLOCK_SUBABORT:
2182 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2183 errmsg("there is already a transaction in progress")));
2186 /* These cases are invalid. Reject them altogether. */
2187 case TBLOCK_DEFAULT:
2189 case TBLOCK_SUBBEGIN:
2190 case TBLOCK_ENDABORT:
2192 case TBLOCK_SUBENDABORT_ALL:
2193 case TBLOCK_SUBENDABORT:
2194 case TBLOCK_SUBABORT_PENDING:
2195 case TBLOCK_SUBENDABORT_RELEASE:
2197 elog(FATAL, "BeginTransactionBlock: unexpected state %s",
2198 BlockStateAsString(s->blockState));
2204 * EndTransactionBlock
2205 * This executes a COMMIT command.
2207 * Since COMMIT may actually do a ROLLBACK, the result indicates what
2208 * happened: TRUE for COMMIT, FALSE for ROLLBACK.
2211 EndTransactionBlock(void)
2213 TransactionState s = CurrentTransactionState;
2214 bool result = false;
2216 switch (s->blockState)
2219 * We are in a transaction block which should commit when we
2220 * get to the upcoming CommitTransactionCommand() so we set the
2221 * state to "END". CommitTransactionCommand() will recognize this
2222 * and commit the transaction and return us to the default state.
2224 case TBLOCK_INPROGRESS:
2225 case TBLOCK_SUBINPROGRESS:
2226 s->blockState = TBLOCK_END;
2231 * We are in a transaction block which aborted. Since the
2232 * AbortTransaction() was already done, we need only
2233 * change to the special "END ABORT" state. The upcoming
2234 * CommitTransactionCommand() will recognise this and then put us
2235 * back in the default state.
2238 s->blockState = TBLOCK_ENDABORT;
2242 * Here we are inside an aborted subtransaction. Go to the "abort
2243 * the whole tree" state so that CommitTransactionCommand() calls
2244 * AbortOutOfAnyTransaction.
2246 case TBLOCK_SUBABORT:
2247 s->blockState = TBLOCK_SUBENDABORT_ALL;
2250 case TBLOCK_STARTED:
2252 * here, the user issued COMMIT when not inside a
2253 * transaction. Issue a WARNING and go to abort state. The
2254 * upcoming call to CommitTransactionCommand() will then put us
2255 * back into the default state.
2258 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2259 errmsg("there is no transaction in progress")));
2261 s->blockState = TBLOCK_ENDABORT;
2264 /* these cases are invalid. */
2265 case TBLOCK_DEFAULT:
2267 case TBLOCK_ENDABORT:
2269 case TBLOCK_SUBBEGIN:
2271 case TBLOCK_SUBENDABORT_ALL:
2272 case TBLOCK_SUBENDABORT:
2273 case TBLOCK_SUBABORT_PENDING:
2274 case TBLOCK_SUBENDABORT_RELEASE:
2275 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2276 BlockStateAsString(s->blockState));
2284 * UserAbortTransactionBlock
2285 * This executes a ROLLBACK command.
2288 UserAbortTransactionBlock(void)
2290 TransactionState s = CurrentTransactionState;
2292 switch (s->blockState)
2295 * We are inside a failed transaction block and we got an
2296 * abort command from the user. Abort processing is already
2297 * done, we just need to move to the ENDABORT state so we will
2298 * end up in the default state after the upcoming
2299 * CommitTransactionCommand().
2302 s->blockState = TBLOCK_ENDABORT;
2306 * We are inside a failed subtransaction and we got an
2307 * abort command from the user. Abort processing is already
2308 * done, so go to the "abort all" state and
2309 * CommitTransactionCommand will call AbortOutOfAnyTransaction
2310 * to set things straight.
2312 case TBLOCK_SUBABORT:
2313 s->blockState = TBLOCK_SUBENDABORT_ALL;
2317 * We are inside a transaction block and we got an abort
2318 * command from the user, so we move to the ENDABORT state and
2319 * do abort processing so we will end up in the default state
2320 * after the upcoming CommitTransactionCommand().
2322 case TBLOCK_INPROGRESS:
2324 s->blockState = TBLOCK_ENDABORT;
2328 * We are inside a subtransaction. Abort the current
2329 * subtransaction and go to the "abort all" state, so
2330 * CommitTransactionCommand will call AbortOutOfAnyTransaction
2331 * to set things straight.
2333 case TBLOCK_SUBINPROGRESS:
2334 AbortSubTransaction();
2335 s->blockState = TBLOCK_SUBENDABORT_ALL;
2339 * The user issued ABORT when not inside a transaction. Issue
2340 * a WARNING and go to abort state. The upcoming call to
2341 * CommitTransactionCommand() will then put us back into the
2344 case TBLOCK_STARTED:
2346 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2347 errmsg("there is no transaction in progress")));
2349 s->blockState = TBLOCK_ENDABORT;
2352 /* These cases are invalid. */
2353 case TBLOCK_DEFAULT:
2356 case TBLOCK_ENDABORT:
2358 case TBLOCK_SUBENDABORT_ALL:
2359 case TBLOCK_SUBENDABORT:
2360 case TBLOCK_SUBABORT_PENDING:
2361 case TBLOCK_SUBENDABORT_RELEASE:
2362 case TBLOCK_SUBBEGIN:
2363 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2364 BlockStateAsString(s->blockState));
2371 * This executes a SAVEPOINT command.
2374 DefineSavepoint(char *name)
2376 TransactionState s = CurrentTransactionState;
2378 switch (s->blockState)
2380 case TBLOCK_INPROGRESS:
2381 case TBLOCK_SUBINPROGRESS:
2382 /* Normal subtransaction start */
2384 s = CurrentTransactionState; /* changed by push */
2386 * Note that we are allocating the savepoint name in the
2387 * parent transaction's CurTransactionContext, since we
2388 * don't yet have a transaction context for the new guy.
2390 s->name = MemoryContextStrdup(CurTransactionContext, name);
2391 s->blockState = TBLOCK_SUBBEGIN;
2394 /* These cases are invalid. Reject them altogether. */
2395 case TBLOCK_DEFAULT:
2396 case TBLOCK_STARTED:
2398 case TBLOCK_SUBBEGIN:
2400 case TBLOCK_SUBABORT:
2401 case TBLOCK_ENDABORT:
2403 case TBLOCK_SUBENDABORT_ALL:
2404 case TBLOCK_SUBENDABORT:
2405 case TBLOCK_SUBABORT_PENDING:
2406 case TBLOCK_SUBENDABORT_RELEASE:
2408 elog(FATAL, "DefineSavepoint: unexpected state %s",
2409 BlockStateAsString(s->blockState));
2416 * This executes a RELEASE command.
2419 ReleaseSavepoint(List *options)
2421 TransactionState s = CurrentTransactionState;
2422 TransactionState target,
2428 * Check valid block state transaction status.
2430 switch (s->blockState)
2432 case TBLOCK_INPROGRESS:
2435 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2436 errmsg("no such savepoint")));
2440 * We are in a non-aborted subtransaction. This is
2441 * the only valid case.
2443 case TBLOCK_SUBINPROGRESS:
2446 /* these cases are invalid. */
2447 case TBLOCK_DEFAULT:
2448 case TBLOCK_STARTED:
2450 case TBLOCK_ENDABORT:
2452 case TBLOCK_SUBABORT:
2453 case TBLOCK_SUBBEGIN:
2455 case TBLOCK_SUBENDABORT_ALL:
2456 case TBLOCK_SUBENDABORT:
2457 case TBLOCK_SUBABORT_PENDING:
2458 case TBLOCK_SUBENDABORT_RELEASE:
2459 elog(FATAL, "ReleaseSavepoint: unexpected state %s",
2460 BlockStateAsString(s->blockState));
2464 foreach (cell, options)
2466 DefElem *elem = lfirst(cell);
2468 if (strcmp(elem->defname, "savepoint_name") == 0)
2469 name = strVal(elem->arg);
2472 Assert(PointerIsValid(name));
2474 for (target = s; PointerIsValid(target); target = target->parent)
2476 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2480 if (!PointerIsValid(target))
2482 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2483 errmsg("no such savepoint")));
2485 /* disallow crossing savepoint level boundaries */
2486 if (target->savepointLevel != s->savepointLevel)
2488 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2489 errmsg("no such savepoint")));
2492 * Mark "commit pending" all subtransactions up to the target
2493 * subtransaction. The actual commits will happen when control
2494 * gets to CommitTransactionCommand.
2496 xact = CurrentTransactionState;
2499 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2500 xact->blockState = TBLOCK_SUBEND;
2503 xact = xact->parent;
2504 Assert(PointerIsValid(xact));
2509 * RollbackToSavepoint
2510 * This executes a ROLLBACK TO <savepoint> command.
2513 RollbackToSavepoint(List *options)
2515 TransactionState s = CurrentTransactionState;
2516 TransactionState target,
2521 switch (s->blockState)
2524 * We can't rollback to a savepoint if there is no saveopint
2528 case TBLOCK_INPROGRESS:
2530 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2531 errmsg("no such savepoint")));
2535 * There is at least one savepoint, so proceed.
2537 case TBLOCK_SUBABORT:
2538 case TBLOCK_SUBINPROGRESS:
2540 * Have to do AbortSubTransaction, but first check
2541 * if this is the right subtransaction
2545 /* these cases are invalid. */
2546 case TBLOCK_DEFAULT:
2547 case TBLOCK_STARTED:
2550 case TBLOCK_ENDABORT:
2552 case TBLOCK_SUBENDABORT_ALL:
2553 case TBLOCK_SUBENDABORT:
2554 case TBLOCK_SUBABORT_PENDING:
2555 case TBLOCK_SUBENDABORT_RELEASE:
2556 case TBLOCK_SUBBEGIN:
2557 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2558 BlockStateAsString(s->blockState));
2562 foreach (cell, options)
2564 DefElem *elem = lfirst(cell);
2566 if (strcmp(elem->defname, "savepoint_name") == 0)
2567 name = strVal(elem->arg);
2570 Assert(PointerIsValid(name));
2572 for (target = s; PointerIsValid(target); target = target->parent)
2574 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2578 if (!PointerIsValid(target))
2580 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2581 errmsg("no such savepoint")));
2583 /* disallow crossing savepoint level boundaries */
2584 if (target->savepointLevel != s->savepointLevel)
2586 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2587 errmsg("no such savepoint")));
2590 * Abort the current subtransaction, if needed. We can't Cleanup the
2591 * savepoint yet, so signal CommitTransactionCommand to do it and
2592 * close all savepoints up to the target level.
2594 if (s->blockState == TBLOCK_SUBINPROGRESS)
2595 AbortSubTransaction();
2596 s->blockState = TBLOCK_SUBENDABORT;
2599 * Mark "abort pending" all subtransactions up to the target
2600 * subtransaction. (Except the current subtransaction!)
2602 xact = CurrentTransactionState;
2604 while (xact != target)
2606 xact = xact->parent;
2607 Assert(PointerIsValid(xact));
2608 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2609 xact->blockState = TBLOCK_SUBABORT_PENDING;
2614 * BeginInternalSubTransaction
2615 * This is the same as DefineSavepoint except it allows TBLOCK_STARTED
2616 * state, and therefore it can safely be used in a function that might
2617 * be called when not inside a BEGIN block. Also, we automatically
2618 * cycle through CommitTransactionCommand/StartTransactionCommand
2619 * instead of expecting the caller to do it.
2621 * Optionally, name can be NULL to create an unnamed savepoint.
2624 BeginInternalSubTransaction(char *name)
2626 TransactionState s = CurrentTransactionState;
2628 switch (s->blockState)
2630 case TBLOCK_STARTED:
2631 case TBLOCK_INPROGRESS:
2632 case TBLOCK_SUBINPROGRESS:
2633 /* Normal subtransaction start */
2635 s = CurrentTransactionState; /* changed by push */
2637 * Note that we are allocating the savepoint name in the
2638 * parent transaction's CurTransactionContext, since we
2639 * don't yet have a transaction context for the new guy.
2642 s->name = MemoryContextStrdup(CurTransactionContext, name);
2643 s->blockState = TBLOCK_SUBBEGIN;
2646 /* These cases are invalid. Reject them altogether. */
2647 case TBLOCK_DEFAULT:
2649 case TBLOCK_SUBBEGIN:
2651 case TBLOCK_SUBABORT:
2652 case TBLOCK_ENDABORT:
2654 case TBLOCK_SUBENDABORT_ALL:
2655 case TBLOCK_SUBENDABORT:
2656 case TBLOCK_SUBABORT_PENDING:
2657 case TBLOCK_SUBENDABORT_RELEASE:
2659 elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
2660 BlockStateAsString(s->blockState));
2664 CommitTransactionCommand();
2665 StartTransactionCommand();
2669 * ReleaseCurrentSubTransaction
2671 * RELEASE (ie, commit) the innermost subtransaction, regardless of its
2672 * savepoint name (if any).
2673 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2676 ReleaseCurrentSubTransaction(void)
2678 TransactionState s = CurrentTransactionState;
2680 if (s->blockState != TBLOCK_SUBINPROGRESS)
2681 elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
2682 BlockStateAsString(s->blockState));
2683 MemoryContextSwitchTo(CurTransactionContext);
2684 CommitTransactionToLevel(GetCurrentTransactionNestLevel());
2688 * RollbackAndReleaseCurrentSubTransaction
2690 * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
2691 * of its savepoint name (if any).
2692 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2695 RollbackAndReleaseCurrentSubTransaction(void)
2697 TransactionState s = CurrentTransactionState;
2699 switch (s->blockState)
2701 /* Must be in a subtransaction */
2702 case TBLOCK_SUBABORT:
2703 case TBLOCK_SUBINPROGRESS:
2706 /* these cases are invalid. */
2707 case TBLOCK_DEFAULT:
2708 case TBLOCK_STARTED:
2710 case TBLOCK_INPROGRESS:
2713 case TBLOCK_ENDABORT:
2715 case TBLOCK_SUBENDABORT_ALL:
2716 case TBLOCK_SUBENDABORT:
2717 case TBLOCK_SUBABORT_PENDING:
2718 case TBLOCK_SUBENDABORT_RELEASE:
2719 case TBLOCK_SUBBEGIN:
2720 elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
2721 BlockStateAsString(s->blockState));
2726 * Abort the current subtransaction, if needed.
2728 if (s->blockState == TBLOCK_SUBINPROGRESS)
2729 AbortSubTransaction();
2730 s->blockState = TBLOCK_SUBENDABORT_RELEASE;
2732 /* And clean it up, too */
2733 CleanupAbortedSubTransactions(false);
2737 * AbortOutOfAnyTransaction
2739 * This routine is provided for error recovery purposes. It aborts any
2740 * active transaction or transaction block, leaving the system in a known
2744 AbortOutOfAnyTransaction(void)
2746 TransactionState s = CurrentTransactionState;
2749 * Get out of any transaction or nested transaction
2752 switch (s->blockState)
2754 case TBLOCK_DEFAULT:
2755 /* Not in a transaction, do nothing */
2757 case TBLOCK_STARTED:
2759 case TBLOCK_INPROGRESS:
2761 /* In a transaction, so clean up */
2763 CleanupTransaction();
2764 s->blockState = TBLOCK_DEFAULT;
2767 case TBLOCK_ENDABORT:
2768 /* AbortTransaction already done, still need Cleanup */
2769 CleanupTransaction();
2770 s->blockState = TBLOCK_DEFAULT;
2772 case TBLOCK_SUBBEGIN:
2774 * We didn't get as far as starting the subxact, so there's
2775 * nothing to abort. Just pop back to parent.
2778 s = CurrentTransactionState; /* changed by pop */
2780 case TBLOCK_SUBINPROGRESS:
2782 case TBLOCK_SUBABORT_PENDING:
2783 /* In a subtransaction, so clean it up and abort parent too */
2784 AbortSubTransaction();
2785 CleanupSubTransaction();
2787 s = CurrentTransactionState; /* changed by pop */
2789 case TBLOCK_SUBABORT:
2790 case TBLOCK_SUBENDABORT_ALL:
2791 case TBLOCK_SUBENDABORT:
2792 case TBLOCK_SUBENDABORT_RELEASE:
2793 /* As above, but AbortSubTransaction already done */
2794 CleanupSubTransaction();
2796 s = CurrentTransactionState; /* changed by pop */
2799 } while (s->blockState != TBLOCK_DEFAULT);
2801 /* Should be out of all subxacts now */
2802 Assert(s->parent == NULL);
2806 * CommitTransactionToLevel
2808 * Commit everything from the current transaction level
2809 * up to the specified level (inclusive).
2812 CommitTransactionToLevel(int level)
2814 TransactionState s = CurrentTransactionState;
2816 Assert(s->state == TRANS_INPROGRESS);
2818 while (s->nestingLevel >= level)
2820 CommitSubTransaction();
2822 s = CurrentTransactionState; /* changed by pop */
2823 Assert(s->state == TRANS_INPROGRESS);
2828 * IsTransactionBlock --- are we within a transaction block?
2831 IsTransactionBlock(void)
2833 TransactionState s = CurrentTransactionState;
2835 if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
2842 * IsTransactionOrTransactionBlock --- are we within either a transaction
2843 * or a transaction block? (The backend is only really "idle" when this
2846 * This should match up with IsTransactionBlock and IsTransactionState.
2849 IsTransactionOrTransactionBlock(void)
2851 TransactionState s = CurrentTransactionState;
2853 if (s->blockState == TBLOCK_DEFAULT)
2860 * TransactionBlockStatusCode - return status code to send in ReadyForQuery
2863 TransactionBlockStatusCode(void)
2865 TransactionState s = CurrentTransactionState;
2867 switch (s->blockState)
2869 case TBLOCK_DEFAULT:
2870 case TBLOCK_STARTED:
2871 return 'I'; /* idle --- not in transaction */
2873 case TBLOCK_INPROGRESS:
2875 case TBLOCK_SUBINPROGRESS:
2876 case TBLOCK_SUBBEGIN:
2878 return 'T'; /* in transaction */
2880 case TBLOCK_ENDABORT:
2881 case TBLOCK_SUBABORT:
2882 case TBLOCK_SUBENDABORT_ALL:
2883 case TBLOCK_SUBENDABORT:
2884 case TBLOCK_SUBABORT_PENDING:
2885 case TBLOCK_SUBENDABORT_RELEASE:
2886 return 'E'; /* in failed transaction */
2889 /* should never get here */
2890 elog(FATAL, "invalid transaction block state: %s",
2891 BlockStateAsString(s->blockState));
2892 return 0; /* keep compiler quiet */
2899 IsSubTransaction(void)
2901 TransactionState s = CurrentTransactionState;
2903 if (s->nestingLevel >= 2)
2910 * StartSubTransaction
2913 StartSubTransaction(void)
2915 TransactionState s = CurrentTransactionState;
2917 if (s->state != TRANS_DEFAULT)
2918 elog(WARNING, "StartSubTransaction while in %s state",
2919 TransStateAsString(s->state));
2921 s->state = TRANS_START;
2924 * must initialize resource-management stuff first
2926 AtSubStart_Memory();
2927 AtSubStart_ResourceOwner();
2930 * Generate a new Xid and record it in pg_subtrans. NB: we must make
2931 * the subtrans entry BEFORE the Xid appears anywhere in shared storage,
2932 * such as in the lock table; because until it's made the Xid may not
2933 * appear to be "running" to other backends. See GetNewTransactionId.
2935 s->transactionIdData = GetNewTransactionId(true);
2937 SubTransSetParent(s->transactionIdData, s->parent->transactionIdData);
2939 XactLockTableInsert(s->transactionIdData);
2942 * Finish setup of other transaction state fields.
2944 s->currentUser = GetUserId();
2945 s->prevXactReadOnly = XactReadOnly;
2948 * Initialize other subsystems for new subtransaction
2951 AtSubStart_Notify();
2952 DeferredTriggerBeginSubXact();
2954 s->state = TRANS_INPROGRESS;
2957 * Call start-of-subxact callbacks
2959 CallXactCallbacks(XACT_EVENT_START_SUB, s->parent->transactionIdData);
2961 ShowTransactionState("StartSubTransaction");
2965 * CommitSubTransaction
2968 CommitSubTransaction(void)
2970 TransactionState s = CurrentTransactionState;
2972 ShowTransactionState("CommitSubTransaction");
2974 if (s->state != TRANS_INPROGRESS)
2975 elog(WARNING, "CommitSubTransaction while in %s state",
2976 TransStateAsString(s->state));
2978 /* Pre-commit processing goes here -- nothing to do at the moment */
2980 s->state = TRANS_COMMIT;
2982 /* Mark subtransaction as subcommitted */
2983 CommandCounterIncrement();
2984 RecordSubTransactionCommit();
2985 AtSubCommit_childXids();
2987 /* Post-commit cleanup */
2988 DeferredTriggerEndSubXact(true);
2989 AtSubCommit_Portals(s->parent->transactionIdData,
2990 s->parent->curTransactionOwner);
2991 AtEOSubXact_LargeObject(true, s->transactionIdData,
2992 s->parent->transactionIdData);
2993 AtSubCommit_Notify();
2994 AtEOSubXact_UpdatePasswordFile(true, s->transactionIdData,
2995 s->parent->transactionIdData);
2998 CallXactCallbacks(XACT_EVENT_COMMIT_SUB, s->parent->transactionIdData);
3000 ResourceOwnerRelease(s->curTransactionOwner,
3001 RESOURCE_RELEASE_BEFORE_LOCKS,
3003 AtEOSubXact_RelationCache(true, s->transactionIdData,
3004 s->parent->transactionIdData);
3005 AtEOSubXact_Inval(true);
3006 ResourceOwnerRelease(s->curTransactionOwner,
3007 RESOURCE_RELEASE_LOCKS,
3009 ResourceOwnerRelease(s->curTransactionOwner,
3010 RESOURCE_RELEASE_AFTER_LOCKS,
3013 AtEOXact_GUC(true, true);
3014 AtEOSubXact_SPI(true, s->transactionIdData);
3015 AtEOSubXact_on_commit_actions(true, s->transactionIdData,
3016 s->parent->transactionIdData);
3017 AtEOSubXact_Namespace(true, s->transactionIdData,
3018 s->parent->transactionIdData);
3019 AtEOSubXact_Files(true, s->transactionIdData,
3020 s->parent->transactionIdData);
3023 * We need to restore the upper transaction's read-only state,
3024 * in case the upper is read-write while the child is read-only;
3025 * GUC will incorrectly think it should leave the child state in place.
3027 XactReadOnly = s->prevXactReadOnly;
3029 CurrentResourceOwner = s->parent->curTransactionOwner;
3030 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3031 ResourceOwnerDelete(s->curTransactionOwner);
3032 s->curTransactionOwner = NULL;
3034 AtSubCommit_Memory();
3036 s->state = TRANS_DEFAULT;
3040 * AbortSubTransaction
3043 AbortSubTransaction(void)
3045 TransactionState s = CurrentTransactionState;
3047 ShowTransactionState("AbortSubTransaction");
3049 if (s->state != TRANS_INPROGRESS)
3050 elog(WARNING, "AbortSubTransaction while in %s state",
3051 TransStateAsString(s->state));
3055 s->state = TRANS_ABORT;
3058 * Release any LW locks we might be holding as quickly as possible.
3059 * (Regular locks, however, must be held till we finish aborting.)
3060 * Releasing LW locks is critical since we might try to grab them
3061 * again while cleaning up!
3063 * FIXME This may be incorrect --- Are there some locks we should keep?
3064 * Buffer locks, for example? I don't think so but I'm not sure.
3074 * do abort processing
3076 AtSubAbort_Memory();
3078 DeferredTriggerEndSubXact(false);
3079 AtSubAbort_Portals(s->parent->transactionIdData,
3080 s->parent->curTransactionOwner);
3081 AtEOSubXact_LargeObject(false, s->transactionIdData,
3082 s->parent->transactionIdData);
3083 AtSubAbort_Notify();
3084 AtEOSubXact_UpdatePasswordFile(false, s->transactionIdData,
3085 s->parent->transactionIdData);
3087 /* Advertise the fact that we aborted in pg_clog. */
3088 RecordSubTransactionAbort();
3090 /* Post-abort cleanup */
3093 CallXactCallbacks(XACT_EVENT_ABORT_SUB, s->parent->transactionIdData);
3095 ResourceOwnerRelease(s->curTransactionOwner,
3096 RESOURCE_RELEASE_BEFORE_LOCKS,
3098 AtEOSubXact_RelationCache(false, s->transactionIdData,
3099 s->parent->transactionIdData);
3100 AtEOSubXact_Inval(false);
3101 ResourceOwnerRelease(s->curTransactionOwner,
3102 RESOURCE_RELEASE_LOCKS,
3104 ResourceOwnerRelease(s->curTransactionOwner,
3105 RESOURCE_RELEASE_AFTER_LOCKS,
3108 AtEOXact_GUC(false, true);
3109 AtEOSubXact_SPI(false, s->transactionIdData);
3110 AtEOSubXact_on_commit_actions(false, s->transactionIdData,
3111 s->parent->transactionIdData);
3112 AtEOSubXact_Namespace(false, s->transactionIdData,
3113 s->parent->transactionIdData);
3114 AtEOSubXact_Files(false, s->transactionIdData,
3115 s->parent->transactionIdData);
3118 * Reset user id which might have been changed transiently. Here we
3119 * want to restore to the userid that was current at subxact entry.
3120 * (As in AbortTransaction, we need not worry about the session userid.)
3122 * Must do this after AtEOXact_GUC to handle the case where we entered
3123 * the subxact inside a SECURITY DEFINER function (hence current and
3124 * session userids were different) and then session auth was changed
3125 * inside the subxact. GUC will reset both current and session userids
3126 * to the entry-time session userid. This is right in every other
3127 * scenario so it seems simplest to let GUC do that and fix it here.
3129 SetUserId(s->currentUser);
3132 * Restore the upper transaction's read-only state, too. This should
3133 * be redundant with GUC's cleanup but we may as well do it for
3134 * consistency with the commit case.
3136 XactReadOnly = s->prevXactReadOnly;
3138 RESUME_INTERRUPTS();
3142 * CleanupSubTransaction
3145 CleanupSubTransaction(void)
3147 TransactionState s = CurrentTransactionState;
3149 ShowTransactionState("CleanupSubTransaction");
3151 if (s->state != TRANS_ABORT)
3152 elog(WARNING, "CleanupSubTransaction while in %s state",
3153 TransStateAsString(s->state));
3155 AtSubCleanup_Portals();
3157 CurrentResourceOwner = s->parent->curTransactionOwner;
3158 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3159 ResourceOwnerDelete(s->curTransactionOwner);
3160 s->curTransactionOwner = NULL;
3162 AtSubCleanup_Memory();
3164 s->state = TRANS_DEFAULT;
3168 * StartAbortedSubTransaction
3170 * This function is used to start a subtransaction and put it immediately
3171 * into aborted state. The end result should be equivalent to
3172 * StartSubTransaction immediately followed by AbortSubTransaction.
3173 * The reason we don't implement it just that way is that many of the backend
3174 * modules aren't designed to handle starting a subtransaction when not
3175 * inside a valid transaction. Rather than making them all capable of
3176 * doing that, we just omit the paired start and abort calls in this path.
3179 StartAbortedSubTransaction(void)
3181 TransactionState s = CurrentTransactionState;
3183 if (s->state != TRANS_DEFAULT)
3184 elog(WARNING, "StartAbortedSubTransaction while in %s state",
3185 TransStateAsString(s->state));
3187 s->state = TRANS_START;
3190 * We don't bother to generate a new Xid, so the end state is not
3191 * *exactly* like we had done a full Start/AbortSubTransaction...
3193 s->transactionIdData = InvalidTransactionId;
3195 /* Make sure currentUser is reasonably valid */
3196 Assert(s->parent != NULL);
3197 s->currentUser = s->parent->currentUser;
3200 * Initialize only what has to be there for CleanupSubTransaction to work.
3202 AtSubStart_Memory();
3203 AtSubStart_ResourceOwner();
3205 s->state = TRANS_ABORT;
3207 AtSubAbort_Memory();
3209 ShowTransactionState("StartAbortedSubTransaction");
3214 * Set up transaction state for a subtransaction
3216 * The caller has to make sure to always reassign CurrentTransactionState
3217 * if it has a local pointer to it after calling this function.
3220 PushTransaction(void)
3222 TransactionState p = CurrentTransactionState;
3226 * We keep subtransaction state nodes in TopTransactionContext.
3228 s = (TransactionState)
3229 MemoryContextAllocZero(TopTransactionContext,
3230 sizeof(TransactionStateData));
3232 s->nestingLevel = p->nestingLevel + 1;
3233 s->savepointLevel = p->savepointLevel;
3234 s->state = TRANS_DEFAULT;
3235 s->blockState = TBLOCK_SUBBEGIN;
3237 /* Command IDs count in a continuous sequence through subtransactions */
3238 s->commandId = p->commandId;
3241 * Copy down some other data so that we will have valid state until
3242 * StartSubTransaction runs.
3244 s->transactionIdData = p->transactionIdData;
3245 s->curTransactionContext = p->curTransactionContext;
3246 s->curTransactionOwner = p->curTransactionOwner;
3247 s->currentUser = p->currentUser;
3249 CurrentTransactionState = s;
3254 * Pop back to parent transaction state
3256 * The caller has to make sure to always reassign CurrentTransactionState
3257 * if it has a local pointer to it after calling this function.
3260 PopTransaction(void)
3262 TransactionState s = CurrentTransactionState;
3264 if (s->state != TRANS_DEFAULT)
3265 elog(WARNING, "PopTransaction while in %s state",
3266 TransStateAsString(s->state));
3268 if (s->parent == NULL)
3269 elog(FATAL, "PopTransaction with no parent");
3271 /* Command IDs count in a continuous sequence through subtransactions */
3272 s->parent->commandId = s->commandId;
3274 CurrentTransactionState = s->parent;
3276 /* Let's just make sure CurTransactionContext is good */
3277 CurTransactionContext = s->parent->curTransactionContext;
3278 MemoryContextSwitchTo(CurTransactionContext);
3280 /* Ditto for ResourceOwner links */
3281 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3282 CurrentResourceOwner = s->parent->curTransactionOwner;
3284 /* Free the old child structure */
3291 * ShowTransactionState
3295 ShowTransactionState(const char *str)
3297 /* skip work if message will definitely not be printed */
3298 if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
3300 elog(DEBUG2, "%s", str);
3301 ShowTransactionStateRec(CurrentTransactionState);
3306 * ShowTransactionStateRec
3307 * Recursive subroutine for ShowTransactionState
3310 ShowTransactionStateRec(TransactionState s)
3313 ShowTransactionStateRec(s->parent);
3315 /* use ereport to suppress computation if msg will not be printed */
3317 (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/cid: %u/%02u, nestlvl: %d, children: %s",
3318 PointerIsValid(s->name) ? s->name : "unnamed",
3319 BlockStateAsString(s->blockState),
3320 TransStateAsString(s->state),
3321 (unsigned int) s->transactionIdData,
3322 (unsigned int) s->commandId,
3324 nodeToString(s->childXids))));
3328 * BlockStateAsString
3332 BlockStateAsString(TBlockState blockState)
3336 case TBLOCK_DEFAULT:
3338 case TBLOCK_STARTED:
3342 case TBLOCK_INPROGRESS:
3343 return "INPROGRESS";
3348 case TBLOCK_ENDABORT:
3350 case TBLOCK_SUBBEGIN:
3352 case TBLOCK_SUBINPROGRESS:
3353 return "SUB INPROGRS";
3356 case TBLOCK_SUBABORT:
3358 case TBLOCK_SUBENDABORT_ALL:
3359 return "SUB ENDAB ALL";
3360 case TBLOCK_SUBENDABORT:
3362 case TBLOCK_SUBABORT_PENDING:
3363 return "SUB ABRT PEND";
3364 case TBLOCK_SUBENDABORT_RELEASE:
3365 return "SUB ENDAB REL";
3367 return "UNRECOGNIZED";
3371 * TransStateAsString
3375 TransStateAsString(TransState state)
3387 case TRANS_INPROGRESS:
3390 return "UNRECOGNIZED";
3394 * xactGetCommittedChildren
3396 * Gets the list of committed children of the current transaction. The return
3397 * value is the number of child transactions. *children is set to point to a
3398 * palloc'd array of TransactionIds. If there are no subxacts, *children is
3402 xactGetCommittedChildren(TransactionId **ptr)
3404 TransactionState s = CurrentTransactionState;
3406 TransactionId *children;
3409 nchildren = list_length(s->childXids);
3416 children = (TransactionId *) palloc(nchildren * sizeof(TransactionId));
3419 foreach(p, s->childXids)
3421 TransactionId child = lfirst_xid(p);
3423 *children++ = child;
3430 * XLOG support routines
3434 xact_redo(XLogRecPtr lsn, XLogRecord *record)
3436 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3438 if (info == XLOG_XACT_COMMIT)
3440 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
3443 TransactionIdCommit(record->xl_xid);
3444 /* Mark committed subtransactions as committed */
3445 TransactionIdCommitTree(xlrec->nsubxacts,
3446 (TransactionId *) &(xlrec->xnodes[xlrec->nrels]));
3447 /* Make sure files supposed to be dropped are dropped */
3448 for (i = 0; i < xlrec->nrels; i++)
3450 XLogCloseRelation(xlrec->xnodes[i]);
3451 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3454 else if (info == XLOG_XACT_ABORT)
3456 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
3459 TransactionIdAbort(record->xl_xid);
3460 /* mark subtransactions as aborted */
3461 TransactionIdAbortTree(xlrec->nsubxacts,
3462 (TransactionId *) &(xlrec->xnodes[xlrec->nrels]));
3463 /* Make sure files supposed to be dropped are dropped */
3464 for (i = 0; i < xlrec->nrels; i++)
3466 XLogCloseRelation(xlrec->xnodes[i]);
3467 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3471 elog(PANIC, "xact_redo: unknown op code %u", info);
3475 xact_undo(XLogRecPtr lsn, XLogRecord *record)
3477 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3479 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
3480 elog(PANIC, "xact_undo: can't undo committed xaction");
3481 else if (info != XLOG_XACT_ABORT)
3482 elog(PANIC, "xact_redo: unknown op code %u", info);
3486 xact_desc(char *buf, uint8 xl_info, char *rec)
3488 uint8 info = xl_info & ~XLR_INFO_MASK;
3491 if (info == XLOG_XACT_COMMIT)
3493 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
3494 struct tm *tm = localtime(&xlrec->xtime);
3496 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
3497 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3498 tm->tm_hour, tm->tm_min, tm->tm_sec);
3499 if (xlrec->nrels > 0)
3501 sprintf(buf + strlen(buf), "; rels:");
3502 for (i = 0; i < xlrec->nrels; i++)
3504 RelFileNode rnode = xlrec->xnodes[i];
3505 sprintf(buf + strlen(buf), " %u/%u/%u",
3506 rnode.spcNode, rnode.dbNode, rnode.relNode);
3509 if (xlrec->nsubxacts > 0)
3511 TransactionId *xacts = (TransactionId *)
3512 &xlrec->xnodes[xlrec->nrels];
3514 sprintf(buf + strlen(buf), "; subxacts:");
3515 for (i = 0; i < xlrec->nsubxacts; i++)
3516 sprintf(buf + strlen(buf), " %u", xacts[i]);
3519 else if (info == XLOG_XACT_ABORT)
3521 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
3522 struct tm *tm = localtime(&xlrec->xtime);
3524 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
3525 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3526 tm->tm_hour, tm->tm_min, tm->tm_sec);
3527 if (xlrec->nrels > 0)
3529 sprintf(buf + strlen(buf), "; rels:");
3530 for (i = 0; i < xlrec->nrels; i++)
3532 RelFileNode rnode = xlrec->xnodes[i];
3533 sprintf(buf + strlen(buf), " %u/%u/%u",
3534 rnode.spcNode, rnode.dbNode, rnode.relNode);
3537 if (xlrec->nsubxacts > 0)
3539 TransactionId *xacts = (TransactionId *)
3540 &xlrec->xnodes[xlrec->nrels];
3542 sprintf(buf + strlen(buf), "; subxacts:");
3543 for (i = 0; i < xlrec->nsubxacts; i++)
3544 sprintf(buf + strlen(buf), " %u", xacts[i]);
3548 strcat(buf, "UNKNOWN");
3552 XactPushRollback(void (*func) (void *), void *data)
3555 if (_RollbackFunc != NULL)
3556 elog(PANIC, "XactPushRollback: already installed");
3559 _RollbackFunc = func;
3560 _RollbackData = data;
3564 XactPopRollback(void)
3566 _RollbackFunc = NULL;