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