]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xact.c
pgindent run.
[postgresql] / src / backend / access / transam / xact.c
1 /*-------------------------------------------------------------------------
2  *
3  * xact.c
4  *        top level transaction system support routines
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.132 2002/09/04 20:31:13 momjian Exp $
12  *
13  * NOTES
14  *              Transaction aborts can now occur two ways:
15  *
16  *              1)      system dies from some internal cause  (Assert, etc..)
17  *              2)      user types abort
18  *
19  *              These two cases used to be treated identically, but now
20  *              we need to distinguish them.  Why?      consider the following
21  *              two situations:
22  *
23  *                              case 1                                                  case 2
24  *                              ------                                                  ------
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
29  *
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)
35  *
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:
41  *
42  *              * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
43  *              * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
44  *
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.
53  *
54  *       NOTES
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)
62  *
63  *              The essential aspects of the transaction system are:
64  *
65  *                              o  transaction id generation
66  *                              o  transaction log updating
67  *                              o  memory cleanup
68  *                              o  cache invalidation
69  *                              o  lock cleanup
70  *
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.
76  *
77  *              The code is layered as follows:
78  *
79  *                              StartTransaction
80  *                              CommitTransaction
81  *                              AbortTransaction
82  *                              CleanupTransaction
83  *
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:
87  *
88  *                              StartTransactionCommand
89  *                              CommitTransactionCommand
90  *                              AbortCurrentTransaction
91  *
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.
95  *
96  *              Support for transaction blocks is provided via the functions:
97  *
98  *                              StartTransactionBlock
99  *                              CommitTransactionBlock
100  *                              AbortTransactionBlock
101  *
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().
106  *
107  *              For example, consider the following sequence of user commands:
108  *
109  *              1)              begin
110  *              2)              retrieve (foo.all)
111  *              3)              append foo (bar = baz)
112  *              4)              end
113  *
114  *              in the main processing loop, this results in the following
115  *              transaction sequence:
116  *
117  *                      /       StartTransactionCommand();
118  *              1) /    ProcessUtility();                               << begin
119  *                 \            StartTransactionBlock();
120  *                      \       CommitTransactionCommand();
121  *
122  *                      /       StartTransactionCommand();
123  *              2) <    ProcessQuery();                                 << retrieve (foo.all)
124  *                      \       CommitTransactionCommand();
125  *
126  *                      /       StartTransactionCommand();
127  *              3) <    ProcessQuery();                                 << append foo (bar = baz)
128  *                      \       CommitTransactionCommand();
129  *
130  *                      /       StartTransactionCommand();
131  *              4) /    ProcessUtility();                               << end
132  *                 \            CommitTransactionBlock();
133  *                      \       CommitTransactionCommand();
134  *
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
140  *              processing.
141  *
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".
145  *              -cim 3/23/90
146  *
147  *-------------------------------------------------------------------------
148  */
149
150 /*
151  * Large object clean up added in CommitTransaction() to prevent buffer leaks.
152  * [PA, 7/17/98]
153  * [PA] is Pascal AndrĂ© <andre@via.ecp.fr>
154  */
155 #include "postgres.h"
156
157 #include <unistd.h>
158 #include <sys/time.h>
159
160 #include "access/gistscan.h"
161 #include "access/hash.h"
162 #include "access/nbtree.h"
163 #include "access/rtree.h"
164 #include "access/xact.h"
165 #include "catalog/heap.h"
166 #include "catalog/index.h"
167 #include "catalog/namespace.h"
168 #include "commands/async.h"
169 #include "commands/trigger.h"
170 #include "executor/spi.h"
171 #include "libpq/be-fsstubs.h"
172 #include "miscadmin.h"
173 #include "storage/proc.h"
174 #include "storage/sinval.h"
175 #include "storage/smgr.h"
176 #include "utils/guc.h"
177 #include "utils/inval.h"
178 #include "utils/memutils.h"
179 #include "utils/portal.h"
180 #include "utils/catcache.h"
181 #include "utils/relcache.h"
182 #include "pgstat.h"
183
184
185 static void AbortTransaction(void);
186 static void AtAbort_Cache(void);
187 static void AtAbort_Locks(void);
188 static void AtAbort_Memory(void);
189 static void AtCleanup_Memory(void);
190 static void AtCommit_Cache(void);
191 static void AtCommit_LocalCache(void);
192 static void AtCommit_Locks(void);
193 static void AtCommit_Memory(void);
194 static void AtStart_Cache(void);
195 static void AtStart_Locks(void);
196 static void AtStart_Memory(void);
197 static void CleanupTransaction(void);
198 static void CommitTransaction(void);
199 static void RecordTransactionAbort(void);
200 static void StartTransaction(void);
201
202 /* ----------------
203  *              global variables holding the current transaction state.
204  * ----------------
205  */
206 static TransactionStateData CurrentTransactionStateData = {
207         0,                                                      /* transaction id */
208         FirstCommandId,                         /* command id */
209         0,                                                      /* scan command id */
210         0x0,                                            /* start time */
211         TRANS_DEFAULT,                          /* transaction state */
212         TBLOCK_DEFAULT                          /* transaction block state */
213 };
214
215 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
216
217 /*
218  * User-tweakable parameters
219  */
220 int                     DefaultXactIsoLevel = XACT_READ_COMMITTED;
221 int                     XactIsoLevel;
222
223 bool            autocommit = true;
224
225 int                     CommitDelay = 0;        /* precommit delay in microseconds */
226 int                     CommitSiblings = 5; /* number of concurrent xacts needed to
227                                                                  * sleep */
228
229
230 static bool suppressChain = false;
231
232 static void (*_RollbackFunc) (void *) = NULL;
233 static void *_RollbackData = NULL;
234
235
236 /* ----------------------------------------------------------------
237  *                                       transaction state accessors
238  * ----------------------------------------------------------------
239  */
240
241 #ifdef NOT_USED
242
243 /* --------------------------------
244  *              TransactionFlushEnabled()
245  *              SetTransactionFlushEnabled()
246  *
247  *              These are used to test and set the "TransactionFlushState"
248  *              varable.  If this variable is true (the default), then
249  *              the system will flush all dirty buffers to disk at the end
250  *              of each transaction.   If false then we are assuming the
251  *              buffer pool resides in stable main memory, in which case we
252  *              only do writes as necessary.
253  * --------------------------------
254  */
255 static int      TransactionFlushState = 1;
256
257 int
258 TransactionFlushEnabled(void)
259 {
260         return TransactionFlushState;
261 }
262
263 void
264 SetTransactionFlushEnabled(bool state)
265 {
266         TransactionFlushState = (state == true);
267 }
268 #endif
269
270
271 /* --------------------------------
272  *              IsTransactionState
273  *
274  *              This returns true if we are currently running a query
275  *              within an executing transaction.
276  * --------------------------------
277  */
278 bool
279 IsTransactionState(void)
280 {
281         TransactionState s = CurrentTransactionState;
282
283         switch (s->state)
284         {
285                 case TRANS_DEFAULT:
286                         return false;
287                 case TRANS_START:
288                         return true;
289                 case TRANS_INPROGRESS:
290                         return true;
291                 case TRANS_COMMIT:
292                         return true;
293                 case TRANS_ABORT:
294                         return true;
295         }
296
297         /*
298          * Shouldn't get here, but lint is not happy with this...
299          */
300         return false;
301 }
302
303 /* --------------------------------
304  *              IsAbortedTransactionBlockState
305  *
306  *              This returns true if we are currently running a query
307  *              within an aborted transaction block.
308  * --------------------------------
309  */
310 bool
311 IsAbortedTransactionBlockState(void)
312 {
313         TransactionState s = CurrentTransactionState;
314
315         if (s->blockState == TBLOCK_ABORT)
316                 return true;
317
318         return false;
319 }
320
321
322 /* --------------------------------
323  *              GetCurrentTransactionId
324  * --------------------------------
325  */
326 TransactionId
327 GetCurrentTransactionId(void)
328 {
329         TransactionState s = CurrentTransactionState;
330
331         return s->transactionIdData;
332 }
333
334
335 /* --------------------------------
336  *              GetCurrentCommandId
337  * --------------------------------
338  */
339 CommandId
340 GetCurrentCommandId(void)
341 {
342         TransactionState s = CurrentTransactionState;
343
344         return s->commandId;
345 }
346
347
348 /* --------------------------------
349  *              GetCurrentTransactionStartTime
350  * --------------------------------
351  */
352 AbsoluteTime
353 GetCurrentTransactionStartTime(void)
354 {
355         TransactionState s = CurrentTransactionState;
356
357         return s->startTime;
358 }
359
360
361 /* --------------------------------
362  *              GetCurrentTransactionStartTimeUsec
363  * --------------------------------
364  */
365 AbsoluteTime
366 GetCurrentTransactionStartTimeUsec(int *msec)
367 {
368         TransactionState s = CurrentTransactionState;
369
370         *msec = s->startTimeUsec;
371
372         return s->startTime;
373 }
374
375
376 /* --------------------------------
377  *              TransactionIdIsCurrentTransactionId
378  *
379  * During bootstrap, we cheat and say "it's not my transaction ID" even though
380  * it is.  Along with transam.c's cheat to say that the bootstrap XID is
381  * already committed, this causes the tqual.c routines to see previously
382  * inserted tuples as committed, which is what we need during bootstrap.
383  * --------------------------------
384  */
385 bool
386 TransactionIdIsCurrentTransactionId(TransactionId xid)
387 {
388         TransactionState s = CurrentTransactionState;
389
390         if (AMI_OVERRIDE)
391         {
392                 Assert(xid == BootstrapTransactionId);
393                 return false;
394         }
395
396         return TransactionIdEquals(xid, s->transactionIdData);
397 }
398
399
400 /* --------------------------------
401  *              CommandIdIsCurrentCommandId
402  * --------------------------------
403  */
404 bool
405 CommandIdIsCurrentCommandId(CommandId cid)
406 {
407         TransactionState s = CurrentTransactionState;
408
409         return (cid == s->commandId) ? true : false;
410 }
411
412
413 /* --------------------------------
414  *              CommandCounterIncrement
415  * --------------------------------
416  */
417 void
418 CommandCounterIncrement(void)
419 {
420         TransactionState s = CurrentTransactionState;
421
422         s->commandId += 1;
423         if (s->commandId == FirstCommandId) /* check for overflow */
424                 elog(ERROR, "You may only have 2^32-1 commands per transaction");
425
426         /* Propagate new command ID into query snapshots, if set */
427         if (QuerySnapshot)
428                 QuerySnapshot->curcid = s->commandId;
429         if (SerializableSnapshot)
430                 SerializableSnapshot->curcid = s->commandId;
431
432         /*
433          * make cache changes visible to me.  AtCommit_LocalCache() instead of
434          * AtCommit_Cache() is called here.
435          */
436         AtCommit_LocalCache();
437         AtStart_Cache();
438 }
439
440
441 /* ----------------------------------------------------------------
442  *                                              StartTransaction stuff
443  * ----------------------------------------------------------------
444  */
445
446 /* --------------------------------
447  *              AtStart_Cache
448  * --------------------------------
449  */
450 static void
451 AtStart_Cache(void)
452 {
453         AcceptInvalidationMessages();
454 }
455
456 /* --------------------------------
457  *              AtStart_Locks
458  * --------------------------------
459  */
460 static void
461 AtStart_Locks(void)
462 {
463         /*
464          * at present, it is unknown to me what belongs here -cim 3/18/90
465          *
466          * There isn't anything to do at the start of a xact for locks. -mer
467          * 5/24/92
468          */
469 }
470
471 /* --------------------------------
472  *              AtStart_Memory
473  * --------------------------------
474  */
475 static void
476 AtStart_Memory(void)
477 {
478         /*
479          * We shouldn't have any transaction contexts already.
480          */
481         Assert(TopTransactionContext == NULL);
482         Assert(TransactionCommandContext == NULL);
483
484         /*
485          * Create a toplevel context for the transaction.
486          */
487         TopTransactionContext =
488                 AllocSetContextCreate(TopMemoryContext,
489                                                           "TopTransactionContext",
490                                                           ALLOCSET_DEFAULT_MINSIZE,
491                                                           ALLOCSET_DEFAULT_INITSIZE,
492                                                           ALLOCSET_DEFAULT_MAXSIZE);
493
494         /*
495          * Create a statement-level context and make it active.
496          */
497         TransactionCommandContext =
498                 AllocSetContextCreate(TopTransactionContext,
499                                                           "TransactionCommandContext",
500                                                           ALLOCSET_DEFAULT_MINSIZE,
501                                                           ALLOCSET_DEFAULT_INITSIZE,
502                                                           ALLOCSET_DEFAULT_MAXSIZE);
503         MemoryContextSwitchTo(TransactionCommandContext);
504 }
505
506
507 /* ----------------------------------------------------------------
508  *                                              CommitTransaction stuff
509  * ----------------------------------------------------------------
510  */
511
512 /*
513  *              RecordTransactionCommit
514  */
515 void
516 RecordTransactionCommit(void)
517 {
518         /*
519          * If we made neither any XLOG entries nor any temp-rel updates, we
520          * can omit recording the transaction commit at all.
521          */
522         if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate)
523         {
524                 TransactionId xid = GetCurrentTransactionId();
525                 XLogRecPtr      recptr;
526
527                 /* Tell bufmgr and smgr to prepare for commit */
528                 BufmgrCommit();
529
530                 START_CRIT_SECTION();
531
532                 /*
533                  * We only need to log the commit in xlog if the transaction made
534                  * any transaction-controlled XLOG entries.  (Otherwise, its XID
535                  * appears nowhere in permanent storage, so no one else will ever
536                  * care if it committed.)
537                  */
538                 if (MyLastRecPtr.xrecoff != 0)
539                 {
540                         /* Need to emit a commit record */
541                         XLogRecData rdata;
542                         xl_xact_commit xlrec;
543
544                         xlrec.xtime = time(NULL);
545                         rdata.buffer = InvalidBuffer;
546                         rdata.data = (char *) (&xlrec);
547                         rdata.len = SizeOfXactCommit;
548                         rdata.next = NULL;
549
550                         /*
551                          * XXX SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
552                          */
553                         recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, &rdata);
554                 }
555                 else
556                 {
557                         /* Just flush through last record written by me */
558                         recptr = ProcLastRecEnd;
559                 }
560
561                 /*
562                  * We must flush our XLOG entries to disk if we made any XLOG
563                  * entries, whether in or out of transaction control.  For
564                  * example, if we reported a nextval() result to the client, this
565                  * ensures that any XLOG record generated by nextval will hit the
566                  * disk before we report the transaction committed.
567                  */
568                 if (MyXactMadeXLogEntry)
569                 {
570                         /*
571                          * Sleep before flush! So we can flush more than one commit
572                          * records per single fsync.  (The idea is some other backend
573                          * may do the XLogFlush while we're sleeping.  This needs work
574                          * still, because on most Unixen, the minimum select() delay
575                          * is 10msec or more, which is way too long.)
576                          *
577                          * We do not sleep if enableFsync is not turned on, nor if there
578                          * are fewer than CommitSiblings other backends with active
579                          * transactions.
580                          */
581                         if (CommitDelay > 0 && enableFsync &&
582                                 CountActiveBackends() >= CommitSiblings)
583                         {
584                                 struct timeval delay;
585
586                                 delay.tv_sec = 0;
587                                 delay.tv_usec = CommitDelay;
588                                 (void) select(0, NULL, NULL, NULL, &delay);
589                         }
590
591                         XLogFlush(recptr);
592                 }
593
594                 /*
595                  * We must mark the transaction committed in clog if its XID
596                  * appears either in permanent rels or in local temporary rels.
597                  * We test this by seeing if we made transaction-controlled
598                  * entries *OR* local-rel tuple updates.  Note that if we made
599                  * only the latter, we have not emitted an XLOG record for our
600                  * commit, and so in the event of a crash the clog update might be
601                  * lost.  This is okay because no one else will ever care whether
602                  * we committed.
603                  */
604                 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
605                         TransactionIdCommit(xid);
606
607                 END_CRIT_SECTION();
608         }
609
610         /* Break the chain of back-links in the XLOG records I output */
611         MyLastRecPtr.xrecoff = 0;
612         MyXactMadeXLogEntry = false;
613         MyXactMadeTempRelUpdate = false;
614
615         /* Show myself as out of the transaction in PGPROC array */
616         MyProc->logRec.xrecoff = 0;
617 }
618
619
620 /* --------------------------------
621  *              AtCommit_Cache
622  * --------------------------------
623  */
624 static void
625 AtCommit_Cache(void)
626 {
627         /*
628          * Clean up the relation cache.
629          */
630         AtEOXact_RelationCache(true);
631
632         /*
633          * Make catalog changes visible to all backends.
634          */
635         AtEOXactInvalidationMessages(true);
636 }
637
638 /* --------------------------------
639  *              AtCommit_LocalCache
640  * --------------------------------
641  */
642 static void
643 AtCommit_LocalCache(void)
644 {
645         /*
646          * Make catalog changes visible to me for the next command.
647          */
648         CommandEndInvalidationMessages(true);
649 }
650
651 /* --------------------------------
652  *              AtCommit_Locks
653  * --------------------------------
654  */
655 static void
656 AtCommit_Locks(void)
657 {
658         /*
659          * XXX What if ProcReleaseLocks fails?  (race condition?)
660          *
661          * Then you're up a creek! -mer 5/24/92
662          */
663         ProcReleaseLocks(true);
664 }
665
666 /* --------------------------------
667  *              AtCommit_Memory
668  * --------------------------------
669  */
670 static void
671 AtCommit_Memory(void)
672 {
673         /*
674          * Now that we're "out" of a transaction, have the system allocate
675          * things in the top memory context instead of per-transaction
676          * contexts.
677          */
678         MemoryContextSwitchTo(TopMemoryContext);
679
680         /*
681          * Release all transaction-local memory.
682          */
683         Assert(TopTransactionContext != NULL);
684         MemoryContextDelete(TopTransactionContext);
685         TopTransactionContext = NULL;
686         TransactionCommandContext = NULL;
687 }
688
689 /* ----------------------------------------------------------------
690  *                                              AbortTransaction stuff
691  * ----------------------------------------------------------------
692  */
693
694 /*
695  *              RecordTransactionAbort
696  */
697 static void
698 RecordTransactionAbort(void)
699 {
700         /*
701          * If we made neither any transaction-controlled XLOG entries nor any
702          * temp-rel updates, we can omit recording the transaction abort at
703          * all. No one will ever care that it aborted.
704          */
705         if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
706         {
707                 TransactionId xid = GetCurrentTransactionId();
708
709                 /*
710                  * Catch the scenario where we aborted partway through
711                  * RecordTransactionCommit ...
712                  */
713                 if (TransactionIdDidCommit(xid))
714                         elog(PANIC, "RecordTransactionAbort: xact %u already committed",
715                                  xid);
716
717                 START_CRIT_SECTION();
718
719                 /*
720                  * We only need to log the abort in XLOG if the transaction made
721                  * any transaction-controlled XLOG entries.  (Otherwise, its XID
722                  * appears nowhere in permanent storage, so no one else will ever
723                  * care if it committed.)  We do not flush XLOG to disk in any
724                  * case, since the default assumption after a crash would be that
725                  * we aborted, anyway.
726                  */
727                 if (MyLastRecPtr.xrecoff != 0)
728                 {
729                         XLogRecData rdata;
730                         xl_xact_abort xlrec;
731                         XLogRecPtr      recptr;
732
733                         xlrec.xtime = time(NULL);
734                         rdata.buffer = InvalidBuffer;
735                         rdata.data = (char *) (&xlrec);
736                         rdata.len = SizeOfXactAbort;
737                         rdata.next = NULL;
738
739                         /*
740                          * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
741                          */
742                         recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
743                 }
744
745                 /*
746                  * Mark the transaction aborted in clog.  This is not absolutely
747                  * necessary but we may as well do it while we are here.
748                  */
749                 TransactionIdAbort(xid);
750
751                 END_CRIT_SECTION();
752         }
753
754         /* Break the chain of back-links in the XLOG records I output */
755         MyLastRecPtr.xrecoff = 0;
756         MyXactMadeXLogEntry = false;
757         MyXactMadeTempRelUpdate = false;
758
759         /* Show myself as out of the transaction in PGPROC array */
760         MyProc->logRec.xrecoff = 0;
761 }
762
763 /* --------------------------------
764  *              AtAbort_Cache
765  * --------------------------------
766  */
767 static void
768 AtAbort_Cache(void)
769 {
770         AtEOXact_RelationCache(false);
771         AtEOXactInvalidationMessages(false);
772 }
773
774 /* --------------------------------
775  *              AtAbort_Locks
776  * --------------------------------
777  */
778 static void
779 AtAbort_Locks(void)
780 {
781         /*
782          * XXX What if ProcReleaseLocks() fails?  (race condition?)
783          *
784          * Then you're up a creek without a paddle! -mer
785          */
786         ProcReleaseLocks(false);
787 }
788
789
790 /* --------------------------------
791  *              AtAbort_Memory
792  * --------------------------------
793  */
794 static void
795 AtAbort_Memory(void)
796 {
797         /*
798          * Make sure we are in a valid context (not a child of
799          * TransactionCommandContext...).  Note that it is possible for this
800          * code to be called when we aren't in a transaction at all; go
801          * directly to TopMemoryContext in that case.
802          */
803         if (TransactionCommandContext != NULL)
804         {
805                 MemoryContextSwitchTo(TransactionCommandContext);
806
807                 /*
808                  * We do not want to destroy transaction contexts yet, but it
809                  * should be OK to delete any command-local memory.
810                  */
811                 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
812         }
813         else
814                 MemoryContextSwitchTo(TopMemoryContext);
815 }
816
817
818 /* ----------------------------------------------------------------
819  *                                              CleanupTransaction stuff
820  * ----------------------------------------------------------------
821  */
822
823 /* --------------------------------
824  *              AtCleanup_Memory
825  * --------------------------------
826  */
827 static void
828 AtCleanup_Memory(void)
829 {
830         /*
831          * Now that we're "out" of a transaction, have the system allocate
832          * things in the top memory context instead of per-transaction
833          * contexts.
834          */
835         MemoryContextSwitchTo(TopMemoryContext);
836
837         /*
838          * Release all transaction-local memory.
839          */
840         if (TopTransactionContext != NULL)
841                 MemoryContextDelete(TopTransactionContext);
842         TopTransactionContext = NULL;
843         TransactionCommandContext = NULL;
844 }
845
846
847 /* ----------------------------------------------------------------
848  *                                              interface routines
849  * ----------------------------------------------------------------
850  */
851
852 /* --------------------------------
853  *              StartTransaction
854  *
855  * --------------------------------
856  */
857 static void
858 StartTransaction(void)
859 {
860         TransactionState s = CurrentTransactionState;
861
862         FreeXactSnapshot();
863         XactIsoLevel = DefaultXactIsoLevel;
864
865         /*
866          * Check the current transaction state.  If the transaction system is
867          * switched off, or if we're already in a transaction, do nothing.
868          * We're already in a transaction when the monitor sends a null
869          * command to the backend to flush the comm channel.  This is a hacky
870          * fix to a communications problem, and we keep having to deal with it
871          * here.  We should fix the comm channel code.  mao 080891
872          */
873         if (s->state == TRANS_INPROGRESS)
874                 return;
875
876         /*
877          * set the current transaction state information appropriately during
878          * start processing
879          */
880         s->state = TRANS_START;
881
882         SetReindexProcessing(false);
883
884         /*
885          * generate a new transaction id
886          */
887         s->transactionIdData = GetNewTransactionId();
888
889         XactLockTableInsert(s->transactionIdData);
890
891         /*
892          * initialize current transaction state fields
893          */
894         s->commandId = FirstCommandId;
895         s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
896
897         /*
898          * initialize the various transaction subsystems
899          */
900         AtStart_Memory();
901         AtStart_Cache();
902         AtStart_Locks();
903
904         /*
905          * Tell the trigger manager to we're starting a transaction
906          */
907         DeferredTriggerBeginXact();
908
909         /*
910          * done with start processing, set current transaction state to "in
911          * progress"
912          */
913         s->state = TRANS_INPROGRESS;
914
915 }
916
917 #ifdef NOT_USED
918 /* ---------------
919  * Tell me if we are currently in progress
920  * ---------------
921  */
922 bool
923 CurrentXactInProgress(void)
924 {
925         return CurrentTransactionState->state == TRANS_INPROGRESS;
926 }
927 #endif
928
929 /* --------------------------------
930  *              CommitTransaction
931  *
932  * --------------------------------
933  */
934 static void
935 CommitTransaction(void)
936 {
937         TransactionState s = CurrentTransactionState;
938
939         /*
940          * check the current transaction state
941          */
942         if (s->state != TRANS_INPROGRESS)
943                 elog(WARNING, "CommitTransaction and not in in-progress state");
944
945         /*
946          * Tell the trigger manager that this transaction is about to be
947          * committed. He'll invoke all trigger deferred until XACT before we
948          * really start on committing the transaction.
949          */
950         DeferredTriggerEndXact();
951
952         /* Prevent cancel/die interrupt while cleaning up */
953         HOLD_INTERRUPTS();
954
955         /*
956          * set the current transaction state information appropriately during
957          * the abort processing
958          */
959         s->state = TRANS_COMMIT;
960
961         /*
962          * do commit processing
963          */
964
965         /* handle commit for large objects [ PA, 7/17/98 ] */
966         lo_commit(true);
967
968         /* NOTIFY commit must also come before lower-level cleanup */
969         AtCommit_Notify();
970
971         AtEOXact_portals();
972
973         /* Here is where we really truly commit. */
974         RecordTransactionCommit();
975
976         /*
977          * Let others know about no transaction in progress by me. Note that
978          * this must be done _before_ releasing locks we hold and _after_
979          * RecordTransactionCommit.
980          *
981          * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
982          * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
983          * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
984          * as running as well or it will see two tuple versions - one deleted
985          * by xid 1 and one inserted by xid 0.  See notes in GetSnapshotData.
986          */
987         if (MyProc != (PGPROC *) NULL)
988         {
989                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
990                 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
991                 MyProc->xid = InvalidTransactionId;
992                 MyProc->xmin = InvalidTransactionId;
993                 LWLockRelease(SInvalLock);
994         }
995
996         /*
997          * This is all post-commit cleanup.  Note that if an error is raised
998          * here, it's too late to abort the transaction.  This should be just
999          * noncritical resource releasing.
1000          */
1001
1002         smgrDoPendingDeletes(true);
1003
1004         AtEOXact_GUC(true);
1005         AtEOXact_SPI();
1006         AtEOXact_gist();
1007         AtEOXact_hash();
1008         AtEOXact_nbtree();
1009         AtEOXact_rtree();
1010         AtEOXact_Namespace(true);
1011         AtCommit_Cache();
1012         AtCommit_Locks();
1013         AtEOXact_CatCache(true);
1014         AtCommit_Memory();
1015         AtEOXact_Buffers(true);
1016         smgrabort();
1017         AtEOXact_Files();
1018
1019         /* Count transaction commit in statistics collector */
1020         pgstat_count_xact_commit();
1021
1022         /*
1023          * done with commit processing, set current transaction state back to
1024          * default
1025          */
1026         s->state = TRANS_DEFAULT;
1027
1028         RESUME_INTERRUPTS();
1029 }
1030
1031 /* --------------------------------
1032  *              AbortTransaction
1033  *
1034  * --------------------------------
1035  */
1036 static void
1037 AbortTransaction(void)
1038 {
1039         TransactionState s = CurrentTransactionState;
1040
1041         /* Prevent cancel/die interrupt while cleaning up */
1042         HOLD_INTERRUPTS();
1043
1044         /*
1045          * Release any LW locks we might be holding as quickly as possible.
1046          * (Regular locks, however, must be held till we finish aborting.)
1047          * Releasing LW locks is critical since we might try to grab them
1048          * again while cleaning up!
1049          */
1050         LWLockReleaseAll();
1051
1052         /* Clean up buffer I/O and buffer context locks, too */
1053         AbortBufferIO();
1054         UnlockBuffers();
1055
1056         /*
1057          * Also clean up any open wait for lock, since the lock manager will
1058          * choke if we try to wait for another lock before doing this.
1059          */
1060         LockWaitCancel();
1061
1062         /*
1063          * check the current transaction state
1064          */
1065         if (s->state != TRANS_INPROGRESS)
1066                 elog(WARNING, "AbortTransaction and not in in-progress state");
1067
1068         /*
1069          * set the current transaction state information appropriately during
1070          * the abort processing
1071          */
1072         s->state = TRANS_ABORT;
1073
1074         /*
1075          * Reset user id which might have been changed transiently
1076          */
1077         SetUserId(GetSessionUserId());
1078
1079         /*
1080          * do abort processing
1081          */
1082         DeferredTriggerAbortXact();
1083         lo_commit(false);                       /* 'false' means it's abort */
1084         AtAbort_Notify();
1085         AtEOXact_portals();
1086
1087         /* Advertise the fact that we aborted in pg_clog. */
1088         RecordTransactionAbort();
1089
1090         /*
1091          * Let others know about no transaction in progress by me. Note that
1092          * this must be done _before_ releasing locks we hold and _after_
1093          * RecordTransactionAbort.
1094          */
1095         if (MyProc != (PGPROC *) NULL)
1096         {
1097                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1098                 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1099                 MyProc->xid = InvalidTransactionId;
1100                 MyProc->xmin = InvalidTransactionId;
1101                 LWLockRelease(SInvalLock);
1102         }
1103
1104         smgrDoPendingDeletes(false);
1105
1106         AtEOXact_GUC(false);
1107         AtEOXact_SPI();
1108         AtEOXact_gist();
1109         AtEOXact_hash();
1110         AtEOXact_nbtree();
1111         AtEOXact_rtree();
1112         AtEOXact_Namespace(false);
1113         AtAbort_Cache();
1114         AtEOXact_CatCache(false);
1115         AtAbort_Memory();
1116         AtEOXact_Buffers(false);
1117         AtEOXact_Files();
1118         AtAbort_Locks();
1119
1120         /* Count transaction abort in statistics collector */
1121         pgstat_count_xact_rollback();
1122
1123         /*
1124          * State remains TRANS_ABORT until CleanupTransaction().
1125          */
1126         RESUME_INTERRUPTS();
1127 }
1128
1129 /* --------------------------------
1130  *              CleanupTransaction
1131  *
1132  * --------------------------------
1133  */
1134 static void
1135 CleanupTransaction(void)
1136 {
1137         TransactionState s = CurrentTransactionState;
1138
1139         /*
1140          * State should still be TRANS_ABORT from AbortTransaction().
1141          */
1142         if (s->state != TRANS_ABORT)
1143                 elog(FATAL, "CleanupTransaction and not in abort state");
1144
1145         /*
1146          * do abort cleanup processing
1147          */
1148         AtCleanup_Memory();
1149
1150         /*
1151          * done with abort processing, set current transaction state back to
1152          * default
1153          */
1154         s->state = TRANS_DEFAULT;
1155 }
1156
1157 /* --------------------------------
1158  *              StartTransactionCommand
1159  *
1160  * preventChain, if true, forces autocommit behavior at the next
1161  * CommitTransactionCommand call.
1162  * --------------------------------
1163  */
1164 void
1165 StartTransactionCommand(bool preventChain)
1166 {
1167         TransactionState s = CurrentTransactionState;
1168
1169         /*
1170          * Remember if caller wants to prevent autocommit-off chaining. This
1171          * is only allowed if not already in a transaction block.
1172          */
1173         suppressChain = preventChain;
1174         if (preventChain && s->blockState != TBLOCK_DEFAULT)
1175                 elog(ERROR, "StartTransactionCommand: can't prevent chain");
1176
1177         switch (s->blockState)
1178         {
1179                         /*
1180                          * if we aren't in a transaction block, we just do our usual
1181                          * start transaction.
1182                          */
1183                 case TBLOCK_DEFAULT:
1184                         StartTransaction();
1185                         break;
1186
1187                         /*
1188                          * We should never experience this -- if we do it means the
1189                          * BEGIN state was not changed in the previous
1190                          * CommitTransactionCommand().  If we get it, we print a
1191                          * warning and change to the in-progress state.
1192                          */
1193                 case TBLOCK_BEGIN:
1194                         elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1195                         s->blockState = TBLOCK_INPROGRESS;
1196                         break;
1197
1198                         /*
1199                          * This is the case when are somewhere in a transaction block
1200                          * and about to start a new command.  For now we do nothing
1201                          * but someday we may do command-local resource
1202                          * initialization.
1203                          */
1204                 case TBLOCK_INPROGRESS:
1205                         break;
1206
1207                         /*
1208                          * As with BEGIN, we should never experience this if we do it
1209                          * means the END state was not changed in the previous
1210                          * CommitTransactionCommand().  If we get it, we print a
1211                          * warning, commit the transaction, start a new transaction
1212                          * and change to the default state.
1213                          */
1214                 case TBLOCK_END:
1215                         elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
1216                         s->blockState = TBLOCK_DEFAULT;
1217                         CommitTransaction();
1218                         StartTransaction();
1219                         break;
1220
1221                         /*
1222                          * Here we are in the middle of a transaction block but one of
1223                          * the commands caused an abort so we do nothing but remain in
1224                          * the abort state.  Eventually we will get to the "END
1225                          * TRANSACTION" which will set things straight.
1226                          */
1227                 case TBLOCK_ABORT:
1228                         break;
1229
1230                         /*
1231                          * This means we somehow aborted and the last call to
1232                          * CommitTransactionCommand() didn't clear the state so we
1233                          * remain in the ENDABORT state and maybe next time we get to
1234                          * CommitTransactionCommand() the state will get reset to
1235                          * default.
1236                          */
1237                 case TBLOCK_ENDABORT:
1238                         elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1239                         break;
1240         }
1241
1242         /*
1243          * We must switch to TransactionCommandContext before returning. This
1244          * is already done if we called StartTransaction, otherwise not.
1245          */
1246         Assert(TransactionCommandContext != NULL);
1247         MemoryContextSwitchTo(TransactionCommandContext);
1248 }
1249
1250 /* --------------------------------
1251  *              CommitTransactionCommand
1252  *
1253  * forceCommit = true forces autocommit behavior even when autocommit is off.
1254  * --------------------------------
1255  */
1256 void
1257 CommitTransactionCommand(bool forceCommit)
1258 {
1259         TransactionState s = CurrentTransactionState;
1260
1261         switch (s->blockState)
1262         {
1263                         /*
1264                          * If we aren't in a transaction block, and we are doing
1265                          * autocommit, just do our usual transaction commit.  But if
1266                          * we aren't doing autocommit, start a transaction block
1267                          * automatically by switching to INPROGRESS state.      (We handle
1268                          * this choice here, and not earlier, so that an explicit
1269                          * BEGIN issued in autocommit-off mode won't issue strange
1270                          * warnings.)
1271                          *
1272                          * Autocommit mode is forced by either a true forceCommit
1273                          * parameter to me, or a true preventChain parameter to the
1274                          * preceding StartTransactionCommand call.      This is needed so
1275                          * that commands like VACUUM can ensure that the right things
1276                          * happen.
1277                          */
1278                 case TBLOCK_DEFAULT:
1279                         if (autocommit || forceCommit || suppressChain)
1280                                 CommitTransaction();
1281                         else
1282                         {
1283                                 BeginTransactionBlock();
1284                                 Assert(s->blockState == TBLOCK_INPROGRESS);
1285                                 /* This code must match the TBLOCK_INPROGRESS case below: */
1286                                 CommandCounterIncrement();
1287                                 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1288                         }
1289                         break;
1290
1291                         /*
1292                          * This is the case right after we get a "BEGIN TRANSACTION"
1293                          * command, but the user hasn't done anything else yet, so we
1294                          * change to the "transaction block in progress" state and
1295                          * return.
1296                          */
1297                 case TBLOCK_BEGIN:
1298                         s->blockState = TBLOCK_INPROGRESS;
1299                         break;
1300
1301                         /*
1302                          * This is the case when we have finished executing a command
1303                          * someplace within a transaction block.  We increment the
1304                          * command counter and return.  Someday we may free resources
1305                          * local to the command.
1306                          *
1307                          * That someday is today, at least for memory allocated in
1308                          * TransactionCommandContext. - vadim 03/25/97
1309                          */
1310                 case TBLOCK_INPROGRESS:
1311                         CommandCounterIncrement();
1312                         MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1313                         break;
1314
1315                         /*
1316                          * This is the case when we just got the "END TRANSACTION"
1317                          * statement, so we commit the transaction and go back to the
1318                          * default state.
1319                          */
1320                 case TBLOCK_END:
1321                         CommitTransaction();
1322                         s->blockState = TBLOCK_DEFAULT;
1323                         break;
1324
1325                         /*
1326                          * Here we are in the middle of a transaction block but one of
1327                          * the commands caused an abort so we do nothing but remain in
1328                          * the abort state.  Eventually we will get to the "END
1329                          * TRANSACTION" which will set things straight.
1330                          */
1331                 case TBLOCK_ABORT:
1332                         break;
1333
1334                         /*
1335                          * Here we were in an aborted transaction block which just
1336                          * processed the "END TRANSACTION" command from the user, so
1337                          * clean up and return to the default state.
1338                          */
1339                 case TBLOCK_ENDABORT:
1340                         CleanupTransaction();
1341                         s->blockState = TBLOCK_DEFAULT;
1342                         break;
1343         }
1344 }
1345
1346 /* --------------------------------
1347  *              AbortCurrentTransaction
1348  * --------------------------------
1349  */
1350 void
1351 AbortCurrentTransaction(void)
1352 {
1353         TransactionState s = CurrentTransactionState;
1354
1355         switch (s->blockState)
1356         {
1357                         /*
1358                          * if we aren't in a transaction block, we just do the basic
1359                          * abort & cleanup transaction.
1360                          */
1361                 case TBLOCK_DEFAULT:
1362                         AbortTransaction();
1363                         CleanupTransaction();
1364                         break;
1365
1366                         /*
1367                          * If we are in the TBLOCK_BEGIN it means something screwed up
1368                          * right after reading "BEGIN TRANSACTION" so we enter the
1369                          * abort state.  Eventually an "END TRANSACTION" will fix
1370                          * things.
1371                          */
1372                 case TBLOCK_BEGIN:
1373                         s->blockState = TBLOCK_ABORT;
1374                         AbortTransaction();
1375                         /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1376                         break;
1377
1378                         /*
1379                          * This is the case when are somewhere in a transaction block
1380                          * which aborted so we abort the transaction and set the ABORT
1381                          * state.  Eventually an "END TRANSACTION" will fix things and
1382                          * restore us to a normal state.
1383                          */
1384                 case TBLOCK_INPROGRESS:
1385                         s->blockState = TBLOCK_ABORT;
1386                         AbortTransaction();
1387                         /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1388                         break;
1389
1390                         /*
1391                          * Here, the system was fouled up just after the user wanted
1392                          * to end the transaction block so we abort the transaction
1393                          * and put us back into the default state.
1394                          */
1395                 case TBLOCK_END:
1396                         s->blockState = TBLOCK_DEFAULT;
1397                         AbortTransaction();
1398                         CleanupTransaction();
1399                         break;
1400
1401                         /*
1402                          * Here, we are already in an aborted transaction state and
1403                          * are waiting for an "END TRANSACTION" to come along and lo
1404                          * and behold, we abort again! So we just remain in the abort
1405                          * state.
1406                          */
1407                 case TBLOCK_ABORT:
1408                         break;
1409
1410                         /*
1411                          * Here we were in an aborted transaction block which just
1412                          * processed the "END TRANSACTION" command but somehow aborted
1413                          * again.. since we must have done the abort processing, we
1414                          * clean up and return to the default state.
1415                          */
1416                 case TBLOCK_ENDABORT:
1417                         CleanupTransaction();
1418                         s->blockState = TBLOCK_DEFAULT;
1419                         break;
1420         }
1421 }
1422
1423 /* ----------------------------------------------------------------
1424  *                                         transaction block support
1425  * ----------------------------------------------------------------
1426  */
1427 /* --------------------------------
1428  *              BeginTransactionBlock
1429  * --------------------------------
1430  */
1431 void
1432 BeginTransactionBlock(void)
1433 {
1434         TransactionState s = CurrentTransactionState;
1435
1436         /*
1437          * check the current transaction state
1438          */
1439         if (s->blockState != TBLOCK_DEFAULT)
1440                 elog(WARNING, "BEGIN: already a transaction in progress");
1441
1442         /*
1443          * set the current transaction block state information appropriately
1444          * during begin processing
1445          */
1446         s->blockState = TBLOCK_BEGIN;
1447
1448         /*
1449          * do begin processing.  NOTE: if you put anything here, check that it
1450          * behaves properly in both autocommit-on and autocommit-off modes. In
1451          * the latter case we will already have done some work in the new
1452          * transaction.
1453          */
1454
1455         /*
1456          * done with begin processing, set block state to inprogress
1457          */
1458         s->blockState = TBLOCK_INPROGRESS;
1459 }
1460
1461 /* --------------------------------
1462  *              EndTransactionBlock
1463  * --------------------------------
1464  */
1465 void
1466 EndTransactionBlock(void)
1467 {
1468         TransactionState s = CurrentTransactionState;
1469
1470         /*
1471          * check the current transaction state
1472          */
1473         if (s->blockState == TBLOCK_INPROGRESS)
1474         {
1475                 /*
1476                  * here we are in a transaction block which should commit when we
1477                  * get to the upcoming CommitTransactionCommand() so we set the
1478                  * state to "END".      CommitTransactionCommand() will recognize this
1479                  * and commit the transaction and return us to the default state
1480                  */
1481                 s->blockState = TBLOCK_END;
1482                 return;
1483         }
1484
1485         if (s->blockState == TBLOCK_ABORT)
1486         {
1487                 /*
1488                  * here, we are in a transaction block which aborted and since the
1489                  * AbortTransaction() was already done, we do whatever is needed
1490                  * and change to the special "END ABORT" state.  The upcoming
1491                  * CommitTransactionCommand() will recognise this and then put us
1492                  * back in the default state.
1493                  */
1494                 s->blockState = TBLOCK_ENDABORT;
1495                 return;
1496         }
1497
1498         /*
1499          * here, the user issued COMMIT when not inside a transaction. Issue a
1500          * WARNING and go to abort state.  The upcoming call to
1501          * CommitTransactionCommand() will then put us back into the default
1502          * state.
1503          */
1504         elog(WARNING, "COMMIT: no transaction in progress");
1505         AbortTransaction();
1506         s->blockState = TBLOCK_ENDABORT;
1507 }
1508
1509 /* --------------------------------
1510  *              AbortTransactionBlock
1511  * --------------------------------
1512  */
1513 #ifdef NOT_USED
1514 static void
1515 AbortTransactionBlock(void)
1516 {
1517         TransactionState s = CurrentTransactionState;
1518
1519         /*
1520          * check the current transaction state
1521          */
1522         if (s->blockState == TBLOCK_INPROGRESS)
1523         {
1524                 /*
1525                  * here we were inside a transaction block something screwed up
1526                  * inside the system so we enter the abort state, do the abort
1527                  * processing and then return. We remain in the abort state until
1528                  * we see an END TRANSACTION command.
1529                  */
1530                 s->blockState = TBLOCK_ABORT;
1531                 AbortTransaction();
1532                 return;
1533         }
1534
1535         /*
1536          * here, the user issued ABORT when not inside a transaction. Issue a
1537          * WARNING and go to abort state.  The upcoming call to
1538          * CommitTransactionCommand() will then put us back into the default
1539          * state.
1540          */
1541         elog(WARNING, "ROLLBACK: no transaction in progress");
1542         AbortTransaction();
1543         s->blockState = TBLOCK_ENDABORT;
1544 }
1545 #endif
1546
1547 /* --------------------------------
1548  *              UserAbortTransactionBlock
1549  * --------------------------------
1550  */
1551 void
1552 UserAbortTransactionBlock(void)
1553 {
1554         TransactionState s = CurrentTransactionState;
1555
1556         /*
1557          * if the transaction has already been automatically aborted with an
1558          * error, and the user subsequently types 'abort', allow it.  (the
1559          * behavior is the same as if they had typed 'end'.)
1560          */
1561         if (s->blockState == TBLOCK_ABORT)
1562         {
1563                 s->blockState = TBLOCK_ENDABORT;
1564                 return;
1565         }
1566
1567         if (s->blockState == TBLOCK_INPROGRESS)
1568         {
1569                 /*
1570                  * here we were inside a transaction block and we got an abort
1571                  * command from the user, so we move to the abort state, do the
1572                  * abort processing and then change to the ENDABORT state so we
1573                  * will end up in the default state after the upcoming
1574                  * CommitTransactionCommand().
1575                  */
1576                 s->blockState = TBLOCK_ABORT;
1577                 AbortTransaction();
1578                 s->blockState = TBLOCK_ENDABORT;
1579                 return;
1580         }
1581
1582         /*
1583          * here, the user issued ABORT when not inside a transaction. Issue a
1584          * WARNING and go to abort state.  The upcoming call to
1585          * CommitTransactionCommand() will then put us back into the default
1586          * state.
1587          */
1588         elog(WARNING, "ROLLBACK: no transaction in progress");
1589         AbortTransaction();
1590         s->blockState = TBLOCK_ENDABORT;
1591 }
1592
1593 /* --------------------------------
1594  *              AbortOutOfAnyTransaction
1595  *
1596  * This routine is provided for error recovery purposes.  It aborts any
1597  * active transaction or transaction block, leaving the system in a known
1598  * idle state.
1599  * --------------------------------
1600  */
1601 void
1602 AbortOutOfAnyTransaction(void)
1603 {
1604         TransactionState s = CurrentTransactionState;
1605
1606         /*
1607          * Get out of any low-level transaction
1608          */
1609         switch (s->state)
1610         {
1611                 case TRANS_START:
1612                 case TRANS_INPROGRESS:
1613                 case TRANS_COMMIT:
1614                         /* In a transaction, so clean up */
1615                         AbortTransaction();
1616                         CleanupTransaction();
1617                         break;
1618                 case TRANS_ABORT:
1619                         /* AbortTransaction already done, still need Cleanup */
1620                         CleanupTransaction();
1621                         break;
1622                 case TRANS_DEFAULT:
1623                         /* Not in a transaction, do nothing */
1624                         break;
1625         }
1626
1627         /*
1628          * Now reset the high-level state
1629          */
1630         s->blockState = TBLOCK_DEFAULT;
1631 }
1632
1633 bool
1634 IsTransactionBlock(void)
1635 {
1636         TransactionState s = CurrentTransactionState;
1637
1638         if (s->blockState == TBLOCK_INPROGRESS
1639                 || s->blockState == TBLOCK_ABORT
1640                 || s->blockState == TBLOCK_ENDABORT)
1641                 return true;
1642
1643         return false;
1644 }
1645
1646 void
1647 xact_redo(XLogRecPtr lsn, XLogRecord *record)
1648 {
1649         uint8           info = record->xl_info & ~XLR_INFO_MASK;
1650
1651         if (info == XLOG_XACT_COMMIT)
1652         {
1653                 TransactionIdCommit(record->xl_xid);
1654                 /* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
1655         }
1656         else if (info == XLOG_XACT_ABORT)
1657         {
1658                 TransactionIdAbort(record->xl_xid);
1659                 /* SHOULD REMOVE FILES OF ALL FAILED-TO-BE-CREATED RELATIONS */
1660         }
1661         else
1662                 elog(PANIC, "xact_redo: unknown op code %u", info);
1663 }
1664
1665 void
1666 xact_undo(XLogRecPtr lsn, XLogRecord *record)
1667 {
1668         uint8           info = record->xl_info & ~XLR_INFO_MASK;
1669
1670         if (info == XLOG_XACT_COMMIT)           /* shouldn't be called by XLOG */
1671                 elog(PANIC, "xact_undo: can't undo committed xaction");
1672         else if (info != XLOG_XACT_ABORT)
1673                 elog(PANIC, "xact_redo: unknown op code %u", info);
1674 }
1675
1676 void
1677 xact_desc(char *buf, uint8 xl_info, char *rec)
1678 {
1679         uint8           info = xl_info & ~XLR_INFO_MASK;
1680
1681         if (info == XLOG_XACT_COMMIT)
1682         {
1683                 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
1684                 struct tm  *tm = localtime(&xlrec->xtime);
1685
1686                 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
1687                                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1688                                 tm->tm_hour, tm->tm_min, tm->tm_sec);
1689         }
1690         else if (info == XLOG_XACT_ABORT)
1691         {
1692                 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
1693                 struct tm  *tm = localtime(&xlrec->xtime);
1694
1695                 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
1696                                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1697                                 tm->tm_hour, tm->tm_min, tm->tm_sec);
1698         }
1699         else
1700                 strcat(buf, "UNKNOWN");
1701 }
1702
1703 void
1704                         XactPushRollback(void (*func) (void *), void *data)
1705 {
1706 #ifdef XLOG_II
1707         if (_RollbackFunc != NULL)
1708                 elog(PANIC, "XactPushRollback: already installed");
1709 #endif
1710
1711         _RollbackFunc = func;
1712         _RollbackData = data;
1713 }
1714
1715 void
1716 XactPopRollback(void)
1717 {
1718         _RollbackFunc = NULL;
1719 }