]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xact.c
Error message editing in backend/access.
[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.149 2003/07/21 20:29:39 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 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.
565                  * We test this by seeing if we made transaction-controlled
566                  * entries *OR* local-rel tuple updates.  Note that if we made
567                  * only the latter, we have not emitted an XLOG record for our
568                  * commit, and so in the event of a crash the clog update might be
569                  * lost.  This is okay because no one else will ever care whether
570                  * we 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
759          * code to be called when we aren't in a transaction at all; go
760          * directly to 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         SetReindexProcessing(false);
838
839         /*
840          * generate a new transaction id
841          */
842         s->transactionIdData = GetNewTransactionId();
843
844         XactLockTableInsert(s->transactionIdData);
845
846         /*
847          * initialize current transaction state fields
848          */
849         s->commandId = FirstCommandId;
850         s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
851
852         /*
853          * initialize the various transaction subsystems
854          */
855         AtStart_Memory();
856         AtStart_Cache();
857         AtStart_Locks();
858
859         /*
860          * Tell the trigger manager to we're starting a transaction
861          */
862         DeferredTriggerBeginXact();
863
864         /*
865          * done with start processing, set current transaction state to "in
866          * progress"
867          */
868         s->state = TRANS_INPROGRESS;
869
870 }
871
872 /*
873  *      CommitTransaction
874  */
875 static void
876 CommitTransaction(void)
877 {
878         TransactionState s = CurrentTransactionState;
879
880         /*
881          * check the current transaction state
882          */
883         if (s->state != TRANS_INPROGRESS)
884                 elog(WARNING, "CommitTransaction and not in in-progress state");
885
886         /*
887          * Tell the trigger manager that this transaction is about to be
888          * committed. He'll invoke all trigger deferred until XACT before we
889          * really start on committing the transaction.
890          */
891         DeferredTriggerEndXact();
892
893         /*
894          * Similarly, let ON COMMIT management do its thing before we start
895          * to commit.
896          */
897         PreCommit_on_commit_actions();
898
899         /* Prevent cancel/die interrupt while cleaning up */
900         HOLD_INTERRUPTS();
901
902         /*
903          * set the current transaction state information appropriately during
904          * the abort processing
905          */
906         s->state = TRANS_COMMIT;
907
908         /*
909          * Do pre-commit processing (most of this stuff requires database
910          * access, and in fact could still cause an error...)
911          */
912
913         AtCommit_Portals();
914
915         /* handle commit for large objects [ PA, 7/17/98 ] */
916         /* XXX probably this does not belong here */
917         lo_commit(true);
918
919         /* NOTIFY commit must come before lower-level cleanup */
920         AtCommit_Notify();
921
922         /* Update the flat password file if we changed pg_shadow or pg_group */
923         AtEOXact_UpdatePasswordFile(true);
924
925         /*
926          * Here is where we really truly commit.
927          */
928         RecordTransactionCommit();
929
930         /*
931          * Let others know about no transaction in progress by me. Note that
932          * this must be done _before_ releasing locks we hold and _after_
933          * RecordTransactionCommit.
934          *
935          * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
936          * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
937          * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
938          * as running as well or it will see two tuple versions - one deleted
939          * by xid 1 and one inserted by xid 0.  See notes in GetSnapshotData.
940          */
941         if (MyProc != (PGPROC *) NULL)
942         {
943                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
944                 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
945                 MyProc->xid = InvalidTransactionId;
946                 MyProc->xmin = InvalidTransactionId;
947                 LWLockRelease(SInvalLock);
948         }
949
950         /*
951          * This is all post-commit cleanup.  Note that if an error is raised
952          * here, it's too late to abort the transaction.  This should be just
953          * noncritical resource releasing.
954          *
955          * The ordering of operations is not entirely random.  The idea is:
956          * release resources visible to other backends (eg, files, buffer pins);
957          * then release locks; then release backend-local resources.  We want
958          * to release locks at the point where any backend waiting for us will
959          * see our transaction as being fully cleaned up.
960          */
961
962         smgrDoPendingDeletes(true);
963         AtCommit_Cache();
964         AtEOXact_Buffers(true);
965         /* smgrcommit already done */
966
967         AtCommit_Locks();
968
969         AtEOXact_GUC(true);
970         AtEOXact_SPI();
971         AtEOXact_gist();
972         AtEOXact_hash();
973         AtEOXact_nbtree();
974         AtEOXact_rtree();
975         AtEOXact_on_commit_actions(true);
976         AtEOXact_Namespace(true);
977         AtEOXact_CatCache(true);
978         AtEOXact_Files();
979         pgstat_count_xact_commit();
980         AtCommit_Memory();
981
982         /*
983          * done with commit processing, set current transaction state back to
984          * default
985          */
986         s->state = TRANS_DEFAULT;
987
988         RESUME_INTERRUPTS();
989 }
990
991 /*
992  *      AbortTransaction
993  */
994 static void
995 AbortTransaction(void)
996 {
997         TransactionState s = CurrentTransactionState;
998
999         /* Prevent cancel/die interrupt while cleaning up */
1000         HOLD_INTERRUPTS();
1001
1002         /*
1003          * Release any LW locks we might be holding as quickly as possible.
1004          * (Regular locks, however, must be held till we finish aborting.)
1005          * Releasing LW locks is critical since we might try to grab them
1006          * again while cleaning up!
1007          */
1008         LWLockReleaseAll();
1009
1010         /* Clean up buffer I/O and buffer context locks, too */
1011         AbortBufferIO();
1012         UnlockBuffers();
1013
1014         /*
1015          * Also clean up any open wait for lock, since the lock manager will
1016          * choke if we try to wait for another lock before doing this.
1017          */
1018         LockWaitCancel();
1019
1020         /*
1021          * check the current transaction state
1022          */
1023         if (s->state != TRANS_INPROGRESS)
1024                 elog(WARNING, "AbortTransaction and not in in-progress state");
1025
1026         /*
1027          * set the current transaction state information appropriately during
1028          * the abort processing
1029          */
1030         s->state = TRANS_ABORT;
1031
1032         /* Make sure we are in a valid memory context */
1033         AtAbort_Memory();
1034
1035         /*
1036          * Reset user id which might have been changed transiently
1037          */
1038         SetUserId(GetSessionUserId());
1039
1040         /*
1041          * do abort processing
1042          */
1043         DeferredTriggerAbortXact();
1044         AtAbort_Portals();
1045         lo_commit(false);                       /* 'false' means it's abort */
1046         AtAbort_Notify();
1047         AtEOXact_UpdatePasswordFile(false);
1048
1049         /* Advertise the fact that we aborted in pg_clog. */
1050         RecordTransactionAbort();
1051
1052         /*
1053          * Let others know about no transaction in progress by me. Note that
1054          * this must be done _before_ releasing locks we hold and _after_
1055          * RecordTransactionAbort.
1056          */
1057         if (MyProc != (PGPROC *) NULL)
1058         {
1059                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1060                 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1061                 MyProc->xid = InvalidTransactionId;
1062                 MyProc->xmin = InvalidTransactionId;
1063                 LWLockRelease(SInvalLock);
1064         }
1065
1066         /*
1067          * Post-abort cleanup.  See notes in CommitTransaction() concerning
1068          * ordering.
1069          */
1070
1071         smgrDoPendingDeletes(false);
1072         AtAbort_Cache();
1073         AtEOXact_Buffers(false);
1074         smgrabort();
1075
1076         AtAbort_Locks();
1077
1078         AtEOXact_GUC(false);
1079         AtEOXact_SPI();
1080         AtEOXact_gist();
1081         AtEOXact_hash();
1082         AtEOXact_nbtree();
1083         AtEOXact_rtree();
1084         AtEOXact_on_commit_actions(false);
1085         AtEOXact_Namespace(false);
1086         AtEOXact_CatCache(false);
1087         AtEOXact_Files();
1088         pgstat_count_xact_rollback();
1089
1090         /*
1091          * State remains TRANS_ABORT until CleanupTransaction().
1092          */
1093         RESUME_INTERRUPTS();
1094 }
1095
1096 /*
1097  *      CleanupTransaction
1098  */
1099 static void
1100 CleanupTransaction(void)
1101 {
1102         TransactionState s = CurrentTransactionState;
1103
1104         /*
1105          * State should still be TRANS_ABORT from AbortTransaction().
1106          */
1107         if (s->state != TRANS_ABORT)
1108                 elog(FATAL, "CleanupTransaction and not in abort state");
1109
1110         /*
1111          * do abort cleanup processing
1112          */
1113         AtCleanup_Portals();            /* now safe to release portal memory */
1114         AtCleanup_Memory();                     /* and transaction memory */
1115
1116         /*
1117          * done with abort processing, set current transaction state back to
1118          * default
1119          */
1120         s->state = TRANS_DEFAULT;
1121 }
1122
1123 /*
1124  *      StartTransactionCommand
1125  */
1126 void
1127 StartTransactionCommand(void)
1128 {
1129         TransactionState s = CurrentTransactionState;
1130
1131         switch (s->blockState)
1132         {
1133                         /*
1134                          * if we aren't in a transaction block, we just do our usual
1135                          * start transaction.
1136                          */
1137                 case TBLOCK_DEFAULT:
1138                         StartTransaction();
1139                         break;
1140
1141                         /*
1142                          * We should never experience this -- if we do it means the
1143                          * BEGIN state was not changed in the previous
1144                          * CommitTransactionCommand().  If we get it, we print a
1145                          * warning and change to the in-progress state.
1146                          */
1147                 case TBLOCK_BEGIN:
1148                         elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1149                         s->blockState = TBLOCK_INPROGRESS;
1150                         break;
1151
1152                         /*
1153                          * This is the case when are somewhere in a transaction block
1154                          * and about to start a new command.  For now we do nothing
1155                          * but someday we may do command-local resource
1156                          * initialization.
1157                          */
1158                 case TBLOCK_INPROGRESS:
1159                         break;
1160
1161                         /*
1162                          * As with BEGIN, we should never experience this if we do it
1163                          * means the END state was not changed in the previous
1164                          * CommitTransactionCommand().  If we get it, we print a
1165                          * warning, commit the transaction, start a new transaction
1166                          * and change to the default state.
1167                          */
1168                 case TBLOCK_END:
1169                         elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
1170                         s->blockState = TBLOCK_DEFAULT;
1171                         CommitTransaction();
1172                         StartTransaction();
1173                         break;
1174
1175                         /*
1176                          * Here we are in the middle of a transaction block but one of
1177                          * the commands caused an abort so we do nothing but remain in
1178                          * the abort state.  Eventually we will get to the "END
1179                          * TRANSACTION" which will set things straight.
1180                          */
1181                 case TBLOCK_ABORT:
1182                         break;
1183
1184                         /*
1185                          * This means we somehow aborted and the last call to
1186                          * CommitTransactionCommand() didn't clear the state so we
1187                          * remain in the ENDABORT state and maybe next time we get to
1188                          * CommitTransactionCommand() the state will get reset to
1189                          * default.
1190                          */
1191                 case TBLOCK_ENDABORT:
1192                         elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1193                         break;
1194         }
1195
1196         /*
1197          * We must switch to TopTransactionContext before returning. This
1198          * is already done if we called StartTransaction, otherwise not.
1199          */
1200         Assert(TopTransactionContext != NULL);
1201         MemoryContextSwitchTo(TopTransactionContext);
1202 }
1203
1204 /*
1205  *      CommitTransactionCommand
1206  */
1207 void
1208 CommitTransactionCommand(void)
1209 {
1210         TransactionState s = CurrentTransactionState;
1211
1212         switch (s->blockState)
1213         {
1214                         /*
1215                          * If we aren't in a transaction block, just do our usual
1216                          * transaction commit.
1217                          */
1218                 case TBLOCK_DEFAULT:
1219                         CommitTransaction();
1220                         break;
1221
1222                         /*
1223                          * This is the case right after we get a "BEGIN TRANSACTION"
1224                          * command, but the user hasn't done anything else yet, so we
1225                          * change to the "transaction block in progress" state and
1226                          * return.
1227                          */
1228                 case TBLOCK_BEGIN:
1229                         s->blockState = TBLOCK_INPROGRESS;
1230                         break;
1231
1232                         /*
1233                          * This is the case when we have finished executing a command
1234                          * someplace within a transaction block.  We increment the
1235                          * command counter and return.
1236                          */
1237                 case TBLOCK_INPROGRESS:
1238                         CommandCounterIncrement();
1239                         break;
1240
1241                         /*
1242                          * This is the case when we just got the "END TRANSACTION"
1243                          * statement, so we commit the transaction and go back to the
1244                          * default state.
1245                          */
1246                 case TBLOCK_END:
1247                         CommitTransaction();
1248                         s->blockState = TBLOCK_DEFAULT;
1249                         break;
1250
1251                         /*
1252                          * Here we are in the middle of a transaction block but one of
1253                          * the commands caused an abort so we do nothing but remain in
1254                          * the abort state.  Eventually we will get to the "END
1255                          * TRANSACTION" which will set things straight.
1256                          */
1257                 case TBLOCK_ABORT:
1258                         break;
1259
1260                         /*
1261                          * Here we were in an aborted transaction block which just
1262                          * processed the "END TRANSACTION" command from the user, so
1263                          * clean up and return to the default state.
1264                          */
1265                 case TBLOCK_ENDABORT:
1266                         CleanupTransaction();
1267                         s->blockState = TBLOCK_DEFAULT;
1268                         break;
1269         }
1270 }
1271
1272 /*
1273  *      AbortCurrentTransaction
1274  */
1275 void
1276 AbortCurrentTransaction(void)
1277 {
1278         TransactionState s = CurrentTransactionState;
1279
1280         switch (s->blockState)
1281         {
1282                         /*
1283                          * if we aren't in a transaction block, we just do the basic
1284                          * abort & cleanup transaction.
1285                          */
1286                 case TBLOCK_DEFAULT:
1287                         AbortTransaction();
1288                         CleanupTransaction();
1289                         break;
1290
1291                         /*
1292                          * If we are in the TBLOCK_BEGIN it means something screwed up
1293                          * right after reading "BEGIN TRANSACTION" so we enter the
1294                          * abort state.  Eventually an "END TRANSACTION" will fix
1295                          * things.
1296                          */
1297                 case TBLOCK_BEGIN:
1298                         s->blockState = TBLOCK_ABORT;
1299                         AbortTransaction();
1300                         /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1301                         break;
1302
1303                         /*
1304                          * This is the case when are somewhere in a transaction block
1305                          * which aborted so we abort the transaction and set the ABORT
1306                          * state.  Eventually an "END TRANSACTION" will fix things and
1307                          * restore us to a normal state.
1308                          */
1309                 case TBLOCK_INPROGRESS:
1310                         s->blockState = TBLOCK_ABORT;
1311                         AbortTransaction();
1312                         /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1313                         break;
1314
1315                         /*
1316                          * Here, the system was fouled up just after the user wanted
1317                          * to end the transaction block so we abort the transaction
1318                          * and put us back into the default state.
1319                          */
1320                 case TBLOCK_END:
1321                         s->blockState = TBLOCK_DEFAULT;
1322                         AbortTransaction();
1323                         CleanupTransaction();
1324                         break;
1325
1326                         /*
1327                          * Here, we are already in an aborted transaction state and
1328                          * are waiting for an "END TRANSACTION" to come along and lo
1329                          * and behold, we abort again! So we just remain in the abort
1330                          * state.
1331                          */
1332                 case TBLOCK_ABORT:
1333                         break;
1334
1335                         /*
1336                          * Here we were in an aborted transaction block which just
1337                          * processed the "END TRANSACTION" command but somehow aborted
1338                          * again.. since we must have done the abort processing, we
1339                          * clean up and return to the default state.
1340                          */
1341                 case TBLOCK_ENDABORT:
1342                         CleanupTransaction();
1343                         s->blockState = TBLOCK_DEFAULT;
1344                         break;
1345         }
1346 }
1347
1348 /*
1349  *      PreventTransactionChain
1350  *
1351  *      This routine is to be called by statements that must not run inside
1352  *      a transaction block, typically because they have non-rollback-able
1353  *      side effects or do internal commits.
1354  *
1355  *      If we have already started a transaction block, issue an error; also issue
1356  *      an error if we appear to be running inside a user-defined function (which
1357  *      could issue more commands and possibly cause a failure after the statement
1358  *      completes).
1359  *
1360  *      stmtNode: pointer to parameter block for statement; this is used in
1361  *      a very klugy way to determine whether we are inside a function.
1362  *      stmtType: statement type name for error messages.
1363  */
1364 void
1365 PreventTransactionChain(void *stmtNode, const char *stmtType)
1366 {
1367         /*
1368          * xact block already started?
1369          */
1370         if (IsTransactionBlock())
1371                 ereport(ERROR,
1372                                 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1373                                  /* translator: %s represents an SQL statement name */
1374                                  errmsg("%s cannot run inside a transaction block",
1375                                                 stmtType)));
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          * Are we inside a function call?  If the statement's parameter block
1419          * was allocated in QueryContext, assume it is an interactive command.
1420          * Otherwise assume it is coming from a function.
1421          */
1422         if (!MemoryContextContains(QueryContext, stmtNode))
1423                 return;
1424         ereport(ERROR,
1425                         (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1426                          /* translator: %s represents an SQL statement name */
1427                          errmsg("%s may only be used in BEGIN/END transaction blocks",
1428                                         stmtType)));
1429 }
1430
1431
1432 /* ----------------------------------------------------------------
1433  *                                         transaction block support
1434  * ----------------------------------------------------------------
1435  */
1436 /*
1437  *      BeginTransactionBlock
1438  */
1439 void
1440 BeginTransactionBlock(void)
1441 {
1442         TransactionState s = CurrentTransactionState;
1443
1444         /*
1445          * check the current transaction state
1446          */
1447         if (s->blockState != TBLOCK_DEFAULT)
1448                 ereport(WARNING,
1449                                 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1450                                  errmsg("there is already a transaction in progress")));
1451
1452         /*
1453          * set the current transaction block state information appropriately
1454          * during begin processing
1455          */
1456         s->blockState = TBLOCK_BEGIN;
1457
1458         /*
1459          * do begin processing here.  Nothing to do at present.
1460          */
1461
1462         /*
1463          * done with begin processing, set block state to inprogress
1464          */
1465         s->blockState = TBLOCK_INPROGRESS;
1466 }
1467
1468 /*
1469  *      EndTransactionBlock
1470  */
1471 void
1472 EndTransactionBlock(void)
1473 {
1474         TransactionState s = CurrentTransactionState;
1475
1476         /*
1477          * check the current transaction state
1478          */
1479         if (s->blockState == TBLOCK_INPROGRESS)
1480         {
1481                 /*
1482                  * here we are in a transaction block which should commit when we
1483                  * get to the upcoming CommitTransactionCommand() so we set the
1484                  * state to "END".      CommitTransactionCommand() will recognize this
1485                  * and commit the transaction and return us to the default state
1486                  */
1487                 s->blockState = TBLOCK_END;
1488                 return;
1489         }
1490
1491         if (s->blockState == TBLOCK_ABORT)
1492         {
1493                 /*
1494                  * here, we are in a transaction block which aborted and since the
1495                  * AbortTransaction() was already done, we do whatever is needed
1496                  * and change to the special "END ABORT" state.  The upcoming
1497                  * CommitTransactionCommand() will recognise this and then put us
1498                  * back in the default state.
1499                  */
1500                 s->blockState = TBLOCK_ENDABORT;
1501                 return;
1502         }
1503
1504         /*
1505          * here, the user issued COMMIT when not inside a transaction. Issue a
1506          * WARNING and go to abort state.  The upcoming call to
1507          * CommitTransactionCommand() will then put us back into the default
1508          * state.
1509          */
1510         ereport(WARNING,
1511                         (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1512                          errmsg("there is no transaction in progress")));
1513         AbortTransaction();
1514         s->blockState = TBLOCK_ENDABORT;
1515 }
1516
1517 /*
1518  *      AbortTransactionBlock
1519  */
1520 #ifdef NOT_USED
1521 static void
1522 AbortTransactionBlock(void)
1523 {
1524         TransactionState s = CurrentTransactionState;
1525
1526         /*
1527          * check the current transaction state
1528          */
1529         if (s->blockState == TBLOCK_INPROGRESS)
1530         {
1531                 /*
1532                  * here we were inside a transaction block something screwed up
1533                  * inside the system so we enter the abort state, do the abort
1534                  * processing and then return. We remain in the abort state until
1535                  * we see an END TRANSACTION command.
1536                  */
1537                 s->blockState = TBLOCK_ABORT;
1538                 AbortTransaction();
1539                 return;
1540         }
1541
1542         /*
1543          * here, the user issued ABORT when not inside a transaction. Issue a
1544          * WARNING and go to abort state.  The upcoming call to
1545          * CommitTransactionCommand() will then put us back into the default
1546          * state.
1547          */
1548         ereport(WARNING,
1549                         (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1550                          errmsg("there is no transaction in progress")));
1551         AbortTransaction();
1552         s->blockState = TBLOCK_ENDABORT;
1553 }
1554 #endif
1555
1556 /*
1557  *      UserAbortTransactionBlock
1558  */
1559 void
1560 UserAbortTransactionBlock(void)
1561 {
1562         TransactionState s = CurrentTransactionState;
1563
1564         /*
1565          * if the transaction has already been automatically aborted with an
1566          * error, and the user subsequently types 'abort', allow it.  (the
1567          * behavior is the same as if they had typed 'end'.)
1568          */
1569         if (s->blockState == TBLOCK_ABORT)
1570         {
1571                 s->blockState = TBLOCK_ENDABORT;
1572                 return;
1573         }
1574
1575         if (s->blockState == TBLOCK_INPROGRESS)
1576         {
1577                 /*
1578                  * here we were inside a transaction block and we got an abort
1579                  * command from the user, so we move to the abort state, do the
1580                  * abort processing and then change to the ENDABORT state so we
1581                  * will end up in the default state after the upcoming
1582                  * CommitTransactionCommand().
1583                  */
1584                 s->blockState = TBLOCK_ABORT;
1585                 AbortTransaction();
1586                 s->blockState = TBLOCK_ENDABORT;
1587                 return;
1588         }
1589
1590         /*
1591          * here, the user issued ABORT when not inside a transaction. Issue a
1592          * WARNING and go to abort state.  The upcoming call to
1593          * CommitTransactionCommand() will then put us back into the default
1594          * state.
1595          */
1596         ereport(WARNING,
1597                         (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
1598                          errmsg("there is no transaction in progress")));
1599         AbortTransaction();
1600         s->blockState = TBLOCK_ENDABORT;
1601 }
1602
1603 /*
1604  *      AbortOutOfAnyTransaction
1605  *
1606  *      This routine is provided for error recovery purposes.  It aborts any
1607  *      active transaction or transaction block, leaving the system in a known
1608  *      idle state.
1609  */
1610 void
1611 AbortOutOfAnyTransaction(void)
1612 {
1613         TransactionState s = CurrentTransactionState;
1614
1615         /*
1616          * Get out of any low-level transaction
1617          */
1618         switch (s->state)
1619         {
1620                 case TRANS_START:
1621                 case TRANS_INPROGRESS:
1622                 case TRANS_COMMIT:
1623                         /* In a transaction, so clean up */
1624                         AbortTransaction();
1625                         CleanupTransaction();
1626                         break;
1627                 case TRANS_ABORT:
1628                         /* AbortTransaction already done, still need Cleanup */
1629                         CleanupTransaction();
1630                         break;
1631                 case TRANS_DEFAULT:
1632                         /* Not in a transaction, do nothing */
1633                         break;
1634         }
1635
1636         /*
1637          * Now reset the high-level state
1638          */
1639         s->blockState = TBLOCK_DEFAULT;
1640 }
1641
1642 /*
1643  * IsTransactionBlock --- are we within a transaction block?
1644  */
1645 bool
1646 IsTransactionBlock(void)
1647 {
1648         TransactionState s = CurrentTransactionState;
1649
1650         if (s->blockState == TBLOCK_DEFAULT)
1651                 return false;
1652
1653         return true;
1654 }
1655
1656 /*
1657  * TransactionBlockStatusCode - return status code to send in ReadyForQuery
1658  */
1659 char
1660 TransactionBlockStatusCode(void)
1661 {
1662         TransactionState s = CurrentTransactionState;
1663
1664         switch (s->blockState)
1665         {
1666                 case TBLOCK_DEFAULT:
1667                         return 'I';                     /* idle --- not in transaction */
1668                 case TBLOCK_BEGIN:
1669                 case TBLOCK_INPROGRESS:
1670                 case TBLOCK_END:
1671                         return 'T';                     /* in transaction */
1672                 case TBLOCK_ABORT:
1673                 case TBLOCK_ENDABORT:
1674                         return 'E';                     /* in failed transaction */
1675         }
1676
1677         /* should never get here */
1678         elog(ERROR, "invalid transaction block state: %d",
1679                  (int) s->blockState);
1680         return 0;                                       /* keep compiler quiet */
1681 }
1682
1683
1684 /*
1685  *      XLOG support routines
1686  */
1687
1688 void
1689 xact_redo(XLogRecPtr lsn, XLogRecord *record)
1690 {
1691         uint8           info = record->xl_info & ~XLR_INFO_MASK;
1692
1693         if (info == XLOG_XACT_COMMIT)
1694         {
1695                 TransactionIdCommit(record->xl_xid);
1696                 /* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
1697         }
1698         else if (info == XLOG_XACT_ABORT)
1699         {
1700                 TransactionIdAbort(record->xl_xid);
1701                 /* SHOULD REMOVE FILES OF ALL FAILED-TO-BE-CREATED RELATIONS */
1702         }
1703         else
1704                 elog(PANIC, "xact_redo: unknown op code %u", info);
1705 }
1706
1707 void
1708 xact_undo(XLogRecPtr lsn, XLogRecord *record)
1709 {
1710         uint8           info = record->xl_info & ~XLR_INFO_MASK;
1711
1712         if (info == XLOG_XACT_COMMIT)           /* shouldn't be called by XLOG */
1713                 elog(PANIC, "xact_undo: can't undo committed xaction");
1714         else if (info != XLOG_XACT_ABORT)
1715                 elog(PANIC, "xact_redo: unknown op code %u", info);
1716 }
1717
1718 void
1719 xact_desc(char *buf, uint8 xl_info, char *rec)
1720 {
1721         uint8           info = xl_info & ~XLR_INFO_MASK;
1722
1723         if (info == XLOG_XACT_COMMIT)
1724         {
1725                 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
1726                 struct tm  *tm = localtime(&xlrec->xtime);
1727
1728                 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
1729                                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1730                                 tm->tm_hour, tm->tm_min, tm->tm_sec);
1731         }
1732         else if (info == XLOG_XACT_ABORT)
1733         {
1734                 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
1735                 struct tm  *tm = localtime(&xlrec->xtime);
1736
1737                 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
1738                                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1739                                 tm->tm_hour, tm->tm_min, tm->tm_sec);
1740         }
1741         else
1742                 strcat(buf, "UNKNOWN");
1743 }
1744
1745 void
1746                         XactPushRollback(void (*func) (void *), void *data)
1747 {
1748 #ifdef XLOG_II
1749         if (_RollbackFunc != NULL)
1750                 elog(PANIC, "XactPushRollback: already installed");
1751 #endif
1752
1753         _RollbackFunc = func;
1754         _RollbackData = data;
1755 }
1756
1757 void
1758 XactPopRollback(void)
1759 {
1760         _RollbackFunc = NULL;
1761 }