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