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