1 /*-------------------------------------------------------------------------
4 * top level transaction system support routines
6 * Portions Copyright (c) 1996-2003, 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.152 2003/08/08 21:41:28 momjian 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 the client
204 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
207 * User-tweakable parameters
209 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
212 bool DefaultXactReadOnly = false;
215 int CommitDelay = 0; /* precommit delay in microseconds */
216 int CommitSiblings = 5; /* number of concurrent xacts needed to
220 static void (*_RollbackFunc) (void *) = NULL;
221 static void *_RollbackData = NULL;
224 /* ----------------------------------------------------------------
225 * transaction state accessors
226 * ----------------------------------------------------------------
231 /* --------------------------------
232 * TransactionFlushEnabled()
233 * SetTransactionFlushEnabled()
235 * These are used to test and set the "TransactionFlushState"
236 * variable. If this variable is true (the default), then
237 * the system will flush all dirty buffers to disk at the end
238 * of each transaction. If false then we are assuming the
239 * buffer pool resides in stable main memory, in which case we
240 * only do writes as necessary.
241 * --------------------------------
243 static int TransactionFlushState = 1;
246 TransactionFlushEnabled(void)
248 return TransactionFlushState;
252 SetTransactionFlushEnabled(bool state)
254 TransactionFlushState = (state == true);
262 * This returns true if we are currently running a query
263 * within an executing transaction.
266 IsTransactionState(void)
268 TransactionState s = CurrentTransactionState;
276 case TRANS_INPROGRESS:
285 * Shouldn't get here, but lint is not happy with this...
291 * IsAbortedTransactionBlockState
293 * This returns true if we are currently running a query
294 * within an aborted transaction block.
297 IsAbortedTransactionBlockState(void)
299 TransactionState s = CurrentTransactionState;
301 if (s->blockState == TBLOCK_ABORT)
309 * GetCurrentTransactionId
312 GetCurrentTransactionId(void)
314 TransactionState s = CurrentTransactionState;
316 return s->transactionIdData;
321 * GetCurrentCommandId
324 GetCurrentCommandId(void)
326 TransactionState s = CurrentTransactionState;
333 * GetCurrentTransactionStartTime
336 GetCurrentTransactionStartTime(void)
338 TransactionState s = CurrentTransactionState;
345 * GetCurrentTransactionStartTimeUsec
348 GetCurrentTransactionStartTimeUsec(int *msec)
350 TransactionState s = CurrentTransactionState;
352 *msec = s->startTimeUsec;
359 * TransactionIdIsCurrentTransactionId
361 * During bootstrap, we cheat and say "it's not my transaction ID" even though
362 * it is. Along with transam.c's cheat to say that the bootstrap XID is
363 * already committed, this causes the tqual.c routines to see previously
364 * inserted tuples as committed, which is what we need during bootstrap.
367 TransactionIdIsCurrentTransactionId(TransactionId xid)
369 TransactionState s = CurrentTransactionState;
373 Assert(xid == BootstrapTransactionId);
377 return TransactionIdEquals(xid, s->transactionIdData);
382 * CommandIdIsCurrentCommandId
385 CommandIdIsCurrentCommandId(CommandId cid)
387 TransactionState s = CurrentTransactionState;
389 return (cid == s->commandId) ? true : false;
394 * CommandCounterIncrement
397 CommandCounterIncrement(void)
399 TransactionState s = CurrentTransactionState;
402 if (s->commandId == FirstCommandId) /* check for overflow */
404 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
405 errmsg("cannot have more than 2^32-1 commands in a transaction")));
407 /* Propagate new command ID into query snapshots, if set */
409 QuerySnapshot->curcid = s->commandId;
410 if (SerializableSnapshot)
411 SerializableSnapshot->curcid = s->commandId;
414 * make cache changes visible to me. AtCommit_LocalCache() instead of
415 * AtCommit_Cache() is called here.
417 AtCommit_LocalCache();
422 /* ----------------------------------------------------------------
423 * StartTransaction stuff
424 * ----------------------------------------------------------------
433 AcceptInvalidationMessages();
443 * at present, it is unknown to me what belongs here -cim 3/18/90
445 * There isn't anything to do at the start of a xact for locks. -mer
457 * We shouldn't have a transaction context already.
459 Assert(TopTransactionContext == NULL);
462 * Create a toplevel context for the transaction, and make it active.
464 TopTransactionContext =
465 AllocSetContextCreate(TopMemoryContext,
466 "TopTransactionContext",
467 ALLOCSET_DEFAULT_MINSIZE,
468 ALLOCSET_DEFAULT_INITSIZE,
469 ALLOCSET_DEFAULT_MAXSIZE);
471 MemoryContextSwitchTo(TopTransactionContext);
475 /* ----------------------------------------------------------------
476 * CommitTransaction stuff
477 * ----------------------------------------------------------------
481 * RecordTransactionCommit
484 RecordTransactionCommit(void)
487 * If we made neither any XLOG entries nor any temp-rel updates, we
488 * can omit recording the transaction commit at all.
490 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate)
492 TransactionId xid = GetCurrentTransactionId();
495 /* Tell bufmgr and smgr to prepare for commit */
498 START_CRIT_SECTION();
501 * We only need to log the commit in xlog if the transaction made
502 * any transaction-controlled XLOG entries. (Otherwise, its XID
503 * appears nowhere in permanent storage, so no one else will ever
504 * care if it committed.)
506 if (MyLastRecPtr.xrecoff != 0)
508 /* Need to emit a commit record */
510 xl_xact_commit xlrec;
512 xlrec.xtime = time(NULL);
513 rdata.buffer = InvalidBuffer;
514 rdata.data = (char *) (&xlrec);
515 rdata.len = SizeOfXactCommit;
519 * XXX SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
521 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, &rdata);
525 /* Just flush through last record written by me */
526 recptr = ProcLastRecEnd;
530 * We must flush our XLOG entries to disk if we made any XLOG
531 * entries, whether in or out of transaction control. For
532 * example, if we reported a nextval() result to the client, this
533 * ensures that any XLOG record generated by nextval will hit the
534 * disk before we report the transaction committed.
536 if (MyXactMadeXLogEntry)
539 * Sleep before flush! So we can flush more than one commit
540 * records per single fsync. (The idea is some other backend
541 * may do the XLogFlush while we're sleeping. This needs work
542 * still, because on most Unixen, the minimum select() delay
543 * is 10msec or more, which is way too long.)
545 * We do not sleep if enableFsync is not turned on, nor if there
546 * are fewer than CommitSiblings other backends with active
549 if (CommitDelay > 0 && enableFsync &&
550 CountActiveBackends() >= CommitSiblings)
552 struct timeval delay;
555 delay.tv_usec = CommitDelay;
556 (void) select(0, NULL, NULL, NULL, &delay);
563 * We must mark the transaction committed in clog if its XID
564 * appears either in permanent rels or in local temporary rels. We
565 * test this by seeing if we made transaction-controlled entries
566 * *OR* local-rel tuple updates. Note that if we made only the
567 * latter, we have not emitted an XLOG record for our commit, and
568 * so in the event of a crash the clog update might be lost. This
569 * is okay because no one else will ever care whether we
572 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
573 TransactionIdCommit(xid);
578 /* Break the chain of back-links in the XLOG records I output */
579 MyLastRecPtr.xrecoff = 0;
580 MyXactMadeXLogEntry = false;
581 MyXactMadeTempRelUpdate = false;
583 /* Show myself as out of the transaction in PGPROC array */
584 MyProc->logRec.xrecoff = 0;
595 * Clean up the relation cache.
597 AtEOXact_RelationCache(true);
600 * Make catalog changes visible to all backends.
602 AtEOXactInvalidationMessages(true);
606 * AtCommit_LocalCache
609 AtCommit_LocalCache(void)
612 * Make catalog changes visible to me for the next command.
614 CommandEndInvalidationMessages(true);
624 * XXX What if ProcReleaseLocks fails? (race condition?)
626 * Then you're up a creek! -mer 5/24/92
628 ProcReleaseLocks(true);
635 AtCommit_Memory(void)
638 * Now that we're "out" of a transaction, have the system allocate
639 * things in the top memory context instead of per-transaction
642 MemoryContextSwitchTo(TopMemoryContext);
645 * Release all transaction-local memory.
647 Assert(TopTransactionContext != NULL);
648 MemoryContextDelete(TopTransactionContext);
649 TopTransactionContext = NULL;
652 /* ----------------------------------------------------------------
653 * AbortTransaction stuff
654 * ----------------------------------------------------------------
658 * RecordTransactionAbort
661 RecordTransactionAbort(void)
664 * If we made neither any transaction-controlled XLOG entries nor any
665 * temp-rel updates, we can omit recording the transaction abort at
666 * all. No one will ever care that it aborted.
668 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
670 TransactionId xid = GetCurrentTransactionId();
673 * Catch the scenario where we aborted partway through
674 * RecordTransactionCommit ...
676 if (TransactionIdDidCommit(xid))
677 elog(PANIC, "cannot abort transaction %u, it was already committed", xid);
679 START_CRIT_SECTION();
682 * We only need to log the abort in XLOG if the transaction made
683 * any transaction-controlled XLOG entries. (Otherwise, its XID
684 * appears nowhere in permanent storage, so no one else will ever
685 * care if it committed.) We do not flush XLOG to disk in any
686 * case, since the default assumption after a crash would be that
687 * we aborted, anyway.
689 if (MyLastRecPtr.xrecoff != 0)
695 xlrec.xtime = time(NULL);
696 rdata.buffer = InvalidBuffer;
697 rdata.data = (char *) (&xlrec);
698 rdata.len = SizeOfXactAbort;
702 * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
704 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
708 * Mark the transaction aborted in clog. This is not absolutely
709 * necessary but we may as well do it while we are here.
711 TransactionIdAbort(xid);
716 /* Break the chain of back-links in the XLOG records I output */
717 MyLastRecPtr.xrecoff = 0;
718 MyXactMadeXLogEntry = false;
719 MyXactMadeTempRelUpdate = false;
721 /* Show myself as out of the transaction in PGPROC array */
722 MyProc->logRec.xrecoff = 0;
731 AtEOXact_RelationCache(false);
732 AtEOXactInvalidationMessages(false);
742 * XXX What if ProcReleaseLocks() fails? (race condition?)
744 * Then you're up a creek without a paddle! -mer
746 ProcReleaseLocks(false);
757 * Make sure we are in a valid context (not a child of
758 * TopTransactionContext...). Note that it is possible for this code
759 * to be called when we aren't in a transaction at all; go directly to
760 * TopMemoryContext in that case.
762 if (TopTransactionContext != NULL)
764 MemoryContextSwitchTo(TopTransactionContext);
767 * We do not want to destroy the transaction's global state yet,
768 * so we can't free any memory here.
772 MemoryContextSwitchTo(TopMemoryContext);
776 /* ----------------------------------------------------------------
777 * CleanupTransaction stuff
778 * ----------------------------------------------------------------
785 AtCleanup_Memory(void)
788 * Now that we're "out" of a transaction, have the system allocate
789 * things in the top memory context instead of per-transaction
792 MemoryContextSwitchTo(TopMemoryContext);
795 * Release all transaction-local memory.
797 if (TopTransactionContext != NULL)
798 MemoryContextDelete(TopTransactionContext);
799 TopTransactionContext = NULL;
803 /* ----------------------------------------------------------------
805 * ----------------------------------------------------------------
812 StartTransaction(void)
814 TransactionState s = CurrentTransactionState;
817 XactIsoLevel = DefaultXactIsoLevel;
818 XactReadOnly = DefaultXactReadOnly;
821 * Check the current transaction state. If the transaction system is
822 * switched off, or if we're already in a transaction, do nothing.
823 * We're already in a transaction when the monitor sends a null
824 * command to the backend to flush the comm channel. This is a hacky
825 * fix to a communications problem, and we keep having to deal with it
826 * here. We should fix the comm channel code. mao 080891
828 if (s->state == TRANS_INPROGRESS)
832 * set the current transaction state information appropriately during
835 s->state = TRANS_START;
837 SetReindexProcessing(false);
840 * generate a new transaction id
842 s->transactionIdData = GetNewTransactionId();
844 XactLockTableInsert(s->transactionIdData);
847 * initialize current transaction state fields
849 s->commandId = FirstCommandId;
850 s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
853 * initialize the various transaction subsystems
860 * Tell the trigger manager to we're starting a transaction
862 DeferredTriggerBeginXact();
865 * done with start processing, set current transaction state to "in
868 s->state = TRANS_INPROGRESS;
876 CommitTransaction(void)
878 TransactionState s = CurrentTransactionState;
881 * check the current transaction state
883 if (s->state != TRANS_INPROGRESS)
884 elog(WARNING, "CommitTransaction and not in in-progress state");
887 * Tell the trigger manager that this transaction is about to be
888 * committed. He'll invoke all trigger deferred until XACT before we
889 * really start on committing the transaction.
891 DeferredTriggerEndXact();
894 * Similarly, let ON COMMIT management do its thing before we start to
897 PreCommit_on_commit_actions();
899 /* Prevent cancel/die interrupt while cleaning up */
903 * set the current transaction state information appropriately during
904 * the abort processing
906 s->state = TRANS_COMMIT;
909 * Do pre-commit processing (most of this stuff requires database
910 * access, and in fact could still cause an error...)
915 /* handle commit for large objects [ PA, 7/17/98 ] */
916 /* XXX probably this does not belong here */
919 /* NOTIFY commit must come before lower-level cleanup */
922 /* Update the flat password file if we changed pg_shadow or pg_group */
923 AtEOXact_UpdatePasswordFile(true);
926 * Here is where we really truly commit.
928 RecordTransactionCommit();
931 * Let others know about no transaction in progress by me. Note that
932 * this must be done _before_ releasing locks we hold and _after_
933 * RecordTransactionCommit.
935 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
936 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
937 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
938 * as running as well or it will see two tuple versions - one deleted
939 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
941 if (MyProc != (PGPROC *) NULL)
943 /* Lock SInvalLock because that's what GetSnapshotData uses. */
944 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
945 MyProc->xid = InvalidTransactionId;
946 MyProc->xmin = InvalidTransactionId;
947 LWLockRelease(SInvalLock);
951 * This is all post-commit cleanup. Note that if an error is raised
952 * here, it's too late to abort the transaction. This should be just
953 * noncritical resource releasing.
955 * The ordering of operations is not entirely random. The idea is:
956 * release resources visible to other backends (eg, files, buffer
957 * pins); then release locks; then release backend-local resources. We
958 * want to release locks at the point where any backend waiting for us
959 * will see our transaction as being fully cleaned up.
962 smgrDoPendingDeletes(true);
964 AtEOXact_Buffers(true);
965 /* smgrcommit already done */
975 AtEOXact_on_commit_actions(true);
976 AtEOXact_Namespace(true);
977 AtEOXact_CatCache(true);
979 pgstat_count_xact_commit();
983 * done with commit processing, set current transaction state back to
986 s->state = TRANS_DEFAULT;
995 AbortTransaction(void)
997 TransactionState s = CurrentTransactionState;
999 /* Prevent cancel/die interrupt while cleaning up */
1003 * Release any LW locks we might be holding as quickly as possible.
1004 * (Regular locks, however, must be held till we finish aborting.)
1005 * Releasing LW locks is critical since we might try to grab them
1006 * again while cleaning up!
1010 /* Clean up buffer I/O and buffer context locks, too */
1015 * Also clean up any open wait for lock, since the lock manager will
1016 * choke if we try to wait for another lock before doing this.
1021 * check the current transaction state
1023 if (s->state != TRANS_INPROGRESS)
1024 elog(WARNING, "AbortTransaction and not in in-progress state");
1027 * set the current transaction state information appropriately during
1028 * the abort processing
1030 s->state = TRANS_ABORT;
1032 /* Make sure we are in a valid memory context */
1036 * Reset user id which might have been changed transiently
1038 SetUserId(GetSessionUserId());
1041 * do abort processing
1043 DeferredTriggerAbortXact();
1045 lo_commit(false); /* 'false' means it's abort */
1047 AtEOXact_UpdatePasswordFile(false);
1049 /* Advertise the fact that we aborted in pg_clog. */
1050 RecordTransactionAbort();
1053 * Let others know about no transaction in progress by me. Note that
1054 * this must be done _before_ releasing locks we hold and _after_
1055 * RecordTransactionAbort.
1057 if (MyProc != (PGPROC *) NULL)
1059 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1060 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1061 MyProc->xid = InvalidTransactionId;
1062 MyProc->xmin = InvalidTransactionId;
1063 LWLockRelease(SInvalLock);
1067 * Post-abort cleanup. See notes in CommitTransaction() concerning
1071 smgrDoPendingDeletes(false);
1073 AtEOXact_Buffers(false);
1078 AtEOXact_GUC(false);
1084 AtEOXact_on_commit_actions(false);
1085 AtEOXact_Namespace(false);
1086 AtEOXact_CatCache(false);
1088 pgstat_count_xact_rollback();
1091 * State remains TRANS_ABORT until CleanupTransaction().
1093 RESUME_INTERRUPTS();
1097 * CleanupTransaction
1100 CleanupTransaction(void)
1102 TransactionState s = CurrentTransactionState;
1105 * State should still be TRANS_ABORT from AbortTransaction().
1107 if (s->state != TRANS_ABORT)
1108 elog(FATAL, "CleanupTransaction and not in abort state");
1111 * do abort cleanup processing
1113 AtCleanup_Portals(); /* now safe to release portal memory */
1114 AtCleanup_Memory(); /* and transaction memory */
1117 * done with abort processing, set current transaction state back to
1120 s->state = TRANS_DEFAULT;
1124 * StartTransactionCommand
1127 StartTransactionCommand(void)
1129 TransactionState s = CurrentTransactionState;
1131 switch (s->blockState)
1134 * if we aren't in a transaction block, we just do our usual
1135 * start transaction.
1137 case TBLOCK_DEFAULT:
1142 * We should never experience this -- if we do it means the
1143 * BEGIN state was not changed in the previous
1144 * CommitTransactionCommand(). If we get it, we print a
1145 * warning and change to the in-progress state.
1148 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1149 s->blockState = TBLOCK_INPROGRESS;
1153 * This is the case when are somewhere in a transaction block
1154 * and about to start a new command. For now we do nothing
1155 * but someday we may do command-local resource
1158 case TBLOCK_INPROGRESS:
1162 * As with BEGIN, we should never experience this if we do it
1163 * means the END state was not changed in the previous
1164 * CommitTransactionCommand(). If we get it, we print a
1165 * warning, commit the transaction, start a new transaction
1166 * and change to the default state.
1169 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
1170 s->blockState = TBLOCK_DEFAULT;
1171 CommitTransaction();
1176 * Here we are in the middle of a transaction block but one of
1177 * the commands caused an abort so we do nothing but remain in
1178 * the abort state. Eventually we will get to the "END
1179 * TRANSACTION" which will set things straight.
1185 * This means we somehow aborted and the last call to
1186 * CommitTransactionCommand() didn't clear the state so we
1187 * remain in the ENDABORT state and maybe next time we get to
1188 * CommitTransactionCommand() the state will get reset to
1191 case TBLOCK_ENDABORT:
1192 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1197 * We must switch to TopTransactionContext before returning. This is
1198 * already done if we called StartTransaction, otherwise not.
1200 Assert(TopTransactionContext != NULL);
1201 MemoryContextSwitchTo(TopTransactionContext);
1205 * CommitTransactionCommand
1208 CommitTransactionCommand(void)
1210 TransactionState s = CurrentTransactionState;
1212 switch (s->blockState)
1215 * If we aren't in a transaction block, just do our usual
1216 * transaction commit.
1218 case TBLOCK_DEFAULT:
1219 CommitTransaction();
1223 * This is the case right after we get a "BEGIN TRANSACTION"
1224 * command, but the user hasn't done anything else yet, so we
1225 * change to the "transaction block in progress" state and
1229 s->blockState = TBLOCK_INPROGRESS;
1233 * This is the case when we have finished executing a command
1234 * someplace within a transaction block. We increment the
1235 * command counter and return.
1237 case TBLOCK_INPROGRESS:
1238 CommandCounterIncrement();
1242 * This is the case when we just got the "END TRANSACTION"
1243 * statement, so we commit the transaction and go back to the
1247 CommitTransaction();
1248 s->blockState = TBLOCK_DEFAULT;
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 * Here we were in an aborted transaction block which just
1262 * processed the "END TRANSACTION" command from the user, so
1263 * clean up and return to the default state.
1265 case TBLOCK_ENDABORT:
1266 CleanupTransaction();
1267 s->blockState = TBLOCK_DEFAULT;
1273 * AbortCurrentTransaction
1276 AbortCurrentTransaction(void)
1278 TransactionState s = CurrentTransactionState;
1280 switch (s->blockState)
1283 * if we aren't in a transaction block, we just do the basic
1284 * abort & cleanup transaction.
1286 case TBLOCK_DEFAULT:
1288 CleanupTransaction();
1292 * If we are in the TBLOCK_BEGIN it means something screwed up
1293 * right after reading "BEGIN TRANSACTION" so we enter the
1294 * abort state. Eventually an "END TRANSACTION" will fix
1298 s->blockState = TBLOCK_ABORT;
1300 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1304 * This is the case when are somewhere in a transaction block
1305 * which aborted so we abort the transaction and set the ABORT
1306 * state. Eventually an "END TRANSACTION" will fix things and
1307 * restore us to a normal state.
1309 case TBLOCK_INPROGRESS:
1310 s->blockState = TBLOCK_ABORT;
1312 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1316 * Here, the system was fouled up just after the user wanted
1317 * to end the transaction block so we abort the transaction
1318 * and put us back into the default state.
1321 s->blockState = TBLOCK_DEFAULT;
1323 CleanupTransaction();
1327 * Here, we are already in an aborted transaction state and
1328 * are waiting for an "END TRANSACTION" to come along and lo
1329 * and behold, we abort again! So we just remain in the abort
1336 * Here we were in an aborted transaction block which just
1337 * processed the "END TRANSACTION" command but somehow aborted
1338 * again.. since we must have done the abort processing, we
1339 * clean up and return to the default state.
1341 case TBLOCK_ENDABORT:
1342 CleanupTransaction();
1343 s->blockState = TBLOCK_DEFAULT;
1349 * PreventTransactionChain
1351 * This routine is to be called by statements that must not run inside
1352 * a transaction block, typically because they have non-rollback-able
1353 * side effects or do internal commits.
1355 * If we have already started a transaction block, issue an error; also issue
1356 * an error if we appear to be running inside a user-defined function (which
1357 * could issue more commands and possibly cause a failure after the statement
1360 * stmtNode: pointer to parameter block for statement; this is used in
1361 * a very klugy way to determine whether we are inside a function.
1362 * stmtType: statement type name for error messages.
1365 PreventTransactionChain(void *stmtNode, const char *stmtType)
1368 * xact block already started?
1370 if (IsTransactionBlock())
1372 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1373 /* translator: %s represents an SQL statement name */
1374 errmsg("%s cannot run inside a transaction block",
1378 * Are we inside a function call? If the statement's parameter block
1379 * was allocated in QueryContext, assume it is an interactive command.
1380 * Otherwise assume it is coming from a function.
1382 if (!MemoryContextContains(QueryContext, stmtNode))
1384 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1385 /* translator: %s represents an SQL statement name */
1386 errmsg("%s cannot be executed from a function", stmtType)));
1387 /* If we got past IsTransactionBlock test, should be in default state */
1388 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
1389 elog(ERROR, "cannot prevent transaction chain");
1394 * RequireTransactionChain
1396 * This routine is to be called by statements that must run inside
1397 * a transaction block, because they have no effects that persist past
1398 * transaction end (and so calling them outside a transaction block
1399 * is presumably an error). DECLARE CURSOR is an example.
1401 * If we appear to be running inside a user-defined function, we do not
1402 * issue an error, since the function could issue more commands that make
1403 * use of the current statement's results. Thus this is an inverse for
1404 * PreventTransactionChain.
1406 * stmtNode: pointer to parameter block for statement; this is used in
1407 * a very klugy way to determine whether we are inside a function.
1408 * stmtType: statement type name for error messages.
1411 RequireTransactionChain(void *stmtNode, const char *stmtType)
1414 * xact block already started?
1416 if (IsTransactionBlock())
1420 * Are we inside a function call? If the statement's parameter block
1421 * was allocated in QueryContext, assume it is an interactive command.
1422 * Otherwise assume it is coming from a function.
1424 if (!MemoryContextContains(QueryContext, stmtNode))
1427 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1428 /* translator: %s represents an SQL statement name */
1429 errmsg("%s may only be used in BEGIN/END transaction blocks",
1434 /* ----------------------------------------------------------------
1435 * transaction block support
1436 * ----------------------------------------------------------------
1439 * BeginTransactionBlock
1442 BeginTransactionBlock(void)
1444 TransactionState s = CurrentTransactionState;
1447 * check the current transaction state
1449 if (s->blockState != TBLOCK_DEFAULT)
1451 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1452 errmsg("there is already a transaction in progress")));
1455 * set the current transaction block state information appropriately
1456 * during begin processing
1458 s->blockState = TBLOCK_BEGIN;
1461 * do begin processing here. Nothing to do at present.
1465 * done with begin processing, set block state to inprogress
1467 s->blockState = TBLOCK_INPROGRESS;
1471 * EndTransactionBlock
1474 EndTransactionBlock(void)
1476 TransactionState s = CurrentTransactionState;
1479 * check the current transaction state
1481 if (s->blockState == TBLOCK_INPROGRESS)
1484 * here we are in a transaction block which should commit when we
1485 * get to the upcoming CommitTransactionCommand() so we set the
1486 * state to "END". CommitTransactionCommand() will recognize this
1487 * and commit the transaction and return us to the default state
1489 s->blockState = TBLOCK_END;
1493 if (s->blockState == TBLOCK_ABORT)
1496 * here, we are in a transaction block which aborted and since the
1497 * AbortTransaction() was already done, we do whatever is needed
1498 * and change to the special "END ABORT" state. The upcoming
1499 * CommitTransactionCommand() will recognise this and then put us
1500 * back in the default state.
1502 s->blockState = TBLOCK_ENDABORT;
1507 * here, the user issued COMMIT when not inside a transaction. Issue a
1508 * WARNING and go to abort state. The upcoming call to
1509 * CommitTransactionCommand() will then put us back into the default
1513 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1514 errmsg("there is no transaction in progress")));
1516 s->blockState = TBLOCK_ENDABORT;
1520 * AbortTransactionBlock
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
1551 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1552 errmsg("there is no transaction in progress")));
1554 s->blockState = TBLOCK_ENDABORT;
1559 * UserAbortTransactionBlock
1562 UserAbortTransactionBlock(void)
1564 TransactionState s = CurrentTransactionState;
1567 * if the transaction has already been automatically aborted with an
1568 * error, and the user subsequently types 'abort', allow it. (the
1569 * behavior is the same as if they had typed 'end'.)
1571 if (s->blockState == TBLOCK_ABORT)
1573 s->blockState = TBLOCK_ENDABORT;
1577 if (s->blockState == TBLOCK_INPROGRESS)
1580 * here we were inside a transaction block and we got an abort
1581 * command from the user, so we move to the abort state, do the
1582 * abort processing and then change to the ENDABORT state so we
1583 * will end up in the default state after the upcoming
1584 * CommitTransactionCommand().
1586 s->blockState = TBLOCK_ABORT;
1588 s->blockState = TBLOCK_ENDABORT;
1593 * here, the user issued ABORT when not inside a transaction. Issue a
1594 * WARNING and go to abort state. The upcoming call to
1595 * CommitTransactionCommand() will then put us back into the default
1599 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1600 errmsg("there is no transaction in progress")));
1602 s->blockState = TBLOCK_ENDABORT;
1606 * AbortOutOfAnyTransaction
1608 * This routine is provided for error recovery purposes. It aborts any
1609 * active transaction or transaction block, leaving the system in a known
1613 AbortOutOfAnyTransaction(void)
1615 TransactionState s = CurrentTransactionState;
1618 * Get out of any low-level transaction
1623 case TRANS_INPROGRESS:
1625 /* In a transaction, so clean up */
1627 CleanupTransaction();
1630 /* AbortTransaction already done, still need Cleanup */
1631 CleanupTransaction();
1634 /* Not in a transaction, do nothing */
1639 * Now reset the high-level state
1641 s->blockState = TBLOCK_DEFAULT;
1645 * IsTransactionBlock --- are we within a transaction block?
1648 IsTransactionBlock(void)
1650 TransactionState s = CurrentTransactionState;
1652 if (s->blockState == TBLOCK_DEFAULT)
1659 * TransactionBlockStatusCode - return status code to send in ReadyForQuery
1662 TransactionBlockStatusCode(void)
1664 TransactionState s = CurrentTransactionState;
1666 switch (s->blockState)
1668 case TBLOCK_DEFAULT:
1669 return 'I'; /* idle --- not in transaction */
1671 case TBLOCK_INPROGRESS:
1673 return 'T'; /* in transaction */
1675 case TBLOCK_ENDABORT:
1676 return 'E'; /* in failed transaction */
1679 /* should never get here */
1680 elog(ERROR, "invalid transaction block state: %d",
1681 (int) s->blockState);
1682 return 0; /* keep compiler quiet */
1687 * XLOG support routines
1691 xact_redo(XLogRecPtr lsn, XLogRecord *record)
1693 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1695 if (info == XLOG_XACT_COMMIT)
1697 TransactionIdCommit(record->xl_xid);
1698 /* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
1700 else if (info == XLOG_XACT_ABORT)
1702 TransactionIdAbort(record->xl_xid);
1703 /* SHOULD REMOVE FILES OF ALL FAILED-TO-BE-CREATED RELATIONS */
1706 elog(PANIC, "xact_redo: unknown op code %u", info);
1710 xact_undo(XLogRecPtr lsn, XLogRecord *record)
1712 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1714 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
1715 elog(PANIC, "xact_undo: can't undo committed xaction");
1716 else if (info != XLOG_XACT_ABORT)
1717 elog(PANIC, "xact_redo: unknown op code %u", info);
1721 xact_desc(char *buf, uint8 xl_info, char *rec)
1723 uint8 info = xl_info & ~XLR_INFO_MASK;
1725 if (info == XLOG_XACT_COMMIT)
1727 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
1728 struct tm *tm = localtime(&xlrec->xtime);
1730 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
1731 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1732 tm->tm_hour, tm->tm_min, tm->tm_sec);
1734 else if (info == XLOG_XACT_ABORT)
1736 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
1737 struct tm *tm = localtime(&xlrec->xtime);
1739 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
1740 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1741 tm->tm_hour, tm->tm_min, tm->tm_sec);
1744 strcat(buf, "UNKNOWN");
1748 XactPushRollback(void (*func) (void *), void *data)
1751 if (_RollbackFunc != NULL)
1752 elog(PANIC, "XactPushRollback: already installed");
1755 _RollbackFunc = func;
1756 _RollbackData = data;
1760 XactPopRollback(void)
1762 _RollbackFunc = NULL;