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.137 2002/11/11 22:19:20 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/tablecmds.h"
170 #include "commands/trigger.h"
171 #include "commands/user.h"
172 #include "executor/spi.h"
173 #include "libpq/be-fsstubs.h"
174 #include "miscadmin.h"
175 #include "storage/proc.h"
176 #include "storage/sinval.h"
177 #include "storage/smgr.h"
178 #include "utils/guc.h"
179 #include "utils/inval.h"
180 #include "utils/memutils.h"
181 #include "utils/portal.h"
182 #include "utils/catcache.h"
183 #include "utils/relcache.h"
187 static void AbortTransaction(void);
188 static void AtAbort_Cache(void);
189 static void AtAbort_Locks(void);
190 static void AtAbort_Memory(void);
191 static void AtCleanup_Memory(void);
192 static void AtCommit_Cache(void);
193 static void AtCommit_LocalCache(void);
194 static void AtCommit_Locks(void);
195 static void AtCommit_Memory(void);
196 static void AtStart_Cache(void);
197 static void AtStart_Locks(void);
198 static void AtStart_Memory(void);
199 static void CleanupTransaction(void);
200 static void CommitTransaction(void);
201 static void RecordTransactionAbort(void);
202 static void StartTransaction(void);
205 * global variables holding the current transaction state.
208 static TransactionStateData CurrentTransactionStateData = {
209 0, /* transaction id */
210 FirstCommandId, /* command id */
211 0, /* scan command id */
212 0x0, /* start time */
213 TRANS_DEFAULT, /* transaction state */
214 TBLOCK_DEFAULT /* transaction block state */
217 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
220 * User-tweakable parameters
222 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
225 bool autocommit = true;
227 int CommitDelay = 0; /* precommit delay in microseconds */
228 int CommitSiblings = 5; /* number of concurrent xacts needed to
232 static bool suppressChain = false;
234 static void (*_RollbackFunc) (void *) = NULL;
235 static void *_RollbackData = NULL;
238 /* ----------------------------------------------------------------
239 * transaction state accessors
240 * ----------------------------------------------------------------
245 /* --------------------------------
246 * TransactionFlushEnabled()
247 * SetTransactionFlushEnabled()
249 * These are used to test and set the "TransactionFlushState"
250 * varable. If this variable is true (the default), then
251 * the system will flush all dirty buffers to disk at the end
252 * of each transaction. If false then we are assuming the
253 * buffer pool resides in stable main memory, in which case we
254 * only do writes as necessary.
255 * --------------------------------
257 static int TransactionFlushState = 1;
260 TransactionFlushEnabled(void)
262 return TransactionFlushState;
266 SetTransactionFlushEnabled(bool state)
268 TransactionFlushState = (state == true);
273 /* --------------------------------
276 * This returns true if we are currently running a query
277 * within an executing transaction.
278 * --------------------------------
281 IsTransactionState(void)
283 TransactionState s = CurrentTransactionState;
291 case TRANS_INPROGRESS:
300 * Shouldn't get here, but lint is not happy with this...
305 /* --------------------------------
306 * IsAbortedTransactionBlockState
308 * This returns true if we are currently running a query
309 * within an aborted transaction block.
310 * --------------------------------
313 IsAbortedTransactionBlockState(void)
315 TransactionState s = CurrentTransactionState;
317 if (s->blockState == TBLOCK_ABORT)
324 /* --------------------------------
325 * GetCurrentTransactionId
326 * --------------------------------
329 GetCurrentTransactionId(void)
331 TransactionState s = CurrentTransactionState;
333 return s->transactionIdData;
337 /* --------------------------------
338 * GetCurrentCommandId
339 * --------------------------------
342 GetCurrentCommandId(void)
344 TransactionState s = CurrentTransactionState;
350 /* --------------------------------
351 * GetCurrentTransactionStartTime
352 * --------------------------------
355 GetCurrentTransactionStartTime(void)
357 TransactionState s = CurrentTransactionState;
363 /* --------------------------------
364 * GetCurrentTransactionStartTimeUsec
365 * --------------------------------
368 GetCurrentTransactionStartTimeUsec(int *msec)
370 TransactionState s = CurrentTransactionState;
372 *msec = s->startTimeUsec;
378 /* --------------------------------
379 * TransactionIdIsCurrentTransactionId
381 * During bootstrap, we cheat and say "it's not my transaction ID" even though
382 * it is. Along with transam.c's cheat to say that the bootstrap XID is
383 * already committed, this causes the tqual.c routines to see previously
384 * inserted tuples as committed, which is what we need during bootstrap.
385 * --------------------------------
388 TransactionIdIsCurrentTransactionId(TransactionId xid)
390 TransactionState s = CurrentTransactionState;
394 Assert(xid == BootstrapTransactionId);
398 return TransactionIdEquals(xid, s->transactionIdData);
402 /* --------------------------------
403 * CommandIdIsCurrentCommandId
404 * --------------------------------
407 CommandIdIsCurrentCommandId(CommandId cid)
409 TransactionState s = CurrentTransactionState;
411 return (cid == s->commandId) ? true : false;
415 /* --------------------------------
416 * CommandCounterIncrement
417 * --------------------------------
420 CommandCounterIncrement(void)
422 TransactionState s = CurrentTransactionState;
425 if (s->commandId == FirstCommandId) /* check for overflow */
426 elog(ERROR, "You may only have 2^32-1 commands per transaction");
428 /* Propagate new command ID into query snapshots, if set */
430 QuerySnapshot->curcid = s->commandId;
431 if (SerializableSnapshot)
432 SerializableSnapshot->curcid = s->commandId;
435 * make cache changes visible to me. AtCommit_LocalCache() instead of
436 * AtCommit_Cache() is called here.
438 AtCommit_LocalCache();
443 /* ----------------------------------------------------------------
444 * StartTransaction stuff
445 * ----------------------------------------------------------------
448 /* --------------------------------
450 * --------------------------------
455 AcceptInvalidationMessages();
458 /* --------------------------------
460 * --------------------------------
466 * at present, it is unknown to me what belongs here -cim 3/18/90
468 * There isn't anything to do at the start of a xact for locks. -mer
473 /* --------------------------------
475 * --------------------------------
481 * We shouldn't have any transaction contexts already.
483 Assert(TopTransactionContext == NULL);
484 Assert(TransactionCommandContext == NULL);
487 * Create a toplevel context for the transaction.
489 TopTransactionContext =
490 AllocSetContextCreate(TopMemoryContext,
491 "TopTransactionContext",
492 ALLOCSET_DEFAULT_MINSIZE,
493 ALLOCSET_DEFAULT_INITSIZE,
494 ALLOCSET_DEFAULT_MAXSIZE);
497 * Create a statement-level context and make it active.
499 TransactionCommandContext =
500 AllocSetContextCreate(TopTransactionContext,
501 "TransactionCommandContext",
502 ALLOCSET_DEFAULT_MINSIZE,
503 ALLOCSET_DEFAULT_INITSIZE,
504 ALLOCSET_DEFAULT_MAXSIZE);
505 MemoryContextSwitchTo(TransactionCommandContext);
509 /* ----------------------------------------------------------------
510 * CommitTransaction stuff
511 * ----------------------------------------------------------------
515 * RecordTransactionCommit
518 RecordTransactionCommit(void)
521 * If we made neither any XLOG entries nor any temp-rel updates, we
522 * can omit recording the transaction commit at all.
524 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate)
526 TransactionId xid = GetCurrentTransactionId();
529 /* Tell bufmgr and smgr to prepare for commit */
532 START_CRIT_SECTION();
535 * We only need to log the commit in xlog if the transaction made
536 * any transaction-controlled XLOG entries. (Otherwise, its XID
537 * appears nowhere in permanent storage, so no one else will ever
538 * care if it committed.)
540 if (MyLastRecPtr.xrecoff != 0)
542 /* Need to emit a commit record */
544 xl_xact_commit xlrec;
546 xlrec.xtime = time(NULL);
547 rdata.buffer = InvalidBuffer;
548 rdata.data = (char *) (&xlrec);
549 rdata.len = SizeOfXactCommit;
553 * XXX SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
555 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, &rdata);
559 /* Just flush through last record written by me */
560 recptr = ProcLastRecEnd;
564 * We must flush our XLOG entries to disk if we made any XLOG
565 * entries, whether in or out of transaction control. For
566 * example, if we reported a nextval() result to the client, this
567 * ensures that any XLOG record generated by nextval will hit the
568 * disk before we report the transaction committed.
570 if (MyXactMadeXLogEntry)
573 * Sleep before flush! So we can flush more than one commit
574 * records per single fsync. (The idea is some other backend
575 * may do the XLogFlush while we're sleeping. This needs work
576 * still, because on most Unixen, the minimum select() delay
577 * is 10msec or more, which is way too long.)
579 * We do not sleep if enableFsync is not turned on, nor if there
580 * are fewer than CommitSiblings other backends with active
583 if (CommitDelay > 0 && enableFsync &&
584 CountActiveBackends() >= CommitSiblings)
586 struct timeval delay;
589 delay.tv_usec = CommitDelay;
590 (void) select(0, NULL, NULL, NULL, &delay);
597 * We must mark the transaction committed in clog if its XID
598 * appears either in permanent rels or in local temporary rels.
599 * We test this by seeing if we made transaction-controlled
600 * entries *OR* local-rel tuple updates. Note that if we made
601 * only the latter, we have not emitted an XLOG record for our
602 * commit, and so in the event of a crash the clog update might be
603 * lost. This is okay because no one else will ever care whether
606 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
607 TransactionIdCommit(xid);
612 /* Break the chain of back-links in the XLOG records I output */
613 MyLastRecPtr.xrecoff = 0;
614 MyXactMadeXLogEntry = false;
615 MyXactMadeTempRelUpdate = false;
617 /* Show myself as out of the transaction in PGPROC array */
618 MyProc->logRec.xrecoff = 0;
622 /* --------------------------------
624 * --------------------------------
630 * Clean up the relation cache.
632 AtEOXact_RelationCache(true);
635 * Make catalog changes visible to all backends.
637 AtEOXactInvalidationMessages(true);
640 /* --------------------------------
641 * AtCommit_LocalCache
642 * --------------------------------
645 AtCommit_LocalCache(void)
648 * Make catalog changes visible to me for the next command.
650 CommandEndInvalidationMessages(true);
653 /* --------------------------------
655 * --------------------------------
661 * XXX What if ProcReleaseLocks fails? (race condition?)
663 * Then you're up a creek! -mer 5/24/92
665 ProcReleaseLocks(true);
668 /* --------------------------------
670 * --------------------------------
673 AtCommit_Memory(void)
676 * Now that we're "out" of a transaction, have the system allocate
677 * things in the top memory context instead of per-transaction
680 MemoryContextSwitchTo(TopMemoryContext);
683 * Release all transaction-local memory.
685 Assert(TopTransactionContext != NULL);
686 MemoryContextDelete(TopTransactionContext);
687 TopTransactionContext = NULL;
688 TransactionCommandContext = NULL;
691 /* ----------------------------------------------------------------
692 * AbortTransaction stuff
693 * ----------------------------------------------------------------
697 * RecordTransactionAbort
700 RecordTransactionAbort(void)
703 * If we made neither any transaction-controlled XLOG entries nor any
704 * temp-rel updates, we can omit recording the transaction abort at
705 * all. No one will ever care that it aborted.
707 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
709 TransactionId xid = GetCurrentTransactionId();
712 * Catch the scenario where we aborted partway through
713 * RecordTransactionCommit ...
715 if (TransactionIdDidCommit(xid))
716 elog(PANIC, "RecordTransactionAbort: xact %u already committed",
719 START_CRIT_SECTION();
722 * We only need to log the abort in XLOG if the transaction made
723 * any transaction-controlled XLOG entries. (Otherwise, its XID
724 * appears nowhere in permanent storage, so no one else will ever
725 * care if it committed.) We do not flush XLOG to disk in any
726 * case, since the default assumption after a crash would be that
727 * we aborted, anyway.
729 if (MyLastRecPtr.xrecoff != 0)
735 xlrec.xtime = time(NULL);
736 rdata.buffer = InvalidBuffer;
737 rdata.data = (char *) (&xlrec);
738 rdata.len = SizeOfXactAbort;
742 * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
744 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
748 * Mark the transaction aborted in clog. This is not absolutely
749 * necessary but we may as well do it while we are here.
751 TransactionIdAbort(xid);
756 /* Break the chain of back-links in the XLOG records I output */
757 MyLastRecPtr.xrecoff = 0;
758 MyXactMadeXLogEntry = false;
759 MyXactMadeTempRelUpdate = false;
761 /* Show myself as out of the transaction in PGPROC array */
762 MyProc->logRec.xrecoff = 0;
765 /* --------------------------------
767 * --------------------------------
772 AtEOXact_RelationCache(false);
773 AtEOXactInvalidationMessages(false);
776 /* --------------------------------
778 * --------------------------------
784 * XXX What if ProcReleaseLocks() fails? (race condition?)
786 * Then you're up a creek without a paddle! -mer
788 ProcReleaseLocks(false);
792 /* --------------------------------
794 * --------------------------------
800 * Make sure we are in a valid context (not a child of
801 * TransactionCommandContext...). Note that it is possible for this
802 * code to be called when we aren't in a transaction at all; go
803 * directly to TopMemoryContext in that case.
805 if (TransactionCommandContext != NULL)
807 MemoryContextSwitchTo(TransactionCommandContext);
810 * We do not want to destroy transaction contexts yet, but it
811 * should be OK to delete any command-local memory.
813 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
816 MemoryContextSwitchTo(TopMemoryContext);
820 /* ----------------------------------------------------------------
821 * CleanupTransaction stuff
822 * ----------------------------------------------------------------
825 /* --------------------------------
827 * --------------------------------
830 AtCleanup_Memory(void)
833 * Now that we're "out" of a transaction, have the system allocate
834 * things in the top memory context instead of per-transaction
837 MemoryContextSwitchTo(TopMemoryContext);
840 * Release all transaction-local memory.
842 if (TopTransactionContext != NULL)
843 MemoryContextDelete(TopTransactionContext);
844 TopTransactionContext = NULL;
845 TransactionCommandContext = NULL;
849 /* ----------------------------------------------------------------
851 * ----------------------------------------------------------------
854 /* --------------------------------
857 * --------------------------------
860 StartTransaction(void)
862 TransactionState s = CurrentTransactionState;
865 XactIsoLevel = DefaultXactIsoLevel;
868 * Check the current transaction state. If the transaction system is
869 * switched off, or if we're already in a transaction, do nothing.
870 * We're already in a transaction when the monitor sends a null
871 * command to the backend to flush the comm channel. This is a hacky
872 * fix to a communications problem, and we keep having to deal with it
873 * here. We should fix the comm channel code. mao 080891
875 if (s->state == TRANS_INPROGRESS)
879 * set the current transaction state information appropriately during
882 s->state = TRANS_START;
884 SetReindexProcessing(false);
887 * generate a new transaction id
889 s->transactionIdData = GetNewTransactionId();
891 XactLockTableInsert(s->transactionIdData);
894 * initialize current transaction state fields
896 s->commandId = FirstCommandId;
897 s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
900 * initialize the various transaction subsystems
907 * Tell the trigger manager to we're starting a transaction
909 DeferredTriggerBeginXact();
912 * done with start processing, set current transaction state to "in
915 s->state = TRANS_INPROGRESS;
921 * Tell me if we are currently in progress
925 CurrentXactInProgress(void)
927 return CurrentTransactionState->state == TRANS_INPROGRESS;
931 /* --------------------------------
934 * --------------------------------
937 CommitTransaction(void)
939 TransactionState s = CurrentTransactionState;
942 * check the current transaction state
944 if (s->state != TRANS_INPROGRESS)
945 elog(WARNING, "CommitTransaction and not in in-progress state");
948 * Tell the trigger manager that this transaction is about to be
949 * committed. He'll invoke all trigger deferred until XACT before we
950 * really start on committing the transaction.
952 DeferredTriggerEndXact();
955 * Similarly, let ON COMMIT management do its thing before we start
958 PreCommit_on_commit_actions();
960 /* Prevent cancel/die interrupt while cleaning up */
964 * set the current transaction state information appropriately during
965 * the abort processing
967 s->state = TRANS_COMMIT;
970 * Do pre-commit processing (most of this stuff requires database
971 * access, and in fact could still cause an error...)
976 /* handle commit for large objects [ PA, 7/17/98 ] */
977 /* XXX probably this does not belong here */
980 /* NOTIFY commit must come before lower-level cleanup */
983 /* Update the flat password file if we changed pg_shadow or pg_group */
984 AtEOXact_UpdatePasswordFile(true);
987 * Here is where we really truly commit.
989 RecordTransactionCommit();
992 * Let others know about no transaction in progress by me. Note that
993 * this must be done _before_ releasing locks we hold and _after_
994 * RecordTransactionCommit.
996 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
997 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
998 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
999 * as running as well or it will see two tuple versions - one deleted
1000 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
1002 if (MyProc != (PGPROC *) NULL)
1004 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1005 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1006 MyProc->xid = InvalidTransactionId;
1007 MyProc->xmin = InvalidTransactionId;
1008 LWLockRelease(SInvalLock);
1012 * This is all post-commit cleanup. Note that if an error is raised
1013 * here, it's too late to abort the transaction. This should be just
1014 * noncritical resource releasing.
1016 * The ordering of operations is not entirely random. The idea is:
1017 * release resources visible to other backends (eg, files, buffer pins);
1018 * then release locks; then release backend-local resources. We want
1019 * to release locks at the point where any backend waiting for us will
1020 * see our transaction as being fully cleaned up.
1023 smgrDoPendingDeletes(true);
1025 AtEOXact_Buffers(true);
1026 /* smgrcommit already done */
1036 AtEOXact_on_commit_actions(true);
1037 AtEOXact_Namespace(true);
1038 AtEOXact_CatCache(true);
1040 pgstat_count_xact_commit();
1044 * done with commit processing, set current transaction state back to
1047 s->state = TRANS_DEFAULT;
1049 RESUME_INTERRUPTS();
1052 /* --------------------------------
1055 * --------------------------------
1058 AbortTransaction(void)
1060 TransactionState s = CurrentTransactionState;
1062 /* Prevent cancel/die interrupt while cleaning up */
1066 * Release any LW locks we might be holding as quickly as possible.
1067 * (Regular locks, however, must be held till we finish aborting.)
1068 * Releasing LW locks is critical since we might try to grab them
1069 * again while cleaning up!
1073 /* Clean up buffer I/O and buffer context locks, too */
1078 * Also clean up any open wait for lock, since the lock manager will
1079 * choke if we try to wait for another lock before doing this.
1084 * check the current transaction state
1086 if (s->state != TRANS_INPROGRESS)
1087 elog(WARNING, "AbortTransaction and not in in-progress state");
1090 * set the current transaction state information appropriately during
1091 * the abort processing
1093 s->state = TRANS_ABORT;
1095 /* Make sure we are in a valid memory context */
1099 * Reset user id which might have been changed transiently
1101 SetUserId(GetSessionUserId());
1104 * do abort processing
1106 DeferredTriggerAbortXact();
1108 lo_commit(false); /* 'false' means it's abort */
1110 AtEOXact_UpdatePasswordFile(false);
1112 /* Advertise the fact that we aborted in pg_clog. */
1113 RecordTransactionAbort();
1116 * Let others know about no transaction in progress by me. Note that
1117 * this must be done _before_ releasing locks we hold and _after_
1118 * RecordTransactionAbort.
1120 if (MyProc != (PGPROC *) NULL)
1122 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1123 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1124 MyProc->xid = InvalidTransactionId;
1125 MyProc->xmin = InvalidTransactionId;
1126 LWLockRelease(SInvalLock);
1130 * Post-abort cleanup. See notes in CommitTransaction() concerning
1134 smgrDoPendingDeletes(false);
1136 AtEOXact_Buffers(false);
1141 AtEOXact_GUC(false);
1147 AtEOXact_on_commit_actions(false);
1148 AtEOXact_Namespace(false);
1149 AtEOXact_CatCache(false);
1151 pgstat_count_xact_rollback();
1154 * State remains TRANS_ABORT until CleanupTransaction().
1156 RESUME_INTERRUPTS();
1159 /* --------------------------------
1160 * CleanupTransaction
1162 * --------------------------------
1165 CleanupTransaction(void)
1167 TransactionState s = CurrentTransactionState;
1170 * State should still be TRANS_ABORT from AbortTransaction().
1172 if (s->state != TRANS_ABORT)
1173 elog(FATAL, "CleanupTransaction and not in abort state");
1176 * do abort cleanup processing
1181 * done with abort processing, set current transaction state back to
1184 s->state = TRANS_DEFAULT;
1187 /* --------------------------------
1188 * StartTransactionCommand
1190 * preventChain, if true, forces autocommit behavior at the next
1191 * CommitTransactionCommand call.
1192 * --------------------------------
1195 StartTransactionCommand(bool preventChain)
1197 TransactionState s = CurrentTransactionState;
1200 * Remember if caller wants to prevent autocommit-off chaining. This
1201 * is only allowed if not already in a transaction block.
1203 suppressChain = preventChain;
1204 if (preventChain && s->blockState != TBLOCK_DEFAULT)
1205 elog(ERROR, "StartTransactionCommand: can't prevent chain");
1207 switch (s->blockState)
1210 * if we aren't in a transaction block, we just do our usual
1211 * start transaction.
1213 case TBLOCK_DEFAULT:
1218 * We should never experience this -- if we do it means the
1219 * BEGIN state was not changed in the previous
1220 * CommitTransactionCommand(). If we get it, we print a
1221 * warning and change to the in-progress state.
1224 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1225 s->blockState = TBLOCK_INPROGRESS;
1229 * This is the case when are somewhere in a transaction block
1230 * and about to start a new command. For now we do nothing
1231 * but someday we may do command-local resource
1234 case TBLOCK_INPROGRESS:
1238 * As with BEGIN, we should never experience this if we do it
1239 * means the END state was not changed in the previous
1240 * CommitTransactionCommand(). If we get it, we print a
1241 * warning, commit the transaction, start a new transaction
1242 * and change to the default state.
1245 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
1246 s->blockState = TBLOCK_DEFAULT;
1247 CommitTransaction();
1252 * Here we are in the middle of a transaction block but one of
1253 * the commands caused an abort so we do nothing but remain in
1254 * the abort state. Eventually we will get to the "END
1255 * TRANSACTION" which will set things straight.
1261 * This means we somehow aborted and the last call to
1262 * CommitTransactionCommand() didn't clear the state so we
1263 * remain in the ENDABORT state and maybe next time we get to
1264 * CommitTransactionCommand() the state will get reset to
1267 case TBLOCK_ENDABORT:
1268 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1273 * We must switch to TransactionCommandContext before returning. This
1274 * is already done if we called StartTransaction, otherwise not.
1276 Assert(TransactionCommandContext != NULL);
1277 MemoryContextSwitchTo(TransactionCommandContext);
1280 /* --------------------------------
1281 * CommitTransactionCommand
1283 * forceCommit = true forces autocommit behavior even when autocommit is off.
1284 * --------------------------------
1287 CommitTransactionCommand(bool forceCommit)
1289 TransactionState s = CurrentTransactionState;
1291 switch (s->blockState)
1294 * If we aren't in a transaction block, and we are doing
1295 * autocommit, just do our usual transaction commit. But if
1296 * we aren't doing autocommit, start a transaction block
1297 * automatically by switching to INPROGRESS state. (We handle
1298 * this choice here, and not earlier, so that an explicit
1299 * BEGIN issued in autocommit-off mode won't issue strange
1302 * Autocommit mode is forced by either a true forceCommit
1303 * parameter to me, or a true preventChain parameter to the
1304 * preceding StartTransactionCommand call, or a
1305 * PreventTransactionChain call during the transaction.
1306 * (The parameters could be omitted, but it turns out most
1307 * callers of StartTransactionCommand/CommitTransactionCommand
1308 * want to force autocommit, so making them all call
1309 * PreventTransactionChain would just be extra notation.)
1311 case TBLOCK_DEFAULT:
1312 if (autocommit || forceCommit || suppressChain)
1313 CommitTransaction();
1316 BeginTransactionBlock();
1317 Assert(s->blockState == TBLOCK_INPROGRESS);
1318 /* This code must match the TBLOCK_INPROGRESS case below: */
1319 CommandCounterIncrement();
1320 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1325 * This is the case right after we get a "BEGIN TRANSACTION"
1326 * command, but the user hasn't done anything else yet, so we
1327 * change to the "transaction block in progress" state and
1331 s->blockState = TBLOCK_INPROGRESS;
1335 * This is the case when we have finished executing a command
1336 * someplace within a transaction block. We increment the
1337 * command counter and return. Someday we may free resources
1338 * local to the command.
1340 * That someday is today, at least for memory allocated in
1341 * TransactionCommandContext. - vadim 03/25/97
1343 case TBLOCK_INPROGRESS:
1344 CommandCounterIncrement();
1345 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1349 * This is the case when we just got the "END TRANSACTION"
1350 * statement, so we commit the transaction and go back to the
1354 CommitTransaction();
1355 s->blockState = TBLOCK_DEFAULT;
1359 * Here we are in the middle of a transaction block but one of
1360 * the commands caused an abort so we do nothing but remain in
1361 * the abort state. Eventually we will get to the "END
1362 * TRANSACTION" which will set things straight.
1368 * Here we were in an aborted transaction block which just
1369 * processed the "END TRANSACTION" command from the user, so
1370 * clean up and return to the default state.
1372 case TBLOCK_ENDABORT:
1373 CleanupTransaction();
1374 s->blockState = TBLOCK_DEFAULT;
1379 /* --------------------------------
1380 * AbortCurrentTransaction
1381 * --------------------------------
1384 AbortCurrentTransaction(void)
1386 TransactionState s = CurrentTransactionState;
1388 switch (s->blockState)
1391 * if we aren't in a transaction block, we just do the basic
1392 * abort & cleanup transaction.
1394 case TBLOCK_DEFAULT:
1396 CleanupTransaction();
1400 * If we are in the TBLOCK_BEGIN it means something screwed up
1401 * right after reading "BEGIN TRANSACTION" so we enter the
1402 * abort state. Eventually an "END TRANSACTION" will fix
1406 s->blockState = TBLOCK_ABORT;
1408 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1412 * This is the case when are somewhere in a transaction block
1413 * which aborted so we abort the transaction and set the ABORT
1414 * state. Eventually an "END TRANSACTION" will fix things and
1415 * restore us to a normal state.
1417 case TBLOCK_INPROGRESS:
1418 s->blockState = TBLOCK_ABORT;
1420 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1424 * Here, the system was fouled up just after the user wanted
1425 * to end the transaction block so we abort the transaction
1426 * and put us back into the default state.
1429 s->blockState = TBLOCK_DEFAULT;
1431 CleanupTransaction();
1435 * Here, we are already in an aborted transaction state and
1436 * are waiting for an "END TRANSACTION" to come along and lo
1437 * and behold, we abort again! So we just remain in the abort
1444 * Here we were in an aborted transaction block which just
1445 * processed the "END TRANSACTION" command but somehow aborted
1446 * again.. since we must have done the abort processing, we
1447 * clean up and return to the default state.
1449 case TBLOCK_ENDABORT:
1450 CleanupTransaction();
1451 s->blockState = TBLOCK_DEFAULT;
1456 /* --------------------------------
1457 * PreventTransactionChain
1459 * This routine is to be called by statements that must not run inside
1460 * a transaction block, typically because they have non-rollback-able
1461 * side effects or do internal commits.
1463 * If we have already started a transaction block, issue an error; also issue
1464 * an error if we appear to be running inside a user-defined function (which
1465 * could issue more commands and possibly cause a failure after the statement
1466 * completes). In autocommit-off mode, we allow the statement if a block is
1467 * not already started, and force the statement to be autocommitted despite
1470 * stmtNode: pointer to parameter block for statement; this is used in
1471 * a very klugy way to determine whether we are inside a function.
1472 * stmtType: statement type name for error messages.
1473 * --------------------------------
1476 PreventTransactionChain(void *stmtNode, const char *stmtType)
1479 * xact block already started?
1481 if (IsTransactionBlock())
1483 /* translator: %s represents an SQL statement name */
1484 elog(ERROR, "%s cannot run inside a transaction block", stmtType);
1487 * Are we inside a function call? If the statement's parameter block
1488 * was allocated in QueryContext, assume it is an interactive command.
1489 * Otherwise assume it is coming from a function.
1491 if (!MemoryContextContains(QueryContext, stmtNode))
1493 /* translator: %s represents an SQL statement name */
1494 elog(ERROR, "%s cannot be executed from a function", stmtType);
1496 /* If we got past IsTransactionBlock test, should be in default state */
1497 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
1498 elog(ERROR, "PreventTransactionChain: can't prevent chain");
1499 /* okay to set the flag */
1500 suppressChain = true;
1501 /* If we're in autocommit-off node, generate a notice */
1504 /* translator: %s represents an SQL statement name */
1505 elog(NOTICE, "%s will be committed automatically", stmtType);
1510 /* ----------------------------------------------------------------
1511 * transaction block support
1512 * ----------------------------------------------------------------
1514 /* --------------------------------
1515 * BeginTransactionBlock
1516 * --------------------------------
1519 BeginTransactionBlock(void)
1521 TransactionState s = CurrentTransactionState;
1524 * check the current transaction state
1526 if (s->blockState != TBLOCK_DEFAULT)
1527 elog(WARNING, "BEGIN: already a transaction in progress");
1530 * set the current transaction block state information appropriately
1531 * during begin processing
1533 s->blockState = TBLOCK_BEGIN;
1536 * do begin processing. NOTE: if you put anything here, check that it
1537 * behaves properly in both autocommit-on and autocommit-off modes. In
1538 * the latter case we will already have done some work in the new
1543 * done with begin processing, set block state to inprogress
1545 s->blockState = TBLOCK_INPROGRESS;
1548 /* --------------------------------
1549 * EndTransactionBlock
1550 * --------------------------------
1553 EndTransactionBlock(void)
1555 TransactionState s = CurrentTransactionState;
1558 * check the current transaction state
1560 if (s->blockState == TBLOCK_INPROGRESS)
1563 * here we are in a transaction block which should commit when we
1564 * get to the upcoming CommitTransactionCommand() so we set the
1565 * state to "END". CommitTransactionCommand() will recognize this
1566 * and commit the transaction and return us to the default state
1568 s->blockState = TBLOCK_END;
1572 if (s->blockState == TBLOCK_ABORT)
1575 * here, we are in a transaction block which aborted and since the
1576 * AbortTransaction() was already done, we do whatever is needed
1577 * and change to the special "END ABORT" state. The upcoming
1578 * CommitTransactionCommand() will recognise this and then put us
1579 * back in the default state.
1581 s->blockState = TBLOCK_ENDABORT;
1586 * here, the user issued COMMIT when not inside a transaction. Issue a
1587 * WARNING and go to abort state. The upcoming call to
1588 * CommitTransactionCommand() will then put us back into the default
1591 elog(WARNING, "COMMIT: no transaction in progress");
1593 s->blockState = TBLOCK_ENDABORT;
1596 /* --------------------------------
1597 * AbortTransactionBlock
1598 * --------------------------------
1602 AbortTransactionBlock(void)
1604 TransactionState s = CurrentTransactionState;
1607 * check the current transaction state
1609 if (s->blockState == TBLOCK_INPROGRESS)
1612 * here we were inside a transaction block something screwed up
1613 * inside the system so we enter the abort state, do the abort
1614 * processing and then return. We remain in the abort state until
1615 * we see an END TRANSACTION command.
1617 s->blockState = TBLOCK_ABORT;
1623 * here, the user issued ABORT when not inside a transaction. Issue a
1624 * WARNING and go to abort state. The upcoming call to
1625 * CommitTransactionCommand() will then put us back into the default
1628 elog(WARNING, "ROLLBACK: no transaction in progress");
1630 s->blockState = TBLOCK_ENDABORT;
1634 /* --------------------------------
1635 * UserAbortTransactionBlock
1636 * --------------------------------
1639 UserAbortTransactionBlock(void)
1641 TransactionState s = CurrentTransactionState;
1644 * if the transaction has already been automatically aborted with an
1645 * error, and the user subsequently types 'abort', allow it. (the
1646 * behavior is the same as if they had typed 'end'.)
1648 if (s->blockState == TBLOCK_ABORT)
1650 s->blockState = TBLOCK_ENDABORT;
1654 if (s->blockState == TBLOCK_INPROGRESS)
1657 * here we were inside a transaction block and we got an abort
1658 * command from the user, so we move to the abort state, do the
1659 * abort processing and then change to the ENDABORT state so we
1660 * will end up in the default state after the upcoming
1661 * CommitTransactionCommand().
1663 s->blockState = TBLOCK_ABORT;
1665 s->blockState = TBLOCK_ENDABORT;
1670 * here, the user issued ABORT when not inside a transaction. Issue a
1671 * WARNING and go to abort state. The upcoming call to
1672 * CommitTransactionCommand() will then put us back into the default
1675 elog(WARNING, "ROLLBACK: no transaction in progress");
1677 s->blockState = TBLOCK_ENDABORT;
1680 /* --------------------------------
1681 * AbortOutOfAnyTransaction
1683 * This routine is provided for error recovery purposes. It aborts any
1684 * active transaction or transaction block, leaving the system in a known
1686 * --------------------------------
1689 AbortOutOfAnyTransaction(void)
1691 TransactionState s = CurrentTransactionState;
1694 * Get out of any low-level transaction
1699 case TRANS_INPROGRESS:
1701 /* In a transaction, so clean up */
1703 CleanupTransaction();
1706 /* AbortTransaction already done, still need Cleanup */
1707 CleanupTransaction();
1710 /* Not in a transaction, do nothing */
1715 * Now reset the high-level state
1717 s->blockState = TBLOCK_DEFAULT;
1721 IsTransactionBlock(void)
1723 TransactionState s = CurrentTransactionState;
1725 if (s->blockState == TBLOCK_INPROGRESS
1726 || s->blockState == TBLOCK_ABORT
1727 || s->blockState == TBLOCK_ENDABORT)
1734 xact_redo(XLogRecPtr lsn, XLogRecord *record)
1736 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1738 if (info == XLOG_XACT_COMMIT)
1740 TransactionIdCommit(record->xl_xid);
1741 /* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
1743 else if (info == XLOG_XACT_ABORT)
1745 TransactionIdAbort(record->xl_xid);
1746 /* SHOULD REMOVE FILES OF ALL FAILED-TO-BE-CREATED RELATIONS */
1749 elog(PANIC, "xact_redo: unknown op code %u", info);
1753 xact_undo(XLogRecPtr lsn, XLogRecord *record)
1755 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1757 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
1758 elog(PANIC, "xact_undo: can't undo committed xaction");
1759 else if (info != XLOG_XACT_ABORT)
1760 elog(PANIC, "xact_redo: unknown op code %u", info);
1764 xact_desc(char *buf, uint8 xl_info, char *rec)
1766 uint8 info = xl_info & ~XLR_INFO_MASK;
1768 if (info == XLOG_XACT_COMMIT)
1770 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
1771 struct tm *tm = localtime(&xlrec->xtime);
1773 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
1774 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1775 tm->tm_hour, tm->tm_min, tm->tm_sec);
1777 else if (info == XLOG_XACT_ABORT)
1779 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
1780 struct tm *tm = localtime(&xlrec->xtime);
1782 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
1783 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1784 tm->tm_hour, tm->tm_min, tm->tm_sec);
1787 strcat(buf, "UNKNOWN");
1791 XactPushRollback(void (*func) (void *), void *data)
1794 if (_RollbackFunc != NULL)
1795 elog(PANIC, "XactPushRollback: already installed");
1798 _RollbackFunc = func;
1799 _RollbackData = data;
1803 XactPopRollback(void)
1805 _RollbackFunc = NULL;