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