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