]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xact.c
c0ef2ca7637f3096741115886086e4cfdc707e7d
[postgresql] / src / backend / access / transam / xact.c
1 /*-------------------------------------------------------------------------
2  *
3  * xact.c
4  *        top level transaction system support routines
5  *
6  * See src/backend/access/transam/README for more information.
7  *
8  * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.184 2004/08/30 02:54:38 momjian Exp $
14  *
15  *-------------------------------------------------------------------------
16  */
17
18 #include "postgres.h"
19
20 #include <time.h>
21 #include <unistd.h>
22
23 #include "access/subtrans.h"
24 #include "access/xact.h"
25 #include "catalog/heap.h"
26 #include "catalog/index.h"
27 #include "catalog/namespace.h"
28 #include "commands/async.h"
29 #include "commands/tablecmds.h"
30 #include "commands/trigger.h"
31 #include "commands/user.h"
32 #include "executor/spi.h"
33 #include "libpq/be-fsstubs.h"
34 #include "miscadmin.h"
35 #include "storage/fd.h"
36 #include "storage/proc.h"
37 #include "storage/sinval.h"
38 #include "storage/smgr.h"
39 #include "utils/guc.h"
40 #include "utils/inval.h"
41 #include "utils/memutils.h"
42 #include "utils/portal.h"
43 #include "utils/relcache.h"
44 #include "utils/resowner.h"
45 #include "pgstat.h"
46
47
48 /*
49  *      transaction states - transaction state from server perspective
50  */
51 typedef enum TransState
52 {
53         TRANS_DEFAULT,
54         TRANS_START,
55         TRANS_INPROGRESS,
56         TRANS_COMMIT,
57         TRANS_ABORT
58 } TransState;
59
60 /*
61  *      transaction block states - transaction state of client queries
62  */
63 typedef enum TBlockState
64 {
65         /* not-in-transaction-block states */
66         TBLOCK_DEFAULT,
67         TBLOCK_STARTED,
68
69         /* transaction block states */
70         TBLOCK_BEGIN,
71         TBLOCK_INPROGRESS,
72         TBLOCK_END,
73         TBLOCK_ABORT,
74         TBLOCK_ENDABORT,
75
76         /* subtransaction states */
77         TBLOCK_SUBBEGIN,
78         TBLOCK_SUBINPROGRESS,
79         TBLOCK_SUBEND,
80         TBLOCK_SUBABORT,
81         TBLOCK_SUBABORT_PENDING,
82         TBLOCK_SUBENDABORT_ALL,
83         TBLOCK_SUBENDABORT_RELEASE,
84         TBLOCK_SUBENDABORT
85 } TBlockState;
86
87 /*
88  *      transaction state structure
89  */
90 typedef struct TransactionStateData
91 {
92         TransactionId transactionIdData;        /* my XID */
93         char       *name;                       /* savepoint name, if any */
94         int                     savepointLevel; /* savepoint level */
95         CommandId       commandId;              /* current CID */
96         TransState      state;                  /* low-level state */
97         TBlockState blockState;         /* high-level state */
98         int                     nestingLevel;   /* nest depth */
99         MemoryContext curTransactionContext;            /* my xact-lifetime
100                                                                                                  * context */
101         ResourceOwner curTransactionOwner;      /* my query resources */
102         List       *childXids;          /* subcommitted child XIDs */
103         AclId           currentUser;    /* subxact start current_user */
104         bool            prevXactReadOnly;               /* entry-time xact r/o state */
105         struct TransactionStateData *parent;            /* back link to parent */
106 } TransactionStateData;
107
108 typedef TransactionStateData *TransactionState;
109
110 /*
111  * childXids is currently implemented as an integer List, relying on the
112  * assumption that TransactionIds are no wider than int.  We use these
113  * macros to provide some isolation in case that changes in the future.
114  */
115 #define lfirst_xid(lc)                          ((TransactionId) lfirst_int(lc))
116 #define lappend_xid(list, datum)        lappend_int(list, (int) (datum))
117
118
119 static void AbortTransaction(void);
120 static void AtAbort_Memory(void);
121 static void AtCleanup_Memory(void);
122 static void AtCommit_LocalCache(void);
123 static void AtCommit_Memory(void);
124 static void AtStart_Cache(void);
125 static void AtStart_Memory(void);
126 static void AtStart_ResourceOwner(void);
127 static void CallXactCallbacks(XactEvent event, TransactionId parentXid);
128 static void CleanupTransaction(void);
129 static void CommitTransaction(void);
130 static void RecordTransactionAbort(void);
131 static void StartTransaction(void);
132
133 static void RecordSubTransactionCommit(void);
134 static void StartSubTransaction(void);
135 static void CommitSubTransaction(void);
136 static void AbortSubTransaction(void);
137 static void CleanupSubTransaction(void);
138 static void StartAbortedSubTransaction(void);
139 static void PushTransaction(void);
140 static void PopTransaction(void);
141 static void CommitTransactionToLevel(int level);
142 static char *CleanupAbortedSubTransactions(bool returnName);
143
144 static void AtSubAbort_Memory(void);
145 static void AtSubCleanup_Memory(void);
146 static void AtSubCommit_Memory(void);
147 static void AtSubStart_Memory(void);
148 static void AtSubStart_ResourceOwner(void);
149
150 static void ShowTransactionState(const char *str);
151 static void ShowTransactionStateRec(TransactionState state);
152 static const char *BlockStateAsString(TBlockState blockState);
153 static const char *TransStateAsString(TransState state);
154
155 /*
156  * CurrentTransactionState always points to the current transaction state
157  * block.  It will point to TopTransactionStateData when not in a
158  * transaction at all, or when in a top-level transaction.
159  */
160 static TransactionStateData TopTransactionStateData = {
161         0,                                                      /* transaction id */
162         NULL,                                           /* savepoint name */
163         0,                                                      /* savepoint level */
164         FirstCommandId,                         /* command id */
165         TRANS_DEFAULT,                          /* transaction state */
166         TBLOCK_DEFAULT,                         /* transaction block state from the client
167                                                                  * perspective */
168         0,                                                      /* nesting level */
169         NULL,                                           /* cur transaction context */
170         NULL,                                           /* cur transaction resource owner */
171         NIL,                                            /* subcommitted child Xids */
172         0,                                                      /* entry-time current userid */
173         false,                                          /* entry-time xact r/o state */
174         NULL                                            /* link to parent state block */
175 };
176
177 static TransactionState CurrentTransactionState = &TopTransactionStateData;
178
179 /*
180  * These vars hold the value of now(), ie, the transaction start time.
181  * This does not change as we enter and exit subtransactions, so we don't
182  * keep it inside the TransactionState stack.
183  */
184 static AbsoluteTime xactStartTime;              /* integer part */
185 static int      xactStartTimeUsec;      /* microsecond part */
186
187
188 /*
189  *      User-tweakable parameters
190  */
191 int                     DefaultXactIsoLevel = XACT_READ_COMMITTED;
192 int                     XactIsoLevel;
193
194 bool            DefaultXactReadOnly = false;
195 bool            XactReadOnly;
196
197 int                     CommitDelay = 0;        /* precommit delay in microseconds */
198 int                     CommitSiblings = 5; /* number of concurrent xacts needed to
199                                                                  * sleep */
200
201
202 /*
203  * List of add-on start- and end-of-xact callbacks
204  */
205 typedef struct XactCallbackItem
206 {
207         struct XactCallbackItem *next;
208         XactCallback callback;
209         void       *arg;
210 } XactCallbackItem;
211
212 static XactCallbackItem *Xact_callbacks = NULL;
213
214 static void (*_RollbackFunc) (void *) = NULL;
215 static void *_RollbackData = NULL;
216
217
218 /* ----------------------------------------------------------------
219  *      transaction state accessors
220  * ----------------------------------------------------------------
221  */
222
223 /*
224  *      IsTransactionState
225  *
226  *      This returns true if we are currently running a query
227  *      within an executing transaction.
228  */
229 bool
230 IsTransactionState(void)
231 {
232         TransactionState s = CurrentTransactionState;
233
234         switch (s->state)
235         {
236                 case TRANS_DEFAULT:
237                         return false;
238                 case TRANS_START:
239                         return true;
240                 case TRANS_INPROGRESS:
241                         return true;
242                 case TRANS_COMMIT:
243                         return true;
244                 case TRANS_ABORT:
245                         return true;
246         }
247
248         /*
249          * Shouldn't get here, but lint is not happy with this...
250          */
251         return false;
252 }
253
254 /*
255  *      IsAbortedTransactionBlockState
256  *
257  *      This returns true if we are currently running a query
258  *      within an aborted transaction block.
259  */
260 bool
261 IsAbortedTransactionBlockState(void)
262 {
263         TransactionState s = CurrentTransactionState;
264
265         if (s->blockState == TBLOCK_ABORT ||
266                 s->blockState == TBLOCK_SUBABORT)
267                 return true;
268
269         return false;
270 }
271
272
273 /*
274  *      GetTopTransactionId
275  *
276  * Get the ID of the main transaction, even if we are currently inside
277  * a subtransaction.
278  */
279 TransactionId
280 GetTopTransactionId(void)
281 {
282         return TopTransactionStateData.transactionIdData;
283 }
284
285
286 /*
287  *      GetCurrentTransactionId
288  */
289 TransactionId
290 GetCurrentTransactionId(void)
291 {
292         TransactionState s = CurrentTransactionState;
293
294         return s->transactionIdData;
295 }
296
297
298 /*
299  *      GetCurrentCommandId
300  */
301 CommandId
302 GetCurrentCommandId(void)
303 {
304         TransactionState s = CurrentTransactionState;
305
306         return s->commandId;
307 }
308
309
310 /*
311  *      GetCurrentTransactionStartTime
312  */
313 AbsoluteTime
314 GetCurrentTransactionStartTime(void)
315 {
316         return xactStartTime;
317 }
318
319
320 /*
321  *      GetCurrentTransactionStartTimeUsec
322  */
323 AbsoluteTime
324 GetCurrentTransactionStartTimeUsec(int *msec)
325 {
326         *msec = xactStartTimeUsec;
327         return xactStartTime;
328 }
329
330
331 /*
332  *      GetCurrentTransactionNestLevel
333  *
334  * Note: this will return zero when not inside any transaction, one when
335  * inside a top-level transaction, etc.
336  */
337 int
338 GetCurrentTransactionNestLevel(void)
339 {
340         TransactionState s = CurrentTransactionState;
341
342         return s->nestingLevel;
343 }
344
345
346 /*
347  *      TransactionIdIsCurrentTransactionId
348  *
349  *      During bootstrap, we cheat and say "it's not my transaction ID" even though
350  *      it is.  Along with transam.c's cheat to say that the bootstrap XID is
351  *      already committed, this causes the tqual.c routines to see previously
352  *      inserted tuples as committed, which is what we need during bootstrap.
353  */
354 bool
355 TransactionIdIsCurrentTransactionId(TransactionId xid)
356 {
357         TransactionState s;
358
359         if (AMI_OVERRIDE)
360         {
361                 Assert(xid == BootstrapTransactionId);
362                 return false;
363         }
364
365         /*
366          * We will return true for the Xid of the current subtransaction, any
367          * of its subcommitted children, any of its parents, or any of their
368          * previously subcommitted children.  However, a transaction being
369          * aborted is no longer "current", even though it may still have an
370          * entry on the state stack.
371          */
372         for (s = CurrentTransactionState; s != NULL; s = s->parent)
373         {
374                 ListCell   *cell;
375
376                 if (s->state == TRANS_ABORT)
377                         continue;
378                 if (TransactionIdEquals(xid, s->transactionIdData))
379                         return true;
380                 foreach(cell, s->childXids)
381                 {
382                         if (TransactionIdEquals(xid, lfirst_xid(cell)))
383                                 return true;
384                 }
385         }
386
387         return false;
388 }
389
390
391 /*
392  *      CommandCounterIncrement
393  */
394 void
395 CommandCounterIncrement(void)
396 {
397         TransactionState s = CurrentTransactionState;
398
399         s->commandId += 1;
400         if (s->commandId == FirstCommandId) /* check for overflow */
401                 ereport(ERROR,
402                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
403                                  errmsg("cannot have more than 2^32-1 commands in a transaction")));
404
405         /* Propagate new command ID into query snapshots, if set */
406         if (QuerySnapshot)
407                 QuerySnapshot->curcid = s->commandId;
408         if (SerializableSnapshot)
409                 SerializableSnapshot->curcid = s->commandId;
410
411         /*
412          * make cache changes visible to me.
413          */
414         AtCommit_LocalCache();
415         AtStart_Cache();
416 }
417
418
419 /* ----------------------------------------------------------------
420  *                                              StartTransaction stuff
421  * ----------------------------------------------------------------
422  */
423
424 /*
425  *      AtStart_Cache
426  */
427 static void
428 AtStart_Cache(void)
429 {
430         AcceptInvalidationMessages();
431 }
432
433 /*
434  *      AtStart_Memory
435  */
436 static void
437 AtStart_Memory(void)
438 {
439         TransactionState s = CurrentTransactionState;
440
441         /*
442          * We shouldn't have a transaction context already.
443          */
444         Assert(TopTransactionContext == NULL);
445
446         /*
447          * Create a toplevel context for the transaction.
448          */
449         TopTransactionContext =
450                 AllocSetContextCreate(TopMemoryContext,
451                                                           "TopTransactionContext",
452                                                           ALLOCSET_DEFAULT_MINSIZE,
453                                                           ALLOCSET_DEFAULT_INITSIZE,
454                                                           ALLOCSET_DEFAULT_MAXSIZE);
455
456         /*
457          * In a top-level transaction, CurTransactionContext is the same as
458          * TopTransactionContext.
459          */
460         CurTransactionContext = TopTransactionContext;
461         s->curTransactionContext = CurTransactionContext;
462
463         /* Make the CurTransactionContext active. */
464         MemoryContextSwitchTo(CurTransactionContext);
465 }
466
467 /*
468  *      AtStart_ResourceOwner
469  */
470 static void
471 AtStart_ResourceOwner(void)
472 {
473         TransactionState s = CurrentTransactionState;
474
475         /*
476          * We shouldn't have a transaction resource owner already.
477          */
478         Assert(TopTransactionResourceOwner == NULL);
479
480         /*
481          * Create a toplevel resource owner for the transaction.
482          */
483         s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
484
485         TopTransactionResourceOwner = s->curTransactionOwner;
486         CurTransactionResourceOwner = s->curTransactionOwner;
487         CurrentResourceOwner = s->curTransactionOwner;
488 }
489
490 /* ----------------------------------------------------------------
491  *                                              StartSubTransaction stuff
492  * ----------------------------------------------------------------
493  */
494
495 /*
496  * AtSubStart_Memory
497  */
498 static void
499 AtSubStart_Memory(void)
500 {
501         TransactionState s = CurrentTransactionState;
502
503         Assert(CurTransactionContext != NULL);
504
505         /*
506          * Create a CurTransactionContext, which will be used to hold data
507          * that survives subtransaction commit but disappears on
508          * subtransaction abort. We make it a child of the immediate parent's
509          * CurTransactionContext.
510          */
511         CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
512                                                                                                   "CurTransactionContext",
513                                                                                                 ALLOCSET_DEFAULT_MINSIZE,
514                                                                                            ALLOCSET_DEFAULT_INITSIZE,
515                                                                                            ALLOCSET_DEFAULT_MAXSIZE);
516         s->curTransactionContext = CurTransactionContext;
517
518         /* Make the CurTransactionContext active. */
519         MemoryContextSwitchTo(CurTransactionContext);
520 }
521
522 /*
523  * AtSubStart_ResourceOwner
524  */
525 static void
526 AtSubStart_ResourceOwner(void)
527 {
528         TransactionState s = CurrentTransactionState;
529
530         Assert(s->parent != NULL);
531
532         /*
533          * Create a resource owner for the subtransaction.      We make it a child
534          * of the immediate parent's resource owner.
535          */
536         s->curTransactionOwner =
537                 ResourceOwnerCreate(s->parent->curTransactionOwner,
538                                                         "SubTransaction");
539
540         CurTransactionResourceOwner = s->curTransactionOwner;
541         CurrentResourceOwner = s->curTransactionOwner;
542 }
543
544 /* ----------------------------------------------------------------
545  *                                              CommitTransaction stuff
546  * ----------------------------------------------------------------
547  */
548
549 /*
550  *      RecordTransactionCommit
551  */
552 void
553 RecordTransactionCommit(void)
554 {
555         int                     nrels;
556         RelFileNode *rptr;
557         int                     nchildren;
558         TransactionId *children;
559
560         /* Get data needed for commit record */
561         nrels = smgrGetPendingDeletes(true, &rptr);
562         nchildren = xactGetCommittedChildren(&children);
563
564         /*
565          * If we made neither any XLOG entries nor any temp-rel updates, and
566          * have no files to be deleted, we can omit recording the transaction
567          * commit at all.  (This test includes the effects of subtransactions,
568          * so the presence of committed subxacts need not alone force a
569          * write.)
570          */
571         if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)
572         {
573                 TransactionId xid = GetCurrentTransactionId();
574                 bool            madeTCentries;
575                 XLogRecPtr      recptr;
576
577                 /* Tell bufmgr and smgr to prepare for commit */
578                 BufmgrCommit();
579
580                 START_CRIT_SECTION();
581
582                 /*
583                  * If our transaction made any transaction-controlled XLOG
584                  * entries, we need to lock out checkpoint start between writing
585                  * our XLOG record and updating pg_clog.  Otherwise it is possible
586                  * for the checkpoint to set REDO after the XLOG record but fail
587                  * to flush the pg_clog update to disk, leading to loss of the
588                  * transaction commit if we crash a little later.  Slightly klugy
589                  * fix for problem discovered 2004-08-10.
590                  *
591                  * (If it made no transaction-controlled XLOG entries, its XID
592                  * appears nowhere in permanent storage, so no one else will ever
593                  * care if it committed; so it doesn't matter if we lose the
594                  * commit flag.)
595                  *
596                  * Note we only need a shared lock.
597                  */
598                 madeTCentries = (MyLastRecPtr.xrecoff != 0);
599                 if (madeTCentries)
600                         LWLockAcquire(CheckpointStartLock, LW_SHARED);
601
602                 /*
603                  * We only need to log the commit in XLOG if the transaction made
604                  * any transaction-controlled XLOG entries or will delete files.
605                  */
606                 if (madeTCentries || nrels > 0)
607                 {
608                         XLogRecData rdata[3];
609                         int                     lastrdata = 0;
610                         xl_xact_commit xlrec;
611
612                         xlrec.xtime = time(NULL);
613                         xlrec.nrels = nrels;
614                         xlrec.nsubxacts = nchildren;
615                         rdata[0].buffer = InvalidBuffer;
616                         rdata[0].data = (char *) (&xlrec);
617                         rdata[0].len = MinSizeOfXactCommit;
618                         /* dump rels to delete */
619                         if (nrels > 0)
620                         {
621                                 rdata[0].next = &(rdata[1]);
622                                 rdata[1].buffer = InvalidBuffer;
623                                 rdata[1].data = (char *) rptr;
624                                 rdata[1].len = nrels * sizeof(RelFileNode);
625                                 lastrdata = 1;
626                         }
627                         /* dump committed child Xids */
628                         if (nchildren > 0)
629                         {
630                                 rdata[lastrdata].next = &(rdata[2]);
631                                 rdata[2].buffer = InvalidBuffer;
632                                 rdata[2].data = (char *) children;
633                                 rdata[2].len = nchildren * sizeof(TransactionId);
634                                 lastrdata = 2;
635                         }
636                         rdata[lastrdata].next = NULL;
637
638                         recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
639                 }
640                 else
641                 {
642                         /* Just flush through last record written by me */
643                         recptr = ProcLastRecEnd;
644                 }
645
646                 /*
647                  * We must flush our XLOG entries to disk if we made any XLOG
648                  * entries, whether in or out of transaction control.  For
649                  * example, if we reported a nextval() result to the client, this
650                  * ensures that any XLOG record generated by nextval will hit the
651                  * disk before we report the transaction committed.
652                  *
653                  * Note: if we generated a commit record above, MyXactMadeXLogEntry
654                  * will certainly be set now.
655                  */
656                 if (MyXactMadeXLogEntry)
657                 {
658                         /*
659                          * Sleep before flush! So we can flush more than one commit
660                          * records per single fsync.  (The idea is some other backend
661                          * may do the XLogFlush while we're sleeping.  This needs work
662                          * still, because on most Unixen, the minimum select() delay
663                          * is 10msec or more, which is way too long.)
664                          *
665                          * We do not sleep if enableFsync is not turned on, nor if there
666                          * are fewer than CommitSiblings other backends with active
667                          * transactions.
668                          */
669                         if (CommitDelay > 0 && enableFsync &&
670                                 CountActiveBackends() >= CommitSiblings)
671                                 pg_usleep(CommitDelay);
672
673                         XLogFlush(recptr);
674                 }
675
676                 /*
677                  * We must mark the transaction committed in clog if its XID
678                  * appears either in permanent rels or in local temporary rels. We
679                  * test this by seeing if we made transaction-controlled entries
680                  * *OR* local-rel tuple updates.  Note that if we made only the
681                  * latter, we have not emitted an XLOG record for our commit, and
682                  * so in the event of a crash the clog update might be lost.  This
683                  * is okay because no one else will ever care whether we
684                  * committed.
685                  */
686                 if (madeTCentries || MyXactMadeTempRelUpdate)
687                 {
688                         TransactionIdCommit(xid);
689                         /* to avoid race conditions, the parent must commit first */
690                         TransactionIdCommitTree(nchildren, children);
691                 }
692
693                 /* Unlock checkpoint lock if we acquired it */
694                 if (madeTCentries)
695                         LWLockRelease(CheckpointStartLock);
696
697                 END_CRIT_SECTION();
698         }
699
700         /* Break the chain of back-links in the XLOG records I output */
701         MyLastRecPtr.xrecoff = 0;
702         MyXactMadeXLogEntry = false;
703         MyXactMadeTempRelUpdate = false;
704
705         /* Show myself as out of the transaction in PGPROC array */
706         MyProc->logRec.xrecoff = 0;
707
708         /* And clean up local data */
709         if (rptr)
710                 pfree(rptr);
711         if (children)
712                 pfree(children);
713 }
714
715
716 /*
717  *      AtCommit_LocalCache
718  */
719 static void
720 AtCommit_LocalCache(void)
721 {
722         /*
723          * Make catalog changes visible to me for the next command.
724          */
725         CommandEndInvalidationMessages();
726 }
727
728 /*
729  *      AtCommit_Memory
730  */
731 static void
732 AtCommit_Memory(void)
733 {
734         /*
735          * Now that we're "out" of a transaction, have the system allocate
736          * things in the top memory context instead of per-transaction
737          * contexts.
738          */
739         MemoryContextSwitchTo(TopMemoryContext);
740
741         /*
742          * Release all transaction-local memory.
743          */
744         Assert(TopTransactionContext != NULL);
745         MemoryContextDelete(TopTransactionContext);
746         TopTransactionContext = NULL;
747         CurTransactionContext = NULL;
748         CurrentTransactionState->curTransactionContext = NULL;
749 }
750
751 /* ----------------------------------------------------------------
752  *                                              CommitSubTransaction stuff
753  * ----------------------------------------------------------------
754  */
755
756 /*
757  * AtSubCommit_Memory
758  *
759  * We do not throw away the child's CurTransactionContext, since the data
760  * it contains will be needed at upper commit.
761  */
762 static void
763 AtSubCommit_Memory(void)
764 {
765         TransactionState s = CurrentTransactionState;
766
767         Assert(s->parent != NULL);
768
769         /* Return to parent transaction level's memory context. */
770         CurTransactionContext = s->parent->curTransactionContext;
771         MemoryContextSwitchTo(CurTransactionContext);
772 }
773
774 /*
775  * AtSubCommit_childXids
776  *
777  * Pass my own XID and my child XIDs up to my parent as committed children.
778  */
779 static void
780 AtSubCommit_childXids(void)
781 {
782         TransactionState s = CurrentTransactionState;
783         MemoryContext old_cxt;
784
785         Assert(s->parent != NULL);
786
787         old_cxt = MemoryContextSwitchTo(s->parent->curTransactionContext);
788
789         s->parent->childXids = lappend_xid(s->parent->childXids,
790                                                                            s->transactionIdData);
791
792         s->parent->childXids = list_concat(s->parent->childXids, s->childXids);
793         s->childXids = NIL;                     /* ensure list not doubly referenced */
794
795         MemoryContextSwitchTo(old_cxt);
796 }
797
798 /*
799  * RecordSubTransactionCommit
800  */
801 static void
802 RecordSubTransactionCommit(void)
803 {
804         /*
805          * We do not log the subcommit in XLOG; it doesn't matter until the
806          * top-level transaction commits.
807          *
808          * We must mark the subtransaction subcommitted in clog if its XID
809          * appears either in permanent rels or in local temporary rels. We
810          * test this by seeing if we made transaction-controlled entries *OR*
811          * local-rel tuple updates.  (The test here actually covers the entire
812          * transaction tree so far, so it may mark subtransactions that don't
813          * really need it, but it's probably not worth being tenser. Note that
814          * if a prior subtransaction dirtied these variables, then
815          * RecordTransactionCommit will have to do the full pushup anyway...)
816          */
817         if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
818         {
819                 TransactionId xid = GetCurrentTransactionId();
820
821                 /* XXX does this really need to be a critical section? */
822                 START_CRIT_SECTION();
823
824                 /* Record subtransaction subcommit */
825                 TransactionIdSubCommit(xid);
826
827                 END_CRIT_SECTION();
828         }
829 }
830
831 /* ----------------------------------------------------------------
832  *                                              AbortTransaction stuff
833  * ----------------------------------------------------------------
834  */
835
836 /*
837  *      RecordTransactionAbort
838  */
839 static void
840 RecordTransactionAbort(void)
841 {
842         int                     nrels;
843         RelFileNode *rptr;
844         int                     nchildren;
845         TransactionId *children;
846
847         /* Get data needed for abort record */
848         nrels = smgrGetPendingDeletes(false, &rptr);
849         nchildren = xactGetCommittedChildren(&children);
850
851         /*
852          * If we made neither any transaction-controlled XLOG entries nor any
853          * temp-rel updates, and are not going to delete any files, we can
854          * omit recording the transaction abort at all.  No one will ever care
855          * that it aborted.  (These tests cover our whole transaction tree.)
856          */
857         if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
858         {
859                 TransactionId xid = GetCurrentTransactionId();
860
861                 /*
862                  * Catch the scenario where we aborted partway through
863                  * RecordTransactionCommit ...
864                  */
865                 if (TransactionIdDidCommit(xid))
866                         elog(PANIC, "cannot abort transaction %u, it was already committed", xid);
867
868                 START_CRIT_SECTION();
869
870                 /*
871                  * We only need to log the abort in XLOG if the transaction made
872                  * any transaction-controlled XLOG entries or will delete files.
873                  * (If it made no transaction-controlled XLOG entries, its XID
874                  * appears nowhere in permanent storage, so no one else will ever
875                  * care if it committed.)
876                  *
877                  * We do not flush XLOG to disk unless deleting files, since the
878                  * default assumption after a crash would be that we aborted,
879                  * anyway. For the same reason, we don't need to worry about
880                  * interlocking against checkpoint start.
881                  */
882                 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
883                 {
884                         XLogRecData rdata[3];
885                         int                     lastrdata = 0;
886                         xl_xact_abort xlrec;
887                         XLogRecPtr      recptr;
888
889                         xlrec.xtime = time(NULL);
890                         xlrec.nrels = nrels;
891                         xlrec.nsubxacts = nchildren;
892                         rdata[0].buffer = InvalidBuffer;
893                         rdata[0].data = (char *) (&xlrec);
894                         rdata[0].len = MinSizeOfXactAbort;
895                         /* dump rels to delete */
896                         if (nrels > 0)
897                         {
898                                 rdata[0].next = &(rdata[1]);
899                                 rdata[1].buffer = InvalidBuffer;
900                                 rdata[1].data = (char *) rptr;
901                                 rdata[1].len = nrels * sizeof(RelFileNode);
902                                 lastrdata = 1;
903                         }
904                         /* dump committed child Xids */
905                         if (nchildren > 0)
906                         {
907                                 rdata[lastrdata].next = &(rdata[2]);
908                                 rdata[2].buffer = InvalidBuffer;
909                                 rdata[2].data = (char *) children;
910                                 rdata[2].len = nchildren * sizeof(TransactionId);
911                                 lastrdata = 2;
912                         }
913                         rdata[lastrdata].next = NULL;
914
915                         recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
916
917                         /* Must flush if we are deleting files... */
918                         if (nrels > 0)
919                                 XLogFlush(recptr);
920                 }
921
922                 /*
923                  * Mark the transaction aborted in clog.  This is not absolutely
924                  * necessary but we may as well do it while we are here.
925                  *
926                  * The ordering here isn't critical but it seems best to mark the
927                  * parent first.  This assures an atomic transition of all the
928                  * subtransactions to aborted state from the point of view of
929                  * concurrent TransactionIdDidAbort calls.
930                  */
931                 TransactionIdAbort(xid);
932                 TransactionIdAbortTree(nchildren, children);
933
934                 END_CRIT_SECTION();
935         }
936
937         /* Break the chain of back-links in the XLOG records I output */
938         MyLastRecPtr.xrecoff = 0;
939         MyXactMadeXLogEntry = false;
940         MyXactMadeTempRelUpdate = false;
941
942         /* Show myself as out of the transaction in PGPROC array */
943         MyProc->logRec.xrecoff = 0;
944
945         /* And clean up local data */
946         if (rptr)
947                 pfree(rptr);
948         if (children)
949                 pfree(children);
950 }
951
952 /*
953  *      AtAbort_Memory
954  */
955 static void
956 AtAbort_Memory(void)
957 {
958         /*
959          * Make sure we are in a valid context (not a child of
960          * TopTransactionContext...).  Note that it is possible for this code
961          * to be called when we aren't in a transaction at all; go directly to
962          * TopMemoryContext in that case.
963          */
964         if (TopTransactionContext != NULL)
965         {
966                 MemoryContextSwitchTo(TopTransactionContext);
967
968                 /*
969                  * We do not want to destroy the transaction's global state yet,
970                  * so we can't free any memory here.
971                  */
972         }
973         else
974                 MemoryContextSwitchTo(TopMemoryContext);
975 }
976
977
978 /*
979  * AtSubAbort_Memory
980  */
981 static void
982 AtSubAbort_Memory(void)
983 {
984         Assert(TopTransactionContext != NULL);
985
986         MemoryContextSwitchTo(TopTransactionContext);
987 }
988
989 /*
990  * RecordSubTransactionAbort
991  */
992 static void
993 RecordSubTransactionAbort(void)
994 {
995         int                     nrels;
996         RelFileNode *rptr;
997         TransactionId xid = GetCurrentTransactionId();
998         int                     nchildren;
999         TransactionId *children;
1000
1001         /* Get data needed for abort record */
1002         nrels = smgrGetPendingDeletes(false, &rptr);
1003         nchildren = xactGetCommittedChildren(&children);
1004
1005         /*
1006          * If we made neither any transaction-controlled XLOG entries nor any
1007          * temp-rel updates, and are not going to delete any files, we can
1008          * omit recording the transaction abort at all.  No one will ever care
1009          * that it aborted.  (These tests cover our whole transaction tree,
1010          * and therefore may mark subxacts that don't really need it, but it's
1011          * probably not worth being tenser.)
1012          *
1013          * In this case we needn't worry about marking subcommitted children as
1014          * aborted, because they didn't mark themselves as subcommitted in the
1015          * first place; see the optimization in RecordSubTransactionCommit.
1016          */
1017         if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
1018         {
1019                 START_CRIT_SECTION();
1020
1021                 /*
1022                  * We only need to log the abort in XLOG if the transaction made
1023                  * any transaction-controlled XLOG entries or will delete files.
1024                  */
1025                 if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1026                 {
1027                         XLogRecData rdata[3];
1028                         int                     lastrdata = 0;
1029                         xl_xact_abort xlrec;
1030                         XLogRecPtr      recptr;
1031
1032                         xlrec.xtime = time(NULL);
1033                         xlrec.nrels = nrels;
1034                         xlrec.nsubxacts = nchildren;
1035                         rdata[0].buffer = InvalidBuffer;
1036                         rdata[0].data = (char *) (&xlrec);
1037                         rdata[0].len = MinSizeOfXactAbort;
1038                         /* dump rels to delete */
1039                         if (nrels > 0)
1040                         {
1041                                 rdata[0].next = &(rdata[1]);
1042                                 rdata[1].buffer = InvalidBuffer;
1043                                 rdata[1].data = (char *) rptr;
1044                                 rdata[1].len = nrels * sizeof(RelFileNode);
1045                                 lastrdata = 1;
1046                         }
1047                         /* dump committed child Xids */
1048                         if (nchildren > 0)
1049                         {
1050                                 rdata[lastrdata].next = &(rdata[2]);
1051                                 rdata[2].buffer = InvalidBuffer;
1052                                 rdata[2].data = (char *) children;
1053                                 rdata[2].len = nchildren * sizeof(TransactionId);
1054                                 lastrdata = 2;
1055                         }
1056                         rdata[lastrdata].next = NULL;
1057
1058                         recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1059
1060                         /* Must flush if we are deleting files... */
1061                         if (nrels > 0)
1062                                 XLogFlush(recptr);
1063                 }
1064
1065                 /*
1066                  * Mark the transaction aborted in clog.  This is not absolutely
1067                  * necessary but we may as well do it while we are here.
1068                  */
1069                 TransactionIdAbort(xid);
1070                 TransactionIdAbortTree(nchildren, children);
1071
1072                 END_CRIT_SECTION();
1073         }
1074
1075         /*
1076          * We can immediately remove failed XIDs from PGPROC's cache of
1077          * running child XIDs. It's easiest to do it here while we have the
1078          * child XID array at hand, even though in the main-transaction case
1079          * the equivalent work happens just after return from
1080          * RecordTransactionAbort.
1081          */
1082         XidCacheRemoveRunningXids(xid, nchildren, children);
1083
1084         /* And clean up local data */
1085         if (rptr)
1086                 pfree(rptr);
1087         if (children)
1088                 pfree(children);
1089 }
1090
1091 /* ----------------------------------------------------------------
1092  *                                              CleanupTransaction stuff
1093  * ----------------------------------------------------------------
1094  */
1095
1096 /*
1097  *      AtCleanup_Memory
1098  */
1099 static void
1100 AtCleanup_Memory(void)
1101 {
1102         /*
1103          * Now that we're "out" of a transaction, have the system allocate
1104          * things in the top memory context instead of per-transaction
1105          * contexts.
1106          */
1107         MemoryContextSwitchTo(TopMemoryContext);
1108
1109         Assert(CurrentTransactionState->parent == NULL);
1110
1111         /*
1112          * Release all transaction-local memory.
1113          */
1114         if (TopTransactionContext != NULL)
1115                 MemoryContextDelete(TopTransactionContext);
1116         TopTransactionContext = NULL;
1117         CurTransactionContext = NULL;
1118         CurrentTransactionState->curTransactionContext = NULL;
1119 }
1120
1121
1122 /* ----------------------------------------------------------------
1123  *                                              CleanupSubTransaction stuff
1124  * ----------------------------------------------------------------
1125  */
1126
1127 /*
1128  * AtSubCleanup_Memory
1129  */
1130 static void
1131 AtSubCleanup_Memory(void)
1132 {
1133         TransactionState s = CurrentTransactionState;
1134
1135         Assert(s->parent != NULL);
1136
1137         /* Make sure we're not in an about-to-be-deleted context */
1138         MemoryContextSwitchTo(s->parent->curTransactionContext);
1139         CurTransactionContext = s->parent->curTransactionContext;
1140
1141         /*
1142          * Delete the subxact local memory contexts. Its CurTransactionContext
1143          * can go too (note this also kills CurTransactionContexts from any
1144          * children of the subxact).
1145          */
1146         MemoryContextDelete(s->curTransactionContext);
1147 }
1148
1149 /* ----------------------------------------------------------------
1150  *                                              interface routines
1151  * ----------------------------------------------------------------
1152  */
1153
1154 /*
1155  *      StartTransaction
1156  */
1157 static void
1158 StartTransaction(void)
1159 {
1160         TransactionState s = CurrentTransactionState;
1161
1162         /*
1163          * check the current transaction state
1164          */
1165         if (s->state != TRANS_DEFAULT)
1166                 elog(WARNING, "StartTransaction while in %s state",
1167                          TransStateAsString(s->state));
1168
1169         /*
1170          * set the current transaction state information appropriately during
1171          * start processing
1172          */
1173         s->state = TRANS_START;
1174
1175         /*
1176          * Make sure we've freed any old snapshot, and reset xact state
1177          * variables
1178          */
1179         FreeXactSnapshot();
1180         XactIsoLevel = DefaultXactIsoLevel;
1181         XactReadOnly = DefaultXactReadOnly;
1182
1183         /*
1184          * must initialize resource-management stuff first
1185          */
1186         AtStart_Memory();
1187         AtStart_ResourceOwner();
1188
1189         /*
1190          * generate a new transaction id
1191          */
1192         s->transactionIdData = GetNewTransactionId(false);
1193
1194         XactLockTableInsert(s->transactionIdData);
1195
1196         /*
1197          * set now()
1198          */
1199         xactStartTime = GetCurrentAbsoluteTimeUsec(&(xactStartTimeUsec));
1200
1201         /*
1202          * initialize current transaction state fields
1203          */
1204         s->commandId = FirstCommandId;
1205         s->nestingLevel = 1;
1206         s->childXids = NIL;
1207
1208         /*
1209          * You might expect to see "s->currentUser = GetUserId();" here, but
1210          * you won't because it doesn't work during startup; the userid isn't
1211          * set yet during a backend's first transaction start.  We only use
1212          * the currentUser field in sub-transaction state structs.
1213          *
1214          * prevXactReadOnly is also valid only in sub-transactions.
1215          */
1216
1217         /*
1218          * initialize other subsystems for new transaction
1219          */
1220         AtStart_Inval();
1221         AtStart_Cache();
1222         DeferredTriggerBeginXact();
1223
1224         /*
1225          * done with start processing, set current transaction state to "in
1226          * progress"
1227          */
1228         s->state = TRANS_INPROGRESS;
1229
1230         ShowTransactionState("StartTransaction");
1231 }
1232
1233 /*
1234  *      CommitTransaction
1235  */
1236 static void
1237 CommitTransaction(void)
1238 {
1239         TransactionState s = CurrentTransactionState;
1240
1241         ShowTransactionState("CommitTransaction");
1242
1243         /*
1244          * check the current transaction state
1245          */
1246         if (s->state != TRANS_INPROGRESS)
1247                 elog(WARNING, "CommitTransaction while in %s state",
1248                          TransStateAsString(s->state));
1249         Assert(s->parent == NULL);
1250
1251         /*
1252          * Tell the trigger manager that this transaction is about to be
1253          * committed. He'll invoke all trigger deferred until XACT before we
1254          * really start on committing the transaction.
1255          */
1256         DeferredTriggerEndXact();
1257
1258         /*
1259          * Similarly, let ON COMMIT management do its thing before we start to
1260          * commit.
1261          */
1262         PreCommit_on_commit_actions();
1263
1264         /* Prevent cancel/die interrupt while cleaning up */
1265         HOLD_INTERRUPTS();
1266
1267         /*
1268          * set the current transaction state information appropriately during
1269          * the abort processing
1270          */
1271         s->state = TRANS_COMMIT;
1272
1273         /*
1274          * Do pre-commit processing (most of this stuff requires database
1275          * access, and in fact could still cause an error...)
1276          */
1277
1278         AtCommit_Portals();
1279
1280         /* close large objects before lower-level cleanup */
1281         AtEOXact_LargeObject(true);
1282
1283         /* NOTIFY commit must come before lower-level cleanup */
1284         AtCommit_Notify();
1285
1286         /* Update the flat password file if we changed pg_shadow or pg_group */
1287         /* This should be the last step before commit */
1288         AtEOXact_UpdatePasswordFile(true);
1289
1290         /*
1291          * Here is where we really truly commit.
1292          */
1293         RecordTransactionCommit();
1294
1295         /*
1296          * Let others know about no transaction in progress by me. Note that
1297          * this must be done _before_ releasing locks we hold and _after_
1298          * RecordTransactionCommit.
1299          *
1300          * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
1301          * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
1302          * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
1303          * as running as well or it will see two tuple versions - one deleted
1304          * by xid 1 and one inserted by xid 0.  See notes in GetSnapshotData.
1305          */
1306         if (MyProc != NULL)
1307         {
1308                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1309                 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1310                 MyProc->xid = InvalidTransactionId;
1311                 MyProc->xmin = InvalidTransactionId;
1312
1313                 /* Clear the subtransaction-XID cache too while holding the lock */
1314                 MyProc->subxids.nxids = 0;
1315                 MyProc->subxids.overflowed = false;
1316
1317                 LWLockRelease(SInvalLock);
1318         }
1319
1320         /*
1321          * This is all post-commit cleanup.  Note that if an error is raised
1322          * here, it's too late to abort the transaction.  This should be just
1323          * noncritical resource releasing.
1324          *
1325          * The ordering of operations is not entirely random.  The idea is:
1326          * release resources visible to other backends (eg, files, buffer
1327          * pins); then release locks; then release backend-local resources. We
1328          * want to release locks at the point where any backend waiting for us
1329          * will see our transaction as being fully cleaned up.
1330          *
1331          * Resources that can be associated with individual queries are handled
1332          * by the ResourceOwner mechanism.      The other calls here are for
1333          * backend-wide state.
1334          */
1335
1336         smgrDoPendingDeletes(true);
1337         /* smgrcommit already done */
1338
1339         CallXactCallbacks(XACT_EVENT_COMMIT, InvalidTransactionId);
1340
1341         ResourceOwnerRelease(TopTransactionResourceOwner,
1342                                                  RESOURCE_RELEASE_BEFORE_LOCKS,
1343                                                  true, true);
1344
1345         /*
1346          * Make catalog changes visible to all backends.  This has to happen
1347          * after relcache references are dropped (see comments for
1348          * AtEOXact_RelationCache), but before locks are released (if anyone
1349          * is waiting for lock on a relation we've modified, we want them to
1350          * know about the catalog change before they start using the
1351          * relation).
1352          */
1353         AtEOXact_Inval(true);
1354
1355         ResourceOwnerRelease(TopTransactionResourceOwner,
1356                                                  RESOURCE_RELEASE_LOCKS,
1357                                                  true, true);
1358         ResourceOwnerRelease(TopTransactionResourceOwner,
1359                                                  RESOURCE_RELEASE_AFTER_LOCKS,
1360                                                  true, true);
1361
1362         AtEOXact_GUC(true, false);
1363         AtEOXact_SPI(true);
1364         AtEOXact_on_commit_actions(true, s->transactionIdData);
1365         AtEOXact_Namespace(true);
1366         AtEOXact_Files();
1367         pgstat_count_xact_commit();
1368
1369         CurrentResourceOwner = NULL;
1370         ResourceOwnerDelete(TopTransactionResourceOwner);
1371         s->curTransactionOwner = NULL;
1372         CurTransactionResourceOwner = NULL;
1373         TopTransactionResourceOwner = NULL;
1374
1375         AtCommit_Memory();
1376
1377         s->nestingLevel = 0;
1378         s->childXids = NIL;
1379
1380         /*
1381          * done with commit processing, set current transaction state back to
1382          * default
1383          */
1384         s->state = TRANS_DEFAULT;
1385
1386         RESUME_INTERRUPTS();
1387 }
1388
1389 /*
1390  *      AbortTransaction
1391  */
1392 static void
1393 AbortTransaction(void)
1394 {
1395         TransactionState s = CurrentTransactionState;
1396
1397         /* Prevent cancel/die interrupt while cleaning up */
1398         HOLD_INTERRUPTS();
1399
1400         /*
1401          * Release any LW locks we might be holding as quickly as possible.
1402          * (Regular locks, however, must be held till we finish aborting.)
1403          * Releasing LW locks is critical since we might try to grab them
1404          * again while cleaning up!
1405          */
1406         LWLockReleaseAll();
1407
1408         /* Clean up buffer I/O and buffer context locks, too */
1409         AbortBufferIO();
1410         UnlockBuffers();
1411
1412         /*
1413          * Also clean up any open wait for lock, since the lock manager will
1414          * choke if we try to wait for another lock before doing this.
1415          */
1416         LockWaitCancel();
1417
1418         /*
1419          * check the current transaction state
1420          */
1421         if (s->state != TRANS_INPROGRESS)
1422                 elog(WARNING, "AbortTransaction while in %s state",
1423                          TransStateAsString(s->state));
1424         Assert(s->parent == NULL);
1425
1426         /*
1427          * set the current transaction state information appropriately during
1428          * the abort processing
1429          */
1430         s->state = TRANS_ABORT;
1431
1432         /* Make sure we are in a valid memory context */
1433         AtAbort_Memory();
1434
1435         /*
1436          * Reset user id which might have been changed transiently.  We cannot
1437          * use s->currentUser, but must get the session userid from
1438          * miscinit.c.
1439          *
1440          * (Note: it is not necessary to restore session authorization here
1441          * because that can only be changed via GUC, and GUC will take care of
1442          * rolling it back if need be.  However, an error within a SECURITY
1443          * DEFINER function could send control here with the wrong current
1444          * userid.)
1445          */
1446         SetUserId(GetSessionUserId());
1447
1448         /*
1449          * do abort processing
1450          */
1451         DeferredTriggerAbortXact();
1452         AtAbort_Portals();
1453         AtEOXact_LargeObject(false);    /* 'false' means it's abort */
1454         AtAbort_Notify();
1455         AtEOXact_UpdatePasswordFile(false);
1456
1457         /* Advertise the fact that we aborted in pg_clog. */
1458         RecordTransactionAbort();
1459
1460         /*
1461          * Let others know about no transaction in progress by me. Note that
1462          * this must be done _before_ releasing locks we hold and _after_
1463          * RecordTransactionAbort.
1464          */
1465         if (MyProc != NULL)
1466         {
1467                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1468                 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1469                 MyProc->xid = InvalidTransactionId;
1470                 MyProc->xmin = InvalidTransactionId;
1471
1472                 /* Clear the subtransaction-XID cache too while holding the lock */
1473                 MyProc->subxids.nxids = 0;
1474                 MyProc->subxids.overflowed = false;
1475
1476                 LWLockRelease(SInvalLock);
1477         }
1478
1479         /*
1480          * Post-abort cleanup.  See notes in CommitTransaction() concerning
1481          * ordering.
1482          */
1483
1484         smgrDoPendingDeletes(false);
1485         smgrabort();
1486
1487         CallXactCallbacks(XACT_EVENT_ABORT, InvalidTransactionId);
1488
1489         ResourceOwnerRelease(TopTransactionResourceOwner,
1490                                                  RESOURCE_RELEASE_BEFORE_LOCKS,
1491                                                  false, true);
1492         AtEOXact_Inval(false);
1493         ResourceOwnerRelease(TopTransactionResourceOwner,
1494                                                  RESOURCE_RELEASE_LOCKS,
1495                                                  false, true);
1496         ResourceOwnerRelease(TopTransactionResourceOwner,
1497                                                  RESOURCE_RELEASE_AFTER_LOCKS,
1498                                                  false, true);
1499
1500         AtEOXact_GUC(false, false);
1501         AtEOXact_SPI(false);
1502         AtEOXact_on_commit_actions(false, s->transactionIdData);
1503         AtEOXact_Namespace(false);
1504         AtEOXact_Files();
1505         pgstat_count_xact_rollback();
1506
1507         /*
1508          * State remains TRANS_ABORT until CleanupTransaction().
1509          */
1510         RESUME_INTERRUPTS();
1511 }
1512
1513 /*
1514  *      CleanupTransaction
1515  */
1516 static void
1517 CleanupTransaction(void)
1518 {
1519         TransactionState s = CurrentTransactionState;
1520
1521         /*
1522          * State should still be TRANS_ABORT from AbortTransaction().
1523          */
1524         if (s->state != TRANS_ABORT)
1525                 elog(FATAL, "CleanupTransaction: unexpected state %s",
1526                          TransStateAsString(s->state));
1527
1528         /*
1529          * do abort cleanup processing
1530          */
1531         AtCleanup_Portals();            /* now safe to release portal memory */
1532
1533         CurrentResourceOwner = NULL;    /* and resource owner */
1534         ResourceOwnerDelete(TopTransactionResourceOwner);
1535         s->curTransactionOwner = NULL;
1536         CurTransactionResourceOwner = NULL;
1537         TopTransactionResourceOwner = NULL;
1538
1539         AtCleanup_Memory();                     /* and transaction memory */
1540
1541         s->nestingLevel = 0;
1542         s->childXids = NIL;
1543
1544         /*
1545          * done with abort processing, set current transaction state back to
1546          * default
1547          */
1548         s->state = TRANS_DEFAULT;
1549 }
1550
1551 /*
1552  *      StartTransactionCommand
1553  */
1554 void
1555 StartTransactionCommand(void)
1556 {
1557         TransactionState s = CurrentTransactionState;
1558
1559         switch (s->blockState)
1560         {
1561                         /*
1562                          * if we aren't in a transaction block, we just do our usual
1563                          * start transaction.
1564                          */
1565                 case TBLOCK_DEFAULT:
1566                         StartTransaction();
1567                         s->blockState = TBLOCK_STARTED;
1568                         break;
1569
1570                         /*
1571                          * This is the case when we are somewhere in a transaction
1572                          * block and about to start a new command.      For now we do
1573                          * nothing but someday we may do command-local resource
1574                          * initialization.
1575                          */
1576                 case TBLOCK_INPROGRESS:
1577                 case TBLOCK_SUBINPROGRESS:
1578                         break;
1579
1580                         /*
1581                          * Here we are in the middle of a transaction block but one of
1582                          * the commands caused an abort so we do nothing but remain in
1583                          * the abort state.  Eventually we will get to the "END
1584                          * TRANSACTION" which will set things straight.
1585                          */
1586                 case TBLOCK_ABORT:
1587                 case TBLOCK_SUBABORT:
1588                         break;
1589
1590                         /* These cases are invalid. */
1591                 case TBLOCK_STARTED:
1592                 case TBLOCK_BEGIN:
1593                 case TBLOCK_SUBBEGIN:
1594                 case TBLOCK_END:
1595                 case TBLOCK_SUBEND:
1596                 case TBLOCK_SUBENDABORT_ALL:
1597                 case TBLOCK_SUBENDABORT:
1598                 case TBLOCK_SUBABORT_PENDING:
1599                 case TBLOCK_SUBENDABORT_RELEASE:
1600                 case TBLOCK_ENDABORT:
1601                         elog(FATAL, "StartTransactionCommand: unexpected state %s",
1602                                  BlockStateAsString(s->blockState));
1603                         break;
1604         }
1605
1606         /*
1607          * We must switch to CurTransactionContext before returning. This is
1608          * already done if we called StartTransaction, otherwise not.
1609          */
1610         Assert(CurTransactionContext != NULL);
1611         MemoryContextSwitchTo(CurTransactionContext);
1612 }
1613
1614 /*
1615  *      CommitTransactionCommand
1616  */
1617 void
1618 CommitTransactionCommand(void)
1619 {
1620         TransactionState s = CurrentTransactionState;
1621
1622         switch (s->blockState)
1623         {
1624                         /*
1625                          * This shouldn't happen, because it means the previous
1626                          * StartTransactionCommand didn't set the STARTED state
1627                          * appropriately, or we didn't manage previous pending abort
1628                          * states.
1629                          */
1630                 case TBLOCK_DEFAULT:
1631                 case TBLOCK_SUBABORT_PENDING:
1632                         elog(FATAL, "CommitTransactionCommand: unexpected state %s",
1633                                  BlockStateAsString(s->blockState));
1634                         break;
1635
1636                         /*
1637                          * If we aren't in a transaction block, just do our usual
1638                          * transaction commit.
1639                          */
1640                 case TBLOCK_STARTED:
1641                         CommitTransaction();
1642                         s->blockState = TBLOCK_DEFAULT;
1643                         break;
1644
1645                         /*
1646                          * This is the case right after we get a "BEGIN TRANSACTION"
1647                          * command, but the user hasn't done anything else yet, so we
1648                          * change to the "transaction block in progress" state and
1649                          * return.
1650                          */
1651                 case TBLOCK_BEGIN:
1652                         s->blockState = TBLOCK_INPROGRESS;
1653                         break;
1654
1655                         /*
1656                          * This is the case when we have finished executing a command
1657                          * someplace within a transaction block.  We increment the
1658                          * command counter and return.
1659                          */
1660                 case TBLOCK_INPROGRESS:
1661                         CommandCounterIncrement();
1662                         break;
1663
1664                         /*
1665                          * This is the case when we just got the "END TRANSACTION"
1666                          * statement, so we commit the transaction and go back to the
1667                          * default state.
1668                          */
1669                 case TBLOCK_END:
1670                         /* commit all open subtransactions */
1671                         if (s->nestingLevel > 1)
1672                                 CommitTransactionToLevel(2);
1673                         s = CurrentTransactionState;
1674                         Assert(s->parent == NULL);
1675                         /* and now the outer transaction */
1676                         CommitTransaction();
1677                         s->blockState = TBLOCK_DEFAULT;
1678                         break;
1679
1680                         /*
1681                          * Here we are in the middle of a transaction block but one of
1682                          * the commands caused an abort so we do nothing but remain in
1683                          * the abort state.  Eventually we will get to the "END
1684                          * TRANSACTION" which will set things straight.
1685                          */
1686                 case TBLOCK_ABORT:
1687                         break;
1688
1689                         /*
1690                          * Here we were in an aborted transaction block which just
1691                          * processed the "END TRANSACTION" command from the user, so
1692                          * clean up and return to the default state.
1693                          */
1694                 case TBLOCK_ENDABORT:
1695                         CleanupTransaction();
1696                         s->blockState = TBLOCK_DEFAULT;
1697                         break;
1698
1699                         /*
1700                          * Ditto, but in a subtransaction.      AbortOutOfAnyTransaction
1701                          * will do the dirty work.
1702                          */
1703                 case TBLOCK_SUBENDABORT_ALL:
1704                         AbortOutOfAnyTransaction();
1705                         s = CurrentTransactionState;            /* changed by
1706                                                                                                  * AbortOutOfAnyTransaction
1707                                                                                                  * */
1708                         /* AbortOutOfAnyTransaction sets the blockState */
1709                         break;
1710
1711                         /*
1712                          * We were just issued a SAVEPOINT inside a transaction block.
1713                          * Start a subtransaction.      (DefineSavepoint already did
1714                          * PushTransaction, so as to have someplace to put the
1715                          * SUBBEGIN state.)
1716                          */
1717                 case TBLOCK_SUBBEGIN:
1718                         StartSubTransaction();
1719                         s->blockState = TBLOCK_SUBINPROGRESS;
1720                         break;
1721
1722                         /*
1723                          * Inside a subtransaction, increment the command counter.
1724                          */
1725                 case TBLOCK_SUBINPROGRESS:
1726                         CommandCounterIncrement();
1727                         break;
1728
1729                         /*
1730                          * We were issued a RELEASE command, so we end the current
1731                          * subtransaction and return to the parent transaction.
1732                          *
1733                          * Since RELEASE can exit multiple levels of subtransaction, we
1734                          * must loop here until we get out of all SUBEND'ed levels.
1735                          */
1736                 case TBLOCK_SUBEND:
1737                         do
1738                         {
1739                                 CommitSubTransaction();
1740                                 PopTransaction();
1741                                 s = CurrentTransactionState;    /* changed by pop */
1742                         } while (s->blockState == TBLOCK_SUBEND);
1743                         break;
1744
1745                         /*
1746                          * If we are in an aborted subtransaction, do nothing.
1747                          */
1748                 case TBLOCK_SUBABORT:
1749                         break;
1750
1751                         /*
1752                          * The current subtransaction is ending.  Do the equivalent of
1753                          * a ROLLBACK TO followed by a RELEASE command.
1754                          */
1755                 case TBLOCK_SUBENDABORT_RELEASE:
1756                         CleanupAbortedSubTransactions(false);
1757                         break;
1758
1759                         /*
1760                          * The current subtransaction is ending due to a ROLLBACK TO
1761                          * command, so close all savepoints up to the target level.
1762                          * When finished, recreate the savepoint.
1763                          */
1764                 case TBLOCK_SUBENDABORT:
1765                         {
1766                                 char       *name = CleanupAbortedSubTransactions(true);
1767
1768                                 Assert(PointerIsValid(name));
1769                                 DefineSavepoint(name);
1770                                 s = CurrentTransactionState;    /* changed by
1771                                                                                                  * DefineSavepoint */
1772                                 pfree(name);
1773
1774                                 /* This is the same as TBLOCK_SUBBEGIN case */
1775                                 AssertState(s->blockState == TBLOCK_SUBBEGIN);
1776                                 StartSubTransaction();
1777                                 s->blockState = TBLOCK_SUBINPROGRESS;
1778                         }
1779                         break;
1780         }
1781 }
1782
1783 /*
1784  * CleanupAbortedSubTransactions
1785  *
1786  * Helper function for CommitTransactionCommand.  Aborts and cleans up
1787  * dead subtransactions after a ROLLBACK TO command.  Optionally returns
1788  * the name of the last dead subtransaction so it can be reused to redefine
1789  * the savepoint.  (Caller is responsible for pfree'ing the result.)
1790  */
1791 static char *
1792 CleanupAbortedSubTransactions(bool returnName)
1793 {
1794         TransactionState s = CurrentTransactionState;
1795         char       *name = NULL;
1796
1797         AssertState(PointerIsValid(s->parent));
1798         Assert(s->parent->blockState == TBLOCK_SUBINPROGRESS ||
1799                    s->parent->blockState == TBLOCK_INPROGRESS ||
1800                    s->parent->blockState == TBLOCK_STARTED ||
1801                    s->parent->blockState == TBLOCK_SUBABORT_PENDING);
1802
1803         /*
1804          * Abort everything up to the target level.  The current
1805          * subtransaction only needs cleanup.  If we need to save the name,
1806          * look for the last subtransaction in TBLOCK_SUBABORT_PENDING state.
1807          */
1808         if (returnName && s->parent->blockState != TBLOCK_SUBABORT_PENDING)
1809                 name = MemoryContextStrdup(TopMemoryContext, s->name);
1810
1811         CleanupSubTransaction();
1812         PopTransaction();
1813         s = CurrentTransactionState;    /* changed by pop */
1814
1815         while (s->blockState == TBLOCK_SUBABORT_PENDING)
1816         {
1817                 AbortSubTransaction();
1818                 if (returnName && s->parent->blockState != TBLOCK_SUBABORT_PENDING)
1819                         name = MemoryContextStrdup(TopMemoryContext, s->name);
1820                 CleanupSubTransaction();
1821                 PopTransaction();
1822                 s = CurrentTransactionState;
1823         }
1824
1825         AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
1826                                 s->blockState == TBLOCK_INPROGRESS ||
1827                                 s->blockState == TBLOCK_STARTED);
1828
1829         return name;
1830 }
1831
1832 /*
1833  *      AbortCurrentTransaction
1834  */
1835 void
1836 AbortCurrentTransaction(void)
1837 {
1838         TransactionState s = CurrentTransactionState;
1839
1840         switch (s->blockState)
1841         {
1842                         /*
1843                          * we aren't in a transaction, so we do nothing.
1844                          */
1845                 case TBLOCK_DEFAULT:
1846                         break;
1847
1848                         /*
1849                          * if we aren't in a transaction block, we just do the basic
1850                          * abort & cleanup transaction.
1851                          */
1852                 case TBLOCK_STARTED:
1853                         AbortTransaction();
1854                         CleanupTransaction();
1855                         s->blockState = TBLOCK_DEFAULT;
1856                         break;
1857
1858                         /*
1859                          * If we are in TBLOCK_BEGIN it means something screwed up
1860                          * right after reading "BEGIN TRANSACTION" so we enter the
1861                          * abort state.  Eventually an "END TRANSACTION" will fix
1862                          * things.
1863                          */
1864                 case TBLOCK_BEGIN:
1865                         AbortTransaction();
1866                         s->blockState = TBLOCK_ABORT;
1867                         /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
1868                         break;
1869
1870                         /*
1871                          * This is the case when we are somewhere in a transaction
1872                          * block and we've gotten a failure, so we abort the
1873                          * transaction and set up the persistent ABORT state.  We will
1874                          * stay in ABORT until we get an "END TRANSACTION".
1875                          */
1876                 case TBLOCK_INPROGRESS:
1877                         AbortTransaction();
1878                         s->blockState = TBLOCK_ABORT;
1879                         /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
1880                         break;
1881
1882                         /*
1883                          * Here, the system was fouled up just after the user wanted
1884                          * to end the transaction block so we abort the transaction
1885                          * and return to the default state.
1886                          */
1887                 case TBLOCK_END:
1888                         AbortTransaction();
1889                         CleanupTransaction();
1890                         s->blockState = TBLOCK_DEFAULT;
1891                         break;
1892
1893                         /*
1894                          * Here, we are already in an aborted transaction state and
1895                          * are waiting for an "END TRANSACTION" to come along and lo
1896                          * and behold, we abort again! So we just remain in the abort
1897                          * state.
1898                          */
1899                 case TBLOCK_ABORT:
1900                 case TBLOCK_SUBABORT:
1901                         break;
1902
1903                         /*
1904                          * Here we were in an aborted transaction block which just
1905                          * processed the "END TRANSACTION" command but somehow aborted
1906                          * again.. since we must have done the abort processing, we
1907                          * clean up and return to the default state.
1908                          */
1909                 case TBLOCK_ENDABORT:
1910                         CleanupTransaction();
1911                         s->blockState = TBLOCK_DEFAULT;
1912                         break;
1913
1914                         /*
1915                          * If we are just starting a subtransaction, put it in aborted
1916                          * state.
1917                          */
1918                 case TBLOCK_SUBBEGIN:
1919                         StartAbortedSubTransaction();
1920                         s->blockState = TBLOCK_SUBABORT;
1921                         break;
1922
1923                 case TBLOCK_SUBINPROGRESS:
1924                         AbortSubTransaction();
1925                         s->blockState = TBLOCK_SUBABORT;
1926                         break;
1927
1928                         /*
1929                          * If we are aborting an ending transaction, we have to abort
1930                          * the parent transaction too.
1931                          */
1932                 case TBLOCK_SUBEND:
1933                 case TBLOCK_SUBABORT_PENDING:
1934                         AbortSubTransaction();
1935                         CleanupSubTransaction();
1936                         PopTransaction();
1937                         s = CurrentTransactionState;            /* changed by pop */
1938                         Assert(s->blockState != TBLOCK_SUBEND &&
1939                                    s->blockState != TBLOCK_SUBENDABORT);
1940                         AbortCurrentTransaction();
1941                         break;
1942
1943                         /*
1944                          * Same as above, except the Abort() was already done.
1945                          */
1946                 case TBLOCK_SUBENDABORT:
1947                 case TBLOCK_SUBENDABORT_RELEASE:
1948                         CleanupSubTransaction();
1949                         PopTransaction();
1950                         s = CurrentTransactionState;            /* changed by pop */
1951                         Assert(s->blockState != TBLOCK_SUBEND &&
1952                                    s->blockState != TBLOCK_SUBENDABORT);
1953                         AbortCurrentTransaction();
1954                         break;
1955
1956                         /*
1957                          * We are already aborting the whole transaction tree. Do
1958                          * nothing, CommitTransactionCommand will call
1959                          * AbortOutOfAnyTransaction and set things straight.
1960                          */
1961                 case TBLOCK_SUBENDABORT_ALL:
1962                         break;
1963         }
1964 }
1965
1966 /*
1967  *      PreventTransactionChain
1968  *
1969  *      This routine is to be called by statements that must not run inside
1970  *      a transaction block, typically because they have non-rollback-able
1971  *      side effects or do internal commits.
1972  *
1973  *      If we have already started a transaction block, issue an error; also issue
1974  *      an error if we appear to be running inside a user-defined function (which
1975  *      could issue more commands and possibly cause a failure after the statement
1976  *      completes).  Subtransactions are verboten too.
1977  *
1978  *      stmtNode: pointer to parameter block for statement; this is used in
1979  *      a very klugy way to determine whether we are inside a function.
1980  *      stmtType: statement type name for error messages.
1981  */
1982 void
1983 PreventTransactionChain(void *stmtNode, const char *stmtType)
1984 {
1985         /*
1986          * xact block already started?
1987          */
1988         if (IsTransactionBlock())
1989                 ereport(ERROR,
1990                                 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1991                 /* translator: %s represents an SQL statement name */
1992                                  errmsg("%s cannot run inside a transaction block",
1993                                                 stmtType)));
1994
1995         /*
1996          * subtransaction?
1997          */
1998         if (IsSubTransaction())
1999                 ereport(ERROR,
2000                                 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2001                 /* translator: %s represents an SQL statement name */
2002                                  errmsg("%s cannot run inside a subtransaction",
2003                                                 stmtType)));
2004
2005         /*
2006          * Are we inside a function call?  If the statement's parameter block
2007          * was allocated in QueryContext, assume it is an interactive command.
2008          * Otherwise assume it is coming from a function.
2009          */
2010         if (!MemoryContextContains(QueryContext, stmtNode))
2011                 ereport(ERROR,
2012                                 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2013                 /* translator: %s represents an SQL statement name */
2014                          errmsg("%s cannot be executed from a function", stmtType)));
2015
2016         /* If we got past IsTransactionBlock test, should be in default state */
2017         if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2018                 CurrentTransactionState->blockState != TBLOCK_STARTED)
2019                 elog(FATAL, "cannot prevent transaction chain");
2020         /* all okay */
2021 }
2022
2023 /*
2024  *      RequireTransactionChain
2025  *
2026  *      This routine is to be called by statements that must run inside
2027  *      a transaction block, because they have no effects that persist past
2028  *      transaction end (and so calling them outside a transaction block
2029  *      is presumably an error).  DECLARE CURSOR is an example.
2030  *
2031  *      If we appear to be running inside a user-defined function, we do not
2032  *      issue an error, since the function could issue more commands that make
2033  *      use of the current statement's results.  Likewise subtransactions.
2034  *      Thus this is an inverse for PreventTransactionChain.
2035  *
2036  *      stmtNode: pointer to parameter block for statement; this is used in
2037  *      a very klugy way to determine whether we are inside a function.
2038  *      stmtType: statement type name for error messages.
2039  */
2040 void
2041 RequireTransactionChain(void *stmtNode, const char *stmtType)
2042 {
2043         /*
2044          * xact block already started?
2045          */
2046         if (IsTransactionBlock())
2047                 return;
2048
2049         /*
2050          * subtransaction?
2051          */
2052         if (IsSubTransaction())
2053                 return;
2054
2055         /*
2056          * Are we inside a function call?  If the statement's parameter block
2057          * was allocated in QueryContext, assume it is an interactive command.
2058          * Otherwise assume it is coming from a function.
2059          */
2060         if (!MemoryContextContains(QueryContext, stmtNode))
2061                 return;
2062         ereport(ERROR,
2063                         (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2064         /* translator: %s represents an SQL statement name */
2065                          errmsg("%s may only be used in transaction blocks",
2066                                         stmtType)));
2067 }
2068
2069 /*
2070  *      IsInTransactionChain
2071  *
2072  *      This routine is for statements that need to behave differently inside
2073  *      a transaction block than when running as single commands.  ANALYZE is
2074  *      currently the only example.
2075  *
2076  *      stmtNode: pointer to parameter block for statement; this is used in
2077  *      a very klugy way to determine whether we are inside a function.
2078  */
2079 bool
2080 IsInTransactionChain(void *stmtNode)
2081 {
2082         /*
2083          * Return true on same conditions that would make
2084          * PreventTransactionChain error out
2085          */
2086         if (IsTransactionBlock())
2087                 return true;
2088
2089         if (IsSubTransaction())
2090                 return true;
2091
2092         if (!MemoryContextContains(QueryContext, stmtNode))
2093                 return true;
2094
2095         if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2096                 CurrentTransactionState->blockState != TBLOCK_STARTED)
2097                 return true;
2098
2099         return false;
2100 }
2101
2102
2103 /*
2104  * Register or deregister callback functions for start- and end-of-xact
2105  * operations.
2106  *
2107  * These functions are intended for use by dynamically loaded modules.
2108  * For built-in modules we generally just hardwire the appropriate calls
2109  * (mainly because it's easier to control the order that way, where needed).
2110  *
2111  * At transaction end, the callback occurs post-commit or post-abort, so the
2112  * callback functions can only do noncritical cleanup.  At subtransaction
2113  * start, the callback is called when the subtransaction has finished
2114  * initializing.
2115  */
2116 void
2117 RegisterXactCallback(XactCallback callback, void *arg)
2118 {
2119         XactCallbackItem *item;
2120
2121         item = (XactCallbackItem *)
2122                 MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
2123         item->callback = callback;
2124         item->arg = arg;
2125         item->next = Xact_callbacks;
2126         Xact_callbacks = item;
2127 }
2128
2129 void
2130 UnregisterXactCallback(XactCallback callback, void *arg)
2131 {
2132         XactCallbackItem *item;
2133         XactCallbackItem *prev;
2134
2135         prev = NULL;
2136         for (item = Xact_callbacks; item; prev = item, item = item->next)
2137         {
2138                 if (item->callback == callback && item->arg == arg)
2139                 {
2140                         if (prev)
2141                                 prev->next = item->next;
2142                         else
2143                                 Xact_callbacks = item->next;
2144                         pfree(item);
2145                         break;
2146                 }
2147         }
2148 }
2149
2150 static void
2151 CallXactCallbacks(XactEvent event, TransactionId parentXid)
2152 {
2153         XactCallbackItem *item;
2154
2155         for (item = Xact_callbacks; item; item = item->next)
2156                 (*item->callback) (event, parentXid, item->arg);
2157 }
2158
2159
2160 /* ----------------------------------------------------------------
2161  *                                         transaction block support
2162  * ----------------------------------------------------------------
2163  */
2164
2165 /*
2166  *      BeginTransactionBlock
2167  *              This executes a BEGIN command.
2168  */
2169 void
2170 BeginTransactionBlock(void)
2171 {
2172         TransactionState s = CurrentTransactionState;
2173
2174         switch (s->blockState)
2175         {
2176                         /*
2177                          * We are not inside a transaction block, so allow one to
2178                          * begin.
2179                          */
2180                 case TBLOCK_STARTED:
2181                         s->blockState = TBLOCK_BEGIN;
2182                         break;
2183
2184                         /*
2185                          * Already a transaction block in progress.
2186                          */
2187                 case TBLOCK_INPROGRESS:
2188                 case TBLOCK_SUBINPROGRESS:
2189                 case TBLOCK_ABORT:
2190                 case TBLOCK_SUBABORT:
2191                         ereport(WARNING,
2192                                         (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2193                                   errmsg("there is already a transaction in progress")));
2194                         break;
2195
2196                         /* These cases are invalid.  Reject them altogether. */
2197                 case TBLOCK_DEFAULT:
2198                 case TBLOCK_BEGIN:
2199                 case TBLOCK_SUBBEGIN:
2200                 case TBLOCK_ENDABORT:
2201                 case TBLOCK_END:
2202                 case TBLOCK_SUBENDABORT_ALL:
2203                 case TBLOCK_SUBENDABORT:
2204                 case TBLOCK_SUBABORT_PENDING:
2205                 case TBLOCK_SUBENDABORT_RELEASE:
2206                 case TBLOCK_SUBEND:
2207                         elog(FATAL, "BeginTransactionBlock: unexpected state %s",
2208                                  BlockStateAsString(s->blockState));
2209                         break;
2210         }
2211 }
2212
2213 /*
2214  *      EndTransactionBlock
2215  *              This executes a COMMIT command.
2216  *
2217  * Since COMMIT may actually do a ROLLBACK, the result indicates what
2218  * happened: TRUE for COMMIT, FALSE for ROLLBACK.
2219  */
2220 bool
2221 EndTransactionBlock(void)
2222 {
2223         TransactionState s = CurrentTransactionState;
2224         bool            result = false;
2225
2226         switch (s->blockState)
2227         {
2228                         /*
2229                          * We are in a transaction block which should commit when we
2230                          * get to the upcoming CommitTransactionCommand() so we set
2231                          * the state to "END".  CommitTransactionCommand() will
2232                          * recognize this and commit the transaction and return us to
2233                          * the default state.
2234                          */
2235                 case TBLOCK_INPROGRESS:
2236                 case TBLOCK_SUBINPROGRESS:
2237                         s->blockState = TBLOCK_END;
2238                         result = true;
2239                         break;
2240
2241                         /*
2242                          * We are in a transaction block which aborted. Since the
2243                          * AbortTransaction() was already done, we need only change to
2244                          * the special "END ABORT" state.  The upcoming
2245                          * CommitTransactionCommand() will recognise this and then put
2246                          * us back in the default state.
2247                          */
2248                 case TBLOCK_ABORT:
2249                         s->blockState = TBLOCK_ENDABORT;
2250                         break;
2251
2252                         /*
2253                          * Here we are inside an aborted subtransaction.  Go to the
2254                          * "abort the whole tree" state so that
2255                          * CommitTransactionCommand() calls AbortOutOfAnyTransaction.
2256                          */
2257                 case TBLOCK_SUBABORT:
2258                         s->blockState = TBLOCK_SUBENDABORT_ALL;
2259                         break;
2260
2261                 case TBLOCK_STARTED:
2262
2263                         /*
2264                          * here, the user issued COMMIT when not inside a transaction.
2265                          * Issue a WARNING and go to abort state.  The upcoming call
2266                          * to CommitTransactionCommand() will then put us back into
2267                          * the default state.
2268                          */
2269                         ereport(WARNING,
2270                                         (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2271                                          errmsg("there is no transaction in progress")));
2272                         AbortTransaction();
2273                         s->blockState = TBLOCK_ENDABORT;
2274                         break;
2275
2276                         /* these cases are invalid. */
2277                 case TBLOCK_DEFAULT:
2278                 case TBLOCK_BEGIN:
2279                 case TBLOCK_ENDABORT:
2280                 case TBLOCK_END:
2281                 case TBLOCK_SUBBEGIN:
2282                 case TBLOCK_SUBEND:
2283                 case TBLOCK_SUBENDABORT_ALL:
2284                 case TBLOCK_SUBENDABORT:
2285                 case TBLOCK_SUBABORT_PENDING:
2286                 case TBLOCK_SUBENDABORT_RELEASE:
2287                         elog(FATAL, "EndTransactionBlock: unexpected state %s",
2288                                  BlockStateAsString(s->blockState));
2289                         break;
2290         }
2291
2292         return result;
2293 }
2294
2295 /*
2296  *      UserAbortTransactionBlock
2297  *              This executes a ROLLBACK command.
2298  */
2299 void
2300 UserAbortTransactionBlock(void)
2301 {
2302         TransactionState s = CurrentTransactionState;
2303
2304         switch (s->blockState)
2305         {
2306                         /*
2307                          * We are inside a failed transaction block and we got an
2308                          * abort command from the user.  Abort processing is already
2309                          * done, we just need to move to the ENDABORT state so we will
2310                          * end up in the default state after the upcoming
2311                          * CommitTransactionCommand().
2312                          */
2313                 case TBLOCK_ABORT:
2314                         s->blockState = TBLOCK_ENDABORT;
2315                         break;
2316
2317                         /*
2318                          * We are inside a failed subtransaction and we got an abort
2319                          * command from the user.  Abort processing is already done,
2320                          * so go to the "abort all" state and CommitTransactionCommand
2321                          * will call AbortOutOfAnyTransaction to set things straight.
2322                          */
2323                 case TBLOCK_SUBABORT:
2324                         s->blockState = TBLOCK_SUBENDABORT_ALL;
2325                         break;
2326
2327                         /*
2328                          * We are inside a transaction block and we got an abort
2329                          * command from the user, so we move to the ENDABORT state and
2330                          * do abort processing so we will end up in the default state
2331                          * after the upcoming CommitTransactionCommand().
2332                          */
2333                 case TBLOCK_INPROGRESS:
2334                         AbortTransaction();
2335                         s->blockState = TBLOCK_ENDABORT;
2336                         break;
2337
2338                         /*
2339                          * We are inside a subtransaction.      Abort the current
2340                          * subtransaction and go to the "abort all" state, so
2341                          * CommitTransactionCommand will call AbortOutOfAnyTransaction
2342                          * to set things straight.
2343                          */
2344                 case TBLOCK_SUBINPROGRESS:
2345                         AbortSubTransaction();
2346                         s->blockState = TBLOCK_SUBENDABORT_ALL;
2347                         break;
2348
2349                         /*
2350                          * The user issued ABORT when not inside a transaction. Issue
2351                          * a WARNING and go to abort state.  The upcoming call to
2352                          * CommitTransactionCommand() will then put us back into the
2353                          * default state.
2354                          */
2355                 case TBLOCK_STARTED:
2356                         ereport(WARNING,
2357                                         (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2358                                          errmsg("there is no transaction in progress")));
2359                         AbortTransaction();
2360                         s->blockState = TBLOCK_ENDABORT;
2361                         break;
2362
2363                         /* These cases are invalid. */
2364                 case TBLOCK_DEFAULT:
2365                 case TBLOCK_BEGIN:
2366                 case TBLOCK_END:
2367                 case TBLOCK_ENDABORT:
2368                 case TBLOCK_SUBEND:
2369                 case TBLOCK_SUBENDABORT_ALL:
2370                 case TBLOCK_SUBENDABORT:
2371                 case TBLOCK_SUBABORT_PENDING:
2372                 case TBLOCK_SUBENDABORT_RELEASE:
2373                 case TBLOCK_SUBBEGIN:
2374                         elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2375                                  BlockStateAsString(s->blockState));
2376                         break;
2377         }
2378 }
2379
2380 /*
2381  * DefineSavepoint
2382  *              This executes a SAVEPOINT command.
2383  */
2384 void
2385 DefineSavepoint(char *name)
2386 {
2387         TransactionState s = CurrentTransactionState;
2388
2389         switch (s->blockState)
2390         {
2391                 case TBLOCK_INPROGRESS:
2392                 case TBLOCK_SUBINPROGRESS:
2393                         /* Normal subtransaction start */
2394                         PushTransaction();
2395                         s = CurrentTransactionState;            /* changed by push */
2396
2397                         /*
2398                          * Note that we are allocating the savepoint name in the
2399                          * parent transaction's CurTransactionContext, since we don't
2400                          * yet have a transaction context for the new guy.
2401                          */
2402                         s->name = MemoryContextStrdup(CurTransactionContext, name);
2403                         s->blockState = TBLOCK_SUBBEGIN;
2404                         break;
2405
2406                         /* These cases are invalid.  Reject them altogether. */
2407                 case TBLOCK_DEFAULT:
2408                 case TBLOCK_STARTED:
2409                 case TBLOCK_BEGIN:
2410                 case TBLOCK_SUBBEGIN:
2411                 case TBLOCK_ABORT:
2412                 case TBLOCK_SUBABORT:
2413                 case TBLOCK_ENDABORT:
2414                 case TBLOCK_END:
2415                 case TBLOCK_SUBENDABORT_ALL:
2416                 case TBLOCK_SUBENDABORT:
2417                 case TBLOCK_SUBABORT_PENDING:
2418                 case TBLOCK_SUBENDABORT_RELEASE:
2419                 case TBLOCK_SUBEND:
2420                         elog(FATAL, "DefineSavepoint: unexpected state %s",
2421                                  BlockStateAsString(s->blockState));
2422                         break;
2423         }
2424 }
2425
2426 /*
2427  * ReleaseSavepoint
2428  *              This executes a RELEASE command.
2429  */
2430 void
2431 ReleaseSavepoint(List *options)
2432 {
2433         TransactionState s = CurrentTransactionState;
2434         TransactionState target,
2435                                 xact;
2436         ListCell   *cell;
2437         char       *name = NULL;
2438
2439         /*
2440          * Check valid block state transaction status.
2441          */
2442         switch (s->blockState)
2443         {
2444                 case TBLOCK_INPROGRESS:
2445                 case TBLOCK_ABORT:
2446                         ereport(ERROR,
2447                                         (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2448                                          errmsg("no such savepoint")));
2449                         break;
2450
2451                         /*
2452                          * We are in a non-aborted subtransaction.      This is the only
2453                          * valid case.
2454                          */
2455                 case TBLOCK_SUBINPROGRESS:
2456                         break;
2457
2458                         /* these cases are invalid. */
2459                 case TBLOCK_DEFAULT:
2460                 case TBLOCK_STARTED:
2461                 case TBLOCK_BEGIN:
2462                 case TBLOCK_ENDABORT:
2463                 case TBLOCK_END:
2464                 case TBLOCK_SUBABORT:
2465                 case TBLOCK_SUBBEGIN:
2466                 case TBLOCK_SUBEND:
2467                 case TBLOCK_SUBENDABORT_ALL:
2468                 case TBLOCK_SUBENDABORT:
2469                 case TBLOCK_SUBABORT_PENDING:
2470                 case TBLOCK_SUBENDABORT_RELEASE:
2471                         elog(FATAL, "ReleaseSavepoint: unexpected state %s",
2472                                  BlockStateAsString(s->blockState));
2473                         break;
2474         }
2475
2476         foreach(cell, options)
2477         {
2478                 DefElem    *elem = lfirst(cell);
2479
2480                 if (strcmp(elem->defname, "savepoint_name") == 0)
2481                         name = strVal(elem->arg);
2482         }
2483
2484         Assert(PointerIsValid(name));
2485
2486         for (target = s; PointerIsValid(target); target = target->parent)
2487         {
2488                 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2489                         break;
2490         }
2491
2492         if (!PointerIsValid(target))
2493                 ereport(ERROR,
2494                                 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2495                                  errmsg("no such savepoint")));
2496
2497         /* disallow crossing savepoint level boundaries */
2498         if (target->savepointLevel != s->savepointLevel)
2499                 ereport(ERROR,
2500                                 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2501                                  errmsg("no such savepoint")));
2502
2503         /*
2504          * Mark "commit pending" all subtransactions up to the target
2505          * subtransaction.      The actual commits will happen when control gets
2506          * to CommitTransactionCommand.
2507          */
2508         xact = CurrentTransactionState;
2509         for (;;)
2510         {
2511                 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2512                 xact->blockState = TBLOCK_SUBEND;
2513                 if (xact == target)
2514                         break;
2515                 xact = xact->parent;
2516                 Assert(PointerIsValid(xact));
2517         }
2518 }
2519
2520 /*
2521  * RollbackToSavepoint
2522  *              This executes a ROLLBACK TO <savepoint> command.
2523  */
2524 void
2525 RollbackToSavepoint(List *options)
2526 {
2527         TransactionState s = CurrentTransactionState;
2528         TransactionState target,
2529                                 xact;
2530         ListCell   *cell;
2531         char       *name = NULL;
2532
2533         switch (s->blockState)
2534         {
2535                         /*
2536                          * We can't rollback to a savepoint if there is no saveopint
2537                          * defined.
2538                          */
2539                 case TBLOCK_ABORT:
2540                 case TBLOCK_INPROGRESS:
2541                         ereport(ERROR,
2542                                         (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2543                                          errmsg("no such savepoint")));
2544                         break;
2545
2546                         /*
2547                          * There is at least one savepoint, so proceed.
2548                          */
2549                 case TBLOCK_SUBABORT:
2550                 case TBLOCK_SUBINPROGRESS:
2551
2552                         /*
2553                          * Have to do AbortSubTransaction, but first check if this is
2554                          * the right subtransaction
2555                          */
2556                         break;
2557
2558                         /* these cases are invalid. */
2559                 case TBLOCK_DEFAULT:
2560                 case TBLOCK_STARTED:
2561                 case TBLOCK_BEGIN:
2562                 case TBLOCK_END:
2563                 case TBLOCK_ENDABORT:
2564                 case TBLOCK_SUBEND:
2565                 case TBLOCK_SUBENDABORT_ALL:
2566                 case TBLOCK_SUBENDABORT:
2567                 case TBLOCK_SUBABORT_PENDING:
2568                 case TBLOCK_SUBENDABORT_RELEASE:
2569                 case TBLOCK_SUBBEGIN:
2570                         elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2571                                  BlockStateAsString(s->blockState));
2572                         break;
2573         }
2574
2575         foreach(cell, options)
2576         {
2577                 DefElem    *elem = lfirst(cell);
2578
2579                 if (strcmp(elem->defname, "savepoint_name") == 0)
2580                         name = strVal(elem->arg);
2581         }
2582
2583         Assert(PointerIsValid(name));
2584
2585         for (target = s; PointerIsValid(target); target = target->parent)
2586         {
2587                 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2588                         break;
2589         }
2590
2591         if (!PointerIsValid(target))
2592                 ereport(ERROR,
2593                                 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2594                                  errmsg("no such savepoint")));
2595
2596         /* disallow crossing savepoint level boundaries */
2597         if (target->savepointLevel != s->savepointLevel)
2598                 ereport(ERROR,
2599                                 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2600                                  errmsg("no such savepoint")));
2601
2602         /*
2603          * Abort the current subtransaction, if needed.  We can't Cleanup the
2604          * savepoint yet, so signal CommitTransactionCommand to do it and
2605          * close all savepoints up to the target level.
2606          */
2607         if (s->blockState == TBLOCK_SUBINPROGRESS)
2608                 AbortSubTransaction();
2609         s->blockState = TBLOCK_SUBENDABORT;
2610
2611         /*
2612          * Mark "abort pending" all subtransactions up to the target
2613          * subtransaction.      (Except the current subtransaction!)
2614          */
2615         xact = CurrentTransactionState;
2616
2617         while (xact != target)
2618         {
2619                 xact = xact->parent;
2620                 Assert(PointerIsValid(xact));
2621                 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2622                 xact->blockState = TBLOCK_SUBABORT_PENDING;
2623         }
2624 }
2625
2626 /*
2627  * BeginInternalSubTransaction
2628  *              This is the same as DefineSavepoint except it allows TBLOCK_STARTED
2629  *              state, and therefore it can safely be used in a function that might
2630  *              be called when not inside a BEGIN block.  Also, we automatically
2631  *              cycle through CommitTransactionCommand/StartTransactionCommand
2632  *              instead of expecting the caller to do it.
2633  *
2634  * Optionally, name can be NULL to create an unnamed savepoint.
2635  */
2636 void
2637 BeginInternalSubTransaction(char *name)
2638 {
2639         TransactionState s = CurrentTransactionState;
2640
2641         switch (s->blockState)
2642         {
2643                 case TBLOCK_STARTED:
2644                 case TBLOCK_INPROGRESS:
2645                 case TBLOCK_SUBINPROGRESS:
2646                         /* Normal subtransaction start */
2647                         PushTransaction();
2648                         s = CurrentTransactionState;            /* changed by push */
2649
2650                         /*
2651                          * Note that we are allocating the savepoint name in the
2652                          * parent transaction's CurTransactionContext, since we don't
2653                          * yet have a transaction context for the new guy.
2654                          */
2655                         if (name)
2656                                 s->name = MemoryContextStrdup(CurTransactionContext, name);
2657                         s->blockState = TBLOCK_SUBBEGIN;
2658                         break;
2659
2660                         /* These cases are invalid.  Reject them altogether. */
2661                 case TBLOCK_DEFAULT:
2662                 case TBLOCK_BEGIN:
2663                 case TBLOCK_SUBBEGIN:
2664                 case TBLOCK_ABORT:
2665                 case TBLOCK_SUBABORT:
2666                 case TBLOCK_ENDABORT:
2667                 case TBLOCK_END:
2668                 case TBLOCK_SUBENDABORT_ALL:
2669                 case TBLOCK_SUBENDABORT:
2670                 case TBLOCK_SUBABORT_PENDING:
2671                 case TBLOCK_SUBENDABORT_RELEASE:
2672                 case TBLOCK_SUBEND:
2673                         elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
2674                                  BlockStateAsString(s->blockState));
2675                         break;
2676         }
2677
2678         CommitTransactionCommand();
2679         StartTransactionCommand();
2680 }
2681
2682 /*
2683  * ReleaseCurrentSubTransaction
2684  *
2685  * RELEASE (ie, commit) the innermost subtransaction, regardless of its
2686  * savepoint name (if any).
2687  * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2688  */
2689 void
2690 ReleaseCurrentSubTransaction(void)
2691 {
2692         TransactionState s = CurrentTransactionState;
2693
2694         if (s->blockState != TBLOCK_SUBINPROGRESS)
2695                 elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
2696                          BlockStateAsString(s->blockState));
2697         MemoryContextSwitchTo(CurTransactionContext);
2698         CommitTransactionToLevel(GetCurrentTransactionNestLevel());
2699 }
2700
2701 /*
2702  * RollbackAndReleaseCurrentSubTransaction
2703  *
2704  * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
2705  * of its savepoint name (if any).
2706  * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2707  */
2708 void
2709 RollbackAndReleaseCurrentSubTransaction(void)
2710 {
2711         TransactionState s = CurrentTransactionState;
2712
2713         switch (s->blockState)
2714         {
2715                         /* Must be in a subtransaction */
2716                 case TBLOCK_SUBABORT:
2717                 case TBLOCK_SUBINPROGRESS:
2718                         break;
2719
2720                         /* these cases are invalid. */
2721                 case TBLOCK_DEFAULT:
2722                 case TBLOCK_STARTED:
2723                 case TBLOCK_ABORT:
2724                 case TBLOCK_INPROGRESS:
2725                 case TBLOCK_BEGIN:
2726                 case TBLOCK_END:
2727                 case TBLOCK_ENDABORT:
2728                 case TBLOCK_SUBEND:
2729                 case TBLOCK_SUBENDABORT_ALL:
2730                 case TBLOCK_SUBENDABORT:
2731                 case TBLOCK_SUBABORT_PENDING:
2732                 case TBLOCK_SUBENDABORT_RELEASE:
2733                 case TBLOCK_SUBBEGIN:
2734                         elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
2735                                  BlockStateAsString(s->blockState));
2736                         break;
2737         }
2738
2739         /*
2740          * Abort the current subtransaction, if needed.
2741          */
2742         if (s->blockState == TBLOCK_SUBINPROGRESS)
2743                 AbortSubTransaction();
2744         s->blockState = TBLOCK_SUBENDABORT_RELEASE;
2745
2746         /* And clean it up, too */
2747         CleanupAbortedSubTransactions(false);
2748 }
2749
2750 /*
2751  *      AbortOutOfAnyTransaction
2752  *
2753  *      This routine is provided for error recovery purposes.  It aborts any
2754  *      active transaction or transaction block, leaving the system in a known
2755  *      idle state.
2756  */
2757 void
2758 AbortOutOfAnyTransaction(void)
2759 {
2760         TransactionState s = CurrentTransactionState;
2761
2762         /*
2763          * Get out of any transaction or nested transaction
2764          */
2765         do
2766         {
2767                 switch (s->blockState)
2768                 {
2769                         case TBLOCK_DEFAULT:
2770                                 /* Not in a transaction, do nothing */
2771                                 break;
2772                         case TBLOCK_STARTED:
2773                         case TBLOCK_BEGIN:
2774                         case TBLOCK_INPROGRESS:
2775                         case TBLOCK_END:
2776                                 /* In a transaction, so clean up */
2777                                 AbortTransaction();
2778                                 CleanupTransaction();
2779                                 s->blockState = TBLOCK_DEFAULT;
2780                                 break;
2781                         case TBLOCK_ABORT:
2782                         case TBLOCK_ENDABORT:
2783                                 /* AbortTransaction already done, still need Cleanup */
2784                                 CleanupTransaction();
2785                                 s->blockState = TBLOCK_DEFAULT;
2786                                 break;
2787                         case TBLOCK_SUBBEGIN:
2788
2789                                 /*
2790                                  * We didn't get as far as starting the subxact, so
2791                                  * there's nothing to abort.  Just pop back to parent.
2792                                  */
2793                                 PopTransaction();
2794                                 s = CurrentTransactionState;    /* changed by pop */
2795                                 break;
2796                         case TBLOCK_SUBINPROGRESS:
2797                         case TBLOCK_SUBEND:
2798                         case TBLOCK_SUBABORT_PENDING:
2799
2800                                 /*
2801                                  * In a subtransaction, so clean it up and abort parent
2802                                  * too
2803                                  */
2804                                 AbortSubTransaction();
2805                                 CleanupSubTransaction();
2806                                 PopTransaction();
2807                                 s = CurrentTransactionState;    /* changed by pop */
2808                                 break;
2809                         case TBLOCK_SUBABORT:
2810                         case TBLOCK_SUBENDABORT_ALL:
2811                         case TBLOCK_SUBENDABORT:
2812                         case TBLOCK_SUBENDABORT_RELEASE:
2813                                 /* As above, but AbortSubTransaction already done */
2814                                 CleanupSubTransaction();
2815                                 PopTransaction();
2816                                 s = CurrentTransactionState;    /* changed by pop */
2817                                 break;
2818                 }
2819         } while (s->blockState != TBLOCK_DEFAULT);
2820
2821         /* Should be out of all subxacts now */
2822         Assert(s->parent == NULL);
2823 }
2824
2825 /*
2826  * CommitTransactionToLevel
2827  *
2828  * Commit everything from the current transaction level
2829  * up to the specified level (inclusive).
2830  */
2831 static void
2832 CommitTransactionToLevel(int level)
2833 {
2834         TransactionState s = CurrentTransactionState;
2835
2836         Assert(s->state == TRANS_INPROGRESS);
2837
2838         while (s->nestingLevel >= level)
2839         {
2840                 CommitSubTransaction();
2841                 PopTransaction();
2842                 s = CurrentTransactionState;    /* changed by pop */
2843                 Assert(s->state == TRANS_INPROGRESS);
2844         }
2845 }
2846
2847 /*
2848  * IsTransactionBlock --- are we within a transaction block?
2849  */
2850 bool
2851 IsTransactionBlock(void)
2852 {
2853         TransactionState s = CurrentTransactionState;
2854
2855         if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
2856                 return false;
2857
2858         return true;
2859 }
2860
2861 /*
2862  * IsTransactionOrTransactionBlock --- are we within either a transaction
2863  * or a transaction block?      (The backend is only really "idle" when this
2864  * returns false.)
2865  *
2866  * This should match up with IsTransactionBlock and IsTransactionState.
2867  */
2868 bool
2869 IsTransactionOrTransactionBlock(void)
2870 {
2871         TransactionState s = CurrentTransactionState;
2872
2873         if (s->blockState == TBLOCK_DEFAULT)
2874                 return false;
2875
2876         return true;
2877 }
2878
2879 /*
2880  * TransactionBlockStatusCode - return status code to send in ReadyForQuery
2881  */
2882 char
2883 TransactionBlockStatusCode(void)
2884 {
2885         TransactionState s = CurrentTransactionState;
2886
2887         switch (s->blockState)
2888         {
2889                 case TBLOCK_DEFAULT:
2890                 case TBLOCK_STARTED:
2891                         return 'I';                     /* idle --- not in transaction */
2892                 case TBLOCK_BEGIN:
2893                 case TBLOCK_INPROGRESS:
2894                 case TBLOCK_END:
2895                 case TBLOCK_SUBINPROGRESS:
2896                 case TBLOCK_SUBBEGIN:
2897                 case TBLOCK_SUBEND:
2898                         return 'T';                     /* in transaction */
2899                 case TBLOCK_ABORT:
2900                 case TBLOCK_ENDABORT:
2901                 case TBLOCK_SUBABORT:
2902                 case TBLOCK_SUBENDABORT_ALL:
2903                 case TBLOCK_SUBENDABORT:
2904                 case TBLOCK_SUBABORT_PENDING:
2905                 case TBLOCK_SUBENDABORT_RELEASE:
2906                         return 'E';                     /* in failed transaction */
2907         }
2908
2909         /* should never get here */
2910         elog(FATAL, "invalid transaction block state: %s",
2911                  BlockStateAsString(s->blockState));
2912         return 0;                                       /* keep compiler quiet */
2913 }
2914
2915 /*
2916  * IsSubTransaction
2917  */
2918 bool
2919 IsSubTransaction(void)
2920 {
2921         TransactionState s = CurrentTransactionState;
2922
2923         if (s->nestingLevel >= 2)
2924                 return true;
2925
2926         return false;
2927 }
2928
2929 /*
2930  * StartSubTransaction
2931  */
2932 static void
2933 StartSubTransaction(void)
2934 {
2935         TransactionState s = CurrentTransactionState;
2936
2937         if (s->state != TRANS_DEFAULT)
2938                 elog(WARNING, "StartSubTransaction while in %s state",
2939                          TransStateAsString(s->state));
2940
2941         s->state = TRANS_START;
2942
2943         /*
2944          * must initialize resource-management stuff first
2945          */
2946         AtSubStart_Memory();
2947         AtSubStart_ResourceOwner();
2948
2949         /*
2950          * Generate a new Xid and record it in pg_subtrans.  NB: we must make
2951          * the subtrans entry BEFORE the Xid appears anywhere in shared
2952          * storage, such as in the lock table; because until it's made the Xid
2953          * may not appear to be "running" to other backends. See
2954          * GetNewTransactionId.
2955          */
2956         s->transactionIdData = GetNewTransactionId(true);
2957
2958         SubTransSetParent(s->transactionIdData, s->parent->transactionIdData);
2959
2960         XactLockTableInsert(s->transactionIdData);
2961
2962         /*
2963          * Finish setup of other transaction state fields.
2964          */
2965         s->currentUser = GetUserId();
2966         s->prevXactReadOnly = XactReadOnly;
2967
2968         /*
2969          * Initialize other subsystems for new subtransaction
2970          */
2971         AtSubStart_Inval();
2972         AtSubStart_Notify();
2973         DeferredTriggerBeginSubXact();
2974
2975         s->state = TRANS_INPROGRESS;
2976
2977         /*
2978          * Call start-of-subxact callbacks
2979          */
2980         CallXactCallbacks(XACT_EVENT_START_SUB, s->parent->transactionIdData);
2981
2982         ShowTransactionState("StartSubTransaction");
2983 }
2984
2985 /*
2986  * CommitSubTransaction
2987  */
2988 static void
2989 CommitSubTransaction(void)
2990 {
2991         TransactionState s = CurrentTransactionState;
2992
2993         ShowTransactionState("CommitSubTransaction");
2994
2995         if (s->state != TRANS_INPROGRESS)
2996                 elog(WARNING, "CommitSubTransaction while in %s state",
2997                          TransStateAsString(s->state));
2998
2999         /* Pre-commit processing goes here -- nothing to do at the moment */
3000
3001         s->state = TRANS_COMMIT;
3002
3003         /* Mark subtransaction as subcommitted */
3004         CommandCounterIncrement();
3005         RecordSubTransactionCommit();
3006         AtSubCommit_childXids();
3007
3008         /* Post-commit cleanup */
3009         DeferredTriggerEndSubXact(true);
3010         AtSubCommit_Portals(s->parent->transactionIdData,
3011                                                 s->parent->curTransactionOwner);
3012         AtEOSubXact_LargeObject(true, s->transactionIdData,
3013                                                         s->parent->transactionIdData);
3014         AtSubCommit_Notify();
3015         AtEOSubXact_UpdatePasswordFile(true, s->transactionIdData,
3016                                                                    s->parent->transactionIdData);
3017         AtSubCommit_smgr();
3018
3019         CallXactCallbacks(XACT_EVENT_COMMIT_SUB, s->parent->transactionIdData);
3020
3021         ResourceOwnerRelease(s->curTransactionOwner,
3022                                                  RESOURCE_RELEASE_BEFORE_LOCKS,
3023                                                  true, false);
3024         AtEOSubXact_RelationCache(true, s->transactionIdData,
3025                                                           s->parent->transactionIdData);
3026         AtEOSubXact_Inval(true);
3027         ResourceOwnerRelease(s->curTransactionOwner,
3028                                                  RESOURCE_RELEASE_LOCKS,
3029                                                  true, false);
3030         ResourceOwnerRelease(s->curTransactionOwner,
3031                                                  RESOURCE_RELEASE_AFTER_LOCKS,
3032                                                  true, false);
3033
3034         AtEOXact_GUC(true, true);
3035         AtEOSubXact_SPI(true, s->transactionIdData);
3036         AtEOSubXact_on_commit_actions(true, s->transactionIdData,
3037                                                                   s->parent->transactionIdData);
3038         AtEOSubXact_Namespace(true, s->transactionIdData,
3039                                                   s->parent->transactionIdData);
3040         AtEOSubXact_Files(true, s->transactionIdData,
3041                                           s->parent->transactionIdData);
3042
3043         /*
3044          * We need to restore the upper transaction's read-only state, in case
3045          * the upper is read-write while the child is read-only; GUC will
3046          * incorrectly think it should leave the child state in place.
3047          */
3048         XactReadOnly = s->prevXactReadOnly;
3049
3050         CurrentResourceOwner = s->parent->curTransactionOwner;
3051         CurTransactionResourceOwner = s->parent->curTransactionOwner;
3052         ResourceOwnerDelete(s->curTransactionOwner);
3053         s->curTransactionOwner = NULL;
3054
3055         AtSubCommit_Memory();
3056
3057         s->state = TRANS_DEFAULT;
3058 }
3059
3060 /*
3061  * AbortSubTransaction
3062  */
3063 static void
3064 AbortSubTransaction(void)
3065 {
3066         TransactionState s = CurrentTransactionState;
3067
3068         ShowTransactionState("AbortSubTransaction");
3069
3070         if (s->state != TRANS_INPROGRESS)
3071                 elog(WARNING, "AbortSubTransaction while in %s state",
3072                          TransStateAsString(s->state));
3073
3074         HOLD_INTERRUPTS();
3075
3076         s->state = TRANS_ABORT;
3077
3078         /*
3079          * Release any LW locks we might be holding as quickly as possible.
3080          * (Regular locks, however, must be held till we finish aborting.)
3081          * Releasing LW locks is critical since we might try to grab them
3082          * again while cleaning up!
3083          *
3084          * FIXME This may be incorrect --- Are there some locks we should keep?
3085          * Buffer locks, for example?  I don't think so but I'm not sure.
3086          */
3087         LWLockReleaseAll();
3088
3089         AbortBufferIO();
3090         UnlockBuffers();
3091
3092         LockWaitCancel();
3093
3094         /*
3095          * do abort processing
3096          */
3097         AtSubAbort_Memory();
3098
3099         DeferredTriggerEndSubXact(false);
3100         AtSubAbort_Portals(s->parent->transactionIdData,
3101                                            s->parent->curTransactionOwner);
3102         AtEOSubXact_LargeObject(false, s->transactionIdData,
3103                                                         s->parent->transactionIdData);
3104         AtSubAbort_Notify();
3105         AtEOSubXact_UpdatePasswordFile(false, s->transactionIdData,
3106                                                                    s->parent->transactionIdData);
3107
3108         /* Advertise the fact that we aborted in pg_clog. */
3109         RecordSubTransactionAbort();
3110
3111         /* Post-abort cleanup */
3112         AtSubAbort_smgr();
3113
3114         CallXactCallbacks(XACT_EVENT_ABORT_SUB, s->parent->transactionIdData);
3115
3116         ResourceOwnerRelease(s->curTransactionOwner,
3117                                                  RESOURCE_RELEASE_BEFORE_LOCKS,
3118                                                  false, false);
3119         AtEOSubXact_RelationCache(false, s->transactionIdData,
3120                                                           s->parent->transactionIdData);
3121         AtEOSubXact_Inval(false);
3122         ResourceOwnerRelease(s->curTransactionOwner,
3123                                                  RESOURCE_RELEASE_LOCKS,
3124                                                  false, false);
3125         ResourceOwnerRelease(s->curTransactionOwner,
3126                                                  RESOURCE_RELEASE_AFTER_LOCKS,
3127                                                  false, false);
3128
3129         AtEOXact_GUC(false, true);
3130         AtEOSubXact_SPI(false, s->transactionIdData);
3131         AtEOSubXact_on_commit_actions(false, s->transactionIdData,
3132                                                                   s->parent->transactionIdData);
3133         AtEOSubXact_Namespace(false, s->transactionIdData,
3134                                                   s->parent->transactionIdData);
3135         AtEOSubXact_Files(false, s->transactionIdData,
3136                                           s->parent->transactionIdData);
3137
3138         /*
3139          * Reset user id which might have been changed transiently.  Here we
3140          * want to restore to the userid that was current at subxact entry.
3141          * (As in AbortTransaction, we need not worry about the session
3142          * userid.)
3143          *
3144          * Must do this after AtEOXact_GUC to handle the case where we entered
3145          * the subxact inside a SECURITY DEFINER function (hence current and
3146          * session userids were different) and then session auth was changed
3147          * inside the subxact.  GUC will reset both current and session
3148          * userids to the entry-time session userid.  This is right in every
3149          * other scenario so it seems simplest to let GUC do that and fix it
3150          * here.
3151          */
3152         SetUserId(s->currentUser);
3153
3154         /*
3155          * Restore the upper transaction's read-only state, too.  This should
3156          * be redundant with GUC's cleanup but we may as well do it for
3157          * consistency with the commit case.
3158          */
3159         XactReadOnly = s->prevXactReadOnly;
3160
3161         RESUME_INTERRUPTS();
3162 }
3163
3164 /*
3165  * CleanupSubTransaction
3166  */
3167 static void
3168 CleanupSubTransaction(void)
3169 {
3170         TransactionState s = CurrentTransactionState;
3171
3172         ShowTransactionState("CleanupSubTransaction");
3173
3174         if (s->state != TRANS_ABORT)
3175                 elog(WARNING, "CleanupSubTransaction while in %s state",
3176                          TransStateAsString(s->state));
3177
3178         AtSubCleanup_Portals();
3179
3180         CurrentResourceOwner = s->parent->curTransactionOwner;
3181         CurTransactionResourceOwner = s->parent->curTransactionOwner;
3182         ResourceOwnerDelete(s->curTransactionOwner);
3183         s->curTransactionOwner = NULL;
3184
3185         AtSubCleanup_Memory();
3186
3187         s->state = TRANS_DEFAULT;
3188 }
3189
3190 /*
3191  * StartAbortedSubTransaction
3192  *
3193  * This function is used to start a subtransaction and put it immediately
3194  * into aborted state.  The end result should be equivalent to
3195  * StartSubTransaction immediately followed by AbortSubTransaction.
3196  * The reason we don't implement it just that way is that many of the backend
3197  * modules aren't designed to handle starting a subtransaction when not
3198  * inside a valid transaction.  Rather than making them all capable of
3199  * doing that, we just omit the paired start and abort calls in this path.
3200  */
3201 static void
3202 StartAbortedSubTransaction(void)
3203 {
3204         TransactionState s = CurrentTransactionState;
3205
3206         if (s->state != TRANS_DEFAULT)
3207                 elog(WARNING, "StartAbortedSubTransaction while in %s state",
3208                          TransStateAsString(s->state));
3209
3210         s->state = TRANS_START;
3211
3212         /*
3213          * We don't bother to generate a new Xid, so the end state is not
3214          * *exactly* like we had done a full Start/AbortSubTransaction...
3215          */
3216         s->transactionIdData = InvalidTransactionId;
3217
3218         /* Make sure currentUser is reasonably valid */
3219         Assert(s->parent != NULL);
3220         s->currentUser = s->parent->currentUser;
3221
3222         /*
3223          * Initialize only what has to be there for CleanupSubTransaction to
3224          * work.
3225          */
3226         AtSubStart_Memory();
3227         AtSubStart_ResourceOwner();
3228
3229         s->state = TRANS_ABORT;
3230
3231         AtSubAbort_Memory();
3232
3233         ShowTransactionState("StartAbortedSubTransaction");
3234 }
3235
3236 /*
3237  * PushTransaction
3238  *              Set up transaction state for a subtransaction
3239  *
3240  *      The caller has to make sure to always reassign CurrentTransactionState
3241  *      if it has a local pointer to it after calling this function.
3242  */
3243 static void
3244 PushTransaction(void)
3245 {
3246         TransactionState p = CurrentTransactionState;
3247         TransactionState s;
3248
3249         /*
3250          * We keep subtransaction state nodes in TopTransactionContext.
3251          */
3252         s = (TransactionState)
3253                 MemoryContextAllocZero(TopTransactionContext,
3254                                                            sizeof(TransactionStateData));
3255         s->parent = p;
3256         s->nestingLevel = p->nestingLevel + 1;
3257         s->savepointLevel = p->savepointLevel;
3258         s->state = TRANS_DEFAULT;
3259         s->blockState = TBLOCK_SUBBEGIN;
3260
3261         /* Command IDs count in a continuous sequence through subtransactions */
3262         s->commandId = p->commandId;
3263
3264         /*
3265          * Copy down some other data so that we will have valid state until
3266          * StartSubTransaction runs.
3267          */
3268         s->transactionIdData = p->transactionIdData;
3269         s->curTransactionContext = p->curTransactionContext;
3270         s->curTransactionOwner = p->curTransactionOwner;
3271         s->currentUser = p->currentUser;
3272
3273         CurrentTransactionState = s;
3274 }
3275
3276 /*
3277  * PopTransaction
3278  *              Pop back to parent transaction state
3279  *
3280  *      The caller has to make sure to always reassign CurrentTransactionState
3281  *      if it has a local pointer to it after calling this function.
3282  */
3283 static void
3284 PopTransaction(void)
3285 {
3286         TransactionState s = CurrentTransactionState;
3287
3288         if (s->state != TRANS_DEFAULT)
3289                 elog(WARNING, "PopTransaction while in %s state",
3290                          TransStateAsString(s->state));
3291
3292         if (s->parent == NULL)
3293                 elog(FATAL, "PopTransaction with no parent");
3294
3295         /* Command IDs count in a continuous sequence through subtransactions */
3296         s->parent->commandId = s->commandId;
3297
3298         CurrentTransactionState = s->parent;
3299
3300         /* Let's just make sure CurTransactionContext is good */
3301         CurTransactionContext = s->parent->curTransactionContext;
3302         MemoryContextSwitchTo(CurTransactionContext);
3303
3304         /* Ditto for ResourceOwner links */
3305         CurTransactionResourceOwner = s->parent->curTransactionOwner;
3306         CurrentResourceOwner = s->parent->curTransactionOwner;
3307
3308         /* Free the old child structure */
3309         if (s->name)
3310                 pfree(s->name);
3311         pfree(s);
3312 }
3313
3314 /*
3315  * ShowTransactionState
3316  *              Debug support
3317  */
3318 static void
3319 ShowTransactionState(const char *str)
3320 {
3321         /* skip work if message will definitely not be printed */
3322         if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
3323         {
3324                 elog(DEBUG2, "%s", str);
3325                 ShowTransactionStateRec(CurrentTransactionState);
3326         }
3327 }
3328
3329 /*
3330  * ShowTransactionStateRec
3331  *              Recursive subroutine for ShowTransactionState
3332  */
3333 static void
3334 ShowTransactionStateRec(TransactionState s)
3335 {
3336         if (s->parent)
3337                 ShowTransactionStateRec(s->parent);
3338
3339         /* use ereport to suppress computation if msg will not be printed */
3340         ereport(DEBUG2,
3341                         (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/cid: %u/%02u, nestlvl: %d, children: %s",
3342                                                    PointerIsValid(s->name) ? s->name : "unnamed",
3343                                                          BlockStateAsString(s->blockState),
3344                                                          TransStateAsString(s->state),
3345                                                          (unsigned int) s->transactionIdData,
3346                                                          (unsigned int) s->commandId,
3347                                                          s->nestingLevel,
3348                                                          nodeToString(s->childXids))));
3349 }
3350
3351 /*
3352  * BlockStateAsString
3353  *              Debug support
3354  */
3355 static const char *
3356 BlockStateAsString(TBlockState blockState)
3357 {
3358         switch (blockState)
3359         {
3360                 case TBLOCK_DEFAULT:
3361                         return "DEFAULT";
3362                 case TBLOCK_STARTED:
3363                         return "STARTED";
3364                 case TBLOCK_BEGIN:
3365                         return "BEGIN";
3366                 case TBLOCK_INPROGRESS:
3367                         return "INPROGRESS";
3368                 case TBLOCK_END:
3369                         return "END";
3370                 case TBLOCK_ABORT:
3371                         return "ABORT";
3372                 case TBLOCK_ENDABORT:
3373                         return "ENDABORT";
3374                 case TBLOCK_SUBBEGIN:
3375                         return "SUB BEGIN";
3376                 case TBLOCK_SUBINPROGRESS:
3377                         return "SUB INPROGRS";
3378                 case TBLOCK_SUBEND:
3379                         return "SUB END";
3380                 case TBLOCK_SUBABORT:
3381                         return "SUB ABORT";
3382                 case TBLOCK_SUBENDABORT_ALL:
3383                         return "SUB ENDAB ALL";
3384                 case TBLOCK_SUBENDABORT:
3385                         return "SUB ENDAB";
3386                 case TBLOCK_SUBABORT_PENDING:
3387                         return "SUB ABRT PEND";
3388                 case TBLOCK_SUBENDABORT_RELEASE:
3389                         return "SUB ENDAB REL";
3390         }
3391         return "UNRECOGNIZED";
3392 }
3393
3394 /*
3395  * TransStateAsString
3396  *              Debug support
3397  */
3398 static const char *
3399 TransStateAsString(TransState state)
3400 {
3401         switch (state)
3402         {
3403                 case TRANS_DEFAULT:
3404                         return "DEFAULT";
3405                 case TRANS_START:
3406                         return "START";
3407                 case TRANS_COMMIT:
3408                         return "COMMIT";
3409                 case TRANS_ABORT:
3410                         return "ABORT";
3411                 case TRANS_INPROGRESS:
3412                         return "INPROGR";
3413         }
3414         return "UNRECOGNIZED";
3415 }
3416
3417 /*
3418  * xactGetCommittedChildren
3419  *
3420  * Gets the list of committed children of the current transaction.      The return
3421  * value is the number of child transactions.  *children is set to point to a
3422  * palloc'd array of TransactionIds.  If there are no subxacts, *children is
3423  * set to NULL.
3424  */
3425 int
3426 xactGetCommittedChildren(TransactionId **ptr)
3427 {
3428         TransactionState s = CurrentTransactionState;
3429         int                     nchildren;
3430         TransactionId *children;
3431         ListCell   *p;
3432
3433         nchildren = list_length(s->childXids);
3434         if (nchildren == 0)
3435         {
3436                 *ptr = NULL;
3437                 return 0;
3438         }
3439
3440         children = (TransactionId *) palloc(nchildren * sizeof(TransactionId));
3441         *ptr = children;
3442
3443         foreach(p, s->childXids)
3444         {
3445                 TransactionId child = lfirst_xid(p);
3446
3447                 *children++ = child;
3448         }
3449
3450         return nchildren;
3451 }
3452
3453 /*
3454  *      XLOG support routines
3455  */
3456
3457 void
3458 xact_redo(XLogRecPtr lsn, XLogRecord *record)
3459 {
3460         uint8           info = record->xl_info & ~XLR_INFO_MASK;
3461
3462         if (info == XLOG_XACT_COMMIT)
3463         {
3464                 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
3465                 int                     i;
3466
3467                 TransactionIdCommit(record->xl_xid);
3468                 /* Mark committed subtransactions as committed */
3469                 TransactionIdCommitTree(xlrec->nsubxacts,
3470                                            (TransactionId *) &(xlrec->xnodes[xlrec->nrels]));
3471                 /* Make sure files supposed to be dropped are dropped */
3472                 for (i = 0; i < xlrec->nrels; i++)
3473                 {
3474                         XLogCloseRelation(xlrec->xnodes[i]);
3475                         smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3476                 }
3477         }
3478         else if (info == XLOG_XACT_ABORT)
3479         {
3480                 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
3481                 int                     i;
3482
3483                 TransactionIdAbort(record->xl_xid);
3484                 /* mark subtransactions as aborted */
3485                 TransactionIdAbortTree(xlrec->nsubxacts,
3486                                            (TransactionId *) &(xlrec->xnodes[xlrec->nrels]));
3487                 /* Make sure files supposed to be dropped are dropped */
3488                 for (i = 0; i < xlrec->nrels; i++)
3489                 {
3490                         XLogCloseRelation(xlrec->xnodes[i]);
3491                         smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3492                 }
3493         }
3494         else
3495                 elog(PANIC, "xact_redo: unknown op code %u", info);
3496 }
3497
3498 void
3499 xact_undo(XLogRecPtr lsn, XLogRecord *record)
3500 {
3501         uint8           info = record->xl_info & ~XLR_INFO_MASK;
3502
3503         if (info == XLOG_XACT_COMMIT)           /* shouldn't be called by XLOG */
3504                 elog(PANIC, "xact_undo: can't undo committed xaction");
3505         else if (info != XLOG_XACT_ABORT)
3506                 elog(PANIC, "xact_redo: unknown op code %u", info);
3507 }
3508
3509 void
3510 xact_desc(char *buf, uint8 xl_info, char *rec)
3511 {
3512         uint8           info = xl_info & ~XLR_INFO_MASK;
3513         int                     i;
3514
3515         if (info == XLOG_XACT_COMMIT)
3516         {
3517                 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
3518                 struct tm  *tm = localtime(&xlrec->xtime);
3519
3520                 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
3521                                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3522                                 tm->tm_hour, tm->tm_min, tm->tm_sec);
3523                 if (xlrec->nrels > 0)
3524                 {
3525                         sprintf(buf + strlen(buf), "; rels:");
3526                         for (i = 0; i < xlrec->nrels; i++)
3527                         {
3528                                 RelFileNode rnode = xlrec->xnodes[i];
3529
3530                                 sprintf(buf + strlen(buf), " %u/%u/%u",
3531                                                 rnode.spcNode, rnode.dbNode, rnode.relNode);
3532                         }
3533                 }
3534                 if (xlrec->nsubxacts > 0)
3535                 {
3536                         TransactionId *xacts = (TransactionId *)
3537                         &xlrec->xnodes[xlrec->nrels];
3538
3539                         sprintf(buf + strlen(buf), "; subxacts:");
3540                         for (i = 0; i < xlrec->nsubxacts; i++)
3541                                 sprintf(buf + strlen(buf), " %u", xacts[i]);
3542                 }
3543         }
3544         else if (info == XLOG_XACT_ABORT)
3545         {
3546                 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
3547                 struct tm  *tm = localtime(&xlrec->xtime);
3548
3549                 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
3550                                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3551                                 tm->tm_hour, tm->tm_min, tm->tm_sec);
3552                 if (xlrec->nrels > 0)
3553                 {
3554                         sprintf(buf + strlen(buf), "; rels:");
3555                         for (i = 0; i < xlrec->nrels; i++)
3556                         {
3557                                 RelFileNode rnode = xlrec->xnodes[i];
3558
3559                                 sprintf(buf + strlen(buf), " %u/%u/%u",
3560                                                 rnode.spcNode, rnode.dbNode, rnode.relNode);
3561                         }
3562                 }
3563                 if (xlrec->nsubxacts > 0)
3564                 {
3565                         TransactionId *xacts = (TransactionId *)
3566                         &xlrec->xnodes[xlrec->nrels];
3567
3568                         sprintf(buf + strlen(buf), "; subxacts:");
3569                         for (i = 0; i < xlrec->nsubxacts; i++)
3570                                 sprintf(buf + strlen(buf), " %u", xacts[i]);
3571                 }
3572         }
3573         else
3574                 strcat(buf, "UNKNOWN");
3575 }
3576
3577 void
3578                         XactPushRollback(void (*func) (void *), void *data)
3579 {
3580 #ifdef XLOG_II
3581         if (_RollbackFunc != NULL)
3582                 elog(PANIC, "XactPushRollback: already installed");
3583 #endif
3584
3585         _RollbackFunc = func;
3586         _RollbackData = data;
3587 }
3588
3589 void
3590 XactPopRollback(void)
3591 {
3592         _RollbackFunc = NULL;
3593 }