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