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