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