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