1 /*-------------------------------------------------------------------------
4 * top level transaction system support routines
6 * See src/backend/access/transam/README for more information.
8 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.184 2004/08/30 02:54:38 momjian 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
101 ResourceOwner curTransactionOwner; /* my query resources */
102 List *childXids; /* subcommitted child XIDs */
103 AclId currentUser; /* subxact start current_user */
104 bool prevXactReadOnly; /* entry-time xact r/o state */
105 struct TransactionStateData *parent; /* back link to parent */
106 } TransactionStateData;
108 typedef TransactionStateData *TransactionState;
111 * childXids is currently implemented as an integer List, relying on the
112 * assumption that TransactionIds are no wider than int. We use these
113 * macros to provide some isolation in case that changes in the future.
115 #define lfirst_xid(lc) ((TransactionId) lfirst_int(lc))
116 #define lappend_xid(list, datum) lappend_int(list, (int) (datum))
119 static void AbortTransaction(void);
120 static void AtAbort_Memory(void);
121 static void AtCleanup_Memory(void);
122 static void AtCommit_LocalCache(void);
123 static void AtCommit_Memory(void);
124 static void AtStart_Cache(void);
125 static void AtStart_Memory(void);
126 static void AtStart_ResourceOwner(void);
127 static void CallXactCallbacks(XactEvent event, TransactionId parentXid);
128 static void CleanupTransaction(void);
129 static void CommitTransaction(void);
130 static void RecordTransactionAbort(void);
131 static void StartTransaction(void);
133 static void RecordSubTransactionCommit(void);
134 static void StartSubTransaction(void);
135 static void CommitSubTransaction(void);
136 static void AbortSubTransaction(void);
137 static void CleanupSubTransaction(void);
138 static void StartAbortedSubTransaction(void);
139 static void PushTransaction(void);
140 static void PopTransaction(void);
141 static void CommitTransactionToLevel(int level);
142 static char *CleanupAbortedSubTransactions(bool returnName);
144 static void AtSubAbort_Memory(void);
145 static void AtSubCleanup_Memory(void);
146 static void AtSubCommit_Memory(void);
147 static void AtSubStart_Memory(void);
148 static void AtSubStart_ResourceOwner(void);
150 static void ShowTransactionState(const char *str);
151 static void ShowTransactionStateRec(TransactionState state);
152 static const char *BlockStateAsString(TBlockState blockState);
153 static const char *TransStateAsString(TransState state);
156 * CurrentTransactionState always points to the current transaction state
157 * block. It will point to TopTransactionStateData when not in a
158 * transaction at all, or when in a top-level transaction.
160 static TransactionStateData TopTransactionStateData = {
161 0, /* transaction id */
162 NULL, /* savepoint name */
163 0, /* savepoint level */
164 FirstCommandId, /* command id */
165 TRANS_DEFAULT, /* transaction state */
166 TBLOCK_DEFAULT, /* transaction block state from the client
168 0, /* nesting level */
169 NULL, /* cur transaction context */
170 NULL, /* cur transaction resource owner */
171 NIL, /* subcommitted child Xids */
172 0, /* entry-time current userid */
173 false, /* entry-time xact r/o state */
174 NULL /* link to parent state block */
177 static TransactionState CurrentTransactionState = &TopTransactionStateData;
180 * These vars hold the value of now(), ie, the transaction start time.
181 * This does not change as we enter and exit subtransactions, so we don't
182 * keep it inside the TransactionState stack.
184 static AbsoluteTime xactStartTime; /* integer part */
185 static int xactStartTimeUsec; /* microsecond part */
189 * User-tweakable parameters
191 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
194 bool DefaultXactReadOnly = false;
197 int CommitDelay = 0; /* precommit delay in microseconds */
198 int CommitSiblings = 5; /* number of concurrent xacts needed to
203 * List of add-on start- and end-of-xact callbacks
205 typedef struct XactCallbackItem
207 struct XactCallbackItem *next;
208 XactCallback callback;
212 static XactCallbackItem *Xact_callbacks = NULL;
214 static void (*_RollbackFunc) (void *) = NULL;
215 static void *_RollbackData = NULL;
218 /* ----------------------------------------------------------------
219 * transaction state accessors
220 * ----------------------------------------------------------------
226 * This returns true if we are currently running a query
227 * within an executing transaction.
230 IsTransactionState(void)
232 TransactionState s = CurrentTransactionState;
240 case TRANS_INPROGRESS:
249 * Shouldn't get here, but lint is not happy with this...
255 * IsAbortedTransactionBlockState
257 * This returns true if we are currently running a query
258 * within an aborted transaction block.
261 IsAbortedTransactionBlockState(void)
263 TransactionState s = CurrentTransactionState;
265 if (s->blockState == TBLOCK_ABORT ||
266 s->blockState == TBLOCK_SUBABORT)
274 * GetTopTransactionId
276 * Get the ID of the main transaction, even if we are currently inside
280 GetTopTransactionId(void)
282 return TopTransactionStateData.transactionIdData;
287 * GetCurrentTransactionId
290 GetCurrentTransactionId(void)
292 TransactionState s = CurrentTransactionState;
294 return s->transactionIdData;
299 * GetCurrentCommandId
302 GetCurrentCommandId(void)
304 TransactionState s = CurrentTransactionState;
311 * GetCurrentTransactionStartTime
314 GetCurrentTransactionStartTime(void)
316 return xactStartTime;
321 * GetCurrentTransactionStartTimeUsec
324 GetCurrentTransactionStartTimeUsec(int *msec)
326 *msec = xactStartTimeUsec;
327 return xactStartTime;
332 * GetCurrentTransactionNestLevel
334 * Note: this will return zero when not inside any transaction, one when
335 * inside a top-level transaction, etc.
338 GetCurrentTransactionNestLevel(void)
340 TransactionState s = CurrentTransactionState;
342 return s->nestingLevel;
347 * TransactionIdIsCurrentTransactionId
349 * During bootstrap, we cheat and say "it's not my transaction ID" even though
350 * it is. Along with transam.c's cheat to say that the bootstrap XID is
351 * already committed, this causes the tqual.c routines to see previously
352 * inserted tuples as committed, which is what we need during bootstrap.
355 TransactionIdIsCurrentTransactionId(TransactionId xid)
361 Assert(xid == BootstrapTransactionId);
366 * We will return true for the Xid of the current subtransaction, any
367 * of its subcommitted children, any of its parents, or any of their
368 * previously subcommitted children. However, a transaction being
369 * aborted is no longer "current", even though it may still have an
370 * entry on the state stack.
372 for (s = CurrentTransactionState; s != NULL; s = s->parent)
376 if (s->state == TRANS_ABORT)
378 if (TransactionIdEquals(xid, s->transactionIdData))
380 foreach(cell, s->childXids)
382 if (TransactionIdEquals(xid, lfirst_xid(cell)))
392 * CommandCounterIncrement
395 CommandCounterIncrement(void)
397 TransactionState s = CurrentTransactionState;
400 if (s->commandId == FirstCommandId) /* check for overflow */
402 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
403 errmsg("cannot have more than 2^32-1 commands in a transaction")));
405 /* Propagate new command ID into query snapshots, if set */
407 QuerySnapshot->curcid = s->commandId;
408 if (SerializableSnapshot)
409 SerializableSnapshot->curcid = s->commandId;
412 * make cache changes visible to me.
414 AtCommit_LocalCache();
419 /* ----------------------------------------------------------------
420 * StartTransaction stuff
421 * ----------------------------------------------------------------
430 AcceptInvalidationMessages();
439 TransactionState s = CurrentTransactionState;
442 * We shouldn't have a transaction context already.
444 Assert(TopTransactionContext == NULL);
447 * Create a toplevel context for the transaction.
449 TopTransactionContext =
450 AllocSetContextCreate(TopMemoryContext,
451 "TopTransactionContext",
452 ALLOCSET_DEFAULT_MINSIZE,
453 ALLOCSET_DEFAULT_INITSIZE,
454 ALLOCSET_DEFAULT_MAXSIZE);
457 * In a top-level transaction, CurTransactionContext is the same as
458 * TopTransactionContext.
460 CurTransactionContext = TopTransactionContext;
461 s->curTransactionContext = CurTransactionContext;
463 /* Make the CurTransactionContext active. */
464 MemoryContextSwitchTo(CurTransactionContext);
468 * AtStart_ResourceOwner
471 AtStart_ResourceOwner(void)
473 TransactionState s = CurrentTransactionState;
476 * We shouldn't have a transaction resource owner already.
478 Assert(TopTransactionResourceOwner == NULL);
481 * Create a toplevel resource owner for the transaction.
483 s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
485 TopTransactionResourceOwner = s->curTransactionOwner;
486 CurTransactionResourceOwner = s->curTransactionOwner;
487 CurrentResourceOwner = s->curTransactionOwner;
490 /* ----------------------------------------------------------------
491 * StartSubTransaction stuff
492 * ----------------------------------------------------------------
499 AtSubStart_Memory(void)
501 TransactionState s = CurrentTransactionState;
503 Assert(CurTransactionContext != NULL);
506 * Create a CurTransactionContext, which will be used to hold data
507 * that survives subtransaction commit but disappears on
508 * subtransaction abort. We make it a child of the immediate parent's
509 * CurTransactionContext.
511 CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
512 "CurTransactionContext",
513 ALLOCSET_DEFAULT_MINSIZE,
514 ALLOCSET_DEFAULT_INITSIZE,
515 ALLOCSET_DEFAULT_MAXSIZE);
516 s->curTransactionContext = CurTransactionContext;
518 /* Make the CurTransactionContext active. */
519 MemoryContextSwitchTo(CurTransactionContext);
523 * AtSubStart_ResourceOwner
526 AtSubStart_ResourceOwner(void)
528 TransactionState s = CurrentTransactionState;
530 Assert(s->parent != NULL);
533 * Create a resource owner for the subtransaction. We make it a child
534 * of the immediate parent's resource owner.
536 s->curTransactionOwner =
537 ResourceOwnerCreate(s->parent->curTransactionOwner,
540 CurTransactionResourceOwner = s->curTransactionOwner;
541 CurrentResourceOwner = s->curTransactionOwner;
544 /* ----------------------------------------------------------------
545 * CommitTransaction stuff
546 * ----------------------------------------------------------------
550 * RecordTransactionCommit
553 RecordTransactionCommit(void)
558 TransactionId *children;
560 /* Get data needed for commit record */
561 nrels = smgrGetPendingDeletes(true, &rptr);
562 nchildren = xactGetCommittedChildren(&children);
565 * If we made neither any XLOG entries nor any temp-rel updates, and
566 * have no files to be deleted, we can omit recording the transaction
567 * commit at all. (This test includes the effects of subtransactions,
568 * so the presence of committed subxacts need not alone force a
571 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)
573 TransactionId xid = GetCurrentTransactionId();
577 /* Tell bufmgr and smgr to prepare for commit */
580 START_CRIT_SECTION();
583 * If our transaction made any transaction-controlled XLOG
584 * entries, we need to lock out checkpoint start between writing
585 * our XLOG record and updating pg_clog. Otherwise it is possible
586 * for the checkpoint to set REDO after the XLOG record but fail
587 * to flush the pg_clog update to disk, leading to loss of the
588 * transaction commit if we crash a little later. Slightly klugy
589 * fix for problem discovered 2004-08-10.
591 * (If it made no transaction-controlled XLOG entries, its XID
592 * appears nowhere in permanent storage, so no one else will ever
593 * care if it committed; so it doesn't matter if we lose the
596 * Note we only need a shared lock.
598 madeTCentries = (MyLastRecPtr.xrecoff != 0);
600 LWLockAcquire(CheckpointStartLock, LW_SHARED);
603 * We only need to log the commit in XLOG if the transaction made
604 * any transaction-controlled XLOG entries or will delete files.
606 if (madeTCentries || nrels > 0)
608 XLogRecData rdata[3];
610 xl_xact_commit xlrec;
612 xlrec.xtime = time(NULL);
614 xlrec.nsubxacts = nchildren;
615 rdata[0].buffer = InvalidBuffer;
616 rdata[0].data = (char *) (&xlrec);
617 rdata[0].len = MinSizeOfXactCommit;
618 /* dump rels to delete */
621 rdata[0].next = &(rdata[1]);
622 rdata[1].buffer = InvalidBuffer;
623 rdata[1].data = (char *) rptr;
624 rdata[1].len = nrels * sizeof(RelFileNode);
627 /* dump committed child Xids */
630 rdata[lastrdata].next = &(rdata[2]);
631 rdata[2].buffer = InvalidBuffer;
632 rdata[2].data = (char *) children;
633 rdata[2].len = nchildren * sizeof(TransactionId);
636 rdata[lastrdata].next = NULL;
638 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
642 /* Just flush through last record written by me */
643 recptr = ProcLastRecEnd;
647 * We must flush our XLOG entries to disk if we made any XLOG
648 * entries, whether in or out of transaction control. For
649 * example, if we reported a nextval() result to the client, this
650 * ensures that any XLOG record generated by nextval will hit the
651 * disk before we report the transaction committed.
653 * Note: if we generated a commit record above, MyXactMadeXLogEntry
654 * will certainly be set now.
656 if (MyXactMadeXLogEntry)
659 * Sleep before flush! So we can flush more than one commit
660 * records per single fsync. (The idea is some other backend
661 * may do the XLogFlush while we're sleeping. This needs work
662 * still, because on most Unixen, the minimum select() delay
663 * is 10msec or more, which is way too long.)
665 * We do not sleep if enableFsync is not turned on, nor if there
666 * are fewer than CommitSiblings other backends with active
669 if (CommitDelay > 0 && enableFsync &&
670 CountActiveBackends() >= CommitSiblings)
671 pg_usleep(CommitDelay);
677 * We must mark the transaction committed in clog if its XID
678 * appears either in permanent rels or in local temporary rels. We
679 * test this by seeing if we made transaction-controlled entries
680 * *OR* local-rel tuple updates. Note that if we made only the
681 * latter, we have not emitted an XLOG record for our commit, and
682 * so in the event of a crash the clog update might be lost. This
683 * is okay because no one else will ever care whether we
686 if (madeTCentries || MyXactMadeTempRelUpdate)
688 TransactionIdCommit(xid);
689 /* to avoid race conditions, the parent must commit first */
690 TransactionIdCommitTree(nchildren, children);
693 /* Unlock checkpoint lock if we acquired it */
695 LWLockRelease(CheckpointStartLock);
700 /* Break the chain of back-links in the XLOG records I output */
701 MyLastRecPtr.xrecoff = 0;
702 MyXactMadeXLogEntry = false;
703 MyXactMadeTempRelUpdate = false;
705 /* Show myself as out of the transaction in PGPROC array */
706 MyProc->logRec.xrecoff = 0;
708 /* And clean up local data */
717 * AtCommit_LocalCache
720 AtCommit_LocalCache(void)
723 * Make catalog changes visible to me for the next command.
725 CommandEndInvalidationMessages();
732 AtCommit_Memory(void)
735 * Now that we're "out" of a transaction, have the system allocate
736 * things in the top memory context instead of per-transaction
739 MemoryContextSwitchTo(TopMemoryContext);
742 * Release all transaction-local memory.
744 Assert(TopTransactionContext != NULL);
745 MemoryContextDelete(TopTransactionContext);
746 TopTransactionContext = NULL;
747 CurTransactionContext = NULL;
748 CurrentTransactionState->curTransactionContext = NULL;
751 /* ----------------------------------------------------------------
752 * CommitSubTransaction stuff
753 * ----------------------------------------------------------------
759 * We do not throw away the child's CurTransactionContext, since the data
760 * it contains will be needed at upper commit.
763 AtSubCommit_Memory(void)
765 TransactionState s = CurrentTransactionState;
767 Assert(s->parent != NULL);
769 /* Return to parent transaction level's memory context. */
770 CurTransactionContext = s->parent->curTransactionContext;
771 MemoryContextSwitchTo(CurTransactionContext);
775 * AtSubCommit_childXids
777 * Pass my own XID and my child XIDs up to my parent as committed children.
780 AtSubCommit_childXids(void)
782 TransactionState s = CurrentTransactionState;
783 MemoryContext old_cxt;
785 Assert(s->parent != NULL);
787 old_cxt = MemoryContextSwitchTo(s->parent->curTransactionContext);
789 s->parent->childXids = lappend_xid(s->parent->childXids,
790 s->transactionIdData);
792 s->parent->childXids = list_concat(s->parent->childXids, s->childXids);
793 s->childXids = NIL; /* ensure list not doubly referenced */
795 MemoryContextSwitchTo(old_cxt);
799 * RecordSubTransactionCommit
802 RecordSubTransactionCommit(void)
805 * We do not log the subcommit in XLOG; it doesn't matter until the
806 * top-level transaction commits.
808 * We must mark the subtransaction subcommitted in clog if its XID
809 * appears either in permanent rels or in local temporary rels. We
810 * test this by seeing if we made transaction-controlled entries *OR*
811 * local-rel tuple updates. (The test here actually covers the entire
812 * transaction tree so far, so it may mark subtransactions that don't
813 * really need it, but it's probably not worth being tenser. Note that
814 * if a prior subtransaction dirtied these variables, then
815 * RecordTransactionCommit will have to do the full pushup anyway...)
817 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
819 TransactionId xid = GetCurrentTransactionId();
821 /* XXX does this really need to be a critical section? */
822 START_CRIT_SECTION();
824 /* Record subtransaction subcommit */
825 TransactionIdSubCommit(xid);
831 /* ----------------------------------------------------------------
832 * AbortTransaction stuff
833 * ----------------------------------------------------------------
837 * RecordTransactionAbort
840 RecordTransactionAbort(void)
845 TransactionId *children;
847 /* Get data needed for abort record */
848 nrels = smgrGetPendingDeletes(false, &rptr);
849 nchildren = xactGetCommittedChildren(&children);
852 * If we made neither any transaction-controlled XLOG entries nor any
853 * temp-rel updates, and are not going to delete any files, we can
854 * omit recording the transaction abort at all. No one will ever care
855 * that it aborted. (These tests cover our whole transaction tree.)
857 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
859 TransactionId xid = GetCurrentTransactionId();
862 * Catch the scenario where we aborted partway through
863 * RecordTransactionCommit ...
865 if (TransactionIdDidCommit(xid))
866 elog(PANIC, "cannot abort transaction %u, it was already committed", xid);
868 START_CRIT_SECTION();
871 * We only need to log the abort in XLOG if the transaction made
872 * any transaction-controlled XLOG entries or will delete files.
873 * (If it made no transaction-controlled XLOG entries, its XID
874 * appears nowhere in permanent storage, so no one else will ever
875 * care if it committed.)
877 * We do not flush XLOG to disk unless deleting files, since the
878 * default assumption after a crash would be that we aborted,
879 * anyway. For the same reason, we don't need to worry about
880 * interlocking against checkpoint start.
882 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
884 XLogRecData rdata[3];
889 xlrec.xtime = time(NULL);
891 xlrec.nsubxacts = nchildren;
892 rdata[0].buffer = InvalidBuffer;
893 rdata[0].data = (char *) (&xlrec);
894 rdata[0].len = MinSizeOfXactAbort;
895 /* dump rels to delete */
898 rdata[0].next = &(rdata[1]);
899 rdata[1].buffer = InvalidBuffer;
900 rdata[1].data = (char *) rptr;
901 rdata[1].len = nrels * sizeof(RelFileNode);
904 /* dump committed child Xids */
907 rdata[lastrdata].next = &(rdata[2]);
908 rdata[2].buffer = InvalidBuffer;
909 rdata[2].data = (char *) children;
910 rdata[2].len = nchildren * sizeof(TransactionId);
913 rdata[lastrdata].next = NULL;
915 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
917 /* Must flush if we are deleting files... */
923 * Mark the transaction aborted in clog. This is not absolutely
924 * necessary but we may as well do it while we are here.
926 * The ordering here isn't critical but it seems best to mark the
927 * parent first. This assures an atomic transition of all the
928 * subtransactions to aborted state from the point of view of
929 * concurrent TransactionIdDidAbort calls.
931 TransactionIdAbort(xid);
932 TransactionIdAbortTree(nchildren, children);
937 /* Break the chain of back-links in the XLOG records I output */
938 MyLastRecPtr.xrecoff = 0;
939 MyXactMadeXLogEntry = false;
940 MyXactMadeTempRelUpdate = false;
942 /* Show myself as out of the transaction in PGPROC array */
943 MyProc->logRec.xrecoff = 0;
945 /* And clean up local data */
959 * Make sure we are in a valid context (not a child of
960 * TopTransactionContext...). Note that it is possible for this code
961 * to be called when we aren't in a transaction at all; go directly to
962 * TopMemoryContext in that case.
964 if (TopTransactionContext != NULL)
966 MemoryContextSwitchTo(TopTransactionContext);
969 * We do not want to destroy the transaction's global state yet,
970 * so we can't free any memory here.
974 MemoryContextSwitchTo(TopMemoryContext);
982 AtSubAbort_Memory(void)
984 Assert(TopTransactionContext != NULL);
986 MemoryContextSwitchTo(TopTransactionContext);
990 * RecordSubTransactionAbort
993 RecordSubTransactionAbort(void)
997 TransactionId xid = GetCurrentTransactionId();
999 TransactionId *children;
1001 /* Get data needed for abort record */
1002 nrels = smgrGetPendingDeletes(false, &rptr);
1003 nchildren = xactGetCommittedChildren(&children);
1006 * If we made neither any transaction-controlled XLOG entries nor any
1007 * temp-rel updates, and are not going to delete any files, we can
1008 * omit recording the transaction abort at all. No one will ever care
1009 * that it aborted. (These tests cover our whole transaction tree,
1010 * and therefore may mark subxacts that don't really need it, but it's
1011 * probably not worth being tenser.)
1013 * In this case we needn't worry about marking subcommitted children as
1014 * aborted, because they didn't mark themselves as subcommitted in the
1015 * first place; see the optimization in RecordSubTransactionCommit.
1017 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
1019 START_CRIT_SECTION();
1022 * We only need to log the abort in XLOG if the transaction made
1023 * any transaction-controlled XLOG entries or will delete files.
1025 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1027 XLogRecData rdata[3];
1029 xl_xact_abort xlrec;
1032 xlrec.xtime = time(NULL);
1033 xlrec.nrels = nrels;
1034 xlrec.nsubxacts = nchildren;
1035 rdata[0].buffer = InvalidBuffer;
1036 rdata[0].data = (char *) (&xlrec);
1037 rdata[0].len = MinSizeOfXactAbort;
1038 /* dump rels to delete */
1041 rdata[0].next = &(rdata[1]);
1042 rdata[1].buffer = InvalidBuffer;
1043 rdata[1].data = (char *) rptr;
1044 rdata[1].len = nrels * sizeof(RelFileNode);
1047 /* dump committed child Xids */
1050 rdata[lastrdata].next = &(rdata[2]);
1051 rdata[2].buffer = InvalidBuffer;
1052 rdata[2].data = (char *) children;
1053 rdata[2].len = nchildren * sizeof(TransactionId);
1056 rdata[lastrdata].next = NULL;
1058 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1060 /* Must flush if we are deleting files... */
1066 * Mark the transaction aborted in clog. This is not absolutely
1067 * necessary but we may as well do it while we are here.
1069 TransactionIdAbort(xid);
1070 TransactionIdAbortTree(nchildren, children);
1076 * We can immediately remove failed XIDs from PGPROC's cache of
1077 * running child XIDs. It's easiest to do it here while we have the
1078 * child XID array at hand, even though in the main-transaction case
1079 * the equivalent work happens just after return from
1080 * RecordTransactionAbort.
1082 XidCacheRemoveRunningXids(xid, nchildren, children);
1084 /* And clean up local data */
1091 /* ----------------------------------------------------------------
1092 * CleanupTransaction stuff
1093 * ----------------------------------------------------------------
1100 AtCleanup_Memory(void)
1103 * Now that we're "out" of a transaction, have the system allocate
1104 * things in the top memory context instead of per-transaction
1107 MemoryContextSwitchTo(TopMemoryContext);
1109 Assert(CurrentTransactionState->parent == NULL);
1112 * Release all transaction-local memory.
1114 if (TopTransactionContext != NULL)
1115 MemoryContextDelete(TopTransactionContext);
1116 TopTransactionContext = NULL;
1117 CurTransactionContext = NULL;
1118 CurrentTransactionState->curTransactionContext = NULL;
1122 /* ----------------------------------------------------------------
1123 * CleanupSubTransaction stuff
1124 * ----------------------------------------------------------------
1128 * AtSubCleanup_Memory
1131 AtSubCleanup_Memory(void)
1133 TransactionState s = CurrentTransactionState;
1135 Assert(s->parent != NULL);
1137 /* Make sure we're not in an about-to-be-deleted context */
1138 MemoryContextSwitchTo(s->parent->curTransactionContext);
1139 CurTransactionContext = s->parent->curTransactionContext;
1142 * Delete the subxact local memory contexts. Its CurTransactionContext
1143 * can go too (note this also kills CurTransactionContexts from any
1144 * children of the subxact).
1146 MemoryContextDelete(s->curTransactionContext);
1149 /* ----------------------------------------------------------------
1150 * interface routines
1151 * ----------------------------------------------------------------
1158 StartTransaction(void)
1160 TransactionState s = CurrentTransactionState;
1163 * check the current transaction state
1165 if (s->state != TRANS_DEFAULT)
1166 elog(WARNING, "StartTransaction while in %s state",
1167 TransStateAsString(s->state));
1170 * set the current transaction state information appropriately during
1173 s->state = TRANS_START;
1176 * Make sure we've freed any old snapshot, and reset xact state
1180 XactIsoLevel = DefaultXactIsoLevel;
1181 XactReadOnly = DefaultXactReadOnly;
1184 * must initialize resource-management stuff first
1187 AtStart_ResourceOwner();
1190 * generate a new transaction id
1192 s->transactionIdData = GetNewTransactionId(false);
1194 XactLockTableInsert(s->transactionIdData);
1199 xactStartTime = GetCurrentAbsoluteTimeUsec(&(xactStartTimeUsec));
1202 * initialize current transaction state fields
1204 s->commandId = FirstCommandId;
1205 s->nestingLevel = 1;
1209 * You might expect to see "s->currentUser = GetUserId();" here, but
1210 * you won't because it doesn't work during startup; the userid isn't
1211 * set yet during a backend's first transaction start. We only use
1212 * the currentUser field in sub-transaction state structs.
1214 * prevXactReadOnly is also valid only in sub-transactions.
1218 * initialize other subsystems for new transaction
1222 DeferredTriggerBeginXact();
1225 * done with start processing, set current transaction state to "in
1228 s->state = TRANS_INPROGRESS;
1230 ShowTransactionState("StartTransaction");
1237 CommitTransaction(void)
1239 TransactionState s = CurrentTransactionState;
1241 ShowTransactionState("CommitTransaction");
1244 * check the current transaction state
1246 if (s->state != TRANS_INPROGRESS)
1247 elog(WARNING, "CommitTransaction while in %s state",
1248 TransStateAsString(s->state));
1249 Assert(s->parent == NULL);
1252 * Tell the trigger manager that this transaction is about to be
1253 * committed. He'll invoke all trigger deferred until XACT before we
1254 * really start on committing the transaction.
1256 DeferredTriggerEndXact();
1259 * Similarly, let ON COMMIT management do its thing before we start to
1262 PreCommit_on_commit_actions();
1264 /* Prevent cancel/die interrupt while cleaning up */
1268 * set the current transaction state information appropriately during
1269 * the abort processing
1271 s->state = TRANS_COMMIT;
1274 * Do pre-commit processing (most of this stuff requires database
1275 * access, and in fact could still cause an error...)
1280 /* close large objects before lower-level cleanup */
1281 AtEOXact_LargeObject(true);
1283 /* NOTIFY commit must come before lower-level cleanup */
1286 /* Update the flat password file if we changed pg_shadow or pg_group */
1287 /* This should be the last step before commit */
1288 AtEOXact_UpdatePasswordFile(true);
1291 * Here is where we really truly commit.
1293 RecordTransactionCommit();
1296 * Let others know about no transaction in progress by me. Note that
1297 * this must be done _before_ releasing locks we hold and _after_
1298 * RecordTransactionCommit.
1300 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
1301 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
1302 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
1303 * as running as well or it will see two tuple versions - one deleted
1304 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
1308 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1309 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1310 MyProc->xid = InvalidTransactionId;
1311 MyProc->xmin = InvalidTransactionId;
1313 /* Clear the subtransaction-XID cache too while holding the lock */
1314 MyProc->subxids.nxids = 0;
1315 MyProc->subxids.overflowed = false;
1317 LWLockRelease(SInvalLock);
1321 * This is all post-commit cleanup. Note that if an error is raised
1322 * here, it's too late to abort the transaction. This should be just
1323 * noncritical resource releasing.
1325 * The ordering of operations is not entirely random. The idea is:
1326 * release resources visible to other backends (eg, files, buffer
1327 * pins); then release locks; then release backend-local resources. We
1328 * want to release locks at the point where any backend waiting for us
1329 * will see our transaction as being fully cleaned up.
1331 * Resources that can be associated with individual queries are handled
1332 * by the ResourceOwner mechanism. The other calls here are for
1333 * backend-wide state.
1336 smgrDoPendingDeletes(true);
1337 /* smgrcommit already done */
1339 CallXactCallbacks(XACT_EVENT_COMMIT, InvalidTransactionId);
1341 ResourceOwnerRelease(TopTransactionResourceOwner,
1342 RESOURCE_RELEASE_BEFORE_LOCKS,
1346 * Make catalog changes visible to all backends. This has to happen
1347 * after relcache references are dropped (see comments for
1348 * AtEOXact_RelationCache), but before locks are released (if anyone
1349 * is waiting for lock on a relation we've modified, we want them to
1350 * know about the catalog change before they start using the
1353 AtEOXact_Inval(true);
1355 ResourceOwnerRelease(TopTransactionResourceOwner,
1356 RESOURCE_RELEASE_LOCKS,
1358 ResourceOwnerRelease(TopTransactionResourceOwner,
1359 RESOURCE_RELEASE_AFTER_LOCKS,
1362 AtEOXact_GUC(true, false);
1364 AtEOXact_on_commit_actions(true, s->transactionIdData);
1365 AtEOXact_Namespace(true);
1367 pgstat_count_xact_commit();
1369 CurrentResourceOwner = NULL;
1370 ResourceOwnerDelete(TopTransactionResourceOwner);
1371 s->curTransactionOwner = NULL;
1372 CurTransactionResourceOwner = NULL;
1373 TopTransactionResourceOwner = NULL;
1377 s->nestingLevel = 0;
1381 * done with commit processing, set current transaction state back to
1384 s->state = TRANS_DEFAULT;
1386 RESUME_INTERRUPTS();
1393 AbortTransaction(void)
1395 TransactionState s = CurrentTransactionState;
1397 /* Prevent cancel/die interrupt while cleaning up */
1401 * Release any LW locks we might be holding as quickly as possible.
1402 * (Regular locks, however, must be held till we finish aborting.)
1403 * Releasing LW locks is critical since we might try to grab them
1404 * again while cleaning up!
1408 /* Clean up buffer I/O and buffer context locks, too */
1413 * Also clean up any open wait for lock, since the lock manager will
1414 * choke if we try to wait for another lock before doing this.
1419 * check the current transaction state
1421 if (s->state != TRANS_INPROGRESS)
1422 elog(WARNING, "AbortTransaction while in %s state",
1423 TransStateAsString(s->state));
1424 Assert(s->parent == NULL);
1427 * set the current transaction state information appropriately during
1428 * the abort processing
1430 s->state = TRANS_ABORT;
1432 /* Make sure we are in a valid memory context */
1436 * Reset user id which might have been changed transiently. We cannot
1437 * use s->currentUser, but must get the session userid from
1440 * (Note: it is not necessary to restore session authorization here
1441 * because that can only be changed via GUC, and GUC will take care of
1442 * rolling it back if need be. However, an error within a SECURITY
1443 * DEFINER function could send control here with the wrong current
1446 SetUserId(GetSessionUserId());
1449 * do abort processing
1451 DeferredTriggerAbortXact();
1453 AtEOXact_LargeObject(false); /* 'false' means it's abort */
1455 AtEOXact_UpdatePasswordFile(false);
1457 /* Advertise the fact that we aborted in pg_clog. */
1458 RecordTransactionAbort();
1461 * Let others know about no transaction in progress by me. Note that
1462 * this must be done _before_ releasing locks we hold and _after_
1463 * RecordTransactionAbort.
1467 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1468 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1469 MyProc->xid = InvalidTransactionId;
1470 MyProc->xmin = InvalidTransactionId;
1472 /* Clear the subtransaction-XID cache too while holding the lock */
1473 MyProc->subxids.nxids = 0;
1474 MyProc->subxids.overflowed = false;
1476 LWLockRelease(SInvalLock);
1480 * Post-abort cleanup. See notes in CommitTransaction() concerning
1484 smgrDoPendingDeletes(false);
1487 CallXactCallbacks(XACT_EVENT_ABORT, InvalidTransactionId);
1489 ResourceOwnerRelease(TopTransactionResourceOwner,
1490 RESOURCE_RELEASE_BEFORE_LOCKS,
1492 AtEOXact_Inval(false);
1493 ResourceOwnerRelease(TopTransactionResourceOwner,
1494 RESOURCE_RELEASE_LOCKS,
1496 ResourceOwnerRelease(TopTransactionResourceOwner,
1497 RESOURCE_RELEASE_AFTER_LOCKS,
1500 AtEOXact_GUC(false, false);
1501 AtEOXact_SPI(false);
1502 AtEOXact_on_commit_actions(false, s->transactionIdData);
1503 AtEOXact_Namespace(false);
1505 pgstat_count_xact_rollback();
1508 * State remains TRANS_ABORT until CleanupTransaction().
1510 RESUME_INTERRUPTS();
1514 * CleanupTransaction
1517 CleanupTransaction(void)
1519 TransactionState s = CurrentTransactionState;
1522 * State should still be TRANS_ABORT from AbortTransaction().
1524 if (s->state != TRANS_ABORT)
1525 elog(FATAL, "CleanupTransaction: unexpected state %s",
1526 TransStateAsString(s->state));
1529 * do abort cleanup processing
1531 AtCleanup_Portals(); /* now safe to release portal memory */
1533 CurrentResourceOwner = NULL; /* and resource owner */
1534 ResourceOwnerDelete(TopTransactionResourceOwner);
1535 s->curTransactionOwner = NULL;
1536 CurTransactionResourceOwner = NULL;
1537 TopTransactionResourceOwner = NULL;
1539 AtCleanup_Memory(); /* and transaction memory */
1541 s->nestingLevel = 0;
1545 * done with abort processing, set current transaction state back to
1548 s->state = TRANS_DEFAULT;
1552 * StartTransactionCommand
1555 StartTransactionCommand(void)
1557 TransactionState s = CurrentTransactionState;
1559 switch (s->blockState)
1562 * if we aren't in a transaction block, we just do our usual
1563 * start transaction.
1565 case TBLOCK_DEFAULT:
1567 s->blockState = TBLOCK_STARTED;
1571 * This is the case when we are somewhere in a transaction
1572 * block and about to start a new command. For now we do
1573 * nothing but someday we may do command-local resource
1576 case TBLOCK_INPROGRESS:
1577 case TBLOCK_SUBINPROGRESS:
1581 * Here we are in the middle of a transaction block but one of
1582 * the commands caused an abort so we do nothing but remain in
1583 * the abort state. Eventually we will get to the "END
1584 * TRANSACTION" which will set things straight.
1587 case TBLOCK_SUBABORT:
1590 /* These cases are invalid. */
1591 case TBLOCK_STARTED:
1593 case TBLOCK_SUBBEGIN:
1596 case TBLOCK_SUBENDABORT_ALL:
1597 case TBLOCK_SUBENDABORT:
1598 case TBLOCK_SUBABORT_PENDING:
1599 case TBLOCK_SUBENDABORT_RELEASE:
1600 case TBLOCK_ENDABORT:
1601 elog(FATAL, "StartTransactionCommand: unexpected state %s",
1602 BlockStateAsString(s->blockState));
1607 * We must switch to CurTransactionContext before returning. This is
1608 * already done if we called StartTransaction, otherwise not.
1610 Assert(CurTransactionContext != NULL);
1611 MemoryContextSwitchTo(CurTransactionContext);
1615 * CommitTransactionCommand
1618 CommitTransactionCommand(void)
1620 TransactionState s = CurrentTransactionState;
1622 switch (s->blockState)
1625 * This shouldn't happen, because it means the previous
1626 * StartTransactionCommand didn't set the STARTED state
1627 * appropriately, or we didn't manage previous pending abort
1630 case TBLOCK_DEFAULT:
1631 case TBLOCK_SUBABORT_PENDING:
1632 elog(FATAL, "CommitTransactionCommand: unexpected state %s",
1633 BlockStateAsString(s->blockState));
1637 * If we aren't in a transaction block, just do our usual
1638 * transaction commit.
1640 case TBLOCK_STARTED:
1641 CommitTransaction();
1642 s->blockState = TBLOCK_DEFAULT;
1646 * This is the case right after we get a "BEGIN TRANSACTION"
1647 * command, but the user hasn't done anything else yet, so we
1648 * change to the "transaction block in progress" state and
1652 s->blockState = TBLOCK_INPROGRESS;
1656 * This is the case when we have finished executing a command
1657 * someplace within a transaction block. We increment the
1658 * command counter and return.
1660 case TBLOCK_INPROGRESS:
1661 CommandCounterIncrement();
1665 * This is the case when we just got the "END TRANSACTION"
1666 * statement, so we commit the transaction and go back to the
1670 /* commit all open subtransactions */
1671 if (s->nestingLevel > 1)
1672 CommitTransactionToLevel(2);
1673 s = CurrentTransactionState;
1674 Assert(s->parent == NULL);
1675 /* and now the outer transaction */
1676 CommitTransaction();
1677 s->blockState = TBLOCK_DEFAULT;
1681 * Here we are in the middle of a transaction block but one of
1682 * the commands caused an abort so we do nothing but remain in
1683 * the abort state. Eventually we will get to the "END
1684 * TRANSACTION" which will set things straight.
1690 * Here we were in an aborted transaction block which just
1691 * processed the "END TRANSACTION" command from the user, so
1692 * clean up and return to the default state.
1694 case TBLOCK_ENDABORT:
1695 CleanupTransaction();
1696 s->blockState = TBLOCK_DEFAULT;
1700 * Ditto, but in a subtransaction. AbortOutOfAnyTransaction
1701 * will do the dirty work.
1703 case TBLOCK_SUBENDABORT_ALL:
1704 AbortOutOfAnyTransaction();
1705 s = CurrentTransactionState; /* changed by
1706 * AbortOutOfAnyTransaction
1708 /* AbortOutOfAnyTransaction sets the blockState */
1712 * We were just issued a SAVEPOINT inside a transaction block.
1713 * Start a subtransaction. (DefineSavepoint already did
1714 * PushTransaction, so as to have someplace to put the
1717 case TBLOCK_SUBBEGIN:
1718 StartSubTransaction();
1719 s->blockState = TBLOCK_SUBINPROGRESS;
1723 * Inside a subtransaction, increment the command counter.
1725 case TBLOCK_SUBINPROGRESS:
1726 CommandCounterIncrement();
1730 * We were issued a RELEASE command, so we end the current
1731 * subtransaction and return to the parent transaction.
1733 * Since RELEASE can exit multiple levels of subtransaction, we
1734 * must loop here until we get out of all SUBEND'ed levels.
1739 CommitSubTransaction();
1741 s = CurrentTransactionState; /* changed by pop */
1742 } while (s->blockState == TBLOCK_SUBEND);
1746 * If we are in an aborted subtransaction, do nothing.
1748 case TBLOCK_SUBABORT:
1752 * The current subtransaction is ending. Do the equivalent of
1753 * a ROLLBACK TO followed by a RELEASE command.
1755 case TBLOCK_SUBENDABORT_RELEASE:
1756 CleanupAbortedSubTransactions(false);
1760 * The current subtransaction is ending due to a ROLLBACK TO
1761 * command, so close all savepoints up to the target level.
1762 * When finished, recreate the savepoint.
1764 case TBLOCK_SUBENDABORT:
1766 char *name = CleanupAbortedSubTransactions(true);
1768 Assert(PointerIsValid(name));
1769 DefineSavepoint(name);
1770 s = CurrentTransactionState; /* changed by
1771 * DefineSavepoint */
1774 /* This is the same as TBLOCK_SUBBEGIN case */
1775 AssertState(s->blockState == TBLOCK_SUBBEGIN);
1776 StartSubTransaction();
1777 s->blockState = TBLOCK_SUBINPROGRESS;
1784 * CleanupAbortedSubTransactions
1786 * Helper function for CommitTransactionCommand. Aborts and cleans up
1787 * dead subtransactions after a ROLLBACK TO command. Optionally returns
1788 * the name of the last dead subtransaction so it can be reused to redefine
1789 * the savepoint. (Caller is responsible for pfree'ing the result.)
1792 CleanupAbortedSubTransactions(bool returnName)
1794 TransactionState s = CurrentTransactionState;
1797 AssertState(PointerIsValid(s->parent));
1798 Assert(s->parent->blockState == TBLOCK_SUBINPROGRESS ||
1799 s->parent->blockState == TBLOCK_INPROGRESS ||
1800 s->parent->blockState == TBLOCK_STARTED ||
1801 s->parent->blockState == TBLOCK_SUBABORT_PENDING);
1804 * Abort everything up to the target level. The current
1805 * subtransaction only needs cleanup. If we need to save the name,
1806 * look for the last subtransaction in TBLOCK_SUBABORT_PENDING state.
1808 if (returnName && s->parent->blockState != TBLOCK_SUBABORT_PENDING)
1809 name = MemoryContextStrdup(TopMemoryContext, s->name);
1811 CleanupSubTransaction();
1813 s = CurrentTransactionState; /* changed by pop */
1815 while (s->blockState == TBLOCK_SUBABORT_PENDING)
1817 AbortSubTransaction();
1818 if (returnName && s->parent->blockState != TBLOCK_SUBABORT_PENDING)
1819 name = MemoryContextStrdup(TopMemoryContext, s->name);
1820 CleanupSubTransaction();
1822 s = CurrentTransactionState;
1825 AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
1826 s->blockState == TBLOCK_INPROGRESS ||
1827 s->blockState == TBLOCK_STARTED);
1833 * AbortCurrentTransaction
1836 AbortCurrentTransaction(void)
1838 TransactionState s = CurrentTransactionState;
1840 switch (s->blockState)
1843 * we aren't in a transaction, so we do nothing.
1845 case TBLOCK_DEFAULT:
1849 * if we aren't in a transaction block, we just do the basic
1850 * abort & cleanup transaction.
1852 case TBLOCK_STARTED:
1854 CleanupTransaction();
1855 s->blockState = TBLOCK_DEFAULT;
1859 * If we are in TBLOCK_BEGIN it means something screwed up
1860 * right after reading "BEGIN TRANSACTION" so we enter the
1861 * abort state. Eventually an "END TRANSACTION" will fix
1866 s->blockState = TBLOCK_ABORT;
1867 /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
1871 * This is the case when we are somewhere in a transaction
1872 * block and we've gotten a failure, so we abort the
1873 * transaction and set up the persistent ABORT state. We will
1874 * stay in ABORT until we get an "END TRANSACTION".
1876 case TBLOCK_INPROGRESS:
1878 s->blockState = TBLOCK_ABORT;
1879 /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
1883 * Here, the system was fouled up just after the user wanted
1884 * to end the transaction block so we abort the transaction
1885 * and return to the default state.
1889 CleanupTransaction();
1890 s->blockState = TBLOCK_DEFAULT;
1894 * Here, we are already in an aborted transaction state and
1895 * are waiting for an "END TRANSACTION" to come along and lo
1896 * and behold, we abort again! So we just remain in the abort
1900 case TBLOCK_SUBABORT:
1904 * Here we were in an aborted transaction block which just
1905 * processed the "END TRANSACTION" command but somehow aborted
1906 * again.. since we must have done the abort processing, we
1907 * clean up and return to the default state.
1909 case TBLOCK_ENDABORT:
1910 CleanupTransaction();
1911 s->blockState = TBLOCK_DEFAULT;
1915 * If we are just starting a subtransaction, put it in aborted
1918 case TBLOCK_SUBBEGIN:
1919 StartAbortedSubTransaction();
1920 s->blockState = TBLOCK_SUBABORT;
1923 case TBLOCK_SUBINPROGRESS:
1924 AbortSubTransaction();
1925 s->blockState = TBLOCK_SUBABORT;
1929 * If we are aborting an ending transaction, we have to abort
1930 * the parent transaction too.
1933 case TBLOCK_SUBABORT_PENDING:
1934 AbortSubTransaction();
1935 CleanupSubTransaction();
1937 s = CurrentTransactionState; /* changed by pop */
1938 Assert(s->blockState != TBLOCK_SUBEND &&
1939 s->blockState != TBLOCK_SUBENDABORT);
1940 AbortCurrentTransaction();
1944 * Same as above, except the Abort() was already done.
1946 case TBLOCK_SUBENDABORT:
1947 case TBLOCK_SUBENDABORT_RELEASE:
1948 CleanupSubTransaction();
1950 s = CurrentTransactionState; /* changed by pop */
1951 Assert(s->blockState != TBLOCK_SUBEND &&
1952 s->blockState != TBLOCK_SUBENDABORT);
1953 AbortCurrentTransaction();
1957 * We are already aborting the whole transaction tree. Do
1958 * nothing, CommitTransactionCommand will call
1959 * AbortOutOfAnyTransaction and set things straight.
1961 case TBLOCK_SUBENDABORT_ALL:
1967 * PreventTransactionChain
1969 * This routine is to be called by statements that must not run inside
1970 * a transaction block, typically because they have non-rollback-able
1971 * side effects or do internal commits.
1973 * If we have already started a transaction block, issue an error; also issue
1974 * an error if we appear to be running inside a user-defined function (which
1975 * could issue more commands and possibly cause a failure after the statement
1976 * completes). Subtransactions are verboten too.
1978 * stmtNode: pointer to parameter block for statement; this is used in
1979 * a very klugy way to determine whether we are inside a function.
1980 * stmtType: statement type name for error messages.
1983 PreventTransactionChain(void *stmtNode, const char *stmtType)
1986 * xact block already started?
1988 if (IsTransactionBlock())
1990 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1991 /* translator: %s represents an SQL statement name */
1992 errmsg("%s cannot run inside a transaction block",
1998 if (IsSubTransaction())
2000 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2001 /* translator: %s represents an SQL statement name */
2002 errmsg("%s cannot run inside a subtransaction",
2006 * Are we inside a function call? If the statement's parameter block
2007 * was allocated in QueryContext, assume it is an interactive command.
2008 * Otherwise assume it is coming from a function.
2010 if (!MemoryContextContains(QueryContext, stmtNode))
2012 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2013 /* translator: %s represents an SQL statement name */
2014 errmsg("%s cannot be executed from a function", stmtType)));
2016 /* If we got past IsTransactionBlock test, should be in default state */
2017 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2018 CurrentTransactionState->blockState != TBLOCK_STARTED)
2019 elog(FATAL, "cannot prevent transaction chain");
2024 * RequireTransactionChain
2026 * This routine is to be called by statements that must run inside
2027 * a transaction block, because they have no effects that persist past
2028 * transaction end (and so calling them outside a transaction block
2029 * is presumably an error). DECLARE CURSOR is an example.
2031 * If we appear to be running inside a user-defined function, we do not
2032 * issue an error, since the function could issue more commands that make
2033 * use of the current statement's results. Likewise subtransactions.
2034 * Thus this is an inverse for PreventTransactionChain.
2036 * stmtNode: pointer to parameter block for statement; this is used in
2037 * a very klugy way to determine whether we are inside a function.
2038 * stmtType: statement type name for error messages.
2041 RequireTransactionChain(void *stmtNode, const char *stmtType)
2044 * xact block already started?
2046 if (IsTransactionBlock())
2052 if (IsSubTransaction())
2056 * Are we inside a function call? If the statement's parameter block
2057 * was allocated in QueryContext, assume it is an interactive command.
2058 * Otherwise assume it is coming from a function.
2060 if (!MemoryContextContains(QueryContext, stmtNode))
2063 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2064 /* translator: %s represents an SQL statement name */
2065 errmsg("%s may only be used in transaction blocks",
2070 * IsInTransactionChain
2072 * This routine is for statements that need to behave differently inside
2073 * a transaction block than when running as single commands. ANALYZE is
2074 * currently the only example.
2076 * stmtNode: pointer to parameter block for statement; this is used in
2077 * a very klugy way to determine whether we are inside a function.
2080 IsInTransactionChain(void *stmtNode)
2083 * Return true on same conditions that would make
2084 * PreventTransactionChain error out
2086 if (IsTransactionBlock())
2089 if (IsSubTransaction())
2092 if (!MemoryContextContains(QueryContext, stmtNode))
2095 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2096 CurrentTransactionState->blockState != TBLOCK_STARTED)
2104 * Register or deregister callback functions for start- and end-of-xact
2107 * These functions are intended for use by dynamically loaded modules.
2108 * For built-in modules we generally just hardwire the appropriate calls
2109 * (mainly because it's easier to control the order that way, where needed).
2111 * At transaction end, the callback occurs post-commit or post-abort, so the
2112 * callback functions can only do noncritical cleanup. At subtransaction
2113 * start, the callback is called when the subtransaction has finished
2117 RegisterXactCallback(XactCallback callback, void *arg)
2119 XactCallbackItem *item;
2121 item = (XactCallbackItem *)
2122 MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
2123 item->callback = callback;
2125 item->next = Xact_callbacks;
2126 Xact_callbacks = item;
2130 UnregisterXactCallback(XactCallback callback, void *arg)
2132 XactCallbackItem *item;
2133 XactCallbackItem *prev;
2136 for (item = Xact_callbacks; item; prev = item, item = item->next)
2138 if (item->callback == callback && item->arg == arg)
2141 prev->next = item->next;
2143 Xact_callbacks = item->next;
2151 CallXactCallbacks(XactEvent event, TransactionId parentXid)
2153 XactCallbackItem *item;
2155 for (item = Xact_callbacks; item; item = item->next)
2156 (*item->callback) (event, parentXid, item->arg);
2160 /* ----------------------------------------------------------------
2161 * transaction block support
2162 * ----------------------------------------------------------------
2166 * BeginTransactionBlock
2167 * This executes a BEGIN command.
2170 BeginTransactionBlock(void)
2172 TransactionState s = CurrentTransactionState;
2174 switch (s->blockState)
2177 * We are not inside a transaction block, so allow one to
2180 case TBLOCK_STARTED:
2181 s->blockState = TBLOCK_BEGIN;
2185 * Already a transaction block in progress.
2187 case TBLOCK_INPROGRESS:
2188 case TBLOCK_SUBINPROGRESS:
2190 case TBLOCK_SUBABORT:
2192 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2193 errmsg("there is already a transaction in progress")));
2196 /* These cases are invalid. Reject them altogether. */
2197 case TBLOCK_DEFAULT:
2199 case TBLOCK_SUBBEGIN:
2200 case TBLOCK_ENDABORT:
2202 case TBLOCK_SUBENDABORT_ALL:
2203 case TBLOCK_SUBENDABORT:
2204 case TBLOCK_SUBABORT_PENDING:
2205 case TBLOCK_SUBENDABORT_RELEASE:
2207 elog(FATAL, "BeginTransactionBlock: unexpected state %s",
2208 BlockStateAsString(s->blockState));
2214 * EndTransactionBlock
2215 * This executes a COMMIT command.
2217 * Since COMMIT may actually do a ROLLBACK, the result indicates what
2218 * happened: TRUE for COMMIT, FALSE for ROLLBACK.
2221 EndTransactionBlock(void)
2223 TransactionState s = CurrentTransactionState;
2224 bool result = false;
2226 switch (s->blockState)
2229 * We are in a transaction block which should commit when we
2230 * get to the upcoming CommitTransactionCommand() so we set
2231 * the state to "END". CommitTransactionCommand() will
2232 * recognize this and commit the transaction and return us to
2233 * the default state.
2235 case TBLOCK_INPROGRESS:
2236 case TBLOCK_SUBINPROGRESS:
2237 s->blockState = TBLOCK_END;
2242 * We are in a transaction block which aborted. Since the
2243 * AbortTransaction() was already done, we need only change to
2244 * the special "END ABORT" state. The upcoming
2245 * CommitTransactionCommand() will recognise this and then put
2246 * us back in the default state.
2249 s->blockState = TBLOCK_ENDABORT;
2253 * Here we are inside an aborted subtransaction. Go to the
2254 * "abort the whole tree" state so that
2255 * CommitTransactionCommand() calls AbortOutOfAnyTransaction.
2257 case TBLOCK_SUBABORT:
2258 s->blockState = TBLOCK_SUBENDABORT_ALL;
2261 case TBLOCK_STARTED:
2264 * here, the user issued COMMIT when not inside a transaction.
2265 * Issue a WARNING and go to abort state. The upcoming call
2266 * to CommitTransactionCommand() will then put us back into
2267 * the default state.
2270 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2271 errmsg("there is no transaction in progress")));
2273 s->blockState = TBLOCK_ENDABORT;
2276 /* these cases are invalid. */
2277 case TBLOCK_DEFAULT:
2279 case TBLOCK_ENDABORT:
2281 case TBLOCK_SUBBEGIN:
2283 case TBLOCK_SUBENDABORT_ALL:
2284 case TBLOCK_SUBENDABORT:
2285 case TBLOCK_SUBABORT_PENDING:
2286 case TBLOCK_SUBENDABORT_RELEASE:
2287 elog(FATAL, "EndTransactionBlock: unexpected state %s",
2288 BlockStateAsString(s->blockState));
2296 * UserAbortTransactionBlock
2297 * This executes a ROLLBACK command.
2300 UserAbortTransactionBlock(void)
2302 TransactionState s = CurrentTransactionState;
2304 switch (s->blockState)
2307 * We are inside a failed transaction block and we got an
2308 * abort command from the user. Abort processing is already
2309 * done, we just need to move to the ENDABORT state so we will
2310 * end up in the default state after the upcoming
2311 * CommitTransactionCommand().
2314 s->blockState = TBLOCK_ENDABORT;
2318 * We are inside a failed subtransaction and we got an abort
2319 * command from the user. Abort processing is already done,
2320 * so go to the "abort all" state and CommitTransactionCommand
2321 * will call AbortOutOfAnyTransaction to set things straight.
2323 case TBLOCK_SUBABORT:
2324 s->blockState = TBLOCK_SUBENDABORT_ALL;
2328 * We are inside a transaction block and we got an abort
2329 * command from the user, so we move to the ENDABORT state and
2330 * do abort processing so we will end up in the default state
2331 * after the upcoming CommitTransactionCommand().
2333 case TBLOCK_INPROGRESS:
2335 s->blockState = TBLOCK_ENDABORT;
2339 * We are inside a subtransaction. Abort the current
2340 * subtransaction and go to the "abort all" state, so
2341 * CommitTransactionCommand will call AbortOutOfAnyTransaction
2342 * to set things straight.
2344 case TBLOCK_SUBINPROGRESS:
2345 AbortSubTransaction();
2346 s->blockState = TBLOCK_SUBENDABORT_ALL;
2350 * The user issued ABORT when not inside a transaction. Issue
2351 * a WARNING and go to abort state. The upcoming call to
2352 * CommitTransactionCommand() will then put us back into the
2355 case TBLOCK_STARTED:
2357 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2358 errmsg("there is no transaction in progress")));
2360 s->blockState = TBLOCK_ENDABORT;
2363 /* These cases are invalid. */
2364 case TBLOCK_DEFAULT:
2367 case TBLOCK_ENDABORT:
2369 case TBLOCK_SUBENDABORT_ALL:
2370 case TBLOCK_SUBENDABORT:
2371 case TBLOCK_SUBABORT_PENDING:
2372 case TBLOCK_SUBENDABORT_RELEASE:
2373 case TBLOCK_SUBBEGIN:
2374 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2375 BlockStateAsString(s->blockState));
2382 * This executes a SAVEPOINT command.
2385 DefineSavepoint(char *name)
2387 TransactionState s = CurrentTransactionState;
2389 switch (s->blockState)
2391 case TBLOCK_INPROGRESS:
2392 case TBLOCK_SUBINPROGRESS:
2393 /* Normal subtransaction start */
2395 s = CurrentTransactionState; /* changed by push */
2398 * Note that we are allocating the savepoint name in the
2399 * parent transaction's CurTransactionContext, since we don't
2400 * yet have a transaction context for the new guy.
2402 s->name = MemoryContextStrdup(CurTransactionContext, name);
2403 s->blockState = TBLOCK_SUBBEGIN;
2406 /* These cases are invalid. Reject them altogether. */
2407 case TBLOCK_DEFAULT:
2408 case TBLOCK_STARTED:
2410 case TBLOCK_SUBBEGIN:
2412 case TBLOCK_SUBABORT:
2413 case TBLOCK_ENDABORT:
2415 case TBLOCK_SUBENDABORT_ALL:
2416 case TBLOCK_SUBENDABORT:
2417 case TBLOCK_SUBABORT_PENDING:
2418 case TBLOCK_SUBENDABORT_RELEASE:
2420 elog(FATAL, "DefineSavepoint: unexpected state %s",
2421 BlockStateAsString(s->blockState));
2428 * This executes a RELEASE command.
2431 ReleaseSavepoint(List *options)
2433 TransactionState s = CurrentTransactionState;
2434 TransactionState target,
2440 * Check valid block state transaction status.
2442 switch (s->blockState)
2444 case TBLOCK_INPROGRESS:
2447 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2448 errmsg("no such savepoint")));
2452 * We are in a non-aborted subtransaction. This is the only
2455 case TBLOCK_SUBINPROGRESS:
2458 /* these cases are invalid. */
2459 case TBLOCK_DEFAULT:
2460 case TBLOCK_STARTED:
2462 case TBLOCK_ENDABORT:
2464 case TBLOCK_SUBABORT:
2465 case TBLOCK_SUBBEGIN:
2467 case TBLOCK_SUBENDABORT_ALL:
2468 case TBLOCK_SUBENDABORT:
2469 case TBLOCK_SUBABORT_PENDING:
2470 case TBLOCK_SUBENDABORT_RELEASE:
2471 elog(FATAL, "ReleaseSavepoint: unexpected state %s",
2472 BlockStateAsString(s->blockState));
2476 foreach(cell, options)
2478 DefElem *elem = lfirst(cell);
2480 if (strcmp(elem->defname, "savepoint_name") == 0)
2481 name = strVal(elem->arg);
2484 Assert(PointerIsValid(name));
2486 for (target = s; PointerIsValid(target); target = target->parent)
2488 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2492 if (!PointerIsValid(target))
2494 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2495 errmsg("no such savepoint")));
2497 /* disallow crossing savepoint level boundaries */
2498 if (target->savepointLevel != s->savepointLevel)
2500 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2501 errmsg("no such savepoint")));
2504 * Mark "commit pending" all subtransactions up to the target
2505 * subtransaction. The actual commits will happen when control gets
2506 * to CommitTransactionCommand.
2508 xact = CurrentTransactionState;
2511 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2512 xact->blockState = TBLOCK_SUBEND;
2515 xact = xact->parent;
2516 Assert(PointerIsValid(xact));
2521 * RollbackToSavepoint
2522 * This executes a ROLLBACK TO <savepoint> command.
2525 RollbackToSavepoint(List *options)
2527 TransactionState s = CurrentTransactionState;
2528 TransactionState target,
2533 switch (s->blockState)
2536 * We can't rollback to a savepoint if there is no saveopint
2540 case TBLOCK_INPROGRESS:
2542 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2543 errmsg("no such savepoint")));
2547 * There is at least one savepoint, so proceed.
2549 case TBLOCK_SUBABORT:
2550 case TBLOCK_SUBINPROGRESS:
2553 * Have to do AbortSubTransaction, but first check if this is
2554 * the right subtransaction
2558 /* these cases are invalid. */
2559 case TBLOCK_DEFAULT:
2560 case TBLOCK_STARTED:
2563 case TBLOCK_ENDABORT:
2565 case TBLOCK_SUBENDABORT_ALL:
2566 case TBLOCK_SUBENDABORT:
2567 case TBLOCK_SUBABORT_PENDING:
2568 case TBLOCK_SUBENDABORT_RELEASE:
2569 case TBLOCK_SUBBEGIN:
2570 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2571 BlockStateAsString(s->blockState));
2575 foreach(cell, options)
2577 DefElem *elem = lfirst(cell);
2579 if (strcmp(elem->defname, "savepoint_name") == 0)
2580 name = strVal(elem->arg);
2583 Assert(PointerIsValid(name));
2585 for (target = s; PointerIsValid(target); target = target->parent)
2587 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2591 if (!PointerIsValid(target))
2593 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2594 errmsg("no such savepoint")));
2596 /* disallow crossing savepoint level boundaries */
2597 if (target->savepointLevel != s->savepointLevel)
2599 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2600 errmsg("no such savepoint")));
2603 * Abort the current subtransaction, if needed. We can't Cleanup the
2604 * savepoint yet, so signal CommitTransactionCommand to do it and
2605 * close all savepoints up to the target level.
2607 if (s->blockState == TBLOCK_SUBINPROGRESS)
2608 AbortSubTransaction();
2609 s->blockState = TBLOCK_SUBENDABORT;
2612 * Mark "abort pending" all subtransactions up to the target
2613 * subtransaction. (Except the current subtransaction!)
2615 xact = CurrentTransactionState;
2617 while (xact != target)
2619 xact = xact->parent;
2620 Assert(PointerIsValid(xact));
2621 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2622 xact->blockState = TBLOCK_SUBABORT_PENDING;
2627 * BeginInternalSubTransaction
2628 * This is the same as DefineSavepoint except it allows TBLOCK_STARTED
2629 * state, and therefore it can safely be used in a function that might
2630 * be called when not inside a BEGIN block. Also, we automatically
2631 * cycle through CommitTransactionCommand/StartTransactionCommand
2632 * instead of expecting the caller to do it.
2634 * Optionally, name can be NULL to create an unnamed savepoint.
2637 BeginInternalSubTransaction(char *name)
2639 TransactionState s = CurrentTransactionState;
2641 switch (s->blockState)
2643 case TBLOCK_STARTED:
2644 case TBLOCK_INPROGRESS:
2645 case TBLOCK_SUBINPROGRESS:
2646 /* Normal subtransaction start */
2648 s = CurrentTransactionState; /* changed by push */
2651 * Note that we are allocating the savepoint name in the
2652 * parent transaction's CurTransactionContext, since we don't
2653 * yet have a transaction context for the new guy.
2656 s->name = MemoryContextStrdup(CurTransactionContext, name);
2657 s->blockState = TBLOCK_SUBBEGIN;
2660 /* These cases are invalid. Reject them altogether. */
2661 case TBLOCK_DEFAULT:
2663 case TBLOCK_SUBBEGIN:
2665 case TBLOCK_SUBABORT:
2666 case TBLOCK_ENDABORT:
2668 case TBLOCK_SUBENDABORT_ALL:
2669 case TBLOCK_SUBENDABORT:
2670 case TBLOCK_SUBABORT_PENDING:
2671 case TBLOCK_SUBENDABORT_RELEASE:
2673 elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
2674 BlockStateAsString(s->blockState));
2678 CommitTransactionCommand();
2679 StartTransactionCommand();
2683 * ReleaseCurrentSubTransaction
2685 * RELEASE (ie, commit) the innermost subtransaction, regardless of its
2686 * savepoint name (if any).
2687 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2690 ReleaseCurrentSubTransaction(void)
2692 TransactionState s = CurrentTransactionState;
2694 if (s->blockState != TBLOCK_SUBINPROGRESS)
2695 elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
2696 BlockStateAsString(s->blockState));
2697 MemoryContextSwitchTo(CurTransactionContext);
2698 CommitTransactionToLevel(GetCurrentTransactionNestLevel());
2702 * RollbackAndReleaseCurrentSubTransaction
2704 * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
2705 * of its savepoint name (if any).
2706 * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2709 RollbackAndReleaseCurrentSubTransaction(void)
2711 TransactionState s = CurrentTransactionState;
2713 switch (s->blockState)
2715 /* Must be in a subtransaction */
2716 case TBLOCK_SUBABORT:
2717 case TBLOCK_SUBINPROGRESS:
2720 /* these cases are invalid. */
2721 case TBLOCK_DEFAULT:
2722 case TBLOCK_STARTED:
2724 case TBLOCK_INPROGRESS:
2727 case TBLOCK_ENDABORT:
2729 case TBLOCK_SUBENDABORT_ALL:
2730 case TBLOCK_SUBENDABORT:
2731 case TBLOCK_SUBABORT_PENDING:
2732 case TBLOCK_SUBENDABORT_RELEASE:
2733 case TBLOCK_SUBBEGIN:
2734 elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
2735 BlockStateAsString(s->blockState));
2740 * Abort the current subtransaction, if needed.
2742 if (s->blockState == TBLOCK_SUBINPROGRESS)
2743 AbortSubTransaction();
2744 s->blockState = TBLOCK_SUBENDABORT_RELEASE;
2746 /* And clean it up, too */
2747 CleanupAbortedSubTransactions(false);
2751 * AbortOutOfAnyTransaction
2753 * This routine is provided for error recovery purposes. It aborts any
2754 * active transaction or transaction block, leaving the system in a known
2758 AbortOutOfAnyTransaction(void)
2760 TransactionState s = CurrentTransactionState;
2763 * Get out of any transaction or nested transaction
2767 switch (s->blockState)
2769 case TBLOCK_DEFAULT:
2770 /* Not in a transaction, do nothing */
2772 case TBLOCK_STARTED:
2774 case TBLOCK_INPROGRESS:
2776 /* In a transaction, so clean up */
2778 CleanupTransaction();
2779 s->blockState = TBLOCK_DEFAULT;
2782 case TBLOCK_ENDABORT:
2783 /* AbortTransaction already done, still need Cleanup */
2784 CleanupTransaction();
2785 s->blockState = TBLOCK_DEFAULT;
2787 case TBLOCK_SUBBEGIN:
2790 * We didn't get as far as starting the subxact, so
2791 * there's nothing to abort. Just pop back to parent.
2794 s = CurrentTransactionState; /* changed by pop */
2796 case TBLOCK_SUBINPROGRESS:
2798 case TBLOCK_SUBABORT_PENDING:
2801 * In a subtransaction, so clean it up and abort parent
2804 AbortSubTransaction();
2805 CleanupSubTransaction();
2807 s = CurrentTransactionState; /* changed by pop */
2809 case TBLOCK_SUBABORT:
2810 case TBLOCK_SUBENDABORT_ALL:
2811 case TBLOCK_SUBENDABORT:
2812 case TBLOCK_SUBENDABORT_RELEASE:
2813 /* As above, but AbortSubTransaction already done */
2814 CleanupSubTransaction();
2816 s = CurrentTransactionState; /* changed by pop */
2819 } while (s->blockState != TBLOCK_DEFAULT);
2821 /* Should be out of all subxacts now */
2822 Assert(s->parent == NULL);
2826 * CommitTransactionToLevel
2828 * Commit everything from the current transaction level
2829 * up to the specified level (inclusive).
2832 CommitTransactionToLevel(int level)
2834 TransactionState s = CurrentTransactionState;
2836 Assert(s->state == TRANS_INPROGRESS);
2838 while (s->nestingLevel >= level)
2840 CommitSubTransaction();
2842 s = CurrentTransactionState; /* changed by pop */
2843 Assert(s->state == TRANS_INPROGRESS);
2848 * IsTransactionBlock --- are we within a transaction block?
2851 IsTransactionBlock(void)
2853 TransactionState s = CurrentTransactionState;
2855 if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
2862 * IsTransactionOrTransactionBlock --- are we within either a transaction
2863 * or a transaction block? (The backend is only really "idle" when this
2866 * This should match up with IsTransactionBlock and IsTransactionState.
2869 IsTransactionOrTransactionBlock(void)
2871 TransactionState s = CurrentTransactionState;
2873 if (s->blockState == TBLOCK_DEFAULT)
2880 * TransactionBlockStatusCode - return status code to send in ReadyForQuery
2883 TransactionBlockStatusCode(void)
2885 TransactionState s = CurrentTransactionState;
2887 switch (s->blockState)
2889 case TBLOCK_DEFAULT:
2890 case TBLOCK_STARTED:
2891 return 'I'; /* idle --- not in transaction */
2893 case TBLOCK_INPROGRESS:
2895 case TBLOCK_SUBINPROGRESS:
2896 case TBLOCK_SUBBEGIN:
2898 return 'T'; /* in transaction */
2900 case TBLOCK_ENDABORT:
2901 case TBLOCK_SUBABORT:
2902 case TBLOCK_SUBENDABORT_ALL:
2903 case TBLOCK_SUBENDABORT:
2904 case TBLOCK_SUBABORT_PENDING:
2905 case TBLOCK_SUBENDABORT_RELEASE:
2906 return 'E'; /* in failed transaction */
2909 /* should never get here */
2910 elog(FATAL, "invalid transaction block state: %s",
2911 BlockStateAsString(s->blockState));
2912 return 0; /* keep compiler quiet */
2919 IsSubTransaction(void)
2921 TransactionState s = CurrentTransactionState;
2923 if (s->nestingLevel >= 2)
2930 * StartSubTransaction
2933 StartSubTransaction(void)
2935 TransactionState s = CurrentTransactionState;
2937 if (s->state != TRANS_DEFAULT)
2938 elog(WARNING, "StartSubTransaction while in %s state",
2939 TransStateAsString(s->state));
2941 s->state = TRANS_START;
2944 * must initialize resource-management stuff first
2946 AtSubStart_Memory();
2947 AtSubStart_ResourceOwner();
2950 * Generate a new Xid and record it in pg_subtrans. NB: we must make
2951 * the subtrans entry BEFORE the Xid appears anywhere in shared
2952 * storage, such as in the lock table; because until it's made the Xid
2953 * may not appear to be "running" to other backends. See
2954 * GetNewTransactionId.
2956 s->transactionIdData = GetNewTransactionId(true);
2958 SubTransSetParent(s->transactionIdData, s->parent->transactionIdData);
2960 XactLockTableInsert(s->transactionIdData);
2963 * Finish setup of other transaction state fields.
2965 s->currentUser = GetUserId();
2966 s->prevXactReadOnly = XactReadOnly;
2969 * Initialize other subsystems for new subtransaction
2972 AtSubStart_Notify();
2973 DeferredTriggerBeginSubXact();
2975 s->state = TRANS_INPROGRESS;
2978 * Call start-of-subxact callbacks
2980 CallXactCallbacks(XACT_EVENT_START_SUB, s->parent->transactionIdData);
2982 ShowTransactionState("StartSubTransaction");
2986 * CommitSubTransaction
2989 CommitSubTransaction(void)
2991 TransactionState s = CurrentTransactionState;
2993 ShowTransactionState("CommitSubTransaction");
2995 if (s->state != TRANS_INPROGRESS)
2996 elog(WARNING, "CommitSubTransaction while in %s state",
2997 TransStateAsString(s->state));
2999 /* Pre-commit processing goes here -- nothing to do at the moment */
3001 s->state = TRANS_COMMIT;
3003 /* Mark subtransaction as subcommitted */
3004 CommandCounterIncrement();
3005 RecordSubTransactionCommit();
3006 AtSubCommit_childXids();
3008 /* Post-commit cleanup */
3009 DeferredTriggerEndSubXact(true);
3010 AtSubCommit_Portals(s->parent->transactionIdData,
3011 s->parent->curTransactionOwner);
3012 AtEOSubXact_LargeObject(true, s->transactionIdData,
3013 s->parent->transactionIdData);
3014 AtSubCommit_Notify();
3015 AtEOSubXact_UpdatePasswordFile(true, s->transactionIdData,
3016 s->parent->transactionIdData);
3019 CallXactCallbacks(XACT_EVENT_COMMIT_SUB, s->parent->transactionIdData);
3021 ResourceOwnerRelease(s->curTransactionOwner,
3022 RESOURCE_RELEASE_BEFORE_LOCKS,
3024 AtEOSubXact_RelationCache(true, s->transactionIdData,
3025 s->parent->transactionIdData);
3026 AtEOSubXact_Inval(true);
3027 ResourceOwnerRelease(s->curTransactionOwner,
3028 RESOURCE_RELEASE_LOCKS,
3030 ResourceOwnerRelease(s->curTransactionOwner,
3031 RESOURCE_RELEASE_AFTER_LOCKS,
3034 AtEOXact_GUC(true, true);
3035 AtEOSubXact_SPI(true, s->transactionIdData);
3036 AtEOSubXact_on_commit_actions(true, s->transactionIdData,
3037 s->parent->transactionIdData);
3038 AtEOSubXact_Namespace(true, s->transactionIdData,
3039 s->parent->transactionIdData);
3040 AtEOSubXact_Files(true, s->transactionIdData,
3041 s->parent->transactionIdData);
3044 * We need to restore the upper transaction's read-only state, in case
3045 * the upper is read-write while the child is read-only; GUC will
3046 * incorrectly think it should leave the child state in place.
3048 XactReadOnly = s->prevXactReadOnly;
3050 CurrentResourceOwner = s->parent->curTransactionOwner;
3051 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3052 ResourceOwnerDelete(s->curTransactionOwner);
3053 s->curTransactionOwner = NULL;
3055 AtSubCommit_Memory();
3057 s->state = TRANS_DEFAULT;
3061 * AbortSubTransaction
3064 AbortSubTransaction(void)
3066 TransactionState s = CurrentTransactionState;
3068 ShowTransactionState("AbortSubTransaction");
3070 if (s->state != TRANS_INPROGRESS)
3071 elog(WARNING, "AbortSubTransaction while in %s state",
3072 TransStateAsString(s->state));
3076 s->state = TRANS_ABORT;
3079 * Release any LW locks we might be holding as quickly as possible.
3080 * (Regular locks, however, must be held till we finish aborting.)
3081 * Releasing LW locks is critical since we might try to grab them
3082 * again while cleaning up!
3084 * FIXME This may be incorrect --- Are there some locks we should keep?
3085 * Buffer locks, for example? I don't think so but I'm not sure.
3095 * do abort processing
3097 AtSubAbort_Memory();
3099 DeferredTriggerEndSubXact(false);
3100 AtSubAbort_Portals(s->parent->transactionIdData,
3101 s->parent->curTransactionOwner);
3102 AtEOSubXact_LargeObject(false, s->transactionIdData,
3103 s->parent->transactionIdData);
3104 AtSubAbort_Notify();
3105 AtEOSubXact_UpdatePasswordFile(false, s->transactionIdData,
3106 s->parent->transactionIdData);
3108 /* Advertise the fact that we aborted in pg_clog. */
3109 RecordSubTransactionAbort();
3111 /* Post-abort cleanup */
3114 CallXactCallbacks(XACT_EVENT_ABORT_SUB, s->parent->transactionIdData);
3116 ResourceOwnerRelease(s->curTransactionOwner,
3117 RESOURCE_RELEASE_BEFORE_LOCKS,
3119 AtEOSubXact_RelationCache(false, s->transactionIdData,
3120 s->parent->transactionIdData);
3121 AtEOSubXact_Inval(false);
3122 ResourceOwnerRelease(s->curTransactionOwner,
3123 RESOURCE_RELEASE_LOCKS,
3125 ResourceOwnerRelease(s->curTransactionOwner,
3126 RESOURCE_RELEASE_AFTER_LOCKS,
3129 AtEOXact_GUC(false, true);
3130 AtEOSubXact_SPI(false, s->transactionIdData);
3131 AtEOSubXact_on_commit_actions(false, s->transactionIdData,
3132 s->parent->transactionIdData);
3133 AtEOSubXact_Namespace(false, s->transactionIdData,
3134 s->parent->transactionIdData);
3135 AtEOSubXact_Files(false, s->transactionIdData,
3136 s->parent->transactionIdData);
3139 * Reset user id which might have been changed transiently. Here we
3140 * want to restore to the userid that was current at subxact entry.
3141 * (As in AbortTransaction, we need not worry about the session
3144 * Must do this after AtEOXact_GUC to handle the case where we entered
3145 * the subxact inside a SECURITY DEFINER function (hence current and
3146 * session userids were different) and then session auth was changed
3147 * inside the subxact. GUC will reset both current and session
3148 * userids to the entry-time session userid. This is right in every
3149 * other scenario so it seems simplest to let GUC do that and fix it
3152 SetUserId(s->currentUser);
3155 * Restore the upper transaction's read-only state, too. This should
3156 * be redundant with GUC's cleanup but we may as well do it for
3157 * consistency with the commit case.
3159 XactReadOnly = s->prevXactReadOnly;
3161 RESUME_INTERRUPTS();
3165 * CleanupSubTransaction
3168 CleanupSubTransaction(void)
3170 TransactionState s = CurrentTransactionState;
3172 ShowTransactionState("CleanupSubTransaction");
3174 if (s->state != TRANS_ABORT)
3175 elog(WARNING, "CleanupSubTransaction while in %s state",
3176 TransStateAsString(s->state));
3178 AtSubCleanup_Portals();
3180 CurrentResourceOwner = s->parent->curTransactionOwner;
3181 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3182 ResourceOwnerDelete(s->curTransactionOwner);
3183 s->curTransactionOwner = NULL;
3185 AtSubCleanup_Memory();
3187 s->state = TRANS_DEFAULT;
3191 * StartAbortedSubTransaction
3193 * This function is used to start a subtransaction and put it immediately
3194 * into aborted state. The end result should be equivalent to
3195 * StartSubTransaction immediately followed by AbortSubTransaction.
3196 * The reason we don't implement it just that way is that many of the backend
3197 * modules aren't designed to handle starting a subtransaction when not
3198 * inside a valid transaction. Rather than making them all capable of
3199 * doing that, we just omit the paired start and abort calls in this path.
3202 StartAbortedSubTransaction(void)
3204 TransactionState s = CurrentTransactionState;
3206 if (s->state != TRANS_DEFAULT)
3207 elog(WARNING, "StartAbortedSubTransaction while in %s state",
3208 TransStateAsString(s->state));
3210 s->state = TRANS_START;
3213 * We don't bother to generate a new Xid, so the end state is not
3214 * *exactly* like we had done a full Start/AbortSubTransaction...
3216 s->transactionIdData = InvalidTransactionId;
3218 /* Make sure currentUser is reasonably valid */
3219 Assert(s->parent != NULL);
3220 s->currentUser = s->parent->currentUser;
3223 * Initialize only what has to be there for CleanupSubTransaction to
3226 AtSubStart_Memory();
3227 AtSubStart_ResourceOwner();
3229 s->state = TRANS_ABORT;
3231 AtSubAbort_Memory();
3233 ShowTransactionState("StartAbortedSubTransaction");
3238 * Set up transaction state for a subtransaction
3240 * The caller has to make sure to always reassign CurrentTransactionState
3241 * if it has a local pointer to it after calling this function.
3244 PushTransaction(void)
3246 TransactionState p = CurrentTransactionState;
3250 * We keep subtransaction state nodes in TopTransactionContext.
3252 s = (TransactionState)
3253 MemoryContextAllocZero(TopTransactionContext,
3254 sizeof(TransactionStateData));
3256 s->nestingLevel = p->nestingLevel + 1;
3257 s->savepointLevel = p->savepointLevel;
3258 s->state = TRANS_DEFAULT;
3259 s->blockState = TBLOCK_SUBBEGIN;
3261 /* Command IDs count in a continuous sequence through subtransactions */
3262 s->commandId = p->commandId;
3265 * Copy down some other data so that we will have valid state until
3266 * StartSubTransaction runs.
3268 s->transactionIdData = p->transactionIdData;
3269 s->curTransactionContext = p->curTransactionContext;
3270 s->curTransactionOwner = p->curTransactionOwner;
3271 s->currentUser = p->currentUser;
3273 CurrentTransactionState = s;
3278 * Pop back to parent transaction state
3280 * The caller has to make sure to always reassign CurrentTransactionState
3281 * if it has a local pointer to it after calling this function.
3284 PopTransaction(void)
3286 TransactionState s = CurrentTransactionState;
3288 if (s->state != TRANS_DEFAULT)
3289 elog(WARNING, "PopTransaction while in %s state",
3290 TransStateAsString(s->state));
3292 if (s->parent == NULL)
3293 elog(FATAL, "PopTransaction with no parent");
3295 /* Command IDs count in a continuous sequence through subtransactions */
3296 s->parent->commandId = s->commandId;
3298 CurrentTransactionState = s->parent;
3300 /* Let's just make sure CurTransactionContext is good */
3301 CurTransactionContext = s->parent->curTransactionContext;
3302 MemoryContextSwitchTo(CurTransactionContext);
3304 /* Ditto for ResourceOwner links */
3305 CurTransactionResourceOwner = s->parent->curTransactionOwner;
3306 CurrentResourceOwner = s->parent->curTransactionOwner;
3308 /* Free the old child structure */
3315 * ShowTransactionState
3319 ShowTransactionState(const char *str)
3321 /* skip work if message will definitely not be printed */
3322 if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
3324 elog(DEBUG2, "%s", str);
3325 ShowTransactionStateRec(CurrentTransactionState);
3330 * ShowTransactionStateRec
3331 * Recursive subroutine for ShowTransactionState
3334 ShowTransactionStateRec(TransactionState s)
3337 ShowTransactionStateRec(s->parent);
3339 /* use ereport to suppress computation if msg will not be printed */
3341 (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/cid: %u/%02u, nestlvl: %d, children: %s",
3342 PointerIsValid(s->name) ? s->name : "unnamed",
3343 BlockStateAsString(s->blockState),
3344 TransStateAsString(s->state),
3345 (unsigned int) s->transactionIdData,
3346 (unsigned int) s->commandId,
3348 nodeToString(s->childXids))));
3352 * BlockStateAsString
3356 BlockStateAsString(TBlockState blockState)
3360 case TBLOCK_DEFAULT:
3362 case TBLOCK_STARTED:
3366 case TBLOCK_INPROGRESS:
3367 return "INPROGRESS";
3372 case TBLOCK_ENDABORT:
3374 case TBLOCK_SUBBEGIN:
3376 case TBLOCK_SUBINPROGRESS:
3377 return "SUB INPROGRS";
3380 case TBLOCK_SUBABORT:
3382 case TBLOCK_SUBENDABORT_ALL:
3383 return "SUB ENDAB ALL";
3384 case TBLOCK_SUBENDABORT:
3386 case TBLOCK_SUBABORT_PENDING:
3387 return "SUB ABRT PEND";
3388 case TBLOCK_SUBENDABORT_RELEASE:
3389 return "SUB ENDAB REL";
3391 return "UNRECOGNIZED";
3395 * TransStateAsString
3399 TransStateAsString(TransState state)
3411 case TRANS_INPROGRESS:
3414 return "UNRECOGNIZED";
3418 * xactGetCommittedChildren
3420 * Gets the list of committed children of the current transaction. The return
3421 * value is the number of child transactions. *children is set to point to a
3422 * palloc'd array of TransactionIds. If there are no subxacts, *children is
3426 xactGetCommittedChildren(TransactionId **ptr)
3428 TransactionState s = CurrentTransactionState;
3430 TransactionId *children;
3433 nchildren = list_length(s->childXids);
3440 children = (TransactionId *) palloc(nchildren * sizeof(TransactionId));
3443 foreach(p, s->childXids)
3445 TransactionId child = lfirst_xid(p);
3447 *children++ = child;
3454 * XLOG support routines
3458 xact_redo(XLogRecPtr lsn, XLogRecord *record)
3460 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3462 if (info == XLOG_XACT_COMMIT)
3464 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
3467 TransactionIdCommit(record->xl_xid);
3468 /* Mark committed subtransactions as committed */
3469 TransactionIdCommitTree(xlrec->nsubxacts,
3470 (TransactionId *) &(xlrec->xnodes[xlrec->nrels]));
3471 /* Make sure files supposed to be dropped are dropped */
3472 for (i = 0; i < xlrec->nrels; i++)
3474 XLogCloseRelation(xlrec->xnodes[i]);
3475 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3478 else if (info == XLOG_XACT_ABORT)
3480 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
3483 TransactionIdAbort(record->xl_xid);
3484 /* mark subtransactions as aborted */
3485 TransactionIdAbortTree(xlrec->nsubxacts,
3486 (TransactionId *) &(xlrec->xnodes[xlrec->nrels]));
3487 /* Make sure files supposed to be dropped are dropped */
3488 for (i = 0; i < xlrec->nrels; i++)
3490 XLogCloseRelation(xlrec->xnodes[i]);
3491 smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3495 elog(PANIC, "xact_redo: unknown op code %u", info);
3499 xact_undo(XLogRecPtr lsn, XLogRecord *record)
3501 uint8 info = record->xl_info & ~XLR_INFO_MASK;
3503 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
3504 elog(PANIC, "xact_undo: can't undo committed xaction");
3505 else if (info != XLOG_XACT_ABORT)
3506 elog(PANIC, "xact_redo: unknown op code %u", info);
3510 xact_desc(char *buf, uint8 xl_info, char *rec)
3512 uint8 info = xl_info & ~XLR_INFO_MASK;
3515 if (info == XLOG_XACT_COMMIT)
3517 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
3518 struct tm *tm = localtime(&xlrec->xtime);
3520 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
3521 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3522 tm->tm_hour, tm->tm_min, tm->tm_sec);
3523 if (xlrec->nrels > 0)
3525 sprintf(buf + strlen(buf), "; rels:");
3526 for (i = 0; i < xlrec->nrels; i++)
3528 RelFileNode rnode = xlrec->xnodes[i];
3530 sprintf(buf + strlen(buf), " %u/%u/%u",
3531 rnode.spcNode, rnode.dbNode, rnode.relNode);
3534 if (xlrec->nsubxacts > 0)
3536 TransactionId *xacts = (TransactionId *)
3537 &xlrec->xnodes[xlrec->nrels];
3539 sprintf(buf + strlen(buf), "; subxacts:");
3540 for (i = 0; i < xlrec->nsubxacts; i++)
3541 sprintf(buf + strlen(buf), " %u", xacts[i]);
3544 else if (info == XLOG_XACT_ABORT)
3546 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
3547 struct tm *tm = localtime(&xlrec->xtime);
3549 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
3550 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3551 tm->tm_hour, tm->tm_min, tm->tm_sec);
3552 if (xlrec->nrels > 0)
3554 sprintf(buf + strlen(buf), "; rels:");
3555 for (i = 0; i < xlrec->nrels; i++)
3557 RelFileNode rnode = xlrec->xnodes[i];
3559 sprintf(buf + strlen(buf), " %u/%u/%u",
3560 rnode.spcNode, rnode.dbNode, rnode.relNode);
3563 if (xlrec->nsubxacts > 0)
3565 TransactionId *xacts = (TransactionId *)
3566 &xlrec->xnodes[xlrec->nrels];
3568 sprintf(buf + strlen(buf), "; subxacts:");
3569 for (i = 0; i < xlrec->nsubxacts; i++)
3570 sprintf(buf + strlen(buf), " %u", xacts[i]);
3574 strcat(buf, "UNKNOWN");
3578 XactPushRollback(void (*func) (void *), void *data)
3581 if (_RollbackFunc != NULL)
3582 elog(PANIC, "XactPushRollback: already installed");
3585 _RollbackFunc = func;
3586 _RollbackData = data;
3590 XactPopRollback(void)
3592 _RollbackFunc = NULL;