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