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.147 2003/05/02 20:54:33 tgl Exp $
14 * Transaction aborts can now occur two ways:
16 * 1) system dies from some internal cause (syntax error, 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 a COMMIT transaction or
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 * TopTransactionContext until this point.
55 * The essential aspects of the transaction system are:
57 * o transaction id generation
58 * o transaction log updating
60 * o cache invalidation
63 * Hence, the functional division of the transaction code is
64 * based on which of the above things need to be done during
65 * a start/commit/abort transaction. For instance, the
66 * routine AtCommit_Memory() takes care of all the memory
67 * cleanup stuff done at commit time.
69 * The code is layered as follows:
76 * are provided to do the lower level work like recording
77 * the transaction status in the log and doing memory cleanup.
78 * above these routines are another set of functions:
80 * StartTransactionCommand
81 * CommitTransactionCommand
82 * AbortCurrentTransaction
84 * These are the routines used in the postgres main processing
85 * loop. They are sensitive to the current transaction block state
86 * and make calls to the lower level routines appropriately.
88 * Support for transaction blocks is provided via the functions:
90 * StartTransactionBlock
91 * CommitTransactionBlock
92 * AbortTransactionBlock
94 * These are invoked only in response to a user "BEGIN WORK", "COMMIT",
95 * or "ROLLBACK" command. The tricky part about these functions
96 * is that they are called within the postgres main loop, in between
97 * the StartTransactionCommand() and CommitTransactionCommand().
99 * For example, consider the following sequence of user commands:
102 * 2) select * from foo
103 * 3) insert into foo (bar = baz)
106 * in the main processing loop, this results in the following
107 * transaction sequence:
109 * / StartTransactionCommand();
110 * 1) / ProcessUtility(); << begin
111 * \ StartTransactionBlock();
112 * \ CommitTransactionCommand();
114 * / StartTransactionCommand();
115 * 2) < ProcessQuery(); << select * from foo
116 * \ CommitTransactionCommand();
118 * / StartTransactionCommand();
119 * 3) < ProcessQuery(); << insert into foo (bar = baz)
120 * \ CommitTransactionCommand();
122 * / StartTransactionCommand();
123 * 4) / ProcessUtility(); << commit
124 * \ CommitTransactionBlock();
125 * \ CommitTransactionCommand();
127 * The point of this example is to demonstrate the need for
128 * StartTransactionCommand() and CommitTransactionCommand() to
129 * be state smart -- they should do nothing in between the calls
130 * to StartTransactionBlock() and EndTransactionBlock() and
131 * outside these calls they need to do normal start/commit
134 * Furthermore, suppose the "select * from foo" caused an abort
135 * condition. We would then want to abort the transaction and
136 * ignore all subsequent commands up to the "commit".
139 *-------------------------------------------------------------------------
142 #include "postgres.h"
145 #include <sys/time.h>
147 #include "access/gistscan.h"
148 #include "access/hash.h"
149 #include "access/nbtree.h"
150 #include "access/rtree.h"
151 #include "access/xact.h"
152 #include "catalog/heap.h"
153 #include "catalog/index.h"
154 #include "catalog/namespace.h"
155 #include "commands/async.h"
156 #include "commands/tablecmds.h"
157 #include "commands/trigger.h"
158 #include "commands/user.h"
159 #include "executor/spi.h"
160 #include "libpq/be-fsstubs.h"
161 #include "miscadmin.h"
162 #include "storage/proc.h"
163 #include "storage/sinval.h"
164 #include "storage/smgr.h"
165 #include "utils/guc.h"
166 #include "utils/inval.h"
167 #include "utils/memutils.h"
168 #include "utils/portal.h"
169 #include "utils/catcache.h"
170 #include "utils/relcache.h"
174 static void AbortTransaction(void);
175 static void AtAbort_Cache(void);
176 static void AtAbort_Locks(void);
177 static void AtAbort_Memory(void);
178 static void AtCleanup_Memory(void);
179 static void AtCommit_Cache(void);
180 static void AtCommit_LocalCache(void);
181 static void AtCommit_Locks(void);
182 static void AtCommit_Memory(void);
183 static void AtStart_Cache(void);
184 static void AtStart_Locks(void);
185 static void AtStart_Memory(void);
186 static void CleanupTransaction(void);
187 static void CommitTransaction(void);
188 static void RecordTransactionAbort(void);
189 static void StartTransaction(void);
192 * global variables holding the current transaction state.
194 static TransactionStateData CurrentTransactionStateData = {
195 0, /* transaction id */
196 FirstCommandId, /* command id */
197 0, /* scan command id */
198 0x0, /* start time */
199 TRANS_DEFAULT, /* transaction state */
200 TBLOCK_DEFAULT /* transaction block state from
201 the client perspective */
204 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
207 * User-tweakable parameters
209 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
212 bool DefaultXactReadOnly = false;
215 bool autocommit = true;
217 int CommitDelay = 0; /* precommit delay in microseconds */
218 int CommitSiblings = 5; /* number of concurrent xacts needed to
222 static bool suppressChain = false;
224 static void (*_RollbackFunc) (void *) = NULL;
225 static void *_RollbackData = NULL;
228 /* ----------------------------------------------------------------
229 * transaction state accessors
230 * ----------------------------------------------------------------
235 /* --------------------------------
236 * TransactionFlushEnabled()
237 * SetTransactionFlushEnabled()
239 * These are used to test and set the "TransactionFlushState"
240 * variable. If this variable is true (the default), then
241 * the system will flush all dirty buffers to disk at the end
242 * of each transaction. If false then we are assuming the
243 * buffer pool resides in stable main memory, in which case we
244 * only do writes as necessary.
245 * --------------------------------
247 static int TransactionFlushState = 1;
250 TransactionFlushEnabled(void)
252 return TransactionFlushState;
256 SetTransactionFlushEnabled(bool state)
258 TransactionFlushState = (state == true);
266 * This returns true if we are currently running a query
267 * within an executing transaction.
270 IsTransactionState(void)
272 TransactionState s = CurrentTransactionState;
280 case TRANS_INPROGRESS:
289 * Shouldn't get here, but lint is not happy with this...
295 * IsAbortedTransactionBlockState
297 * This returns true if we are currently running a query
298 * within an aborted transaction block.
301 IsAbortedTransactionBlockState(void)
303 TransactionState s = CurrentTransactionState;
305 if (s->blockState == TBLOCK_ABORT)
313 * GetCurrentTransactionId
316 GetCurrentTransactionId(void)
318 TransactionState s = CurrentTransactionState;
320 return s->transactionIdData;
325 * GetCurrentCommandId
328 GetCurrentCommandId(void)
330 TransactionState s = CurrentTransactionState;
337 * GetCurrentTransactionStartTime
340 GetCurrentTransactionStartTime(void)
342 TransactionState s = CurrentTransactionState;
349 * GetCurrentTransactionStartTimeUsec
352 GetCurrentTransactionStartTimeUsec(int *msec)
354 TransactionState s = CurrentTransactionState;
356 *msec = s->startTimeUsec;
363 * TransactionIdIsCurrentTransactionId
365 * During bootstrap, we cheat and say "it's not my transaction ID" even though
366 * it is. Along with transam.c's cheat to say that the bootstrap XID is
367 * already committed, this causes the tqual.c routines to see previously
368 * inserted tuples as committed, which is what we need during bootstrap.
371 TransactionIdIsCurrentTransactionId(TransactionId xid)
373 TransactionState s = CurrentTransactionState;
377 Assert(xid == BootstrapTransactionId);
381 return TransactionIdEquals(xid, s->transactionIdData);
386 * CommandIdIsCurrentCommandId
389 CommandIdIsCurrentCommandId(CommandId cid)
391 TransactionState s = CurrentTransactionState;
393 return (cid == s->commandId) ? true : false;
398 * CommandCounterIncrement
401 CommandCounterIncrement(void)
403 TransactionState s = CurrentTransactionState;
406 if (s->commandId == FirstCommandId) /* check for overflow */
407 elog(ERROR, "You may only have 2^32-1 commands per transaction");
409 /* Propagate new command ID into query snapshots, if set */
411 QuerySnapshot->curcid = s->commandId;
412 if (SerializableSnapshot)
413 SerializableSnapshot->curcid = s->commandId;
416 * make cache changes visible to me. AtCommit_LocalCache() instead of
417 * AtCommit_Cache() is called here.
419 AtCommit_LocalCache();
424 /* ----------------------------------------------------------------
425 * StartTransaction stuff
426 * ----------------------------------------------------------------
435 AcceptInvalidationMessages();
445 * at present, it is unknown to me what belongs here -cim 3/18/90
447 * There isn't anything to do at the start of a xact for locks. -mer
459 * We shouldn't have a transaction context already.
461 Assert(TopTransactionContext == NULL);
464 * Create a toplevel context for the transaction, and make it active.
466 TopTransactionContext =
467 AllocSetContextCreate(TopMemoryContext,
468 "TopTransactionContext",
469 ALLOCSET_DEFAULT_MINSIZE,
470 ALLOCSET_DEFAULT_INITSIZE,
471 ALLOCSET_DEFAULT_MAXSIZE);
473 MemoryContextSwitchTo(TopTransactionContext);
477 /* ----------------------------------------------------------------
478 * CommitTransaction stuff
479 * ----------------------------------------------------------------
483 * RecordTransactionCommit
486 RecordTransactionCommit(void)
489 * If we made neither any XLOG entries nor any temp-rel updates, we
490 * can omit recording the transaction commit at all.
492 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate)
494 TransactionId xid = GetCurrentTransactionId();
497 /* Tell bufmgr and smgr to prepare for commit */
500 START_CRIT_SECTION();
503 * We only need to log the commit in xlog if the transaction made
504 * any transaction-controlled XLOG entries. (Otherwise, its XID
505 * appears nowhere in permanent storage, so no one else will ever
506 * care if it committed.)
508 if (MyLastRecPtr.xrecoff != 0)
510 /* Need to emit a commit record */
512 xl_xact_commit xlrec;
514 xlrec.xtime = time(NULL);
515 rdata.buffer = InvalidBuffer;
516 rdata.data = (char *) (&xlrec);
517 rdata.len = SizeOfXactCommit;
521 * XXX SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
523 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, &rdata);
527 /* Just flush through last record written by me */
528 recptr = ProcLastRecEnd;
532 * We must flush our XLOG entries to disk if we made any XLOG
533 * entries, whether in or out of transaction control. For
534 * example, if we reported a nextval() result to the client, this
535 * ensures that any XLOG record generated by nextval will hit the
536 * disk before we report the transaction committed.
538 if (MyXactMadeXLogEntry)
541 * Sleep before flush! So we can flush more than one commit
542 * records per single fsync. (The idea is some other backend
543 * may do the XLogFlush while we're sleeping. This needs work
544 * still, because on most Unixen, the minimum select() delay
545 * is 10msec or more, which is way too long.)
547 * We do not sleep if enableFsync is not turned on, nor if there
548 * are fewer than CommitSiblings other backends with active
551 if (CommitDelay > 0 && enableFsync &&
552 CountActiveBackends() >= CommitSiblings)
554 struct timeval delay;
557 delay.tv_usec = CommitDelay;
558 (void) select(0, NULL, NULL, NULL, &delay);
565 * We must mark the transaction committed in clog if its XID
566 * appears either in permanent rels or in local temporary rels.
567 * We test this by seeing if we made transaction-controlled
568 * entries *OR* local-rel tuple updates. Note that if we made
569 * only the latter, we have not emitted an XLOG record for our
570 * commit, and so in the event of a crash the clog update might be
571 * lost. This is okay because no one else will ever care whether
574 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
575 TransactionIdCommit(xid);
580 /* Break the chain of back-links in the XLOG records I output */
581 MyLastRecPtr.xrecoff = 0;
582 MyXactMadeXLogEntry = false;
583 MyXactMadeTempRelUpdate = false;
585 /* Show myself as out of the transaction in PGPROC array */
586 MyProc->logRec.xrecoff = 0;
597 * Clean up the relation cache.
599 AtEOXact_RelationCache(true);
602 * Make catalog changes visible to all backends.
604 AtEOXactInvalidationMessages(true);
608 * AtCommit_LocalCache
611 AtCommit_LocalCache(void)
614 * Make catalog changes visible to me for the next command.
616 CommandEndInvalidationMessages(true);
626 * XXX What if ProcReleaseLocks fails? (race condition?)
628 * Then you're up a creek! -mer 5/24/92
630 ProcReleaseLocks(true);
637 AtCommit_Memory(void)
640 * Now that we're "out" of a transaction, have the system allocate
641 * things in the top memory context instead of per-transaction
644 MemoryContextSwitchTo(TopMemoryContext);
647 * Release all transaction-local memory.
649 Assert(TopTransactionContext != NULL);
650 MemoryContextDelete(TopTransactionContext);
651 TopTransactionContext = NULL;
654 /* ----------------------------------------------------------------
655 * AbortTransaction stuff
656 * ----------------------------------------------------------------
660 * RecordTransactionAbort
663 RecordTransactionAbort(void)
666 * If we made neither any transaction-controlled XLOG entries nor any
667 * temp-rel updates, we can omit recording the transaction abort at
668 * all. No one will ever care that it aborted.
670 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
672 TransactionId xid = GetCurrentTransactionId();
675 * Catch the scenario where we aborted partway through
676 * RecordTransactionCommit ...
678 if (TransactionIdDidCommit(xid))
679 elog(PANIC, "RecordTransactionAbort: xact %u already committed",
682 START_CRIT_SECTION();
685 * We only need to log the abort in XLOG if the transaction made
686 * any transaction-controlled XLOG entries. (Otherwise, its XID
687 * appears nowhere in permanent storage, so no one else will ever
688 * care if it committed.) We do not flush XLOG to disk in any
689 * case, since the default assumption after a crash would be that
690 * we aborted, anyway.
692 if (MyLastRecPtr.xrecoff != 0)
698 xlrec.xtime = time(NULL);
699 rdata.buffer = InvalidBuffer;
700 rdata.data = (char *) (&xlrec);
701 rdata.len = SizeOfXactAbort;
705 * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
707 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
711 * Mark the transaction aborted in clog. This is not absolutely
712 * necessary but we may as well do it while we are here.
714 TransactionIdAbort(xid);
719 /* Break the chain of back-links in the XLOG records I output */
720 MyLastRecPtr.xrecoff = 0;
721 MyXactMadeXLogEntry = false;
722 MyXactMadeTempRelUpdate = false;
724 /* Show myself as out of the transaction in PGPROC array */
725 MyProc->logRec.xrecoff = 0;
734 AtEOXact_RelationCache(false);
735 AtEOXactInvalidationMessages(false);
745 * XXX What if ProcReleaseLocks() fails? (race condition?)
747 * Then you're up a creek without a paddle! -mer
749 ProcReleaseLocks(false);
760 * Make sure we are in a valid context (not a child of
761 * TopTransactionContext...). Note that it is possible for this
762 * code to be called when we aren't in a transaction at all; go
763 * directly to TopMemoryContext in that case.
765 if (TopTransactionContext != NULL)
767 MemoryContextSwitchTo(TopTransactionContext);
770 * We do not want to destroy the transaction's global state yet,
771 * so we can't free any memory here.
775 MemoryContextSwitchTo(TopMemoryContext);
779 /* ----------------------------------------------------------------
780 * CleanupTransaction stuff
781 * ----------------------------------------------------------------
788 AtCleanup_Memory(void)
791 * Now that we're "out" of a transaction, have the system allocate
792 * things in the top memory context instead of per-transaction
795 MemoryContextSwitchTo(TopMemoryContext);
798 * Release all transaction-local memory.
800 if (TopTransactionContext != NULL)
801 MemoryContextDelete(TopTransactionContext);
802 TopTransactionContext = NULL;
806 /* ----------------------------------------------------------------
808 * ----------------------------------------------------------------
815 StartTransaction(void)
817 TransactionState s = CurrentTransactionState;
820 XactIsoLevel = DefaultXactIsoLevel;
821 XactReadOnly = DefaultXactReadOnly;
824 * Check the current transaction state. If the transaction system is
825 * switched off, or if we're already in a transaction, do nothing.
826 * We're already in a transaction when the monitor sends a null
827 * command to the backend to flush the comm channel. This is a hacky
828 * fix to a communications problem, and we keep having to deal with it
829 * here. We should fix the comm channel code. mao 080891
831 if (s->state == TRANS_INPROGRESS)
835 * set the current transaction state information appropriately during
838 s->state = TRANS_START;
840 SetReindexProcessing(false);
843 * generate a new transaction id
845 s->transactionIdData = GetNewTransactionId();
847 XactLockTableInsert(s->transactionIdData);
850 * initialize current transaction state fields
852 s->commandId = FirstCommandId;
853 s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
856 * initialize the various transaction subsystems
863 * Tell the trigger manager to we're starting a transaction
865 DeferredTriggerBeginXact();
868 * done with start processing, set current transaction state to "in
871 s->state = TRANS_INPROGRESS;
879 CommitTransaction(void)
881 TransactionState s = CurrentTransactionState;
884 * check the current transaction state
886 if (s->state != TRANS_INPROGRESS)
887 elog(WARNING, "CommitTransaction and not in in-progress state");
890 * Tell the trigger manager that this transaction is about to be
891 * committed. He'll invoke all trigger deferred until XACT before we
892 * really start on committing the transaction.
894 DeferredTriggerEndXact();
897 * Similarly, let ON COMMIT management do its thing before we start
900 PreCommit_on_commit_actions();
902 /* Prevent cancel/die interrupt while cleaning up */
906 * set the current transaction state information appropriately during
907 * the abort processing
909 s->state = TRANS_COMMIT;
912 * Do pre-commit processing (most of this stuff requires database
913 * access, and in fact could still cause an error...)
918 /* handle commit for large objects [ PA, 7/17/98 ] */
919 /* XXX probably this does not belong here */
922 /* NOTIFY commit must come before lower-level cleanup */
925 /* Update the flat password file if we changed pg_shadow or pg_group */
926 AtEOXact_UpdatePasswordFile(true);
929 * Here is where we really truly commit.
931 RecordTransactionCommit();
934 * Let others know about no transaction in progress by me. Note that
935 * this must be done _before_ releasing locks we hold and _after_
936 * RecordTransactionCommit.
938 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
939 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
940 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
941 * as running as well or it will see two tuple versions - one deleted
942 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
944 if (MyProc != (PGPROC *) NULL)
946 /* Lock SInvalLock because that's what GetSnapshotData uses. */
947 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
948 MyProc->xid = InvalidTransactionId;
949 MyProc->xmin = InvalidTransactionId;
950 LWLockRelease(SInvalLock);
954 * This is all post-commit cleanup. Note that if an error is raised
955 * here, it's too late to abort the transaction. This should be just
956 * noncritical resource releasing.
958 * The ordering of operations is not entirely random. The idea is:
959 * release resources visible to other backends (eg, files, buffer pins);
960 * then release locks; then release backend-local resources. We want
961 * to release locks at the point where any backend waiting for us will
962 * see our transaction as being fully cleaned up.
965 smgrDoPendingDeletes(true);
967 AtEOXact_Buffers(true);
968 /* smgrcommit already done */
978 AtEOXact_on_commit_actions(true);
979 AtEOXact_Namespace(true);
980 AtEOXact_CatCache(true);
982 pgstat_count_xact_commit();
986 * done with commit processing, set current transaction state back to
989 s->state = TRANS_DEFAULT;
998 AbortTransaction(void)
1000 TransactionState s = CurrentTransactionState;
1002 /* Prevent cancel/die interrupt while cleaning up */
1006 * Release any LW locks we might be holding as quickly as possible.
1007 * (Regular locks, however, must be held till we finish aborting.)
1008 * Releasing LW locks is critical since we might try to grab them
1009 * again while cleaning up!
1013 /* Clean up buffer I/O and buffer context locks, too */
1018 * Also clean up any open wait for lock, since the lock manager will
1019 * choke if we try to wait for another lock before doing this.
1024 * check the current transaction state
1026 if (s->state != TRANS_INPROGRESS)
1027 elog(WARNING, "AbortTransaction and not in in-progress state");
1030 * set the current transaction state information appropriately during
1031 * the abort processing
1033 s->state = TRANS_ABORT;
1035 /* Make sure we are in a valid memory context */
1039 * Reset user id which might have been changed transiently
1041 SetUserId(GetSessionUserId());
1044 * do abort processing
1046 DeferredTriggerAbortXact();
1048 lo_commit(false); /* 'false' means it's abort */
1050 AtEOXact_UpdatePasswordFile(false);
1052 /* Advertise the fact that we aborted in pg_clog. */
1053 RecordTransactionAbort();
1056 * Let others know about no transaction in progress by me. Note that
1057 * this must be done _before_ releasing locks we hold and _after_
1058 * RecordTransactionAbort.
1060 if (MyProc != (PGPROC *) NULL)
1062 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1063 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1064 MyProc->xid = InvalidTransactionId;
1065 MyProc->xmin = InvalidTransactionId;
1066 LWLockRelease(SInvalLock);
1070 * Post-abort cleanup. See notes in CommitTransaction() concerning
1074 smgrDoPendingDeletes(false);
1076 AtEOXact_Buffers(false);
1081 AtEOXact_GUC(false);
1087 AtEOXact_on_commit_actions(false);
1088 AtEOXact_Namespace(false);
1089 AtEOXact_CatCache(false);
1091 pgstat_count_xact_rollback();
1094 * State remains TRANS_ABORT until CleanupTransaction().
1096 RESUME_INTERRUPTS();
1100 * CleanupTransaction
1103 CleanupTransaction(void)
1105 TransactionState s = CurrentTransactionState;
1108 * State should still be TRANS_ABORT from AbortTransaction().
1110 if (s->state != TRANS_ABORT)
1111 elog(FATAL, "CleanupTransaction and not in abort state");
1114 * do abort cleanup processing
1116 AtCleanup_Portals(); /* now safe to release portal memory */
1117 AtCleanup_Memory(); /* and transaction memory */
1120 * done with abort processing, set current transaction state back to
1123 s->state = TRANS_DEFAULT;
1127 * StartTransactionCommand
1129 * preventChain, if true, forces autocommit behavior at the next
1130 * CommitTransactionCommand call.
1133 StartTransactionCommand(bool preventChain)
1135 TransactionState s = CurrentTransactionState;
1138 * Remember if caller wants to prevent autocommit-off chaining. This
1139 * is only allowed if not already in a transaction block.
1141 suppressChain = preventChain;
1142 if (preventChain && s->blockState != TBLOCK_DEFAULT)
1143 elog(ERROR, "StartTransactionCommand: can't prevent chain");
1145 switch (s->blockState)
1148 * if we aren't in a transaction block, we just do our usual
1149 * start transaction.
1151 case TBLOCK_DEFAULT:
1156 * We should never experience this -- if we do it means the
1157 * BEGIN state was not changed in the previous
1158 * CommitTransactionCommand(). If we get it, we print a
1159 * warning and change to the in-progress state.
1162 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1163 s->blockState = TBLOCK_INPROGRESS;
1167 * This is the case when are somewhere in a transaction block
1168 * and about to start a new command. For now we do nothing
1169 * but someday we may do command-local resource
1172 case TBLOCK_INPROGRESS:
1176 * As with BEGIN, we should never experience this if we do it
1177 * means the END state was not changed in the previous
1178 * CommitTransactionCommand(). If we get it, we print a
1179 * warning, commit the transaction, start a new transaction
1180 * and change to the default state.
1183 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
1184 s->blockState = TBLOCK_DEFAULT;
1185 CommitTransaction();
1190 * Here we are in the middle of a transaction block but one of
1191 * the commands caused an abort so we do nothing but remain in
1192 * the abort state. Eventually we will get to the "END
1193 * TRANSACTION" which will set things straight.
1199 * This means we somehow aborted and the last call to
1200 * CommitTransactionCommand() didn't clear the state so we
1201 * remain in the ENDABORT state and maybe next time we get to
1202 * CommitTransactionCommand() the state will get reset to
1205 case TBLOCK_ENDABORT:
1206 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1211 * We must switch to TopTransactionContext before returning. This
1212 * is already done if we called StartTransaction, otherwise not.
1214 Assert(TopTransactionContext != NULL);
1215 MemoryContextSwitchTo(TopTransactionContext);
1219 * CommitTransactionCommand
1221 * forceCommit = true forces autocommit behavior even when autocommit is off.
1224 CommitTransactionCommand(bool forceCommit)
1226 TransactionState s = CurrentTransactionState;
1228 switch (s->blockState)
1231 * If we aren't in a transaction block, and we are doing
1232 * autocommit, just do our usual transaction commit. But if
1233 * we aren't doing autocommit, start a transaction block
1234 * automatically by switching to INPROGRESS state. (We handle
1235 * this choice here, and not earlier, so that an explicit
1236 * BEGIN issued in autocommit-off mode won't issue strange
1239 * Autocommit mode is forced by either a true forceCommit
1240 * parameter to me, or a true preventChain parameter to the
1241 * preceding StartTransactionCommand call, or a
1242 * PreventTransactionChain call during the transaction.
1243 * (The parameters could be omitted, but it turns out most
1244 * callers of StartTransactionCommand/CommitTransactionCommand
1245 * want to force autocommit, so making them all call
1246 * PreventTransactionChain would just be extra notation.)
1248 case TBLOCK_DEFAULT:
1249 if (autocommit || forceCommit || suppressChain)
1250 CommitTransaction();
1253 BeginTransactionBlock();
1254 Assert(s->blockState == TBLOCK_INPROGRESS);
1255 /* This code must match the TBLOCK_INPROGRESS case below: */
1256 CommandCounterIncrement();
1261 * This is the case right after we get a "BEGIN TRANSACTION"
1262 * command, but the user hasn't done anything else yet, so we
1263 * change to the "transaction block in progress" state and
1267 s->blockState = TBLOCK_INPROGRESS;
1271 * This is the case when we have finished executing a command
1272 * someplace within a transaction block. We increment the
1273 * command counter and return.
1275 case TBLOCK_INPROGRESS:
1276 CommandCounterIncrement();
1280 * This is the case when we just got the "END TRANSACTION"
1281 * statement, so we commit the transaction and go back to the
1285 CommitTransaction();
1286 s->blockState = TBLOCK_DEFAULT;
1290 * Here we are in the middle of a transaction block but one of
1291 * the commands caused an abort so we do nothing but remain in
1292 * the abort state. Eventually we will get to the "END
1293 * TRANSACTION" which will set things straight.
1299 * Here we were in an aborted transaction block which just
1300 * processed the "END TRANSACTION" command from the user, so
1301 * clean up and return to the default state.
1303 case TBLOCK_ENDABORT:
1304 CleanupTransaction();
1305 s->blockState = TBLOCK_DEFAULT;
1311 * AbortCurrentTransaction
1314 AbortCurrentTransaction(void)
1316 TransactionState s = CurrentTransactionState;
1318 switch (s->blockState)
1321 * if we aren't in a transaction block, we just do the basic
1322 * abort & cleanup transaction.
1324 case TBLOCK_DEFAULT:
1326 if (autocommit || suppressChain)
1327 CleanupTransaction();
1329 s->blockState = TBLOCK_ABORT;
1333 * If we are in the TBLOCK_BEGIN it means something screwed up
1334 * right after reading "BEGIN TRANSACTION" so we enter the
1335 * abort state. Eventually an "END TRANSACTION" will fix
1339 s->blockState = TBLOCK_ABORT;
1341 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1345 * This is the case when are somewhere in a transaction block
1346 * which aborted so we abort the transaction and set the ABORT
1347 * state. Eventually an "END TRANSACTION" will fix things and
1348 * restore us to a normal state.
1350 case TBLOCK_INPROGRESS:
1351 s->blockState = TBLOCK_ABORT;
1353 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1357 * Here, the system was fouled up just after the user wanted
1358 * to end the transaction block so we abort the transaction
1359 * and put us back into the default state.
1362 s->blockState = TBLOCK_DEFAULT;
1364 CleanupTransaction();
1368 * Here, we are already in an aborted transaction state and
1369 * are waiting for an "END TRANSACTION" to come along and lo
1370 * and behold, we abort again! So we just remain in the abort
1377 * Here we were in an aborted transaction block which just
1378 * processed the "END TRANSACTION" command but somehow aborted
1379 * again.. since we must have done the abort processing, we
1380 * clean up and return to the default state.
1382 case TBLOCK_ENDABORT:
1383 CleanupTransaction();
1384 s->blockState = TBLOCK_DEFAULT;
1390 * PreventTransactionChain
1392 * This routine is to be called by statements that must not run inside
1393 * a transaction block, typically because they have non-rollback-able
1394 * side effects or do internal commits.
1396 * If we have already started a transaction block, issue an error; also issue
1397 * an error if we appear to be running inside a user-defined function (which
1398 * could issue more commands and possibly cause a failure after the statement
1399 * completes). In autocommit-off mode, we allow the statement if a block is
1400 * not already started, and force the statement to be autocommitted despite
1403 * stmtNode: pointer to parameter block for statement; this is used in
1404 * a very klugy way to determine whether we are inside a function.
1405 * stmtType: statement type name for error messages.
1408 PreventTransactionChain(void *stmtNode, const char *stmtType)
1411 * xact block already started?
1413 if (IsTransactionBlock())
1415 /* translator: %s represents an SQL statement name */
1416 elog(ERROR, "%s cannot run inside a transaction block", stmtType);
1419 * Are we inside a function call? If the statement's parameter block
1420 * was allocated in QueryContext, assume it is an interactive command.
1421 * Otherwise assume it is coming from a function.
1423 if (!MemoryContextContains(QueryContext, stmtNode))
1425 /* translator: %s represents an SQL statement name */
1426 elog(ERROR, "%s cannot be executed from a function", stmtType);
1428 /* If we got past IsTransactionBlock test, should be in default state */
1429 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
1430 elog(ERROR, "PreventTransactionChain: can't prevent chain");
1431 /* okay to set the flag */
1432 suppressChain = true;
1433 /* If we're in autocommit-off node, generate a notice */
1436 /* translator: %s represents an SQL statement name */
1437 elog(NOTICE, "%s will be committed automatically", stmtType);
1442 * RequireTransactionChain
1444 * This routine is to be called by statements that must run inside
1445 * a transaction block, because they have no effects that persist past
1446 * transaction end (and so calling them outside a transaction block
1447 * is presumably an error). DECLARE CURSOR is an example.
1449 * If we appear to be running inside a user-defined function, we do not
1450 * issue an error, since the function could issue more commands that make
1451 * use of the current statement's results. Thus this is an inverse for
1452 * PreventTransactionChain.
1454 * stmtNode: pointer to parameter block for statement; this is used in
1455 * a very klugy way to determine whether we are inside a function.
1456 * stmtType: statement type name for error messages.
1459 RequireTransactionChain(void *stmtNode, const char *stmtType)
1462 * xact block already started?
1464 if (IsTransactionBlock())
1467 * Are we inside a function call? If the statement's parameter block
1468 * was allocated in QueryContext, assume it is an interactive command.
1469 * Otherwise assume it is coming from a function.
1471 if (!MemoryContextContains(QueryContext, stmtNode))
1474 * If we are in autocommit-off mode then it's okay, because this
1475 * statement will itself start a transaction block.
1477 if (!autocommit && !suppressChain)
1479 /* translator: %s represents an SQL statement name */
1480 elog(ERROR, "%s may only be used in begin/end transaction blocks",
1485 /* ----------------------------------------------------------------
1486 * transaction block support
1487 * ----------------------------------------------------------------
1490 * BeginTransactionBlock
1493 BeginTransactionBlock(void)
1495 TransactionState s = CurrentTransactionState;
1498 * check the current transaction state
1500 if (s->blockState != TBLOCK_DEFAULT)
1501 elog(WARNING, "BEGIN: already a transaction in progress");
1504 * set the current transaction block state information appropriately
1505 * during begin processing
1507 s->blockState = TBLOCK_BEGIN;
1510 * do begin processing. NOTE: if you put anything here, check that it
1511 * behaves properly in both autocommit-on and autocommit-off modes. In
1512 * the latter case we will already have done some work in the new
1517 * done with begin processing, set block state to inprogress
1519 s->blockState = TBLOCK_INPROGRESS;
1523 * EndTransactionBlock
1526 EndTransactionBlock(void)
1528 TransactionState s = CurrentTransactionState;
1531 * check the current transaction state
1533 if (s->blockState == TBLOCK_INPROGRESS)
1536 * here we are in a transaction block which should commit when we
1537 * get to the upcoming CommitTransactionCommand() so we set the
1538 * state to "END". CommitTransactionCommand() will recognize this
1539 * and commit the transaction and return us to the default state
1541 s->blockState = TBLOCK_END;
1545 if (s->blockState == TBLOCK_ABORT)
1548 * here, we are in a transaction block which aborted and since the
1549 * AbortTransaction() was already done, we do whatever is needed
1550 * and change to the special "END ABORT" state. The upcoming
1551 * CommitTransactionCommand() will recognise this and then put us
1552 * back in the default state.
1554 s->blockState = TBLOCK_ENDABORT;
1559 * here, the user issued COMMIT when not inside a transaction. Issue a
1560 * WARNING and go to abort state. The upcoming call to
1561 * CommitTransactionCommand() will then put us back into the default
1564 elog(WARNING, "COMMIT: no transaction in progress");
1566 s->blockState = TBLOCK_ENDABORT;
1570 * AbortTransactionBlock
1574 AbortTransactionBlock(void)
1576 TransactionState s = CurrentTransactionState;
1579 * check the current transaction state
1581 if (s->blockState == TBLOCK_INPROGRESS)
1584 * here we were inside a transaction block something screwed up
1585 * inside the system so we enter the abort state, do the abort
1586 * processing and then return. We remain in the abort state until
1587 * we see an END TRANSACTION command.
1589 s->blockState = TBLOCK_ABORT;
1595 * here, the user issued ABORT when not inside a transaction. Issue a
1596 * WARNING and go to abort state. The upcoming call to
1597 * CommitTransactionCommand() will then put us back into the default
1600 elog(WARNING, "ROLLBACK: no transaction in progress");
1602 s->blockState = TBLOCK_ENDABORT;
1607 * UserAbortTransactionBlock
1610 UserAbortTransactionBlock(void)
1612 TransactionState s = CurrentTransactionState;
1615 * if the transaction has already been automatically aborted with an
1616 * error, and the user subsequently types 'abort', allow it. (the
1617 * behavior is the same as if they had typed 'end'.)
1619 if (s->blockState == TBLOCK_ABORT)
1621 s->blockState = TBLOCK_ENDABORT;
1625 if (s->blockState == TBLOCK_INPROGRESS)
1628 * here we were inside a transaction block and we got an abort
1629 * command from the user, so we move to the abort state, do the
1630 * abort processing and then change to the ENDABORT state so we
1631 * will end up in the default state after the upcoming
1632 * CommitTransactionCommand().
1634 s->blockState = TBLOCK_ABORT;
1636 s->blockState = TBLOCK_ENDABORT;
1641 * here, the user issued ABORT when not inside a transaction. Issue a
1642 * WARNING and go to abort state. The upcoming call to
1643 * CommitTransactionCommand() will then put us back into the default
1646 elog(WARNING, "ROLLBACK: no transaction in progress");
1648 s->blockState = TBLOCK_ENDABORT;
1652 * AbortOutOfAnyTransaction
1654 * This routine is provided for error recovery purposes. It aborts any
1655 * active transaction or transaction block, leaving the system in a known
1659 AbortOutOfAnyTransaction(void)
1661 TransactionState s = CurrentTransactionState;
1664 * Get out of any low-level transaction
1669 case TRANS_INPROGRESS:
1671 /* In a transaction, so clean up */
1673 CleanupTransaction();
1676 /* AbortTransaction already done, still need Cleanup */
1677 CleanupTransaction();
1680 /* Not in a transaction, do nothing */
1685 * Now reset the high-level state
1687 s->blockState = TBLOCK_DEFAULT;
1691 * IsTransactionBlock --- are we within a transaction block?
1694 IsTransactionBlock(void)
1696 TransactionState s = CurrentTransactionState;
1698 if (s->blockState == TBLOCK_DEFAULT)
1705 * TransactionBlockStatusCode - return status code to send in ReadyForQuery
1708 TransactionBlockStatusCode(void)
1710 TransactionState s = CurrentTransactionState;
1712 switch (s->blockState)
1714 case TBLOCK_DEFAULT:
1715 return 'I'; /* idle --- not in transaction */
1717 case TBLOCK_INPROGRESS:
1719 return 'T'; /* in transaction */
1721 case TBLOCK_ENDABORT:
1722 return 'E'; /* in failed transaction */
1725 /* should never get here */
1726 elog(ERROR, "bogus transaction block state");
1727 return 0; /* keep compiler quiet */
1732 * XLOG support routines
1736 xact_redo(XLogRecPtr lsn, XLogRecord *record)
1738 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1740 if (info == XLOG_XACT_COMMIT)
1742 TransactionIdCommit(record->xl_xid);
1743 /* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
1745 else if (info == XLOG_XACT_ABORT)
1747 TransactionIdAbort(record->xl_xid);
1748 /* SHOULD REMOVE FILES OF ALL FAILED-TO-BE-CREATED RELATIONS */
1751 elog(PANIC, "xact_redo: unknown op code %u", info);
1755 xact_undo(XLogRecPtr lsn, XLogRecord *record)
1757 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1759 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
1760 elog(PANIC, "xact_undo: can't undo committed xaction");
1761 else if (info != XLOG_XACT_ABORT)
1762 elog(PANIC, "xact_redo: unknown op code %u", info);
1766 xact_desc(char *buf, uint8 xl_info, char *rec)
1768 uint8 info = xl_info & ~XLR_INFO_MASK;
1770 if (info == XLOG_XACT_COMMIT)
1772 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
1773 struct tm *tm = localtime(&xlrec->xtime);
1775 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
1776 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1777 tm->tm_hour, tm->tm_min, tm->tm_sec);
1779 else if (info == XLOG_XACT_ABORT)
1781 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
1782 struct tm *tm = localtime(&xlrec->xtime);
1784 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
1785 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1786 tm->tm_hour, tm->tm_min, tm->tm_sec);
1789 strcat(buf, "UNKNOWN");
1793 XactPushRollback(void (*func) (void *), void *data)
1796 if (_RollbackFunc != NULL)
1797 elog(PANIC, "XactPushRollback: already installed");
1800 _RollbackFunc = func;
1801 _RollbackData = data;
1805 XactPopRollback(void)
1807 _RollbackFunc = NULL;