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