1 /*-------------------------------------------------------------------------
4 * top level transaction system support routines
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.133 2002/10/21 19:46:45 tgl Exp $
14 * Transaction aborts can now occur two ways:
16 * 1) system dies from some internal cause (Assert, etc..)
19 * These two cases used to be treated identically, but now
20 * we need to distinguish them. Why? consider the following
25 * 1) user types BEGIN 1) user types BEGIN
26 * 2) user does something 2) user does something
27 * 3) user does not like what 3) system aborts for some reason
28 * she sees and types ABORT
30 * In case 1, we want to abort the transaction and return to the
31 * default state. In case 2, there may be more commands coming
32 * our way which are part of the same transaction block and we have
33 * to ignore these commands until we see an END transaction.
34 * (or an ABORT! --djm)
36 * Internal aborts are now handled by AbortTransactionBlock(), just as
37 * they always have been, and user aborts are now handled by
38 * UserAbortTransactionBlock(). Both of them rely on AbortTransaction()
39 * to do all the real work. The only difference is what state we
40 * enter after AbortTransaction() does its work:
42 * * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
43 * * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
45 * Low-level transaction abort handling is divided into two phases:
46 * * AbortTransaction() executes as soon as we realize the transaction
47 * has failed. It should release all shared resources (locks etc)
48 * so that we do not delay other backends unnecessarily.
49 * * CleanupTransaction() executes when we finally see a user COMMIT
50 * or ROLLBACK command; it cleans things up and gets us out of
51 * the transaction internally. In particular, we mustn't destroy
52 * TransactionCommandContext until this point.
55 * This file is an attempt at a redesign of the upper layer
56 * of the V1 transaction system which was too poorly thought
57 * out to describe. This new system hopes to be both simpler
58 * in design, simpler to extend and needs to contain added
59 * functionality to solve problems beyond the scope of the V1
60 * system. (In particuler, communication of transaction
61 * information between parallel backends has to be supported)
63 * The essential aspects of the transaction system are:
65 * o transaction id generation
66 * o transaction log updating
68 * o cache invalidation
71 * Hence, the functional division of the transaction code is
72 * based on what of the above things need to be done during
73 * a start/commit/abort transaction. For instance, the
74 * routine AtCommit_Memory() takes care of all the memory
75 * cleanup stuff done at commit time.
77 * The code is layered as follows:
84 * are provided to do the lower level work like recording
85 * the transaction status in the log and doing memory cleanup.
86 * above these routines are another set of functions:
88 * StartTransactionCommand
89 * CommitTransactionCommand
90 * AbortCurrentTransaction
92 * These are the routines used in the postgres main processing
93 * loop. They are sensitive to the current transaction block state
94 * and make calls to the lower level routines appropriately.
96 * Support for transaction blocks is provided via the functions:
98 * StartTransactionBlock
99 * CommitTransactionBlock
100 * AbortTransactionBlock
102 * These are invoked only in responce to a user "BEGIN", "END",
103 * or "ABORT" command. The tricky part about these functions
104 * is that they are called within the postgres main loop, in between
105 * the StartTransactionCommand() and CommitTransactionCommand().
107 * For example, consider the following sequence of user commands:
110 * 2) retrieve (foo.all)
111 * 3) append foo (bar = baz)
114 * in the main processing loop, this results in the following
115 * transaction sequence:
117 * / StartTransactionCommand();
118 * 1) / ProcessUtility(); << begin
119 * \ StartTransactionBlock();
120 * \ CommitTransactionCommand();
122 * / StartTransactionCommand();
123 * 2) < ProcessQuery(); << retrieve (foo.all)
124 * \ CommitTransactionCommand();
126 * / StartTransactionCommand();
127 * 3) < ProcessQuery(); << append foo (bar = baz)
128 * \ CommitTransactionCommand();
130 * / StartTransactionCommand();
131 * 4) / ProcessUtility(); << end
132 * \ CommitTransactionBlock();
133 * \ CommitTransactionCommand();
135 * The point of this example is to demonstrate the need for
136 * StartTransactionCommand() and CommitTransactionCommand() to
137 * be state smart -- they should do nothing in between the calls
138 * to StartTransactionBlock() and EndTransactionBlock() and
139 * outside these calls they need to do normal start/commit
142 * Furthermore, suppose the "retrieve (foo.all)" caused an abort
143 * condition. We would then want to abort the transaction and
144 * ignore all subsequent commands up to the "end".
147 *-------------------------------------------------------------------------
151 * Large object clean up added in CommitTransaction() to prevent buffer leaks.
153 * [PA] is Pascal André <andre@via.ecp.fr>
155 #include "postgres.h"
158 #include <sys/time.h>
160 #include "access/gistscan.h"
161 #include "access/hash.h"
162 #include "access/nbtree.h"
163 #include "access/rtree.h"
164 #include "access/xact.h"
165 #include "catalog/heap.h"
166 #include "catalog/index.h"
167 #include "catalog/namespace.h"
168 #include "commands/async.h"
169 #include "commands/trigger.h"
170 #include "commands/user.h"
171 #include "executor/spi.h"
172 #include "libpq/be-fsstubs.h"
173 #include "miscadmin.h"
174 #include "storage/proc.h"
175 #include "storage/sinval.h"
176 #include "storage/smgr.h"
177 #include "utils/guc.h"
178 #include "utils/inval.h"
179 #include "utils/memutils.h"
180 #include "utils/portal.h"
181 #include "utils/catcache.h"
182 #include "utils/relcache.h"
186 static void AbortTransaction(void);
187 static void AtAbort_Cache(void);
188 static void AtAbort_Locks(void);
189 static void AtAbort_Memory(void);
190 static void AtCleanup_Memory(void);
191 static void AtCommit_Cache(void);
192 static void AtCommit_LocalCache(void);
193 static void AtCommit_Locks(void);
194 static void AtCommit_Memory(void);
195 static void AtStart_Cache(void);
196 static void AtStart_Locks(void);
197 static void AtStart_Memory(void);
198 static void CleanupTransaction(void);
199 static void CommitTransaction(void);
200 static void RecordTransactionAbort(void);
201 static void StartTransaction(void);
204 * global variables holding the current transaction state.
207 static TransactionStateData CurrentTransactionStateData = {
208 0, /* transaction id */
209 FirstCommandId, /* command id */
210 0, /* scan command id */
211 0x0, /* start time */
212 TRANS_DEFAULT, /* transaction state */
213 TBLOCK_DEFAULT /* transaction block state */
216 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
219 * User-tweakable parameters
221 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
224 bool autocommit = true;
226 int CommitDelay = 0; /* precommit delay in microseconds */
227 int CommitSiblings = 5; /* number of concurrent xacts needed to
231 static bool suppressChain = false;
233 static void (*_RollbackFunc) (void *) = NULL;
234 static void *_RollbackData = NULL;
237 /* ----------------------------------------------------------------
238 * transaction state accessors
239 * ----------------------------------------------------------------
244 /* --------------------------------
245 * TransactionFlushEnabled()
246 * SetTransactionFlushEnabled()
248 * These are used to test and set the "TransactionFlushState"
249 * varable. If this variable is true (the default), then
250 * the system will flush all dirty buffers to disk at the end
251 * of each transaction. If false then we are assuming the
252 * buffer pool resides in stable main memory, in which case we
253 * only do writes as necessary.
254 * --------------------------------
256 static int TransactionFlushState = 1;
259 TransactionFlushEnabled(void)
261 return TransactionFlushState;
265 SetTransactionFlushEnabled(bool state)
267 TransactionFlushState = (state == true);
272 /* --------------------------------
275 * This returns true if we are currently running a query
276 * within an executing transaction.
277 * --------------------------------
280 IsTransactionState(void)
282 TransactionState s = CurrentTransactionState;
290 case TRANS_INPROGRESS:
299 * Shouldn't get here, but lint is not happy with this...
304 /* --------------------------------
305 * IsAbortedTransactionBlockState
307 * This returns true if we are currently running a query
308 * within an aborted transaction block.
309 * --------------------------------
312 IsAbortedTransactionBlockState(void)
314 TransactionState s = CurrentTransactionState;
316 if (s->blockState == TBLOCK_ABORT)
323 /* --------------------------------
324 * GetCurrentTransactionId
325 * --------------------------------
328 GetCurrentTransactionId(void)
330 TransactionState s = CurrentTransactionState;
332 return s->transactionIdData;
336 /* --------------------------------
337 * GetCurrentCommandId
338 * --------------------------------
341 GetCurrentCommandId(void)
343 TransactionState s = CurrentTransactionState;
349 /* --------------------------------
350 * GetCurrentTransactionStartTime
351 * --------------------------------
354 GetCurrentTransactionStartTime(void)
356 TransactionState s = CurrentTransactionState;
362 /* --------------------------------
363 * GetCurrentTransactionStartTimeUsec
364 * --------------------------------
367 GetCurrentTransactionStartTimeUsec(int *msec)
369 TransactionState s = CurrentTransactionState;
371 *msec = s->startTimeUsec;
377 /* --------------------------------
378 * TransactionIdIsCurrentTransactionId
380 * During bootstrap, we cheat and say "it's not my transaction ID" even though
381 * it is. Along with transam.c's cheat to say that the bootstrap XID is
382 * already committed, this causes the tqual.c routines to see previously
383 * inserted tuples as committed, which is what we need during bootstrap.
384 * --------------------------------
387 TransactionIdIsCurrentTransactionId(TransactionId xid)
389 TransactionState s = CurrentTransactionState;
393 Assert(xid == BootstrapTransactionId);
397 return TransactionIdEquals(xid, s->transactionIdData);
401 /* --------------------------------
402 * CommandIdIsCurrentCommandId
403 * --------------------------------
406 CommandIdIsCurrentCommandId(CommandId cid)
408 TransactionState s = CurrentTransactionState;
410 return (cid == s->commandId) ? true : false;
414 /* --------------------------------
415 * CommandCounterIncrement
416 * --------------------------------
419 CommandCounterIncrement(void)
421 TransactionState s = CurrentTransactionState;
424 if (s->commandId == FirstCommandId) /* check for overflow */
425 elog(ERROR, "You may only have 2^32-1 commands per transaction");
427 /* Propagate new command ID into query snapshots, if set */
429 QuerySnapshot->curcid = s->commandId;
430 if (SerializableSnapshot)
431 SerializableSnapshot->curcid = s->commandId;
434 * make cache changes visible to me. AtCommit_LocalCache() instead of
435 * AtCommit_Cache() is called here.
437 AtCommit_LocalCache();
442 /* ----------------------------------------------------------------
443 * StartTransaction stuff
444 * ----------------------------------------------------------------
447 /* --------------------------------
449 * --------------------------------
454 AcceptInvalidationMessages();
457 /* --------------------------------
459 * --------------------------------
465 * at present, it is unknown to me what belongs here -cim 3/18/90
467 * There isn't anything to do at the start of a xact for locks. -mer
472 /* --------------------------------
474 * --------------------------------
480 * We shouldn't have any transaction contexts already.
482 Assert(TopTransactionContext == NULL);
483 Assert(TransactionCommandContext == NULL);
486 * Create a toplevel context for the transaction.
488 TopTransactionContext =
489 AllocSetContextCreate(TopMemoryContext,
490 "TopTransactionContext",
491 ALLOCSET_DEFAULT_MINSIZE,
492 ALLOCSET_DEFAULT_INITSIZE,
493 ALLOCSET_DEFAULT_MAXSIZE);
496 * Create a statement-level context and make it active.
498 TransactionCommandContext =
499 AllocSetContextCreate(TopTransactionContext,
500 "TransactionCommandContext",
501 ALLOCSET_DEFAULT_MINSIZE,
502 ALLOCSET_DEFAULT_INITSIZE,
503 ALLOCSET_DEFAULT_MAXSIZE);
504 MemoryContextSwitchTo(TransactionCommandContext);
508 /* ----------------------------------------------------------------
509 * CommitTransaction stuff
510 * ----------------------------------------------------------------
514 * RecordTransactionCommit
517 RecordTransactionCommit(void)
520 * If we made neither any XLOG entries nor any temp-rel updates, we
521 * can omit recording the transaction commit at all.
523 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate)
525 TransactionId xid = GetCurrentTransactionId();
528 /* Tell bufmgr and smgr to prepare for commit */
531 START_CRIT_SECTION();
534 * We only need to log the commit in xlog if the transaction made
535 * any transaction-controlled XLOG entries. (Otherwise, its XID
536 * appears nowhere in permanent storage, so no one else will ever
537 * care if it committed.)
539 if (MyLastRecPtr.xrecoff != 0)
541 /* Need to emit a commit record */
543 xl_xact_commit xlrec;
545 xlrec.xtime = time(NULL);
546 rdata.buffer = InvalidBuffer;
547 rdata.data = (char *) (&xlrec);
548 rdata.len = SizeOfXactCommit;
552 * XXX SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
554 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, &rdata);
558 /* Just flush through last record written by me */
559 recptr = ProcLastRecEnd;
563 * We must flush our XLOG entries to disk if we made any XLOG
564 * entries, whether in or out of transaction control. For
565 * example, if we reported a nextval() result to the client, this
566 * ensures that any XLOG record generated by nextval will hit the
567 * disk before we report the transaction committed.
569 if (MyXactMadeXLogEntry)
572 * Sleep before flush! So we can flush more than one commit
573 * records per single fsync. (The idea is some other backend
574 * may do the XLogFlush while we're sleeping. This needs work
575 * still, because on most Unixen, the minimum select() delay
576 * is 10msec or more, which is way too long.)
578 * We do not sleep if enableFsync is not turned on, nor if there
579 * are fewer than CommitSiblings other backends with active
582 if (CommitDelay > 0 && enableFsync &&
583 CountActiveBackends() >= CommitSiblings)
585 struct timeval delay;
588 delay.tv_usec = CommitDelay;
589 (void) select(0, NULL, NULL, NULL, &delay);
596 * We must mark the transaction committed in clog if its XID
597 * appears either in permanent rels or in local temporary rels.
598 * We test this by seeing if we made transaction-controlled
599 * entries *OR* local-rel tuple updates. Note that if we made
600 * only the latter, we have not emitted an XLOG record for our
601 * commit, and so in the event of a crash the clog update might be
602 * lost. This is okay because no one else will ever care whether
605 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
606 TransactionIdCommit(xid);
611 /* Break the chain of back-links in the XLOG records I output */
612 MyLastRecPtr.xrecoff = 0;
613 MyXactMadeXLogEntry = false;
614 MyXactMadeTempRelUpdate = false;
616 /* Show myself as out of the transaction in PGPROC array */
617 MyProc->logRec.xrecoff = 0;
621 /* --------------------------------
623 * --------------------------------
629 * Clean up the relation cache.
631 AtEOXact_RelationCache(true);
634 * Make catalog changes visible to all backends.
636 AtEOXactInvalidationMessages(true);
639 /* --------------------------------
640 * AtCommit_LocalCache
641 * --------------------------------
644 AtCommit_LocalCache(void)
647 * Make catalog changes visible to me for the next command.
649 CommandEndInvalidationMessages(true);
652 /* --------------------------------
654 * --------------------------------
660 * XXX What if ProcReleaseLocks fails? (race condition?)
662 * Then you're up a creek! -mer 5/24/92
664 ProcReleaseLocks(true);
667 /* --------------------------------
669 * --------------------------------
672 AtCommit_Memory(void)
675 * Now that we're "out" of a transaction, have the system allocate
676 * things in the top memory context instead of per-transaction
679 MemoryContextSwitchTo(TopMemoryContext);
682 * Release all transaction-local memory.
684 Assert(TopTransactionContext != NULL);
685 MemoryContextDelete(TopTransactionContext);
686 TopTransactionContext = NULL;
687 TransactionCommandContext = NULL;
690 /* ----------------------------------------------------------------
691 * AbortTransaction stuff
692 * ----------------------------------------------------------------
696 * RecordTransactionAbort
699 RecordTransactionAbort(void)
702 * If we made neither any transaction-controlled XLOG entries nor any
703 * temp-rel updates, we can omit recording the transaction abort at
704 * all. No one will ever care that it aborted.
706 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
708 TransactionId xid = GetCurrentTransactionId();
711 * Catch the scenario where we aborted partway through
712 * RecordTransactionCommit ...
714 if (TransactionIdDidCommit(xid))
715 elog(PANIC, "RecordTransactionAbort: xact %u already committed",
718 START_CRIT_SECTION();
721 * We only need to log the abort in XLOG if the transaction made
722 * any transaction-controlled XLOG entries. (Otherwise, its XID
723 * appears nowhere in permanent storage, so no one else will ever
724 * care if it committed.) We do not flush XLOG to disk in any
725 * case, since the default assumption after a crash would be that
726 * we aborted, anyway.
728 if (MyLastRecPtr.xrecoff != 0)
734 xlrec.xtime = time(NULL);
735 rdata.buffer = InvalidBuffer;
736 rdata.data = (char *) (&xlrec);
737 rdata.len = SizeOfXactAbort;
741 * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
743 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
747 * Mark the transaction aborted in clog. This is not absolutely
748 * necessary but we may as well do it while we are here.
750 TransactionIdAbort(xid);
755 /* Break the chain of back-links in the XLOG records I output */
756 MyLastRecPtr.xrecoff = 0;
757 MyXactMadeXLogEntry = false;
758 MyXactMadeTempRelUpdate = false;
760 /* Show myself as out of the transaction in PGPROC array */
761 MyProc->logRec.xrecoff = 0;
764 /* --------------------------------
766 * --------------------------------
771 AtEOXact_RelationCache(false);
772 AtEOXactInvalidationMessages(false);
775 /* --------------------------------
777 * --------------------------------
783 * XXX What if ProcReleaseLocks() fails? (race condition?)
785 * Then you're up a creek without a paddle! -mer
787 ProcReleaseLocks(false);
791 /* --------------------------------
793 * --------------------------------
799 * Make sure we are in a valid context (not a child of
800 * TransactionCommandContext...). Note that it is possible for this
801 * code to be called when we aren't in a transaction at all; go
802 * directly to TopMemoryContext in that case.
804 if (TransactionCommandContext != NULL)
806 MemoryContextSwitchTo(TransactionCommandContext);
809 * We do not want to destroy transaction contexts yet, but it
810 * should be OK to delete any command-local memory.
812 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
815 MemoryContextSwitchTo(TopMemoryContext);
819 /* ----------------------------------------------------------------
820 * CleanupTransaction stuff
821 * ----------------------------------------------------------------
824 /* --------------------------------
826 * --------------------------------
829 AtCleanup_Memory(void)
832 * Now that we're "out" of a transaction, have the system allocate
833 * things in the top memory context instead of per-transaction
836 MemoryContextSwitchTo(TopMemoryContext);
839 * Release all transaction-local memory.
841 if (TopTransactionContext != NULL)
842 MemoryContextDelete(TopTransactionContext);
843 TopTransactionContext = NULL;
844 TransactionCommandContext = NULL;
848 /* ----------------------------------------------------------------
850 * ----------------------------------------------------------------
853 /* --------------------------------
856 * --------------------------------
859 StartTransaction(void)
861 TransactionState s = CurrentTransactionState;
864 XactIsoLevel = DefaultXactIsoLevel;
867 * Check the current transaction state. If the transaction system is
868 * switched off, or if we're already in a transaction, do nothing.
869 * We're already in a transaction when the monitor sends a null
870 * command to the backend to flush the comm channel. This is a hacky
871 * fix to a communications problem, and we keep having to deal with it
872 * here. We should fix the comm channel code. mao 080891
874 if (s->state == TRANS_INPROGRESS)
878 * set the current transaction state information appropriately during
881 s->state = TRANS_START;
883 SetReindexProcessing(false);
886 * generate a new transaction id
888 s->transactionIdData = GetNewTransactionId();
890 XactLockTableInsert(s->transactionIdData);
893 * initialize current transaction state fields
895 s->commandId = FirstCommandId;
896 s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
899 * initialize the various transaction subsystems
906 * Tell the trigger manager to we're starting a transaction
908 DeferredTriggerBeginXact();
911 * done with start processing, set current transaction state to "in
914 s->state = TRANS_INPROGRESS;
920 * Tell me if we are currently in progress
924 CurrentXactInProgress(void)
926 return CurrentTransactionState->state == TRANS_INPROGRESS;
930 /* --------------------------------
933 * --------------------------------
936 CommitTransaction(void)
938 TransactionState s = CurrentTransactionState;
941 * check the current transaction state
943 if (s->state != TRANS_INPROGRESS)
944 elog(WARNING, "CommitTransaction and not in in-progress state");
947 * Tell the trigger manager that this transaction is about to be
948 * committed. He'll invoke all trigger deferred until XACT before we
949 * really start on committing the transaction.
951 DeferredTriggerEndXact();
953 /* Prevent cancel/die interrupt while cleaning up */
957 * set the current transaction state information appropriately during
958 * the abort processing
960 s->state = TRANS_COMMIT;
963 * Do pre-commit processing (most of this stuff requires database
964 * access, and in fact could still cause an error...)
969 /* handle commit for large objects [ PA, 7/17/98 ] */
970 /* XXX probably this does not belong here */
973 /* NOTIFY commit must come before lower-level cleanup */
976 /* Update the flat password file if we changed pg_shadow or pg_group */
977 AtEOXact_UpdatePasswordFile(true);
980 * Here is where we really truly commit.
982 RecordTransactionCommit();
985 * Let others know about no transaction in progress by me. Note that
986 * this must be done _before_ releasing locks we hold and _after_
987 * RecordTransactionCommit.
989 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
990 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
991 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
992 * as running as well or it will see two tuple versions - one deleted
993 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
995 if (MyProc != (PGPROC *) NULL)
997 /* Lock SInvalLock because that's what GetSnapshotData uses. */
998 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
999 MyProc->xid = InvalidTransactionId;
1000 MyProc->xmin = InvalidTransactionId;
1001 LWLockRelease(SInvalLock);
1005 * This is all post-commit cleanup. Note that if an error is raised
1006 * here, it's too late to abort the transaction. This should be just
1007 * noncritical resource releasing.
1010 smgrDoPendingDeletes(true);
1018 AtEOXact_Namespace(true);
1021 AtEOXact_CatCache(true);
1023 AtEOXact_Buffers(true);
1026 /* Count transaction commit in statistics collector */
1027 pgstat_count_xact_commit();
1030 * done with commit processing, set current transaction state back to
1033 s->state = TRANS_DEFAULT;
1035 RESUME_INTERRUPTS();
1038 /* --------------------------------
1041 * --------------------------------
1044 AbortTransaction(void)
1046 TransactionState s = CurrentTransactionState;
1048 /* Prevent cancel/die interrupt while cleaning up */
1052 * Release any LW locks we might be holding as quickly as possible.
1053 * (Regular locks, however, must be held till we finish aborting.)
1054 * Releasing LW locks is critical since we might try to grab them
1055 * again while cleaning up!
1059 /* Clean up buffer I/O and buffer context locks, too */
1064 * Also clean up any open wait for lock, since the lock manager will
1065 * choke if we try to wait for another lock before doing this.
1070 * check the current transaction state
1072 if (s->state != TRANS_INPROGRESS)
1073 elog(WARNING, "AbortTransaction and not in in-progress state");
1076 * set the current transaction state information appropriately during
1077 * the abort processing
1079 s->state = TRANS_ABORT;
1082 * Reset user id which might have been changed transiently
1084 SetUserId(GetSessionUserId());
1087 * do abort processing
1089 DeferredTriggerAbortXact();
1091 lo_commit(false); /* 'false' means it's abort */
1093 AtEOXact_UpdatePasswordFile(false);
1095 /* Advertise the fact that we aborted in pg_clog. */
1096 RecordTransactionAbort();
1099 * Let others know about no transaction in progress by me. Note that
1100 * this must be done _before_ releasing locks we hold and _after_
1101 * RecordTransactionAbort.
1103 if (MyProc != (PGPROC *) NULL)
1105 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1106 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1107 MyProc->xid = InvalidTransactionId;
1108 MyProc->xmin = InvalidTransactionId;
1109 LWLockRelease(SInvalLock);
1112 smgrDoPendingDeletes(false);
1114 AtEOXact_GUC(false);
1120 AtEOXact_Namespace(false);
1122 AtEOXact_CatCache(false);
1124 AtEOXact_Buffers(false);
1129 /* Count transaction abort in statistics collector */
1130 pgstat_count_xact_rollback();
1133 * State remains TRANS_ABORT until CleanupTransaction().
1135 RESUME_INTERRUPTS();
1138 /* --------------------------------
1139 * CleanupTransaction
1141 * --------------------------------
1144 CleanupTransaction(void)
1146 TransactionState s = CurrentTransactionState;
1149 * State should still be TRANS_ABORT from AbortTransaction().
1151 if (s->state != TRANS_ABORT)
1152 elog(FATAL, "CleanupTransaction and not in abort state");
1155 * do abort cleanup processing
1160 * done with abort processing, set current transaction state back to
1163 s->state = TRANS_DEFAULT;
1166 /* --------------------------------
1167 * StartTransactionCommand
1169 * preventChain, if true, forces autocommit behavior at the next
1170 * CommitTransactionCommand call.
1171 * --------------------------------
1174 StartTransactionCommand(bool preventChain)
1176 TransactionState s = CurrentTransactionState;
1179 * Remember if caller wants to prevent autocommit-off chaining. This
1180 * is only allowed if not already in a transaction block.
1182 suppressChain = preventChain;
1183 if (preventChain && s->blockState != TBLOCK_DEFAULT)
1184 elog(ERROR, "StartTransactionCommand: can't prevent chain");
1186 switch (s->blockState)
1189 * if we aren't in a transaction block, we just do our usual
1190 * start transaction.
1192 case TBLOCK_DEFAULT:
1197 * We should never experience this -- if we do it means the
1198 * BEGIN state was not changed in the previous
1199 * CommitTransactionCommand(). If we get it, we print a
1200 * warning and change to the in-progress state.
1203 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1204 s->blockState = TBLOCK_INPROGRESS;
1208 * This is the case when are somewhere in a transaction block
1209 * and about to start a new command. For now we do nothing
1210 * but someday we may do command-local resource
1213 case TBLOCK_INPROGRESS:
1217 * As with BEGIN, we should never experience this if we do it
1218 * means the END state was not changed in the previous
1219 * CommitTransactionCommand(). If we get it, we print a
1220 * warning, commit the transaction, start a new transaction
1221 * and change to the default state.
1224 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
1225 s->blockState = TBLOCK_DEFAULT;
1226 CommitTransaction();
1231 * Here we are in the middle of a transaction block but one of
1232 * the commands caused an abort so we do nothing but remain in
1233 * the abort state. Eventually we will get to the "END
1234 * TRANSACTION" which will set things straight.
1240 * This means we somehow aborted and the last call to
1241 * CommitTransactionCommand() didn't clear the state so we
1242 * remain in the ENDABORT state and maybe next time we get to
1243 * CommitTransactionCommand() the state will get reset to
1246 case TBLOCK_ENDABORT:
1247 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1252 * We must switch to TransactionCommandContext before returning. This
1253 * is already done if we called StartTransaction, otherwise not.
1255 Assert(TransactionCommandContext != NULL);
1256 MemoryContextSwitchTo(TransactionCommandContext);
1259 /* --------------------------------
1260 * CommitTransactionCommand
1262 * forceCommit = true forces autocommit behavior even when autocommit is off.
1263 * --------------------------------
1266 CommitTransactionCommand(bool forceCommit)
1268 TransactionState s = CurrentTransactionState;
1270 switch (s->blockState)
1273 * If we aren't in a transaction block, and we are doing
1274 * autocommit, just do our usual transaction commit. But if
1275 * we aren't doing autocommit, start a transaction block
1276 * automatically by switching to INPROGRESS state. (We handle
1277 * this choice here, and not earlier, so that an explicit
1278 * BEGIN issued in autocommit-off mode won't issue strange
1281 * Autocommit mode is forced by either a true forceCommit
1282 * parameter to me, or a true preventChain parameter to the
1283 * preceding StartTransactionCommand call. This is needed so
1284 * that commands like VACUUM can ensure that the right things
1287 case TBLOCK_DEFAULT:
1288 if (autocommit || forceCommit || suppressChain)
1289 CommitTransaction();
1292 BeginTransactionBlock();
1293 Assert(s->blockState == TBLOCK_INPROGRESS);
1294 /* This code must match the TBLOCK_INPROGRESS case below: */
1295 CommandCounterIncrement();
1296 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1301 * This is the case right after we get a "BEGIN TRANSACTION"
1302 * command, but the user hasn't done anything else yet, so we
1303 * change to the "transaction block in progress" state and
1307 s->blockState = TBLOCK_INPROGRESS;
1311 * This is the case when we have finished executing a command
1312 * someplace within a transaction block. We increment the
1313 * command counter and return. Someday we may free resources
1314 * local to the command.
1316 * That someday is today, at least for memory allocated in
1317 * TransactionCommandContext. - vadim 03/25/97
1319 case TBLOCK_INPROGRESS:
1320 CommandCounterIncrement();
1321 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1325 * This is the case when we just got the "END TRANSACTION"
1326 * statement, so we commit the transaction and go back to the
1330 CommitTransaction();
1331 s->blockState = TBLOCK_DEFAULT;
1335 * Here we are in the middle of a transaction block but one of
1336 * the commands caused an abort so we do nothing but remain in
1337 * the abort state. Eventually we will get to the "END
1338 * TRANSACTION" which will set things straight.
1344 * Here we were in an aborted transaction block which just
1345 * processed the "END TRANSACTION" command from the user, so
1346 * clean up and return to the default state.
1348 case TBLOCK_ENDABORT:
1349 CleanupTransaction();
1350 s->blockState = TBLOCK_DEFAULT;
1355 /* --------------------------------
1356 * AbortCurrentTransaction
1357 * --------------------------------
1360 AbortCurrentTransaction(void)
1362 TransactionState s = CurrentTransactionState;
1364 switch (s->blockState)
1367 * if we aren't in a transaction block, we just do the basic
1368 * abort & cleanup transaction.
1370 case TBLOCK_DEFAULT:
1372 CleanupTransaction();
1376 * If we are in the TBLOCK_BEGIN it means something screwed up
1377 * right after reading "BEGIN TRANSACTION" so we enter the
1378 * abort state. Eventually an "END TRANSACTION" will fix
1382 s->blockState = TBLOCK_ABORT;
1384 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1388 * This is the case when are somewhere in a transaction block
1389 * which aborted so we abort the transaction and set the ABORT
1390 * state. Eventually an "END TRANSACTION" will fix things and
1391 * restore us to a normal state.
1393 case TBLOCK_INPROGRESS:
1394 s->blockState = TBLOCK_ABORT;
1396 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1400 * Here, the system was fouled up just after the user wanted
1401 * to end the transaction block so we abort the transaction
1402 * and put us back into the default state.
1405 s->blockState = TBLOCK_DEFAULT;
1407 CleanupTransaction();
1411 * Here, we are already in an aborted transaction state and
1412 * are waiting for an "END TRANSACTION" to come along and lo
1413 * and behold, we abort again! So we just remain in the abort
1420 * Here we were in an aborted transaction block which just
1421 * processed the "END TRANSACTION" command but somehow aborted
1422 * again.. since we must have done the abort processing, we
1423 * clean up and return to the default state.
1425 case TBLOCK_ENDABORT:
1426 CleanupTransaction();
1427 s->blockState = TBLOCK_DEFAULT;
1432 /* ----------------------------------------------------------------
1433 * transaction block support
1434 * ----------------------------------------------------------------
1436 /* --------------------------------
1437 * BeginTransactionBlock
1438 * --------------------------------
1441 BeginTransactionBlock(void)
1443 TransactionState s = CurrentTransactionState;
1446 * check the current transaction state
1448 if (s->blockState != TBLOCK_DEFAULT)
1449 elog(WARNING, "BEGIN: already a transaction in progress");
1452 * set the current transaction block state information appropriately
1453 * during begin processing
1455 s->blockState = TBLOCK_BEGIN;
1458 * do begin processing. NOTE: if you put anything here, check that it
1459 * behaves properly in both autocommit-on and autocommit-off modes. In
1460 * the latter case we will already have done some work in the new
1465 * done with begin processing, set block state to inprogress
1467 s->blockState = TBLOCK_INPROGRESS;
1470 /* --------------------------------
1471 * EndTransactionBlock
1472 * --------------------------------
1475 EndTransactionBlock(void)
1477 TransactionState s = CurrentTransactionState;
1480 * check the current transaction state
1482 if (s->blockState == TBLOCK_INPROGRESS)
1485 * here we are in a transaction block which should commit when we
1486 * get to the upcoming CommitTransactionCommand() so we set the
1487 * state to "END". CommitTransactionCommand() will recognize this
1488 * and commit the transaction and return us to the default state
1490 s->blockState = TBLOCK_END;
1494 if (s->blockState == TBLOCK_ABORT)
1497 * here, we are in a transaction block which aborted and since the
1498 * AbortTransaction() was already done, we do whatever is needed
1499 * and change to the special "END ABORT" state. The upcoming
1500 * CommitTransactionCommand() will recognise this and then put us
1501 * back in the default state.
1503 s->blockState = TBLOCK_ENDABORT;
1508 * here, the user issued COMMIT when not inside a transaction. Issue a
1509 * WARNING and go to abort state. The upcoming call to
1510 * CommitTransactionCommand() will then put us back into the default
1513 elog(WARNING, "COMMIT: no transaction in progress");
1515 s->blockState = TBLOCK_ENDABORT;
1518 /* --------------------------------
1519 * AbortTransactionBlock
1520 * --------------------------------
1524 AbortTransactionBlock(void)
1526 TransactionState s = CurrentTransactionState;
1529 * check the current transaction state
1531 if (s->blockState == TBLOCK_INPROGRESS)
1534 * here we were inside a transaction block something screwed up
1535 * inside the system so we enter the abort state, do the abort
1536 * processing and then return. We remain in the abort state until
1537 * we see an END TRANSACTION command.
1539 s->blockState = TBLOCK_ABORT;
1545 * here, the user issued ABORT when not inside a transaction. Issue a
1546 * WARNING and go to abort state. The upcoming call to
1547 * CommitTransactionCommand() will then put us back into the default
1550 elog(WARNING, "ROLLBACK: no transaction in progress");
1552 s->blockState = TBLOCK_ENDABORT;
1556 /* --------------------------------
1557 * UserAbortTransactionBlock
1558 * --------------------------------
1561 UserAbortTransactionBlock(void)
1563 TransactionState s = CurrentTransactionState;
1566 * if the transaction has already been automatically aborted with an
1567 * error, and the user subsequently types 'abort', allow it. (the
1568 * behavior is the same as if they had typed 'end'.)
1570 if (s->blockState == TBLOCK_ABORT)
1572 s->blockState = TBLOCK_ENDABORT;
1576 if (s->blockState == TBLOCK_INPROGRESS)
1579 * here we were inside a transaction block and we got an abort
1580 * command from the user, so we move to the abort state, do the
1581 * abort processing and then change to the ENDABORT state so we
1582 * will end up in the default state after the upcoming
1583 * CommitTransactionCommand().
1585 s->blockState = TBLOCK_ABORT;
1587 s->blockState = TBLOCK_ENDABORT;
1592 * here, the user issued ABORT when not inside a transaction. Issue a
1593 * WARNING and go to abort state. The upcoming call to
1594 * CommitTransactionCommand() will then put us back into the default
1597 elog(WARNING, "ROLLBACK: no transaction in progress");
1599 s->blockState = TBLOCK_ENDABORT;
1602 /* --------------------------------
1603 * AbortOutOfAnyTransaction
1605 * This routine is provided for error recovery purposes. It aborts any
1606 * active transaction or transaction block, leaving the system in a known
1608 * --------------------------------
1611 AbortOutOfAnyTransaction(void)
1613 TransactionState s = CurrentTransactionState;
1616 * Get out of any low-level transaction
1621 case TRANS_INPROGRESS:
1623 /* In a transaction, so clean up */
1625 CleanupTransaction();
1628 /* AbortTransaction already done, still need Cleanup */
1629 CleanupTransaction();
1632 /* Not in a transaction, do nothing */
1637 * Now reset the high-level state
1639 s->blockState = TBLOCK_DEFAULT;
1643 IsTransactionBlock(void)
1645 TransactionState s = CurrentTransactionState;
1647 if (s->blockState == TBLOCK_INPROGRESS
1648 || s->blockState == TBLOCK_ABORT
1649 || s->blockState == TBLOCK_ENDABORT)
1656 xact_redo(XLogRecPtr lsn, XLogRecord *record)
1658 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1660 if (info == XLOG_XACT_COMMIT)
1662 TransactionIdCommit(record->xl_xid);
1663 /* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
1665 else if (info == XLOG_XACT_ABORT)
1667 TransactionIdAbort(record->xl_xid);
1668 /* SHOULD REMOVE FILES OF ALL FAILED-TO-BE-CREATED RELATIONS */
1671 elog(PANIC, "xact_redo: unknown op code %u", info);
1675 xact_undo(XLogRecPtr lsn, XLogRecord *record)
1677 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1679 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
1680 elog(PANIC, "xact_undo: can't undo committed xaction");
1681 else if (info != XLOG_XACT_ABORT)
1682 elog(PANIC, "xact_redo: unknown op code %u", info);
1686 xact_desc(char *buf, uint8 xl_info, char *rec)
1688 uint8 info = xl_info & ~XLR_INFO_MASK;
1690 if (info == XLOG_XACT_COMMIT)
1692 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
1693 struct tm *tm = localtime(&xlrec->xtime);
1695 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
1696 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1697 tm->tm_hour, tm->tm_min, tm->tm_sec);
1699 else if (info == XLOG_XACT_ABORT)
1701 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
1702 struct tm *tm = localtime(&xlrec->xtime);
1704 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
1705 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1706 tm->tm_hour, tm->tm_min, tm->tm_sec);
1709 strcat(buf, "UNKNOWN");
1713 XactPushRollback(void (*func) (void *), void *data)
1716 if (_RollbackFunc != NULL)
1717 elog(PANIC, "XactPushRollback: already installed");
1720 _RollbackFunc = func;
1721 _RollbackData = data;
1725 XactPopRollback(void)
1727 _RollbackFunc = NULL;