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