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