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