1
/*-------------------------------------------------------------------------
4
* top level transaction system support routines
6
* See src/backend/access/transam/README for more information.
8
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
9
* Portions Copyright (c) 1994, Regents of the University of California
13
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.195.4.1 2005-04-11 19:51:31 tgl Exp $
15
*-------------------------------------------------------------------------
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"
49
* User-tweakable parameters
51
int DefaultXactIsoLevel = XACT_READ_COMMITTED;
54
bool DefaultXactReadOnly = false;
57
int CommitDelay = 0; /* precommit delay in microseconds */
58
int CommitSiblings = 5; /* # concurrent xacts needed to sleep */
62
* transaction states - transaction state from server perspective
64
typedef enum TransState
74
* transaction block states - transaction state of client queries
76
* Note: the subtransaction states are used only for non-topmost
77
* transactions; the others appear only in the topmost transaction.
79
typedef enum TBlockState
81
/* not-in-transaction-block states */
82
TBLOCK_DEFAULT, /* idle */
83
TBLOCK_STARTED, /* running single-query transaction */
85
/* transaction block states */
86
TBLOCK_BEGIN, /* starting transaction block */
87
TBLOCK_INPROGRESS, /* live transaction */
88
TBLOCK_END, /* COMMIT received */
89
TBLOCK_ABORT, /* failed xact, awaiting ROLLBACK */
90
TBLOCK_ABORT_END, /* failed xact, ROLLBACK received */
91
TBLOCK_ABORT_PENDING, /* live xact, ROLLBACK received */
93
/* subtransaction states */
94
TBLOCK_SUBBEGIN, /* starting a subtransaction */
95
TBLOCK_SUBINPROGRESS, /* live subtransaction */
96
TBLOCK_SUBEND, /* RELEASE received */
97
TBLOCK_SUBABORT, /* failed subxact, awaiting ROLLBACK */
98
TBLOCK_SUBABORT_END, /* failed subxact, ROLLBACK received */
99
TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received */
100
TBLOCK_SUBRESTART, /* live subxact, ROLLBACK TO received */
101
TBLOCK_SUBABORT_RESTART /* failed subxact, ROLLBACK TO received */
105
* transaction state structure
107
typedef struct TransactionStateData
109
TransactionId transactionId; /* my XID, or Invalid if none */
110
SubTransactionId subTransactionId; /* my subxact ID */
111
char *name; /* savepoint name, if any */
112
int savepointLevel; /* savepoint level */
113
TransState state; /* low-level state */
114
TBlockState blockState; /* high-level state */
115
int nestingLevel; /* nest depth */
116
MemoryContext curTransactionContext; /* my xact-lifetime
118
ResourceOwner curTransactionOwner; /* my query resources */
119
List *childXids; /* subcommitted child XIDs */
120
AclId currentUser; /* subxact start current_user */
121
bool prevXactReadOnly; /* entry-time xact r/o state */
122
struct TransactionStateData *parent; /* back link to parent */
123
} TransactionStateData;
125
typedef TransactionStateData *TransactionState;
128
* childXids is currently implemented as an integer List, relying on the
129
* assumption that TransactionIds are no wider than int. We use these
130
* macros to provide some isolation in case that changes in the future.
132
#define lfirst_xid(lc) ((TransactionId) lfirst_int(lc))
133
#define lappend_xid(list, datum) lappend_int(list, (int) (datum))
136
* CurrentTransactionState always points to the current transaction state
137
* block. It will point to TopTransactionStateData when not in a
138
* transaction at all, or when in a top-level transaction.
140
static TransactionStateData TopTransactionStateData = {
141
0, /* transaction id */
142
0, /* subtransaction id */
143
NULL, /* savepoint name */
144
0, /* savepoint level */
145
TRANS_DEFAULT, /* transaction state */
146
TBLOCK_DEFAULT, /* transaction block state from the client
148
0, /* nesting level */
149
NULL, /* cur transaction context */
150
NULL, /* cur transaction resource owner */
151
NIL, /* subcommitted child Xids */
152
0, /* entry-time current userid */
153
false, /* entry-time xact r/o state */
154
NULL /* link to parent state block */
157
static TransactionState CurrentTransactionState = &TopTransactionStateData;
160
* The subtransaction ID and command ID assignment counters are global
161
* to a whole transaction, so we do not keep them in the state stack.
163
static SubTransactionId currentSubTransactionId;
164
static CommandId currentCommandId;
167
* These vars hold the value of now(), ie, the transaction start time.
168
* This does not change as we enter and exit subtransactions, so we don't
169
* keep it inside the TransactionState stack.
171
static AbsoluteTime xactStartTime; /* integer part */
172
static int xactStartTimeUsec; /* microsecond part */
176
* List of add-on start- and end-of-xact callbacks
178
typedef struct XactCallbackItem
180
struct XactCallbackItem *next;
181
XactCallback callback;
185
static XactCallbackItem *Xact_callbacks = NULL;
188
* List of add-on start- and end-of-subxact callbacks
190
typedef struct SubXactCallbackItem
192
struct SubXactCallbackItem *next;
193
SubXactCallback callback;
195
} SubXactCallbackItem;
197
static SubXactCallbackItem *SubXact_callbacks = NULL;
199
static void (*_RollbackFunc) (void *) = NULL;
200
static void *_RollbackData = NULL;
203
/* local function prototypes */
204
static void AssignSubTransactionId(TransactionState s);
205
static void AbortTransaction(void);
206
static void AtAbort_Memory(void);
207
static void AtCleanup_Memory(void);
208
static void AtAbort_ResourceOwner(void);
209
static void AtCommit_LocalCache(void);
210
static void AtCommit_Memory(void);
211
static void AtStart_Cache(void);
212
static void AtStart_Memory(void);
213
static void AtStart_ResourceOwner(void);
214
static void CallXactCallbacks(XactEvent event);
215
static void CallSubXactCallbacks(SubXactEvent event,
216
SubTransactionId mySubid,
217
SubTransactionId parentSubid);
218
static void CleanupTransaction(void);
219
static void CommitTransaction(void);
220
static void RecordTransactionAbort(void);
221
static void StartTransaction(void);
223
static void RecordSubTransactionCommit(void);
224
static void StartSubTransaction(void);
225
static void CommitSubTransaction(void);
226
static void AbortSubTransaction(void);
227
static void CleanupSubTransaction(void);
228
static void PushTransaction(void);
229
static void PopTransaction(void);
231
static void AtSubAbort_Memory(void);
232
static void AtSubCleanup_Memory(void);
233
static void AtSubAbort_ResourceOwner(void);
234
static void AtSubCommit_Memory(void);
235
static void AtSubStart_Memory(void);
236
static void AtSubStart_ResourceOwner(void);
238
static void ShowTransactionState(const char *str);
239
static void ShowTransactionStateRec(TransactionState state);
240
static const char *BlockStateAsString(TBlockState blockState);
241
static const char *TransStateAsString(TransState state);
244
/* ----------------------------------------------------------------
245
* transaction state accessors
246
* ----------------------------------------------------------------
252
* This returns true if we are currently running a query
253
* within an executing transaction.
256
IsTransactionState(void)
258
TransactionState s = CurrentTransactionState;
266
case TRANS_INPROGRESS:
275
* Shouldn't get here, but lint is not happy with this...
281
* IsAbortedTransactionBlockState
283
* This returns true if we are currently running a query
284
* within an aborted transaction block.
287
IsAbortedTransactionBlockState(void)
289
TransactionState s = CurrentTransactionState;
291
if (s->blockState == TBLOCK_ABORT ||
292
s->blockState == TBLOCK_SUBABORT)
300
* GetTopTransactionId
302
* Get the ID of the main transaction, even if we are currently inside
306
GetTopTransactionId(void)
308
return TopTransactionStateData.transactionId;
313
* GetCurrentTransactionId
315
* We do not assign XIDs to subtransactions until/unless this is called.
316
* When we do assign an XID to a subtransaction, recursively make sure
317
* its parent has one as well (this maintains the invariant that a child
318
* transaction has an XID following its parent's).
321
GetCurrentTransactionId(void)
323
TransactionState s = CurrentTransactionState;
325
if (!TransactionIdIsValid(s->transactionId))
326
AssignSubTransactionId(s);
328
return s->transactionId;
332
AssignSubTransactionId(TransactionState s)
334
ResourceOwner currentOwner;
336
Assert(s->parent != NULL);
337
Assert(s->state == TRANS_INPROGRESS);
338
if (!TransactionIdIsValid(s->parent->transactionId))
339
AssignSubTransactionId(s->parent);
342
* Generate a new Xid and record it in PG_PROC and pg_subtrans.
344
* NB: we must make the subtrans entry BEFORE the Xid appears anywhere
345
* in shared storage other than PG_PROC; because if there's no room for
346
* it in PG_PROC, the subtrans entry is needed to ensure that other
347
* backends see the Xid as "running". See GetNewTransactionId.
349
s->transactionId = GetNewTransactionId(true);
351
SubTransSetParent(s->transactionId, s->parent->transactionId);
354
* Acquire lock on the transaction XID. (We assume this cannot block.)
355
* We have to be sure that the lock is assigned to the transaction's
358
currentOwner = CurrentResourceOwner;
361
CurrentResourceOwner = s->curTransactionOwner;
363
XactLockTableInsert(s->transactionId);
367
/* Ensure CurrentResourceOwner is restored on error */
368
CurrentResourceOwner = currentOwner;
372
CurrentResourceOwner = currentOwner;
377
* GetCurrentTransactionIdIfAny
379
* Unlike GetCurrentTransactionId, this will return InvalidTransactionId
380
* if we are currently not in a transaction, or in a transaction or
381
* subtransaction that has not yet assigned itself an XID.
384
GetCurrentTransactionIdIfAny(void)
386
TransactionState s = CurrentTransactionState;
388
return s->transactionId;
393
* GetCurrentSubTransactionId
396
GetCurrentSubTransactionId(void)
398
TransactionState s = CurrentTransactionState;
400
return s->subTransactionId;
405
* GetCurrentCommandId
408
GetCurrentCommandId(void)
410
/* this is global to a transaction, not subtransaction-local */
411
return currentCommandId;
416
* GetCurrentTransactionStartTime
419
GetCurrentTransactionStartTime(void)
421
return xactStartTime;
426
* GetCurrentTransactionStartTimeUsec
429
GetCurrentTransactionStartTimeUsec(int *msec)
431
*msec = xactStartTimeUsec;
432
return xactStartTime;
437
* GetCurrentTransactionNestLevel
439
* Note: this will return zero when not inside any transaction, one when
440
* inside a top-level transaction, etc.
443
GetCurrentTransactionNestLevel(void)
445
TransactionState s = CurrentTransactionState;
447
return s->nestingLevel;
452
* TransactionIdIsCurrentTransactionId
454
* During bootstrap, we cheat and say "it's not my transaction ID" even though
455
* it is. Along with transam.c's cheat to say that the bootstrap XID is
456
* already committed, this causes the tqual.c routines to see previously
457
* inserted tuples as committed, which is what we need during bootstrap.
460
TransactionIdIsCurrentTransactionId(TransactionId xid)
466
Assert(xid == BootstrapTransactionId);
471
* We will return true for the Xid of the current subtransaction, any
472
* of its subcommitted children, any of its parents, or any of their
473
* previously subcommitted children. However, a transaction being
474
* aborted is no longer "current", even though it may still have an
475
* entry on the state stack.
477
for (s = CurrentTransactionState; s != NULL; s = s->parent)
481
if (s->state == TRANS_ABORT)
483
if (!TransactionIdIsValid(s->transactionId))
484
continue; /* it can't have any child XIDs either */
485
if (TransactionIdEquals(xid, s->transactionId))
487
foreach(cell, s->childXids)
489
if (TransactionIdEquals(xid, lfirst_xid(cell)))
499
* CommandCounterIncrement
502
CommandCounterIncrement(void)
504
currentCommandId += 1;
505
if (currentCommandId == FirstCommandId) /* check for overflow */
507
currentCommandId -= 1;
509
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
510
errmsg("cannot have more than 2^32-1 commands in a transaction")));
513
/* Propagate new command ID into static snapshots, if set */
514
if (SerializableSnapshot)
515
SerializableSnapshot->curcid = currentCommandId;
517
LatestSnapshot->curcid = currentCommandId;
520
* make cache changes visible to me.
522
AtCommit_LocalCache();
527
/* ----------------------------------------------------------------
528
* StartTransaction stuff
529
* ----------------------------------------------------------------
538
AcceptInvalidationMessages();
547
TransactionState s = CurrentTransactionState;
550
* We shouldn't have a transaction context already.
552
Assert(TopTransactionContext == NULL);
555
* Create a toplevel context for the transaction.
557
TopTransactionContext =
558
AllocSetContextCreate(TopMemoryContext,
559
"TopTransactionContext",
560
ALLOCSET_DEFAULT_MINSIZE,
561
ALLOCSET_DEFAULT_INITSIZE,
562
ALLOCSET_DEFAULT_MAXSIZE);
565
* In a top-level transaction, CurTransactionContext is the same as
566
* TopTransactionContext.
568
CurTransactionContext = TopTransactionContext;
569
s->curTransactionContext = CurTransactionContext;
571
/* Make the CurTransactionContext active. */
572
MemoryContextSwitchTo(CurTransactionContext);
576
* AtStart_ResourceOwner
579
AtStart_ResourceOwner(void)
581
TransactionState s = CurrentTransactionState;
584
* We shouldn't have a transaction resource owner already.
586
Assert(TopTransactionResourceOwner == NULL);
589
* Create a toplevel resource owner for the transaction.
591
s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
593
TopTransactionResourceOwner = s->curTransactionOwner;
594
CurTransactionResourceOwner = s->curTransactionOwner;
595
CurrentResourceOwner = s->curTransactionOwner;
598
/* ----------------------------------------------------------------
599
* StartSubTransaction stuff
600
* ----------------------------------------------------------------
607
AtSubStart_Memory(void)
609
TransactionState s = CurrentTransactionState;
611
Assert(CurTransactionContext != NULL);
614
* Create a CurTransactionContext, which will be used to hold data
615
* that survives subtransaction commit but disappears on
616
* subtransaction abort. We make it a child of the immediate parent's
617
* CurTransactionContext.
619
CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
620
"CurTransactionContext",
621
ALLOCSET_DEFAULT_MINSIZE,
622
ALLOCSET_DEFAULT_INITSIZE,
623
ALLOCSET_DEFAULT_MAXSIZE);
624
s->curTransactionContext = CurTransactionContext;
626
/* Make the CurTransactionContext active. */
627
MemoryContextSwitchTo(CurTransactionContext);
631
* AtSubStart_ResourceOwner
634
AtSubStart_ResourceOwner(void)
636
TransactionState s = CurrentTransactionState;
638
Assert(s->parent != NULL);
641
* Create a resource owner for the subtransaction. We make it a child
642
* of the immediate parent's resource owner.
644
s->curTransactionOwner =
645
ResourceOwnerCreate(s->parent->curTransactionOwner,
648
CurTransactionResourceOwner = s->curTransactionOwner;
649
CurrentResourceOwner = s->curTransactionOwner;
652
/* ----------------------------------------------------------------
653
* CommitTransaction stuff
654
* ----------------------------------------------------------------
658
* RecordTransactionCommit
661
RecordTransactionCommit(void)
666
TransactionId *children;
668
/* Get data needed for commit record */
669
nrels = smgrGetPendingDeletes(true, &rptr);
670
nchildren = xactGetCommittedChildren(&children);
673
* If we made neither any XLOG entries nor any temp-rel updates, and
674
* have no files to be deleted, we can omit recording the transaction
675
* commit at all. (This test includes the effects of subtransactions,
676
* so the presence of committed subxacts need not alone force a
679
if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)
681
TransactionId xid = GetCurrentTransactionId();
685
/* Tell bufmgr and smgr to prepare for commit */
688
START_CRIT_SECTION();
691
* If our transaction made any transaction-controlled XLOG
692
* entries, we need to lock out checkpoint start between writing
693
* our XLOG record and updating pg_clog. Otherwise it is possible
694
* for the checkpoint to set REDO after the XLOG record but fail
695
* to flush the pg_clog update to disk, leading to loss of the
696
* transaction commit if we crash a little later. Slightly klugy
697
* fix for problem discovered 2004-08-10.
699
* (If it made no transaction-controlled XLOG entries, its XID
700
* appears nowhere in permanent storage, so no one else will ever
701
* care if it committed; so it doesn't matter if we lose the
704
* Note we only need a shared lock.
706
madeTCentries = (MyLastRecPtr.xrecoff != 0);
708
LWLockAcquire(CheckpointStartLock, LW_SHARED);
711
* We only need to log the commit in XLOG if the transaction made
712
* any transaction-controlled XLOG entries or will delete files.
714
if (madeTCentries || nrels > 0)
716
XLogRecData rdata[3];
718
xl_xact_commit xlrec;
720
xlrec.xtime = time(NULL);
722
xlrec.nsubxacts = nchildren;
723
rdata[0].buffer = InvalidBuffer;
724
rdata[0].data = (char *) (&xlrec);
725
rdata[0].len = MinSizeOfXactCommit;
726
/* dump rels to delete */
729
rdata[0].next = &(rdata[1]);
730
rdata[1].buffer = InvalidBuffer;
731
rdata[1].data = (char *) rptr;
732
rdata[1].len = nrels * sizeof(RelFileNode);
735
/* dump committed child Xids */
738
rdata[lastrdata].next = &(rdata[2]);
739
rdata[2].buffer = InvalidBuffer;
740
rdata[2].data = (char *) children;
741
rdata[2].len = nchildren * sizeof(TransactionId);
744
rdata[lastrdata].next = NULL;
746
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
750
/* Just flush through last record written by me */
751
recptr = ProcLastRecEnd;
755
* We must flush our XLOG entries to disk if we made any XLOG
756
* entries, whether in or out of transaction control. For
757
* example, if we reported a nextval() result to the client, this
758
* ensures that any XLOG record generated by nextval will hit the
759
* disk before we report the transaction committed.
761
* Note: if we generated a commit record above, MyXactMadeXLogEntry
762
* will certainly be set now.
764
if (MyXactMadeXLogEntry)
767
* Sleep before flush! So we can flush more than one commit
768
* records per single fsync. (The idea is some other backend
769
* may do the XLogFlush while we're sleeping. This needs work
770
* still, because on most Unixen, the minimum select() delay
771
* is 10msec or more, which is way too long.)
773
* We do not sleep if enableFsync is not turned on, nor if there
774
* are fewer than CommitSiblings other backends with active
777
if (CommitDelay > 0 && enableFsync &&
778
CountActiveBackends() >= CommitSiblings)
779
pg_usleep(CommitDelay);
785
* We must mark the transaction committed in clog if its XID
786
* appears either in permanent rels or in local temporary rels. We
787
* test this by seeing if we made transaction-controlled entries
788
* *OR* local-rel tuple updates. Note that if we made only the
789
* latter, we have not emitted an XLOG record for our commit, and
790
* so in the event of a crash the clog update might be lost. This
791
* is okay because no one else will ever care whether we
794
if (madeTCentries || MyXactMadeTempRelUpdate)
796
TransactionIdCommit(xid);
797
/* to avoid race conditions, the parent must commit first */
798
TransactionIdCommitTree(nchildren, children);
801
/* Unlock checkpoint lock if we acquired it */
803
LWLockRelease(CheckpointStartLock);
808
/* Break the chain of back-links in the XLOG records I output */
809
MyLastRecPtr.xrecoff = 0;
810
MyXactMadeXLogEntry = false;
811
MyXactMadeTempRelUpdate = false;
813
/* Show myself as out of the transaction in PGPROC array */
814
MyProc->logRec.xrecoff = 0;
816
/* And clean up local data */
825
* AtCommit_LocalCache
828
AtCommit_LocalCache(void)
831
* Make catalog changes visible to me for the next command.
833
CommandEndInvalidationMessages();
840
AtCommit_Memory(void)
843
* Now that we're "out" of a transaction, have the system allocate
844
* things in the top memory context instead of per-transaction
847
MemoryContextSwitchTo(TopMemoryContext);
850
* Release all transaction-local memory.
852
Assert(TopTransactionContext != NULL);
853
MemoryContextDelete(TopTransactionContext);
854
TopTransactionContext = NULL;
855
CurTransactionContext = NULL;
856
CurrentTransactionState->curTransactionContext = NULL;
859
/* ----------------------------------------------------------------
860
* CommitSubTransaction stuff
861
* ----------------------------------------------------------------
868
AtSubCommit_Memory(void)
870
TransactionState s = CurrentTransactionState;
872
Assert(s->parent != NULL);
874
/* Return to parent transaction level's memory context. */
875
CurTransactionContext = s->parent->curTransactionContext;
876
MemoryContextSwitchTo(CurTransactionContext);
879
* Ordinarily we cannot throw away the child's CurTransactionContext,
880
* since the data it contains will be needed at upper commit. However,
881
* if there isn't actually anything in it, we can throw it away. This
882
* avoids a small memory leak in the common case of "trivial" subxacts.
884
if (MemoryContextIsEmpty(s->curTransactionContext))
886
MemoryContextDelete(s->curTransactionContext);
887
s->curTransactionContext = NULL;
892
* AtSubCommit_childXids
894
* Pass my own XID and my child XIDs up to my parent as committed children.
897
AtSubCommit_childXids(void)
899
TransactionState s = CurrentTransactionState;
900
MemoryContext old_cxt;
902
Assert(s->parent != NULL);
905
* We keep the child-XID lists in TopTransactionContext; this avoids
906
* setting up child-transaction contexts for what might be just a few
907
* bytes of grandchild XIDs.
909
old_cxt = MemoryContextSwitchTo(TopTransactionContext);
911
s->parent->childXids = lappend_xid(s->parent->childXids,
914
if (s->childXids != NIL)
916
s->parent->childXids = list_concat(s->parent->childXids,
919
* list_concat doesn't free the list header for the second list;
920
* do so here to avoid memory leakage (kluge)
926
MemoryContextSwitchTo(old_cxt);
930
* RecordSubTransactionCommit
933
RecordSubTransactionCommit(void)
936
* We do not log the subcommit in XLOG; it doesn't matter until the
937
* top-level transaction commits.
939
* We must mark the subtransaction subcommitted in clog if its XID
940
* appears either in permanent rels or in local temporary rels. We
941
* test this by seeing if we made transaction-controlled entries *OR*
942
* local-rel tuple updates. (The test here actually covers the entire
943
* transaction tree so far, so it may mark subtransactions that don't
944
* really need it, but it's probably not worth being tenser. Note that
945
* if a prior subtransaction dirtied these variables, then
946
* RecordTransactionCommit will have to do the full pushup anyway...)
948
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
950
TransactionId xid = GetCurrentTransactionId();
952
/* XXX does this really need to be a critical section? */
953
START_CRIT_SECTION();
955
/* Record subtransaction subcommit */
956
TransactionIdSubCommit(xid);
962
/* ----------------------------------------------------------------
963
* AbortTransaction stuff
964
* ----------------------------------------------------------------
968
* RecordTransactionAbort
971
RecordTransactionAbort(void)
976
TransactionId *children;
978
/* Get data needed for abort record */
979
nrels = smgrGetPendingDeletes(false, &rptr);
980
nchildren = xactGetCommittedChildren(&children);
983
* If we made neither any transaction-controlled XLOG entries nor any
984
* temp-rel updates, and are not going to delete any files, we can
985
* omit recording the transaction abort at all. No one will ever care
986
* that it aborted. (These tests cover our whole transaction tree.)
988
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
990
TransactionId xid = GetCurrentTransactionId();
993
* Catch the scenario where we aborted partway through
994
* RecordTransactionCommit ...
996
if (TransactionIdDidCommit(xid))
997
elog(PANIC, "cannot abort transaction %u, it was already committed", xid);
999
START_CRIT_SECTION();
1002
* We only need to log the abort in XLOG if the transaction made
1003
* any transaction-controlled XLOG entries or will delete files.
1004
* (If it made no transaction-controlled XLOG entries, its XID
1005
* appears nowhere in permanent storage, so no one else will ever
1006
* care if it committed.)
1008
* We do not flush XLOG to disk unless deleting files, since the
1009
* default assumption after a crash would be that we aborted,
1010
* anyway. For the same reason, we don't need to worry about
1011
* interlocking against checkpoint start.
1013
if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1015
XLogRecData rdata[3];
1017
xl_xact_abort xlrec;
1020
xlrec.xtime = time(NULL);
1021
xlrec.nrels = nrels;
1022
xlrec.nsubxacts = nchildren;
1023
rdata[0].buffer = InvalidBuffer;
1024
rdata[0].data = (char *) (&xlrec);
1025
rdata[0].len = MinSizeOfXactAbort;
1026
/* dump rels to delete */
1029
rdata[0].next = &(rdata[1]);
1030
rdata[1].buffer = InvalidBuffer;
1031
rdata[1].data = (char *) rptr;
1032
rdata[1].len = nrels * sizeof(RelFileNode);
1035
/* dump committed child Xids */
1038
rdata[lastrdata].next = &(rdata[2]);
1039
rdata[2].buffer = InvalidBuffer;
1040
rdata[2].data = (char *) children;
1041
rdata[2].len = nchildren * sizeof(TransactionId);
1044
rdata[lastrdata].next = NULL;
1046
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1048
/* Must flush if we are deleting files... */
1054
* Mark the transaction aborted in clog. This is not absolutely
1055
* necessary but we may as well do it while we are here.
1057
* The ordering here isn't critical but it seems best to mark the
1058
* parent first. This assures an atomic transition of all the
1059
* subtransactions to aborted state from the point of view of
1060
* concurrent TransactionIdDidAbort calls.
1062
TransactionIdAbort(xid);
1063
TransactionIdAbortTree(nchildren, children);
1068
/* Break the chain of back-links in the XLOG records I output */
1069
MyLastRecPtr.xrecoff = 0;
1070
MyXactMadeXLogEntry = false;
1071
MyXactMadeTempRelUpdate = false;
1073
/* Show myself as out of the transaction in PGPROC array */
1074
MyProc->logRec.xrecoff = 0;
1076
/* And clean up local data */
1087
AtAbort_Memory(void)
1090
* Make sure we are in a valid context (not a child of
1091
* TopTransactionContext...). Note that it is possible for this code
1092
* to be called when we aren't in a transaction at all; go directly to
1093
* TopMemoryContext in that case.
1095
if (TopTransactionContext != NULL)
1097
MemoryContextSwitchTo(TopTransactionContext);
1100
* We do not want to destroy the transaction's global state yet,
1101
* so we can't free any memory here.
1105
MemoryContextSwitchTo(TopMemoryContext);
1112
AtSubAbort_Memory(void)
1114
Assert(TopTransactionContext != NULL);
1116
MemoryContextSwitchTo(TopTransactionContext);
1121
* AtAbort_ResourceOwner
1124
AtAbort_ResourceOwner(void)
1127
* Make sure we have a valid ResourceOwner, if possible (else it
1128
* will be NULL, which is OK)
1130
CurrentResourceOwner = TopTransactionResourceOwner;
1134
* AtSubAbort_ResourceOwner
1137
AtSubAbort_ResourceOwner(void)
1139
TransactionState s = CurrentTransactionState;
1141
/* Make sure we have a valid ResourceOwner */
1142
CurrentResourceOwner = s->curTransactionOwner;
1147
* AtSubAbort_childXids
1150
AtSubAbort_childXids(void)
1152
TransactionState s = CurrentTransactionState;
1155
* We keep the child-XID lists in TopTransactionContext (see
1156
* AtSubCommit_childXids). This means we'd better free the list
1157
* explicitly at abort to avoid leakage.
1159
list_free(s->childXids);
1164
* RecordSubTransactionAbort
1167
RecordSubTransactionAbort(void)
1171
TransactionId xid = GetCurrentTransactionId();
1173
TransactionId *children;
1175
/* Get data needed for abort record */
1176
nrels = smgrGetPendingDeletes(false, &rptr);
1177
nchildren = xactGetCommittedChildren(&children);
1180
* If we made neither any transaction-controlled XLOG entries nor any
1181
* temp-rel updates, and are not going to delete any files, we can
1182
* omit recording the transaction abort at all. No one will ever care
1183
* that it aborted. (These tests cover our whole transaction tree,
1184
* and therefore may mark subxacts that don't really need it, but it's
1185
* probably not worth being tenser.)
1187
* In this case we needn't worry about marking subcommitted children as
1188
* aborted, because they didn't mark themselves as subcommitted in the
1189
* first place; see the optimization in RecordSubTransactionCommit.
1191
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
1193
START_CRIT_SECTION();
1196
* We only need to log the abort in XLOG if the transaction made
1197
* any transaction-controlled XLOG entries or will delete files.
1199
if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
1201
XLogRecData rdata[3];
1203
xl_xact_abort xlrec;
1206
xlrec.xtime = time(NULL);
1207
xlrec.nrels = nrels;
1208
xlrec.nsubxacts = nchildren;
1209
rdata[0].buffer = InvalidBuffer;
1210
rdata[0].data = (char *) (&xlrec);
1211
rdata[0].len = MinSizeOfXactAbort;
1212
/* dump rels to delete */
1215
rdata[0].next = &(rdata[1]);
1216
rdata[1].buffer = InvalidBuffer;
1217
rdata[1].data = (char *) rptr;
1218
rdata[1].len = nrels * sizeof(RelFileNode);
1221
/* dump committed child Xids */
1224
rdata[lastrdata].next = &(rdata[2]);
1225
rdata[2].buffer = InvalidBuffer;
1226
rdata[2].data = (char *) children;
1227
rdata[2].len = nchildren * sizeof(TransactionId);
1230
rdata[lastrdata].next = NULL;
1232
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1234
/* Must flush if we are deleting files... */
1240
* Mark the transaction aborted in clog. This is not absolutely
1241
* necessary but XactLockTableWait makes use of it to avoid waiting
1242
* for already-aborted subtransactions.
1244
TransactionIdAbort(xid);
1245
TransactionIdAbortTree(nchildren, children);
1251
* We can immediately remove failed XIDs from PGPROC's cache of
1252
* running child XIDs. It's easiest to do it here while we have the
1253
* child XID array at hand, even though in the main-transaction case
1254
* the equivalent work happens just after return from
1255
* RecordTransactionAbort.
1257
XidCacheRemoveRunningXids(xid, nchildren, children);
1259
/* And clean up local data */
1266
/* ----------------------------------------------------------------
1267
* CleanupTransaction stuff
1268
* ----------------------------------------------------------------
1275
AtCleanup_Memory(void)
1278
* Now that we're "out" of a transaction, have the system allocate
1279
* things in the top memory context instead of per-transaction
1282
MemoryContextSwitchTo(TopMemoryContext);
1284
Assert(CurrentTransactionState->parent == NULL);
1287
* Release all transaction-local memory.
1289
if (TopTransactionContext != NULL)
1290
MemoryContextDelete(TopTransactionContext);
1291
TopTransactionContext = NULL;
1292
CurTransactionContext = NULL;
1293
CurrentTransactionState->curTransactionContext = NULL;
1297
/* ----------------------------------------------------------------
1298
* CleanupSubTransaction stuff
1299
* ----------------------------------------------------------------
1303
* AtSubCleanup_Memory
1306
AtSubCleanup_Memory(void)
1308
TransactionState s = CurrentTransactionState;
1310
Assert(s->parent != NULL);
1312
/* Make sure we're not in an about-to-be-deleted context */
1313
MemoryContextSwitchTo(s->parent->curTransactionContext);
1314
CurTransactionContext = s->parent->curTransactionContext;
1317
* Delete the subxact local memory contexts. Its CurTransactionContext
1318
* can go too (note this also kills CurTransactionContexts from any
1319
* children of the subxact).
1321
if (s->curTransactionContext)
1322
MemoryContextDelete(s->curTransactionContext);
1323
s->curTransactionContext = NULL;
1326
/* ----------------------------------------------------------------
1327
* interface routines
1328
* ----------------------------------------------------------------
1335
StartTransaction(void)
1340
* Let's just make sure the state stack is empty
1342
s = &TopTransactionStateData;
1343
CurrentTransactionState = s;
1346
* check the current transaction state
1348
if (s->state != TRANS_DEFAULT)
1349
elog(WARNING, "StartTransaction while in %s state",
1350
TransStateAsString(s->state));
1353
* set the current transaction state information appropriately during
1356
s->state = TRANS_START;
1359
* Make sure we've freed any old snapshot, and reset xact state
1363
XactIsoLevel = DefaultXactIsoLevel;
1364
XactReadOnly = DefaultXactReadOnly;
1367
* reinitialize within-transaction counters
1369
s->subTransactionId = TopSubTransactionId;
1370
currentSubTransactionId = TopSubTransactionId;
1371
currentCommandId = FirstCommandId;
1374
* must initialize resource-management stuff first
1377
AtStart_ResourceOwner();
1380
* generate a new transaction id
1382
s->transactionId = GetNewTransactionId(false);
1384
XactLockTableInsert(s->transactionId);
1389
xactStartTime = GetCurrentAbsoluteTimeUsec(&(xactStartTimeUsec));
1392
* initialize current transaction state fields
1394
s->nestingLevel = 1;
1398
* You might expect to see "s->currentUser = GetUserId();" here, but
1399
* you won't because it doesn't work during startup; the userid isn't
1400
* set yet during a backend's first transaction start. We only use
1401
* the currentUser field in sub-transaction state structs.
1403
* prevXactReadOnly is also valid only in sub-transactions.
1407
* initialize other subsystems for new transaction
1411
AfterTriggerBeginXact();
1414
* done with start processing, set current transaction state to "in
1417
s->state = TRANS_INPROGRESS;
1419
ShowTransactionState("StartTransaction");
1426
CommitTransaction(void)
1428
TransactionState s = CurrentTransactionState;
1430
ShowTransactionState("CommitTransaction");
1433
* check the current transaction state
1435
if (s->state != TRANS_INPROGRESS)
1436
elog(WARNING, "CommitTransaction while in %s state",
1437
TransStateAsString(s->state));
1438
Assert(s->parent == NULL);
1441
* Do pre-commit processing (most of this stuff requires database
1442
* access, and in fact could still cause an error...)
1444
* It is possible for CommitHoldablePortals to invoke functions that
1445
* queue deferred triggers, and it's also possible that triggers create
1446
* holdable cursors. So we have to loop until there's nothing left to
1452
* Fire all currently pending deferred triggers.
1454
AfterTriggerFireDeferred();
1457
* Convert any open holdable cursors into static portals. If there
1458
* weren't any, we are done ... otherwise loop back to check if they
1459
* queued deferred triggers. Lather, rinse, repeat.
1461
if (!CommitHoldablePortals())
1465
/* Now we can shut down the deferred-trigger manager */
1466
AfterTriggerEndXact(true);
1468
/* Close any open regular cursors */
1472
* Let ON COMMIT management do its thing (must happen after closing
1473
* cursors, to avoid dangling-reference problems)
1475
PreCommit_on_commit_actions();
1477
/* close large objects before lower-level cleanup */
1478
AtEOXact_LargeObject(true);
1480
/* NOTIFY commit must come before lower-level cleanup */
1483
/* Update the flat password file if we changed pg_shadow or pg_group */
1484
/* This should be the last step before commit */
1485
AtEOXact_UpdatePasswordFile(true);
1487
/* Prevent cancel/die interrupt while cleaning up */
1491
* set the current transaction state information appropriately during
1492
* the abort processing
1494
s->state = TRANS_COMMIT;
1497
* Here is where we really truly commit.
1499
RecordTransactionCommit();
1502
* Let others know about no transaction in progress by me. Note that
1503
* this must be done _before_ releasing locks we hold and _after_
1504
* RecordTransactionCommit.
1506
* LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
1507
* xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
1508
* xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
1509
* as running as well or it will see two tuple versions - one deleted
1510
* by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
1514
/* Lock SInvalLock because that's what GetSnapshotData uses. */
1515
LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1516
MyProc->xid = InvalidTransactionId;
1517
MyProc->xmin = InvalidTransactionId;
1519
/* Clear the subtransaction-XID cache too while holding the lock */
1520
MyProc->subxids.nxids = 0;
1521
MyProc->subxids.overflowed = false;
1523
LWLockRelease(SInvalLock);
1527
* This is all post-commit cleanup. Note that if an error is raised
1528
* here, it's too late to abort the transaction. This should be just
1529
* noncritical resource releasing.
1531
* The ordering of operations is not entirely random. The idea is:
1532
* release resources visible to other backends (eg, files, buffer
1533
* pins); then release locks; then release backend-local resources. We
1534
* want to release locks at the point where any backend waiting for us
1535
* will see our transaction as being fully cleaned up.
1537
* Resources that can be associated with individual queries are handled
1538
* by the ResourceOwner mechanism. The other calls here are for
1539
* backend-wide state.
1542
CallXactCallbacks(XACT_EVENT_COMMIT);
1544
ResourceOwnerRelease(TopTransactionResourceOwner,
1545
RESOURCE_RELEASE_BEFORE_LOCKS,
1548
/* Check we've released all buffer pins */
1549
AtEOXact_Buffers(true);
1552
* Make catalog changes visible to all backends. This has to happen
1553
* after relcache references are dropped (see comments for
1554
* AtEOXact_RelationCache), but before locks are released (if anyone
1555
* is waiting for lock on a relation we've modified, we want them to
1556
* know about the catalog change before they start using the
1559
AtEOXact_Inval(true);
1562
* Likewise, dropping of files deleted during the transaction is best done
1563
* after releasing relcache and buffer pins. (This is not strictly
1564
* necessary during commit, since such pins should have been released
1565
* already, but this ordering is definitely critical during abort.)
1567
smgrDoPendingDeletes(true);
1569
ResourceOwnerRelease(TopTransactionResourceOwner,
1570
RESOURCE_RELEASE_LOCKS,
1572
ResourceOwnerRelease(TopTransactionResourceOwner,
1573
RESOURCE_RELEASE_AFTER_LOCKS,
1576
AtEOXact_GUC(true, false);
1578
AtEOXact_on_commit_actions(true);
1579
AtEOXact_Namespace(true);
1580
/* smgrcommit already done */
1582
pgstat_count_xact_commit();
1584
CurrentResourceOwner = NULL;
1585
ResourceOwnerDelete(TopTransactionResourceOwner);
1586
s->curTransactionOwner = NULL;
1587
CurTransactionResourceOwner = NULL;
1588
TopTransactionResourceOwner = NULL;
1592
s->transactionId = InvalidTransactionId;
1593
s->subTransactionId = InvalidSubTransactionId;
1594
s->nestingLevel = 0;
1598
* done with commit processing, set current transaction state back to
1601
s->state = TRANS_DEFAULT;
1603
RESUME_INTERRUPTS();
1610
AbortTransaction(void)
1612
TransactionState s = CurrentTransactionState;
1614
/* Prevent cancel/die interrupt while cleaning up */
1618
* Release any LW locks we might be holding as quickly as possible.
1619
* (Regular locks, however, must be held till we finish aborting.)
1620
* Releasing LW locks is critical since we might try to grab them
1621
* again while cleaning up!
1625
/* Clean up buffer I/O and buffer context locks, too */
1630
* Also clean up any open wait for lock, since the lock manager will
1631
* choke if we try to wait for another lock before doing this.
1636
* check the current transaction state
1638
if (s->state != TRANS_INPROGRESS)
1639
elog(WARNING, "AbortTransaction while in %s state",
1640
TransStateAsString(s->state));
1641
Assert(s->parent == NULL);
1644
* set the current transaction state information appropriately during
1645
* the abort processing
1647
s->state = TRANS_ABORT;
1649
/* Make sure we have a valid memory context and resource owner */
1651
AtAbort_ResourceOwner();
1654
* Reset user id which might have been changed transiently. We cannot
1655
* use s->currentUser, but must get the session userid from
1658
* (Note: it is not necessary to restore session authorization here
1659
* because that can only be changed via GUC, and GUC will take care of
1660
* rolling it back if need be. However, an error within a SECURITY
1661
* DEFINER function could send control here with the wrong current
1664
SetUserId(GetSessionUserId());
1667
* do abort processing
1669
AfterTriggerEndXact(false);
1671
AtEOXact_LargeObject(false); /* 'false' means it's abort */
1673
AtEOXact_UpdatePasswordFile(false);
1675
/* Advertise the fact that we aborted in pg_clog. */
1676
RecordTransactionAbort();
1679
* Let others know about no transaction in progress by me. Note that
1680
* this must be done _before_ releasing locks we hold and _after_
1681
* RecordTransactionAbort.
1685
/* Lock SInvalLock because that's what GetSnapshotData uses. */
1686
LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1687
MyProc->xid = InvalidTransactionId;
1688
MyProc->xmin = InvalidTransactionId;
1690
/* Clear the subtransaction-XID cache too while holding the lock */
1691
MyProc->subxids.nxids = 0;
1692
MyProc->subxids.overflowed = false;
1694
LWLockRelease(SInvalLock);
1698
* Post-abort cleanup. See notes in CommitTransaction() concerning
1702
CallXactCallbacks(XACT_EVENT_ABORT);
1704
ResourceOwnerRelease(TopTransactionResourceOwner,
1705
RESOURCE_RELEASE_BEFORE_LOCKS,
1707
AtEOXact_Buffers(false);
1708
AtEOXact_Inval(false);
1709
smgrDoPendingDeletes(false);
1710
ResourceOwnerRelease(TopTransactionResourceOwner,
1711
RESOURCE_RELEASE_LOCKS,
1713
ResourceOwnerRelease(TopTransactionResourceOwner,
1714
RESOURCE_RELEASE_AFTER_LOCKS,
1717
AtEOXact_GUC(false, false);
1718
AtEOXact_SPI(false);
1719
AtEOXact_on_commit_actions(false);
1720
AtEOXact_Namespace(false);
1723
pgstat_count_xact_rollback();
1726
* State remains TRANS_ABORT until CleanupTransaction().
1728
RESUME_INTERRUPTS();
1732
* CleanupTransaction
1735
CleanupTransaction(void)
1737
TransactionState s = CurrentTransactionState;
1740
* State should still be TRANS_ABORT from AbortTransaction().
1742
if (s->state != TRANS_ABORT)
1743
elog(FATAL, "CleanupTransaction: unexpected state %s",
1744
TransStateAsString(s->state));
1747
* do abort cleanup processing
1749
AtCleanup_Portals(); /* now safe to release portal memory */
1751
CurrentResourceOwner = NULL; /* and resource owner */
1752
if (TopTransactionResourceOwner)
1753
ResourceOwnerDelete(TopTransactionResourceOwner);
1754
s->curTransactionOwner = NULL;
1755
CurTransactionResourceOwner = NULL;
1756
TopTransactionResourceOwner = NULL;
1758
AtCleanup_Memory(); /* and transaction memory */
1760
s->transactionId = InvalidTransactionId;
1761
s->subTransactionId = InvalidSubTransactionId;
1762
s->nestingLevel = 0;
1766
* done with abort processing, set current transaction state back to
1769
s->state = TRANS_DEFAULT;
1773
* StartTransactionCommand
1776
StartTransactionCommand(void)
1778
TransactionState s = CurrentTransactionState;
1780
switch (s->blockState)
1783
* if we aren't in a transaction block, we just do our usual
1784
* start transaction.
1786
case TBLOCK_DEFAULT:
1788
s->blockState = TBLOCK_STARTED;
1792
* We are somewhere in a transaction block or subtransaction
1793
* and about to start a new command. For now we do nothing,
1794
* but someday we may do command-local resource initialization.
1795
* (Note that any needed CommandCounterIncrement was done by
1796
* the previous CommitTransactionCommand.)
1798
case TBLOCK_INPROGRESS:
1799
case TBLOCK_SUBINPROGRESS:
1803
* Here we are in a failed transaction block (one of
1804
* the commands caused an abort) so we do nothing but remain in
1805
* the abort state. Eventually we will get a ROLLBACK command
1806
* which will get us out of this state. (It is up to other
1807
* code to ensure that no commands other than ROLLBACK will be
1808
* processed in these states.)
1811
case TBLOCK_SUBABORT:
1814
/* These cases are invalid. */
1815
case TBLOCK_STARTED:
1817
case TBLOCK_SUBBEGIN:
1820
case TBLOCK_ABORT_END:
1821
case TBLOCK_SUBABORT_END:
1822
case TBLOCK_ABORT_PENDING:
1823
case TBLOCK_SUBABORT_PENDING:
1824
case TBLOCK_SUBRESTART:
1825
case TBLOCK_SUBABORT_RESTART:
1826
elog(ERROR, "StartTransactionCommand: unexpected state %s",
1827
BlockStateAsString(s->blockState));
1832
* We must switch to CurTransactionContext before returning. This is
1833
* already done if we called StartTransaction, otherwise not.
1835
Assert(CurTransactionContext != NULL);
1836
MemoryContextSwitchTo(CurTransactionContext);
1840
* CommitTransactionCommand
1843
CommitTransactionCommand(void)
1845
TransactionState s = CurrentTransactionState;
1847
switch (s->blockState)
1850
* This shouldn't happen, because it means the previous
1851
* StartTransactionCommand didn't set the STARTED state
1854
case TBLOCK_DEFAULT:
1855
elog(FATAL, "CommitTransactionCommand: unexpected state %s",
1856
BlockStateAsString(s->blockState));
1860
* If we aren't in a transaction block, just do our usual
1861
* transaction commit, and return to the idle state.
1863
case TBLOCK_STARTED:
1864
CommitTransaction();
1865
s->blockState = TBLOCK_DEFAULT;
1869
* We are completing a "BEGIN TRANSACTION" command, so we
1870
* change to the "transaction block in progress" state and
1871
* return. (We assume the BEGIN did nothing to the database,
1872
* so we need no CommandCounterIncrement.)
1875
s->blockState = TBLOCK_INPROGRESS;
1879
* This is the case when we have finished executing a command
1880
* someplace within a transaction block. We increment the
1881
* command counter and return.
1883
case TBLOCK_INPROGRESS:
1884
case TBLOCK_SUBINPROGRESS:
1885
CommandCounterIncrement();
1889
* We are completing a "COMMIT" command. Do it and return to
1893
CommitTransaction();
1894
s->blockState = TBLOCK_DEFAULT;
1898
* Here we are in the middle of a transaction block but one of
1899
* the commands caused an abort so we do nothing but remain in
1900
* the abort state. Eventually we will get a ROLLBACK comand.
1903
case TBLOCK_SUBABORT:
1907
* Here we were in an aborted transaction block and we just
1908
* got the ROLLBACK command from the user, so clean up the
1909
* already-aborted transaction and return to the idle state.
1911
case TBLOCK_ABORT_END:
1912
CleanupTransaction();
1913
s->blockState = TBLOCK_DEFAULT;
1917
* Here we were in a perfectly good transaction block but the
1918
* user told us to ROLLBACK anyway. We have to abort the
1919
* transaction and then clean up.
1921
case TBLOCK_ABORT_PENDING:
1923
CleanupTransaction();
1924
s->blockState = TBLOCK_DEFAULT;
1928
* We were just issued a SAVEPOINT inside a transaction block.
1929
* Start a subtransaction. (DefineSavepoint already did
1930
* PushTransaction, so as to have someplace to put the
1933
case TBLOCK_SUBBEGIN:
1934
StartSubTransaction();
1935
s->blockState = TBLOCK_SUBINPROGRESS;
1939
* We were issued a COMMIT or RELEASE command, so we end the
1940
* current subtransaction and return to the parent transaction.
1941
* The parent might be ended too, so repeat till we are all the
1942
* way out or find an INPROGRESS transaction.
1947
CommitSubTransaction();
1948
s = CurrentTransactionState; /* changed by pop */
1949
} while (s->blockState == TBLOCK_SUBEND);
1950
/* If we had a COMMIT command, finish off the main xact too */
1951
if (s->blockState == TBLOCK_END)
1953
Assert(s->parent == NULL);
1954
CommitTransaction();
1955
s->blockState = TBLOCK_DEFAULT;
1959
Assert(s->blockState == TBLOCK_INPROGRESS ||
1960
s->blockState == TBLOCK_SUBINPROGRESS);
1965
* The current already-failed subtransaction is ending due to a
1966
* ROLLBACK or ROLLBACK TO command, so pop it and recursively
1967
* examine the parent (which could be in any of several states).
1969
case TBLOCK_SUBABORT_END:
1970
CleanupSubTransaction();
1971
CommitTransactionCommand();
1975
* As above, but it's not dead yet, so abort first.
1977
case TBLOCK_SUBABORT_PENDING:
1978
AbortSubTransaction();
1979
CleanupSubTransaction();
1980
CommitTransactionCommand();
1984
* The current subtransaction is the target of a ROLLBACK TO
1985
* command. Abort and pop it, then start a new subtransaction
1986
* with the same name.
1988
case TBLOCK_SUBRESTART:
1993
/* save name and keep Cleanup from freeing it */
1996
savepointLevel = s->savepointLevel;
1998
AbortSubTransaction();
1999
CleanupSubTransaction();
2001
DefineSavepoint(NULL);
2002
s = CurrentTransactionState; /* changed by push */
2004
s->savepointLevel = savepointLevel;
2006
/* This is the same as TBLOCK_SUBBEGIN case */
2007
AssertState(s->blockState == TBLOCK_SUBBEGIN);
2008
StartSubTransaction();
2009
s->blockState = TBLOCK_SUBINPROGRESS;
2014
* Same as above, but the subtransaction had already failed,
2015
* so we don't need AbortSubTransaction.
2017
case TBLOCK_SUBABORT_RESTART:
2022
/* save name and keep Cleanup from freeing it */
2025
savepointLevel = s->savepointLevel;
2027
CleanupSubTransaction();
2029
DefineSavepoint(NULL);
2030
s = CurrentTransactionState; /* changed by push */
2032
s->savepointLevel = savepointLevel;
2034
/* This is the same as TBLOCK_SUBBEGIN case */
2035
AssertState(s->blockState == TBLOCK_SUBBEGIN);
2036
StartSubTransaction();
2037
s->blockState = TBLOCK_SUBINPROGRESS;
2044
* AbortCurrentTransaction
2047
AbortCurrentTransaction(void)
2049
TransactionState s = CurrentTransactionState;
2051
switch (s->blockState)
2054
* we aren't in a transaction, so we do nothing.
2056
case TBLOCK_DEFAULT:
2060
* if we aren't in a transaction block, we just do the basic
2061
* abort & cleanup transaction.
2063
case TBLOCK_STARTED:
2065
CleanupTransaction();
2066
s->blockState = TBLOCK_DEFAULT;
2070
* If we are in TBLOCK_BEGIN it means something screwed up
2071
* right after reading "BEGIN TRANSACTION". We assume that
2072
* the user will interpret the error as meaning the BEGIN
2073
* failed to get him into a transaction block, so we should
2074
* abort and return to idle state.
2078
CleanupTransaction();
2079
s->blockState = TBLOCK_DEFAULT;
2083
* We are somewhere in a transaction block and we've gotten a
2084
* failure, so we abort the transaction and set up the persistent
2085
* ABORT state. We will stay in ABORT until we get a ROLLBACK.
2087
case TBLOCK_INPROGRESS:
2089
s->blockState = TBLOCK_ABORT;
2090
/* CleanupTransaction happens when we exit TBLOCK_ABORT_END */
2094
* Here, we failed while trying to COMMIT. Clean up the
2095
* transaction and return to idle state (we do not want to
2096
* stay in the transaction).
2100
CleanupTransaction();
2101
s->blockState = TBLOCK_DEFAULT;
2105
* Here, we are already in an aborted transaction state and
2106
* are waiting for a ROLLBACK, but for some reason we failed
2107
* again! So we just remain in the abort state.
2110
case TBLOCK_SUBABORT:
2114
* We are in a failed transaction and we got the ROLLBACK command.
2115
* We have already aborted, we just need to cleanup and go to
2118
case TBLOCK_ABORT_END:
2119
CleanupTransaction();
2120
s->blockState = TBLOCK_DEFAULT;
2124
* We are in a live transaction and we got a ROLLBACK command.
2125
* Abort, cleanup, go to idle state.
2127
case TBLOCK_ABORT_PENDING:
2129
CleanupTransaction();
2130
s->blockState = TBLOCK_DEFAULT;
2134
* We got an error inside a subtransaction. Abort just the
2135
* subtransaction, and go to the persistent SUBABORT state
2136
* until we get ROLLBACK.
2138
case TBLOCK_SUBINPROGRESS:
2139
AbortSubTransaction();
2140
s->blockState = TBLOCK_SUBABORT;
2144
* If we failed while trying to create a subtransaction, clean up
2145
* the broken subtransaction and abort the parent. The same
2146
* applies if we get a failure while ending a subtransaction.
2148
case TBLOCK_SUBBEGIN:
2150
case TBLOCK_SUBABORT_PENDING:
2151
case TBLOCK_SUBRESTART:
2152
AbortSubTransaction();
2153
CleanupSubTransaction();
2154
AbortCurrentTransaction();
2158
* Same as above, except the Abort() was already done.
2160
case TBLOCK_SUBABORT_END:
2161
case TBLOCK_SUBABORT_RESTART:
2162
CleanupSubTransaction();
2163
AbortCurrentTransaction();
2169
* PreventTransactionChain
2171
* This routine is to be called by statements that must not run inside
2172
* a transaction block, typically because they have non-rollback-able
2173
* side effects or do internal commits.
2175
* If we have already started a transaction block, issue an error; also issue
2176
* an error if we appear to be running inside a user-defined function (which
2177
* could issue more commands and possibly cause a failure after the statement
2178
* completes). Subtransactions are verboten too.
2180
* stmtNode: pointer to parameter block for statement; this is used in
2181
* a very klugy way to determine whether we are inside a function.
2182
* stmtType: statement type name for error messages.
2185
PreventTransactionChain(void *stmtNode, const char *stmtType)
2188
* xact block already started?
2190
if (IsTransactionBlock())
2192
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2193
/* translator: %s represents an SQL statement name */
2194
errmsg("%s cannot run inside a transaction block",
2200
if (IsSubTransaction())
2202
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2203
/* translator: %s represents an SQL statement name */
2204
errmsg("%s cannot run inside a subtransaction",
2208
* Are we inside a function call? If the statement's parameter block
2209
* was allocated in QueryContext, assume it is an interactive command.
2210
* Otherwise assume it is coming from a function.
2212
if (!MemoryContextContains(QueryContext, stmtNode))
2214
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2215
/* translator: %s represents an SQL statement name */
2216
errmsg("%s cannot be executed from a function", stmtType)));
2218
/* If we got past IsTransactionBlock test, should be in default state */
2219
if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2220
CurrentTransactionState->blockState != TBLOCK_STARTED)
2221
elog(FATAL, "cannot prevent transaction chain");
2226
* RequireTransactionChain
2228
* This routine is to be called by statements that must run inside
2229
* a transaction block, because they have no effects that persist past
2230
* transaction end (and so calling them outside a transaction block
2231
* is presumably an error). DECLARE CURSOR is an example.
2233
* If we appear to be running inside a user-defined function, we do not
2234
* issue an error, since the function could issue more commands that make
2235
* use of the current statement's results. Likewise subtransactions.
2236
* Thus this is an inverse for PreventTransactionChain.
2238
* stmtNode: pointer to parameter block for statement; this is used in
2239
* a very klugy way to determine whether we are inside a function.
2240
* stmtType: statement type name for error messages.
2243
RequireTransactionChain(void *stmtNode, const char *stmtType)
2246
* xact block already started?
2248
if (IsTransactionBlock())
2254
if (IsSubTransaction())
2258
* Are we inside a function call? If the statement's parameter block
2259
* was allocated in QueryContext, assume it is an interactive command.
2260
* Otherwise assume it is coming from a function.
2262
if (!MemoryContextContains(QueryContext, stmtNode))
2265
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2266
/* translator: %s represents an SQL statement name */
2267
errmsg("%s may only be used in transaction blocks",
2272
* IsInTransactionChain
2274
* This routine is for statements that need to behave differently inside
2275
* a transaction block than when running as single commands. ANALYZE is
2276
* currently the only example.
2278
* stmtNode: pointer to parameter block for statement; this is used in
2279
* a very klugy way to determine whether we are inside a function.
2282
IsInTransactionChain(void *stmtNode)
2285
* Return true on same conditions that would make
2286
* PreventTransactionChain error out
2288
if (IsTransactionBlock())
2291
if (IsSubTransaction())
2294
if (!MemoryContextContains(QueryContext, stmtNode))
2297
if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2298
CurrentTransactionState->blockState != TBLOCK_STARTED)
2306
* Register or deregister callback functions for start- and end-of-xact
2309
* These functions are intended for use by dynamically loaded modules.
2310
* For built-in modules we generally just hardwire the appropriate calls
2311
* (mainly because it's easier to control the order that way, where needed).
2313
* At transaction end, the callback occurs post-commit or post-abort, so the
2314
* callback functions can only do noncritical cleanup.
2317
RegisterXactCallback(XactCallback callback, void *arg)
2319
XactCallbackItem *item;
2321
item = (XactCallbackItem *)
2322
MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
2323
item->callback = callback;
2325
item->next = Xact_callbacks;
2326
Xact_callbacks = item;
2330
UnregisterXactCallback(XactCallback callback, void *arg)
2332
XactCallbackItem *item;
2333
XactCallbackItem *prev;
2336
for (item = Xact_callbacks; item; prev = item, item = item->next)
2338
if (item->callback == callback && item->arg == arg)
2341
prev->next = item->next;
2343
Xact_callbacks = item->next;
2351
CallXactCallbacks(XactEvent event)
2353
XactCallbackItem *item;
2355
for (item = Xact_callbacks; item; item = item->next)
2356
(*item->callback) (event, item->arg);
2361
* Register or deregister callback functions for start- and end-of-subxact
2364
* Pretty much same as above, but for subtransaction events.
2366
* At subtransaction end, the callback occurs post-subcommit or post-subabort,
2367
* so the callback functions can only do noncritical cleanup. At
2368
* subtransaction start, the callback is called when the subtransaction has
2369
* finished initializing.
2372
RegisterSubXactCallback(SubXactCallback callback, void *arg)
2374
SubXactCallbackItem *item;
2376
item = (SubXactCallbackItem *)
2377
MemoryContextAlloc(TopMemoryContext, sizeof(SubXactCallbackItem));
2378
item->callback = callback;
2380
item->next = SubXact_callbacks;
2381
SubXact_callbacks = item;
2385
UnregisterSubXactCallback(SubXactCallback callback, void *arg)
2387
SubXactCallbackItem *item;
2388
SubXactCallbackItem *prev;
2391
for (item = SubXact_callbacks; item; prev = item, item = item->next)
2393
if (item->callback == callback && item->arg == arg)
2396
prev->next = item->next;
2398
SubXact_callbacks = item->next;
2406
CallSubXactCallbacks(SubXactEvent event,
2407
SubTransactionId mySubid,
2408
SubTransactionId parentSubid)
2410
SubXactCallbackItem *item;
2412
for (item = SubXact_callbacks; item; item = item->next)
2413
(*item->callback) (event, mySubid, parentSubid, item->arg);
2417
/* ----------------------------------------------------------------
2418
* transaction block support
2419
* ----------------------------------------------------------------
2423
* BeginTransactionBlock
2424
* This executes a BEGIN command.
2427
BeginTransactionBlock(void)
2429
TransactionState s = CurrentTransactionState;
2431
switch (s->blockState)
2434
* We are not inside a transaction block, so allow one to
2437
case TBLOCK_STARTED:
2438
s->blockState = TBLOCK_BEGIN;
2442
* Already a transaction block in progress.
2444
case TBLOCK_INPROGRESS:
2445
case TBLOCK_SUBINPROGRESS:
2447
case TBLOCK_SUBABORT:
2449
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2450
errmsg("there is already a transaction in progress")));
2453
/* These cases are invalid. */
2454
case TBLOCK_DEFAULT:
2456
case TBLOCK_SUBBEGIN:
2459
case TBLOCK_ABORT_END:
2460
case TBLOCK_SUBABORT_END:
2461
case TBLOCK_ABORT_PENDING:
2462
case TBLOCK_SUBABORT_PENDING:
2463
case TBLOCK_SUBRESTART:
2464
case TBLOCK_SUBABORT_RESTART:
2465
elog(FATAL, "BeginTransactionBlock: unexpected state %s",
2466
BlockStateAsString(s->blockState));
2472
* EndTransactionBlock
2473
* This executes a COMMIT command.
2475
* Since COMMIT may actually do a ROLLBACK, the result indicates what
2476
* happened: TRUE for COMMIT, FALSE for ROLLBACK.
2478
* Note that we don't actually do anything here except change blockState.
2479
* The real work will be done in the upcoming CommitTransactionCommand().
2480
* We do it this way because it's not convenient to change memory context,
2481
* resource owner, etc while executing inside a Portal.
2484
EndTransactionBlock(void)
2486
TransactionState s = CurrentTransactionState;
2487
bool result = false;
2489
switch (s->blockState)
2492
* We are in a transaction block, so tell CommitTransactionCommand
2495
case TBLOCK_INPROGRESS:
2496
s->blockState = TBLOCK_END;
2501
* We are in a failed transaction block. Tell
2502
* CommitTransactionCommand it's time to exit the block.
2505
s->blockState = TBLOCK_ABORT_END;
2509
* We are in a live subtransaction block. Set up to subcommit
2510
* all open subtransactions and then commit the main transaction.
2512
case TBLOCK_SUBINPROGRESS:
2513
while (s->parent != NULL)
2515
if (s->blockState == TBLOCK_SUBINPROGRESS)
2516
s->blockState = TBLOCK_SUBEND;
2518
elog(FATAL, "EndTransactionBlock: unexpected state %s",
2519
BlockStateAsString(s->blockState));
2522
if (s->blockState == TBLOCK_INPROGRESS)
2523
s->blockState = TBLOCK_END;
2525
elog(FATAL, "EndTransactionBlock: unexpected state %s",
2526
BlockStateAsString(s->blockState));
2531
* Here we are inside an aborted subtransaction. Treat the
2532
* COMMIT as ROLLBACK: set up to abort everything and exit
2533
* the main transaction.
2535
case TBLOCK_SUBABORT:
2536
while (s->parent != NULL)
2538
if (s->blockState == TBLOCK_SUBINPROGRESS)
2539
s->blockState = TBLOCK_SUBABORT_PENDING;
2540
else if (s->blockState == TBLOCK_SUBABORT)
2541
s->blockState = TBLOCK_SUBABORT_END;
2543
elog(FATAL, "EndTransactionBlock: unexpected state %s",
2544
BlockStateAsString(s->blockState));
2547
if (s->blockState == TBLOCK_INPROGRESS)
2548
s->blockState = TBLOCK_ABORT_PENDING;
2549
else if (s->blockState == TBLOCK_ABORT)
2550
s->blockState = TBLOCK_ABORT_END;
2552
elog(FATAL, "EndTransactionBlock: unexpected state %s",
2553
BlockStateAsString(s->blockState));
2557
* The user issued COMMIT when not inside a transaction. Issue a
2558
* WARNING, staying in TBLOCK_STARTED state. The upcoming call to
2559
* CommitTransactionCommand() will then close the transaction and
2560
* put us back into the default state.
2562
case TBLOCK_STARTED:
2564
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2565
errmsg("there is no transaction in progress")));
2569
/* These cases are invalid. */
2570
case TBLOCK_DEFAULT:
2572
case TBLOCK_SUBBEGIN:
2575
case TBLOCK_ABORT_END:
2576
case TBLOCK_SUBABORT_END:
2577
case TBLOCK_ABORT_PENDING:
2578
case TBLOCK_SUBABORT_PENDING:
2579
case TBLOCK_SUBRESTART:
2580
case TBLOCK_SUBABORT_RESTART:
2581
elog(FATAL, "EndTransactionBlock: unexpected state %s",
2582
BlockStateAsString(s->blockState));
2590
* UserAbortTransactionBlock
2591
* This executes a ROLLBACK command.
2593
* As above, we don't actually do anything here except change blockState.
2596
UserAbortTransactionBlock(void)
2598
TransactionState s = CurrentTransactionState;
2600
switch (s->blockState)
2603
* We are inside a transaction block and we got a ROLLBACK
2604
* command from the user, so tell CommitTransactionCommand
2605
* to abort and exit the transaction block.
2607
case TBLOCK_INPROGRESS:
2608
s->blockState = TBLOCK_ABORT_PENDING;
2612
* We are inside a failed transaction block and we got a ROLLBACK
2613
* command from the user. Abort processing is already done,
2614
* so CommitTransactionCommand just has to cleanup and go back
2618
s->blockState = TBLOCK_ABORT_END;
2622
* We are inside a subtransaction. Mark everything
2623
* up to top level as exitable.
2625
case TBLOCK_SUBINPROGRESS:
2626
case TBLOCK_SUBABORT:
2627
while (s->parent != NULL)
2629
if (s->blockState == TBLOCK_SUBINPROGRESS)
2630
s->blockState = TBLOCK_SUBABORT_PENDING;
2631
else if (s->blockState == TBLOCK_SUBABORT)
2632
s->blockState = TBLOCK_SUBABORT_END;
2634
elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2635
BlockStateAsString(s->blockState));
2638
if (s->blockState == TBLOCK_INPROGRESS)
2639
s->blockState = TBLOCK_ABORT_PENDING;
2640
else if (s->blockState == TBLOCK_ABORT)
2641
s->blockState = TBLOCK_ABORT_END;
2643
elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2644
BlockStateAsString(s->blockState));
2648
* The user issued ABORT when not inside a transaction. Issue
2649
* a WARNING and go to abort state. The upcoming call to
2650
* CommitTransactionCommand() will then put us back into the
2653
case TBLOCK_STARTED:
2655
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2656
errmsg("there is no transaction in progress")));
2657
s->blockState = TBLOCK_ABORT_PENDING;
2660
/* These cases are invalid. */
2661
case TBLOCK_DEFAULT:
2663
case TBLOCK_SUBBEGIN:
2666
case TBLOCK_ABORT_END:
2667
case TBLOCK_SUBABORT_END:
2668
case TBLOCK_ABORT_PENDING:
2669
case TBLOCK_SUBABORT_PENDING:
2670
case TBLOCK_SUBRESTART:
2671
case TBLOCK_SUBABORT_RESTART:
2672
elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
2673
BlockStateAsString(s->blockState));
2680
* This executes a SAVEPOINT command.
2683
DefineSavepoint(char *name)
2685
TransactionState s = CurrentTransactionState;
2687
switch (s->blockState)
2689
case TBLOCK_INPROGRESS:
2690
case TBLOCK_SUBINPROGRESS:
2691
/* Normal subtransaction start */
2693
s = CurrentTransactionState; /* changed by push */
2696
* Savepoint names, like the TransactionState block itself,
2697
* live in TopTransactionContext.
2700
s->name = MemoryContextStrdup(TopTransactionContext, name);
2703
/* These cases are invalid. */
2704
case TBLOCK_DEFAULT:
2705
case TBLOCK_STARTED:
2707
case TBLOCK_SUBBEGIN:
2711
case TBLOCK_SUBABORT:
2712
case TBLOCK_ABORT_END:
2713
case TBLOCK_SUBABORT_END:
2714
case TBLOCK_ABORT_PENDING:
2715
case TBLOCK_SUBABORT_PENDING:
2716
case TBLOCK_SUBRESTART:
2717
case TBLOCK_SUBABORT_RESTART:
2718
elog(FATAL, "DefineSavepoint: unexpected state %s",
2719
BlockStateAsString(s->blockState));
2726
* This executes a RELEASE command.
2728
* As above, we don't actually do anything here except change blockState.
2731
ReleaseSavepoint(List *options)
2733
TransactionState s = CurrentTransactionState;
2734
TransactionState target,
2739
switch (s->blockState)
2742
* We can't rollback to a savepoint if there is no savepoint
2745
case TBLOCK_INPROGRESS:
2747
(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2748
errmsg("no such savepoint")));
2752
* We are in a non-aborted subtransaction. This is the only
2755
case TBLOCK_SUBINPROGRESS:
2758
/* These cases are invalid. */
2759
case TBLOCK_DEFAULT:
2760
case TBLOCK_STARTED:
2762
case TBLOCK_SUBBEGIN:
2766
case TBLOCK_SUBABORT:
2767
case TBLOCK_ABORT_END:
2768
case TBLOCK_SUBABORT_END:
2769
case TBLOCK_ABORT_PENDING:
2770
case TBLOCK_SUBABORT_PENDING:
2771
case TBLOCK_SUBRESTART:
2772
case TBLOCK_SUBABORT_RESTART:
2773
elog(FATAL, "ReleaseSavepoint: unexpected state %s",
2774
BlockStateAsString(s->blockState));
2778
foreach(cell, options)
2780
DefElem *elem = lfirst(cell);
2782
if (strcmp(elem->defname, "savepoint_name") == 0)
2783
name = strVal(elem->arg);
2786
Assert(PointerIsValid(name));
2788
for (target = s; PointerIsValid(target); target = target->parent)
2790
if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2794
if (!PointerIsValid(target))
2796
(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2797
errmsg("no such savepoint")));
2799
/* disallow crossing savepoint level boundaries */
2800
if (target->savepointLevel != s->savepointLevel)
2802
(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2803
errmsg("no such savepoint")));
2806
* Mark "commit pending" all subtransactions up to the target
2807
* subtransaction. The actual commits will happen when control gets
2808
* to CommitTransactionCommand.
2810
xact = CurrentTransactionState;
2813
Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
2814
xact->blockState = TBLOCK_SUBEND;
2817
xact = xact->parent;
2818
Assert(PointerIsValid(xact));
2823
* RollbackToSavepoint
2824
* This executes a ROLLBACK TO <savepoint> command.
2826
* As above, we don't actually do anything here except change blockState.
2829
RollbackToSavepoint(List *options)
2831
TransactionState s = CurrentTransactionState;
2832
TransactionState target,
2837
switch (s->blockState)
2840
* We can't rollback to a savepoint if there is no savepoint
2843
case TBLOCK_INPROGRESS:
2846
(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2847
errmsg("no such savepoint")));
2851
* There is at least one savepoint, so proceed.
2853
case TBLOCK_SUBINPROGRESS:
2854
case TBLOCK_SUBABORT:
2857
/* These cases are invalid. */
2858
case TBLOCK_DEFAULT:
2859
case TBLOCK_STARTED:
2861
case TBLOCK_SUBBEGIN:
2864
case TBLOCK_ABORT_END:
2865
case TBLOCK_SUBABORT_END:
2866
case TBLOCK_ABORT_PENDING:
2867
case TBLOCK_SUBABORT_PENDING:
2868
case TBLOCK_SUBRESTART:
2869
case TBLOCK_SUBABORT_RESTART:
2870
elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2871
BlockStateAsString(s->blockState));
2875
foreach(cell, options)
2877
DefElem *elem = lfirst(cell);
2879
if (strcmp(elem->defname, "savepoint_name") == 0)
2880
name = strVal(elem->arg);
2883
Assert(PointerIsValid(name));
2885
for (target = s; PointerIsValid(target); target = target->parent)
2887
if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
2891
if (!PointerIsValid(target))
2893
(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2894
errmsg("no such savepoint")));
2896
/* disallow crossing savepoint level boundaries */
2897
if (target->savepointLevel != s->savepointLevel)
2899
(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
2900
errmsg("no such savepoint")));
2903
* Mark "abort pending" all subtransactions up to the target
2904
* subtransaction. The actual aborts will happen when control gets
2905
* to CommitTransactionCommand.
2907
xact = CurrentTransactionState;
2912
if (xact->blockState == TBLOCK_SUBINPROGRESS)
2913
xact->blockState = TBLOCK_SUBABORT_PENDING;
2914
else if (xact->blockState == TBLOCK_SUBABORT)
2915
xact->blockState = TBLOCK_SUBABORT_END;
2917
elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2918
BlockStateAsString(xact->blockState));
2919
xact = xact->parent;
2920
Assert(PointerIsValid(xact));
2923
/* And mark the target as "restart pending" */
2924
if (xact->blockState == TBLOCK_SUBINPROGRESS)
2925
xact->blockState = TBLOCK_SUBRESTART;
2926
else if (xact->blockState == TBLOCK_SUBABORT)
2927
xact->blockState = TBLOCK_SUBABORT_RESTART;
2929
elog(FATAL, "RollbackToSavepoint: unexpected state %s",
2930
BlockStateAsString(xact->blockState));
2934
* BeginInternalSubTransaction
2935
* This is the same as DefineSavepoint except it allows TBLOCK_STARTED
2936
* state, and therefore it can safely be used in a function that might
2937
* be called when not inside a BEGIN block. Also, we automatically
2938
* cycle through CommitTransactionCommand/StartTransactionCommand
2939
* instead of expecting the caller to do it.
2942
BeginInternalSubTransaction(char *name)
2944
TransactionState s = CurrentTransactionState;
2946
switch (s->blockState)
2948
case TBLOCK_STARTED:
2949
case TBLOCK_INPROGRESS:
2950
case TBLOCK_SUBINPROGRESS:
2951
/* Normal subtransaction start */
2953
s = CurrentTransactionState; /* changed by push */
2956
* Savepoint names, like the TransactionState block itself,
2957
* live in TopTransactionContext.
2960
s->name = MemoryContextStrdup(TopTransactionContext, name);
2963
/* These cases are invalid. */
2964
case TBLOCK_DEFAULT:
2966
case TBLOCK_SUBBEGIN:
2970
case TBLOCK_SUBABORT:
2971
case TBLOCK_ABORT_END:
2972
case TBLOCK_SUBABORT_END:
2973
case TBLOCK_ABORT_PENDING:
2974
case TBLOCK_SUBABORT_PENDING:
2975
case TBLOCK_SUBRESTART:
2976
case TBLOCK_SUBABORT_RESTART:
2977
elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
2978
BlockStateAsString(s->blockState));
2982
CommitTransactionCommand();
2983
StartTransactionCommand();
2987
* ReleaseCurrentSubTransaction
2989
* RELEASE (ie, commit) the innermost subtransaction, regardless of its
2990
* savepoint name (if any).
2991
* NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2994
ReleaseCurrentSubTransaction(void)
2996
TransactionState s = CurrentTransactionState;
2998
if (s->blockState != TBLOCK_SUBINPROGRESS)
2999
elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
3000
BlockStateAsString(s->blockState));
3001
Assert(s->state == TRANS_INPROGRESS);
3002
MemoryContextSwitchTo(CurTransactionContext);
3003
CommitSubTransaction();
3004
s = CurrentTransactionState; /* changed by pop */
3005
Assert(s->state == TRANS_INPROGRESS);
3009
* RollbackAndReleaseCurrentSubTransaction
3011
* ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
3012
* of its savepoint name (if any).
3013
* NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
3016
RollbackAndReleaseCurrentSubTransaction(void)
3018
TransactionState s = CurrentTransactionState;
3020
switch (s->blockState)
3022
/* Must be in a subtransaction */
3023
case TBLOCK_SUBINPROGRESS:
3024
case TBLOCK_SUBABORT:
3027
/* These cases are invalid. */
3028
case TBLOCK_DEFAULT:
3029
case TBLOCK_STARTED:
3031
case TBLOCK_SUBBEGIN:
3032
case TBLOCK_INPROGRESS:
3036
case TBLOCK_ABORT_END:
3037
case TBLOCK_SUBABORT_END:
3038
case TBLOCK_ABORT_PENDING:
3039
case TBLOCK_SUBABORT_PENDING:
3040
case TBLOCK_SUBRESTART:
3041
case TBLOCK_SUBABORT_RESTART:
3042
elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
3043
BlockStateAsString(s->blockState));
3048
* Abort the current subtransaction, if needed.
3050
if (s->blockState == TBLOCK_SUBINPROGRESS)
3051
AbortSubTransaction();
3053
/* And clean it up, too */
3054
CleanupSubTransaction();
3056
s = CurrentTransactionState; /* changed by pop */
3057
AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
3058
s->blockState == TBLOCK_INPROGRESS ||
3059
s->blockState == TBLOCK_STARTED);
3063
* AbortOutOfAnyTransaction
3065
* This routine is provided for error recovery purposes. It aborts any
3066
* active transaction or transaction block, leaving the system in a known
3070
AbortOutOfAnyTransaction(void)
3072
TransactionState s = CurrentTransactionState;
3075
* Get out of any transaction or nested transaction
3079
switch (s->blockState)
3081
case TBLOCK_DEFAULT:
3082
/* Not in a transaction, do nothing */
3084
case TBLOCK_STARTED:
3086
case TBLOCK_INPROGRESS:
3088
case TBLOCK_ABORT_PENDING:
3089
/* In a transaction, so clean up */
3091
CleanupTransaction();
3092
s->blockState = TBLOCK_DEFAULT;
3095
case TBLOCK_ABORT_END:
3096
/* AbortTransaction already done, still need Cleanup */
3097
CleanupTransaction();
3098
s->blockState = TBLOCK_DEFAULT;
3102
* In a subtransaction, so clean it up and abort parent
3105
case TBLOCK_SUBBEGIN:
3106
case TBLOCK_SUBINPROGRESS:
3108
case TBLOCK_SUBABORT_PENDING:
3109
case TBLOCK_SUBRESTART:
3110
AbortSubTransaction();
3111
CleanupSubTransaction();
3112
s = CurrentTransactionState; /* changed by pop */
3115
case TBLOCK_SUBABORT:
3116
case TBLOCK_SUBABORT_END:
3117
case TBLOCK_SUBABORT_RESTART:
3118
/* As above, but AbortSubTransaction already done */
3119
CleanupSubTransaction();
3120
s = CurrentTransactionState; /* changed by pop */
3123
} while (s->blockState != TBLOCK_DEFAULT);
3125
/* Should be out of all subxacts now */
3126
Assert(s->parent == NULL);
3130
* IsTransactionBlock --- are we within a transaction block?
3133
IsTransactionBlock(void)
3135
TransactionState s = CurrentTransactionState;
3137
if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
3144
* IsTransactionOrTransactionBlock --- are we within either a transaction
3145
* or a transaction block? (The backend is only really "idle" when this
3148
* This should match up with IsTransactionBlock and IsTransactionState.
3151
IsTransactionOrTransactionBlock(void)
3153
TransactionState s = CurrentTransactionState;
3155
if (s->blockState == TBLOCK_DEFAULT)
3162
* TransactionBlockStatusCode - return status code to send in ReadyForQuery
3165
TransactionBlockStatusCode(void)
3167
TransactionState s = CurrentTransactionState;
3169
switch (s->blockState)
3171
case TBLOCK_DEFAULT:
3172
case TBLOCK_STARTED:
3173
return 'I'; /* idle --- not in transaction */
3175
case TBLOCK_SUBBEGIN:
3176
case TBLOCK_INPROGRESS:
3177
case TBLOCK_SUBINPROGRESS:
3180
return 'T'; /* in transaction */
3182
case TBLOCK_SUBABORT:
3183
case TBLOCK_ABORT_END:
3184
case TBLOCK_SUBABORT_END:
3185
case TBLOCK_ABORT_PENDING:
3186
case TBLOCK_SUBABORT_PENDING:
3187
case TBLOCK_SUBRESTART:
3188
case TBLOCK_SUBABORT_RESTART:
3189
return 'E'; /* in failed transaction */
3192
/* should never get here */
3193
elog(FATAL, "invalid transaction block state: %s",
3194
BlockStateAsString(s->blockState));
3195
return 0; /* keep compiler quiet */
3202
IsSubTransaction(void)
3204
TransactionState s = CurrentTransactionState;
3206
if (s->nestingLevel >= 2)
3213
* StartSubTransaction
3215
* If you're wondering why this is separate from PushTransaction: it's because
3216
* we can't conveniently do this stuff right inside DefineSavepoint. The
3217
* SAVEPOINT utility command will be executed inside a Portal, and if we
3218
* muck with CurrentMemoryContext or CurrentResourceOwner then exit from
3219
* the Portal will undo those settings. So we make DefineSavepoint just
3220
* push a dummy transaction block, and when control returns to the main
3221
* idle loop, CommitTransactionCommand will be called, and we'll come here
3222
* to finish starting the subtransaction.
3225
StartSubTransaction(void)
3227
TransactionState s = CurrentTransactionState;
3229
if (s->state != TRANS_DEFAULT)
3230
elog(WARNING, "StartSubTransaction while in %s state",
3231
TransStateAsString(s->state));
3233
s->state = TRANS_START;
3236
* Initialize subsystems for new subtransaction
3238
* must initialize resource-management stuff first
3240
AtSubStart_Memory();
3241
AtSubStart_ResourceOwner();
3243
AtSubStart_Notify();
3244
AfterTriggerBeginSubXact();
3246
s->state = TRANS_INPROGRESS;
3249
* Call start-of-subxact callbacks
3251
CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
3252
s->parent->subTransactionId);
3254
ShowTransactionState("StartSubTransaction");
3258
* CommitSubTransaction
3260
* The caller has to make sure to always reassign CurrentTransactionState
3261
* if it has a local pointer to it after calling this function.
3264
CommitSubTransaction(void)
3266
TransactionState s = CurrentTransactionState;
3268
ShowTransactionState("CommitSubTransaction");
3270
if (s->state != TRANS_INPROGRESS)
3271
elog(WARNING, "CommitSubTransaction while in %s state",
3272
TransStateAsString(s->state));
3274
/* Pre-commit processing goes here -- nothing to do at the moment */
3276
s->state = TRANS_COMMIT;
3278
/* Must CCI to ensure commands of subtransaction are seen as done */
3279
CommandCounterIncrement();
3281
/* Mark subtransaction as subcommitted */
3282
if (TransactionIdIsValid(s->transactionId))
3284
RecordSubTransactionCommit();
3285
AtSubCommit_childXids();
3288
/* Post-commit cleanup */
3289
AfterTriggerEndSubXact(true);
3290
AtSubCommit_Portals(s->subTransactionId,
3291
s->parent->subTransactionId,
3292
s->parent->curTransactionOwner);
3293
AtEOSubXact_LargeObject(true, s->subTransactionId,
3294
s->parent->subTransactionId);
3295
AtSubCommit_Notify();
3296
AtEOSubXact_UpdatePasswordFile(true, s->subTransactionId,
3297
s->parent->subTransactionId);
3299
CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
3300
s->parent->subTransactionId);
3302
ResourceOwnerRelease(s->curTransactionOwner,
3303
RESOURCE_RELEASE_BEFORE_LOCKS,
3305
AtEOSubXact_RelationCache(true, s->subTransactionId,
3306
s->parent->subTransactionId);
3307
AtEOSubXact_Inval(true);
3311
* The only lock we actually release here is the subtransaction XID lock.
3312
* The rest just get transferred to the parent resource owner.
3314
CurrentResourceOwner = s->curTransactionOwner;
3315
if (TransactionIdIsValid(s->transactionId))
3316
XactLockTableDelete(s->transactionId);
3318
ResourceOwnerRelease(s->curTransactionOwner,
3319
RESOURCE_RELEASE_LOCKS,
3321
ResourceOwnerRelease(s->curTransactionOwner,
3322
RESOURCE_RELEASE_AFTER_LOCKS,
3325
AtEOXact_GUC(true, true);
3326
AtEOSubXact_SPI(true, s->subTransactionId);
3327
AtEOSubXact_on_commit_actions(true, s->subTransactionId,
3328
s->parent->subTransactionId);
3329
AtEOSubXact_Namespace(true, s->subTransactionId,
3330
s->parent->subTransactionId);
3331
AtEOSubXact_Files(true, s->subTransactionId,
3332
s->parent->subTransactionId);
3335
* We need to restore the upper transaction's read-only state, in case
3336
* the upper is read-write while the child is read-only; GUC will
3337
* incorrectly think it should leave the child state in place.
3339
XactReadOnly = s->prevXactReadOnly;
3341
CurrentResourceOwner = s->parent->curTransactionOwner;
3342
CurTransactionResourceOwner = s->parent->curTransactionOwner;
3343
ResourceOwnerDelete(s->curTransactionOwner);
3344
s->curTransactionOwner = NULL;
3346
AtSubCommit_Memory();
3348
s->state = TRANS_DEFAULT;
3354
* AbortSubTransaction
3357
AbortSubTransaction(void)
3359
TransactionState s = CurrentTransactionState;
3361
ShowTransactionState("AbortSubTransaction");
3363
if (s->state != TRANS_INPROGRESS)
3364
elog(WARNING, "AbortSubTransaction while in %s state",
3365
TransStateAsString(s->state));
3369
s->state = TRANS_ABORT;
3372
* Release any LW locks we might be holding as quickly as possible.
3373
* (Regular locks, however, must be held till we finish aborting.)
3374
* Releasing LW locks is critical since we might try to grab them
3375
* again while cleaning up!
3377
* FIXME This may be incorrect --- Are there some locks we should keep?
3378
* Buffer locks, for example? I don't think so but I'm not sure.
3388
* do abort processing
3390
AtSubAbort_Memory();
3391
AtSubAbort_ResourceOwner();
3394
* We can skip all this stuff if the subxact failed before creating
3395
* a ResourceOwner...
3397
if (s->curTransactionOwner)
3399
AfterTriggerEndSubXact(false);
3400
AtSubAbort_Portals(s->subTransactionId,
3401
s->parent->subTransactionId,
3402
s->parent->curTransactionOwner);
3403
AtEOSubXact_LargeObject(false, s->subTransactionId,
3404
s->parent->subTransactionId);
3405
AtSubAbort_Notify();
3406
AtEOSubXact_UpdatePasswordFile(false, s->subTransactionId,
3407
s->parent->subTransactionId);
3409
/* Advertise the fact that we aborted in pg_clog. */
3410
if (TransactionIdIsValid(s->transactionId))
3412
RecordSubTransactionAbort();
3413
AtSubAbort_childXids();
3416
/* Post-abort cleanup */
3417
CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
3418
s->parent->subTransactionId);
3420
ResourceOwnerRelease(s->curTransactionOwner,
3421
RESOURCE_RELEASE_BEFORE_LOCKS,
3423
AtEOSubXact_RelationCache(false, s->subTransactionId,
3424
s->parent->subTransactionId);
3425
AtEOSubXact_Inval(false);
3427
ResourceOwnerRelease(s->curTransactionOwner,
3428
RESOURCE_RELEASE_LOCKS,
3430
ResourceOwnerRelease(s->curTransactionOwner,
3431
RESOURCE_RELEASE_AFTER_LOCKS,
3434
AtEOXact_GUC(false, true);
3435
AtEOSubXact_SPI(false, s->subTransactionId);
3436
AtEOSubXact_on_commit_actions(false, s->subTransactionId,
3437
s->parent->subTransactionId);
3438
AtEOSubXact_Namespace(false, s->subTransactionId,
3439
s->parent->subTransactionId);
3440
AtEOSubXact_Files(false, s->subTransactionId,
3441
s->parent->subTransactionId);
3445
* Reset user id which might have been changed transiently. Here we
3446
* want to restore to the userid that was current at subxact entry.
3447
* (As in AbortTransaction, we need not worry about the session
3450
* Must do this after AtEOXact_GUC to handle the case where we entered
3451
* the subxact inside a SECURITY DEFINER function (hence current and
3452
* session userids were different) and then session auth was changed
3453
* inside the subxact. GUC will reset both current and session
3454
* userids to the entry-time session userid. This is right in every
3455
* other scenario so it seems simplest to let GUC do that and fix it
3458
SetUserId(s->currentUser);
3461
* Restore the upper transaction's read-only state, too. This should
3462
* be redundant with GUC's cleanup but we may as well do it for
3463
* consistency with the commit case.
3465
XactReadOnly = s->prevXactReadOnly;
3467
RESUME_INTERRUPTS();
3471
* CleanupSubTransaction
3473
* The caller has to make sure to always reassign CurrentTransactionState
3474
* if it has a local pointer to it after calling this function.
3477
CleanupSubTransaction(void)
3479
TransactionState s = CurrentTransactionState;
3481
ShowTransactionState("CleanupSubTransaction");
3483
if (s->state != TRANS_ABORT)
3484
elog(WARNING, "CleanupSubTransaction while in %s state",
3485
TransStateAsString(s->state));
3487
AtSubCleanup_Portals(s->subTransactionId);
3489
CurrentResourceOwner = s->parent->curTransactionOwner;
3490
CurTransactionResourceOwner = s->parent->curTransactionOwner;
3491
if (s->curTransactionOwner)
3492
ResourceOwnerDelete(s->curTransactionOwner);
3493
s->curTransactionOwner = NULL;
3495
AtSubCleanup_Memory();
3497
s->state = TRANS_DEFAULT;
3504
* Create transaction state stack entry for a subtransaction
3506
* The caller has to make sure to always reassign CurrentTransactionState
3507
* if it has a local pointer to it after calling this function.
3510
PushTransaction(void)
3512
TransactionState p = CurrentTransactionState;
3517
* At present, GetUserId cannot fail, but let's not assume that. Get
3518
* the ID before entering the critical code sequence.
3520
currentUser = GetUserId();
3523
* We keep subtransaction state nodes in TopTransactionContext.
3525
s = (TransactionState)
3526
MemoryContextAllocZero(TopTransactionContext,
3527
sizeof(TransactionStateData));
3529
* Assign a subtransaction ID, watching out for counter wraparound.
3531
currentSubTransactionId += 1;
3532
if (currentSubTransactionId == InvalidSubTransactionId)
3534
currentSubTransactionId -= 1;
3537
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3538
errmsg("cannot have more than 2^32-1 subtransactions in a transaction")));
3541
* We can now stack a minimally valid subtransaction without fear of
3544
s->transactionId = InvalidTransactionId; /* until assigned */
3545
s->subTransactionId = currentSubTransactionId;
3547
s->nestingLevel = p->nestingLevel + 1;
3548
s->savepointLevel = p->savepointLevel;
3549
s->state = TRANS_DEFAULT;
3550
s->blockState = TBLOCK_SUBBEGIN;
3551
s->currentUser = currentUser;
3552
s->prevXactReadOnly = XactReadOnly;
3554
CurrentTransactionState = s;
3557
* AbortSubTransaction and CleanupSubTransaction have to be able to
3558
* cope with the subtransaction from here on out; in particular they
3559
* should not assume that it necessarily has a transaction context,
3560
* resource owner, or XID.
3566
* Pop back to parent transaction state
3568
* The caller has to make sure to always reassign CurrentTransactionState
3569
* if it has a local pointer to it after calling this function.
3572
PopTransaction(void)
3574
TransactionState s = CurrentTransactionState;
3576
if (s->state != TRANS_DEFAULT)
3577
elog(WARNING, "PopTransaction while in %s state",
3578
TransStateAsString(s->state));
3580
if (s->parent == NULL)
3581
elog(FATAL, "PopTransaction with no parent");
3583
CurrentTransactionState = s->parent;
3585
/* Let's just make sure CurTransactionContext is good */
3586
CurTransactionContext = s->parent->curTransactionContext;
3587
MemoryContextSwitchTo(CurTransactionContext);
3589
/* Ditto for ResourceOwner links */
3590
CurTransactionResourceOwner = s->parent->curTransactionOwner;
3591
CurrentResourceOwner = s->parent->curTransactionOwner;
3593
/* Free the old child structure */
3600
* ShowTransactionState
3604
ShowTransactionState(const char *str)
3606
/* skip work if message will definitely not be printed */
3607
if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
3609
elog(DEBUG2, "%s", str);
3610
ShowTransactionStateRec(CurrentTransactionState);
3615
* ShowTransactionStateRec
3616
* Recursive subroutine for ShowTransactionState
3619
ShowTransactionStateRec(TransactionState s)
3622
ShowTransactionStateRec(s->parent);
3624
/* use ereport to suppress computation if msg will not be printed */
3626
(errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u, nestlvl: %d, children: %s",
3627
PointerIsValid(s->name) ? s->name : "unnamed",
3628
BlockStateAsString(s->blockState),
3629
TransStateAsString(s->state),
3630
(unsigned int) s->transactionId,
3631
(unsigned int) s->subTransactionId,
3632
(unsigned int) currentCommandId,
3634
nodeToString(s->childXids))));
3638
* BlockStateAsString
3642
BlockStateAsString(TBlockState blockState)
3646
case TBLOCK_DEFAULT:
3648
case TBLOCK_STARTED:
3652
case TBLOCK_INPROGRESS:
3653
return "INPROGRESS";
3658
case TBLOCK_ABORT_END:
3660
case TBLOCK_ABORT_PENDING:
3661
return "ABORT PEND";
3662
case TBLOCK_SUBBEGIN:
3664
case TBLOCK_SUBINPROGRESS:
3665
return "SUB INPROGRS";
3668
case TBLOCK_SUBABORT:
3670
case TBLOCK_SUBABORT_END:
3671
return "SUB ABORT END";
3672
case TBLOCK_SUBABORT_PENDING:
3673
return "SUB ABRT PEND";
3674
case TBLOCK_SUBRESTART:
3675
return "SUB RESTART";
3676
case TBLOCK_SUBABORT_RESTART:
3677
return "SUB AB RESTRT";
3679
return "UNRECOGNIZED";
3683
* TransStateAsString
3687
TransStateAsString(TransState state)
3699
case TRANS_INPROGRESS:
3702
return "UNRECOGNIZED";
3706
* xactGetCommittedChildren
3708
* Gets the list of committed children of the current transaction. The return
3709
* value is the number of child transactions. *children is set to point to a
3710
* palloc'd array of TransactionIds. If there are no subxacts, *children is
3714
xactGetCommittedChildren(TransactionId **ptr)
3716
TransactionState s = CurrentTransactionState;
3718
TransactionId *children;
3721
nchildren = list_length(s->childXids);
3728
children = (TransactionId *) palloc(nchildren * sizeof(TransactionId));
3731
foreach(p, s->childXids)
3733
TransactionId child = lfirst_xid(p);
3735
*children++ = child;
3742
* XLOG support routines
3746
xact_redo(XLogRecPtr lsn, XLogRecord *record)
3748
uint8 info = record->xl_info & ~XLR_INFO_MASK;
3750
if (info == XLOG_XACT_COMMIT)
3752
xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
3753
TransactionId *sub_xids;
3754
TransactionId max_xid;
3757
TransactionIdCommit(record->xl_xid);
3759
/* Mark committed subtransactions as committed */
3760
sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
3761
TransactionIdCommitTree(xlrec->nsubxacts, sub_xids);
3763
/* Make sure nextXid is beyond any XID mentioned in the record */
3764
max_xid = record->xl_xid;
3765
for (i = 0; i < xlrec->nsubxacts; i++)
3767
if (TransactionIdPrecedes(max_xid, sub_xids[i]))
3768
max_xid = sub_xids[i];
3770
if (TransactionIdFollowsOrEquals(max_xid,
3771
ShmemVariableCache->nextXid))
3773
ShmemVariableCache->nextXid = max_xid;
3774
TransactionIdAdvance(ShmemVariableCache->nextXid);
3777
/* Make sure files supposed to be dropped are dropped */
3778
for (i = 0; i < xlrec->nrels; i++)
3780
XLogCloseRelation(xlrec->xnodes[i]);
3781
smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3784
else if (info == XLOG_XACT_ABORT)
3786
xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
3787
TransactionId *sub_xids;
3788
TransactionId max_xid;
3791
TransactionIdAbort(record->xl_xid);
3793
/* Mark subtransactions as aborted */
3794
sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
3795
TransactionIdAbortTree(xlrec->nsubxacts, sub_xids);
3797
/* Make sure nextXid is beyond any XID mentioned in the record */
3798
max_xid = record->xl_xid;
3799
for (i = 0; i < xlrec->nsubxacts; i++)
3801
if (TransactionIdPrecedes(max_xid, sub_xids[i]))
3802
max_xid = sub_xids[i];
3804
if (TransactionIdFollowsOrEquals(max_xid,
3805
ShmemVariableCache->nextXid))
3807
ShmemVariableCache->nextXid = max_xid;
3808
TransactionIdAdvance(ShmemVariableCache->nextXid);
3811
/* Make sure files supposed to be dropped are dropped */
3812
for (i = 0; i < xlrec->nrels; i++)
3814
XLogCloseRelation(xlrec->xnodes[i]);
3815
smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
3819
elog(PANIC, "xact_redo: unknown op code %u", info);
3823
xact_undo(XLogRecPtr lsn, XLogRecord *record)
3825
uint8 info = record->xl_info & ~XLR_INFO_MASK;
3827
if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
3828
elog(PANIC, "xact_undo: can't undo committed xaction");
3829
else if (info != XLOG_XACT_ABORT)
3830
elog(PANIC, "xact_redo: unknown op code %u", info);
3834
xact_desc(char *buf, uint8 xl_info, char *rec)
3836
uint8 info = xl_info & ~XLR_INFO_MASK;
3839
if (info == XLOG_XACT_COMMIT)
3841
xl_xact_commit *xlrec = (xl_xact_commit *) rec;
3842
struct tm *tm = localtime(&xlrec->xtime);
3844
sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
3845
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3846
tm->tm_hour, tm->tm_min, tm->tm_sec);
3847
if (xlrec->nrels > 0)
3849
sprintf(buf + strlen(buf), "; rels:");
3850
for (i = 0; i < xlrec->nrels; i++)
3852
RelFileNode rnode = xlrec->xnodes[i];
3854
sprintf(buf + strlen(buf), " %u/%u/%u",
3855
rnode.spcNode, rnode.dbNode, rnode.relNode);
3858
if (xlrec->nsubxacts > 0)
3860
TransactionId *xacts = (TransactionId *)
3861
&xlrec->xnodes[xlrec->nrels];
3863
sprintf(buf + strlen(buf), "; subxacts:");
3864
for (i = 0; i < xlrec->nsubxacts; i++)
3865
sprintf(buf + strlen(buf), " %u", xacts[i]);
3868
else if (info == XLOG_XACT_ABORT)
3870
xl_xact_abort *xlrec = (xl_xact_abort *) rec;
3871
struct tm *tm = localtime(&xlrec->xtime);
3873
sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
3874
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3875
tm->tm_hour, tm->tm_min, tm->tm_sec);
3876
if (xlrec->nrels > 0)
3878
sprintf(buf + strlen(buf), "; rels:");
3879
for (i = 0; i < xlrec->nrels; i++)
3881
RelFileNode rnode = xlrec->xnodes[i];
3883
sprintf(buf + strlen(buf), " %u/%u/%u",
3884
rnode.spcNode, rnode.dbNode, rnode.relNode);
3887
if (xlrec->nsubxacts > 0)
3889
TransactionId *xacts = (TransactionId *)
3890
&xlrec->xnodes[xlrec->nrels];
3892
sprintf(buf + strlen(buf), "; subxacts:");
3893
for (i = 0; i < xlrec->nsubxacts; i++)
3894
sprintf(buf + strlen(buf), " %u", xacts[i]);
3898
strcat(buf, "UNKNOWN");
3902
XactPushRollback(void (*func) (void *), void *data)
3905
if (_RollbackFunc != NULL)
3906
elog(PANIC, "XactPushRollback: already installed");
3909
_RollbackFunc = func;
3910
_RollbackData = data;
3914
XactPopRollback(void)
3916
_RollbackFunc = NULL;