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