00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "postgres.h"
00019
00020 #include <time.h>
00021 #include <unistd.h>
00022
00023 #include "access/multixact.h"
00024 #include "access/subtrans.h"
00025 #include "access/transam.h"
00026 #include "access/twophase.h"
00027 #include "access/xact.h"
00028 #include "access/xlogutils.h"
00029 #include "catalog/catalog.h"
00030 #include "catalog/namespace.h"
00031 #include "catalog/storage.h"
00032 #include "commands/async.h"
00033 #include "commands/tablecmds.h"
00034 #include "commands/trigger.h"
00035 #include "executor/spi.h"
00036 #include "libpq/be-fsstubs.h"
00037 #include "miscadmin.h"
00038 #include "pgstat.h"
00039 #include "replication/walsender.h"
00040 #include "replication/syncrep.h"
00041 #include "storage/fd.h"
00042 #include "storage/lmgr.h"
00043 #include "storage/predicate.h"
00044 #include "storage/proc.h"
00045 #include "storage/procarray.h"
00046 #include "storage/sinvaladt.h"
00047 #include "storage/smgr.h"
00048 #include "utils/catcache.h"
00049 #include "utils/combocid.h"
00050 #include "utils/guc.h"
00051 #include "utils/inval.h"
00052 #include "utils/memutils.h"
00053 #include "utils/relmapper.h"
00054 #include "utils/snapmgr.h"
00055 #include "utils/timestamp.h"
00056 #include "pg_trace.h"
00057
00058
00059
00060
00061
00062 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
00063 int XactIsoLevel;
00064
00065 bool DefaultXactReadOnly = false;
00066 bool XactReadOnly;
00067
00068 bool DefaultXactDeferrable = false;
00069 bool XactDeferrable;
00070
00071 int synchronous_commit = SYNCHRONOUS_COMMIT_ON;
00072
00073
00074
00075
00076
00077
00078 bool MyXactAccessedTempRel = false;
00079
00080
00081
00082
00083
00084 typedef enum TransState
00085 {
00086 TRANS_DEFAULT,
00087 TRANS_START,
00088 TRANS_INPROGRESS,
00089 TRANS_COMMIT,
00090 TRANS_ABORT,
00091 TRANS_PREPARE
00092 } TransState;
00093
00094
00095
00096
00097
00098
00099
00100 typedef enum TBlockState
00101 {
00102
00103 TBLOCK_DEFAULT,
00104 TBLOCK_STARTED,
00105
00106
00107 TBLOCK_BEGIN,
00108 TBLOCK_INPROGRESS,
00109 TBLOCK_END,
00110 TBLOCK_ABORT,
00111 TBLOCK_ABORT_END,
00112 TBLOCK_ABORT_PENDING,
00113 TBLOCK_PREPARE,
00114
00115
00116 TBLOCK_SUBBEGIN,
00117 TBLOCK_SUBINPROGRESS,
00118 TBLOCK_SUBRELEASE,
00119 TBLOCK_SUBCOMMIT,
00120 TBLOCK_SUBABORT,
00121 TBLOCK_SUBABORT_END,
00122 TBLOCK_SUBABORT_PENDING,
00123 TBLOCK_SUBRESTART,
00124 TBLOCK_SUBABORT_RESTART
00125 } TBlockState;
00126
00127
00128
00129
00130 typedef struct TransactionStateData
00131 {
00132 TransactionId transactionId;
00133 SubTransactionId subTransactionId;
00134 char *name;
00135 int savepointLevel;
00136 TransState state;
00137 TBlockState blockState;
00138 int nestingLevel;
00139 int gucNestLevel;
00140 MemoryContext curTransactionContext;
00141 ResourceOwner curTransactionOwner;
00142 TransactionId *childXids;
00143 int nChildXids;
00144 int maxChildXids;
00145 Oid prevUser;
00146 int prevSecContext;
00147 bool prevXactReadOnly;
00148 bool startedInRecovery;
00149 struct TransactionStateData *parent;
00150 } TransactionStateData;
00151
00152 typedef TransactionStateData *TransactionState;
00153
00154
00155
00156
00157
00158
00159 static TransactionStateData TopTransactionStateData = {
00160 0,
00161 0,
00162 NULL,
00163 0,
00164 TRANS_DEFAULT,
00165 TBLOCK_DEFAULT,
00166
00167 0,
00168 0,
00169 NULL,
00170 NULL,
00171 NULL,
00172 0,
00173 0,
00174 InvalidOid,
00175 0,
00176 false,
00177 false,
00178 NULL
00179 };
00180
00181
00182
00183
00184
00185 static int nUnreportedXids;
00186 static TransactionId unreportedXids[PGPROC_MAX_CACHED_SUBXIDS];
00187
00188 static TransactionState CurrentTransactionState = &TopTransactionStateData;
00189
00190
00191
00192
00193
00194 static SubTransactionId currentSubTransactionId;
00195 static CommandId currentCommandId;
00196 static bool currentCommandIdUsed;
00197
00198
00199
00200
00201
00202
00203
00204
00205 static TimestampTz xactStartTimestamp;
00206 static TimestampTz stmtStartTimestamp;
00207 static TimestampTz xactStopTimestamp;
00208
00209
00210
00211
00212
00213 static char *prepareGID;
00214
00215
00216
00217
00218 static bool forceSyncCommit = false;
00219
00220
00221
00222
00223
00224
00225 static MemoryContext TransactionAbortContext = NULL;
00226
00227
00228
00229
00230 typedef struct XactCallbackItem
00231 {
00232 struct XactCallbackItem *next;
00233 XactCallback callback;
00234 void *arg;
00235 } XactCallbackItem;
00236
00237 static XactCallbackItem *Xact_callbacks = NULL;
00238
00239
00240
00241
00242 typedef struct SubXactCallbackItem
00243 {
00244 struct SubXactCallbackItem *next;
00245 SubXactCallback callback;
00246 void *arg;
00247 } SubXactCallbackItem;
00248
00249 static SubXactCallbackItem *SubXact_callbacks = NULL;
00250
00251
00252
00253 static void AssignTransactionId(TransactionState s);
00254 static void AbortTransaction(void);
00255 static void AtAbort_Memory(void);
00256 static void AtCleanup_Memory(void);
00257 static void AtAbort_ResourceOwner(void);
00258 static void AtCCI_LocalCache(void);
00259 static void AtCommit_Memory(void);
00260 static void AtStart_Cache(void);
00261 static void AtStart_Memory(void);
00262 static void AtStart_ResourceOwner(void);
00263 static void CallXactCallbacks(XactEvent event);
00264 static void CallSubXactCallbacks(SubXactEvent event,
00265 SubTransactionId mySubid,
00266 SubTransactionId parentSubid);
00267 static void CleanupTransaction(void);
00268 static void CommitTransaction(void);
00269 static TransactionId RecordTransactionAbort(bool isSubXact);
00270 static void StartTransaction(void);
00271
00272 static void StartSubTransaction(void);
00273 static void CommitSubTransaction(void);
00274 static void AbortSubTransaction(void);
00275 static void CleanupSubTransaction(void);
00276 static void PushTransaction(void);
00277 static void PopTransaction(void);
00278
00279 static void AtSubAbort_Memory(void);
00280 static void AtSubCleanup_Memory(void);
00281 static void AtSubAbort_ResourceOwner(void);
00282 static void AtSubCommit_Memory(void);
00283 static void AtSubStart_Memory(void);
00284 static void AtSubStart_ResourceOwner(void);
00285
00286 static void ShowTransactionState(const char *str);
00287 static void ShowTransactionStateRec(TransactionState state);
00288 static const char *BlockStateAsString(TBlockState blockState);
00289 static const char *TransStateAsString(TransState state);
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 bool
00304 IsTransactionState(void)
00305 {
00306 TransactionState s = CurrentTransactionState;
00307
00308
00309
00310
00311
00312
00313
00314
00315 return (s->state == TRANS_INPROGRESS);
00316 }
00317
00318
00319
00320
00321
00322
00323 bool
00324 IsAbortedTransactionBlockState(void)
00325 {
00326 TransactionState s = CurrentTransactionState;
00327
00328 if (s->blockState == TBLOCK_ABORT ||
00329 s->blockState == TBLOCK_SUBABORT)
00330 return true;
00331
00332 return false;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342 TransactionId
00343 GetTopTransactionId(void)
00344 {
00345 if (!TransactionIdIsValid(TopTransactionStateData.transactionId))
00346 AssignTransactionId(&TopTransactionStateData);
00347 return TopTransactionStateData.transactionId;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357 TransactionId
00358 GetTopTransactionIdIfAny(void)
00359 {
00360 return TopTransactionStateData.transactionId;
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370 TransactionId
00371 GetCurrentTransactionId(void)
00372 {
00373 TransactionState s = CurrentTransactionState;
00374
00375 if (!TransactionIdIsValid(s->transactionId))
00376 AssignTransactionId(s);
00377 return s->transactionId;
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387 TransactionId
00388 GetCurrentTransactionIdIfAny(void)
00389 {
00390 return CurrentTransactionState->transactionId;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 TransactionId
00402 GetStableLatestTransactionId(void)
00403 {
00404 static LocalTransactionId lxid = InvalidLocalTransactionId;
00405 static TransactionId stablexid = InvalidTransactionId;
00406
00407 if (lxid != MyProc->lxid)
00408 {
00409 lxid = MyProc->lxid;
00410 stablexid = GetTopTransactionIdIfAny();
00411 if (!TransactionIdIsValid(stablexid))
00412 stablexid = ReadNewTransactionId();
00413 }
00414
00415 Assert(TransactionIdIsValid(stablexid));
00416
00417 return stablexid;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 static void
00430 AssignTransactionId(TransactionState s)
00431 {
00432 bool isSubXact = (s->parent != NULL);
00433 ResourceOwner currentOwner;
00434
00435
00436 Assert(!TransactionIdIsValid(s->transactionId));
00437 Assert(s->state == TRANS_INPROGRESS);
00438
00439
00440
00441
00442
00443
00444
00445 if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
00446 {
00447 TransactionState p = s->parent;
00448 TransactionState *parents;
00449 size_t parentOffset = 0;
00450
00451 parents = palloc(sizeof(TransactionState) * s->nestingLevel);
00452 while (p != NULL && !TransactionIdIsValid(p->transactionId))
00453 {
00454 parents[parentOffset++] = p;
00455 p = p->parent;
00456 }
00457
00458
00459
00460
00461
00462 while (parentOffset != 0)
00463 AssignTransactionId(parents[--parentOffset]);
00464
00465 pfree(parents);
00466 }
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 s->transactionId = GetNewTransactionId(isSubXact);
00477
00478 if (isSubXact)
00479 SubTransSetParent(s->transactionId, s->parent->transactionId, false);
00480
00481
00482
00483
00484
00485 if (!isSubXact)
00486 RegisterPredicateLockingXid(s->transactionId);
00487
00488
00489
00490
00491
00492
00493 currentOwner = CurrentResourceOwner;
00494 PG_TRY();
00495 {
00496 CurrentResourceOwner = s->curTransactionOwner;
00497 XactLockTableInsert(s->transactionId);
00498 }
00499 PG_CATCH();
00500 {
00501
00502 CurrentResourceOwner = currentOwner;
00503 PG_RE_THROW();
00504 }
00505 PG_END_TRY();
00506 CurrentResourceOwner = currentOwner;
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 if (isSubXact && XLogStandbyInfoActive())
00524 {
00525 unreportedXids[nUnreportedXids] = s->transactionId;
00526 nUnreportedXids++;
00527
00528
00529
00530
00531
00532 if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS)
00533 {
00534 XLogRecData rdata[2];
00535 xl_xact_assignment xlrec;
00536
00537
00538
00539
00540
00541 xlrec.xtop = GetTopTransactionId();
00542 Assert(TransactionIdIsValid(xlrec.xtop));
00543 xlrec.nsubxacts = nUnreportedXids;
00544
00545 rdata[0].data = (char *) &xlrec;
00546 rdata[0].len = MinSizeOfXactAssignment;
00547 rdata[0].buffer = InvalidBuffer;
00548 rdata[0].next = &rdata[1];
00549
00550 rdata[1].data = (char *) unreportedXids;
00551 rdata[1].len = PGPROC_MAX_CACHED_SUBXIDS * sizeof(TransactionId);
00552 rdata[1].buffer = InvalidBuffer;
00553 rdata[1].next = NULL;
00554
00555 (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT, rdata);
00556
00557 nUnreportedXids = 0;
00558 }
00559 }
00560 }
00561
00562
00563
00564
00565 SubTransactionId
00566 GetCurrentSubTransactionId(void)
00567 {
00568 TransactionState s = CurrentTransactionState;
00569
00570 return s->subTransactionId;
00571 }
00572
00573
00574
00575
00576
00577
00578
00579 bool
00580 SubTransactionIsActive(SubTransactionId subxid)
00581 {
00582 TransactionState s;
00583
00584 for (s = CurrentTransactionState; s != NULL; s = s->parent)
00585 {
00586 if (s->state == TRANS_ABORT)
00587 continue;
00588 if (s->subTransactionId == subxid)
00589 return true;
00590 }
00591 return false;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 CommandId
00604 GetCurrentCommandId(bool used)
00605 {
00606
00607 if (used)
00608 currentCommandIdUsed = true;
00609 return currentCommandId;
00610 }
00611
00612
00613
00614
00615 TimestampTz
00616 GetCurrentTransactionStartTimestamp(void)
00617 {
00618 return xactStartTimestamp;
00619 }
00620
00621
00622
00623
00624 TimestampTz
00625 GetCurrentStatementStartTimestamp(void)
00626 {
00627 return stmtStartTimestamp;
00628 }
00629
00630
00631
00632
00633
00634
00635
00636 TimestampTz
00637 GetCurrentTransactionStopTimestamp(void)
00638 {
00639 if (xactStopTimestamp != 0)
00640 return xactStopTimestamp;
00641 return GetCurrentTimestamp();
00642 }
00643
00644
00645
00646
00647 void
00648 SetCurrentStatementStartTimestamp(void)
00649 {
00650 stmtStartTimestamp = GetCurrentTimestamp();
00651 }
00652
00653
00654
00655
00656 static inline void
00657 SetCurrentTransactionStopTimestamp(void)
00658 {
00659 xactStopTimestamp = GetCurrentTimestamp();
00660 }
00661
00662
00663
00664
00665
00666
00667
00668 int
00669 GetCurrentTransactionNestLevel(void)
00670 {
00671 TransactionState s = CurrentTransactionState;
00672
00673 return s->nestingLevel;
00674 }
00675
00676
00677
00678
00679
00680 bool
00681 TransactionIdIsCurrentTransactionId(TransactionId xid)
00682 {
00683 TransactionState s;
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698 if (!TransactionIdIsNormal(xid))
00699 return false;
00700
00701
00702
00703
00704
00705
00706
00707
00708 for (s = CurrentTransactionState; s != NULL; s = s->parent)
00709 {
00710 int low,
00711 high;
00712
00713 if (s->state == TRANS_ABORT)
00714 continue;
00715 if (!TransactionIdIsValid(s->transactionId))
00716 continue;
00717 if (TransactionIdEquals(xid, s->transactionId))
00718 return true;
00719
00720 low = 0;
00721 high = s->nChildXids - 1;
00722 while (low <= high)
00723 {
00724 int middle;
00725 TransactionId probe;
00726
00727 middle = low + (high - low) / 2;
00728 probe = s->childXids[middle];
00729 if (TransactionIdEquals(probe, xid))
00730 return true;
00731 else if (TransactionIdPrecedes(probe, xid))
00732 low = middle + 1;
00733 else
00734 high = middle - 1;
00735 }
00736 }
00737
00738 return false;
00739 }
00740
00741
00742
00743
00744
00745
00746
00747
00748 bool
00749 TransactionStartedDuringRecovery(void)
00750 {
00751 return CurrentTransactionState->startedInRecovery;
00752 }
00753
00754
00755
00756
00757 void
00758 CommandCounterIncrement(void)
00759 {
00760
00761
00762
00763
00764
00765
00766 if (currentCommandIdUsed)
00767 {
00768 currentCommandId += 1;
00769 if (currentCommandId == FirstCommandId)
00770 {
00771 currentCommandId -= 1;
00772 ereport(ERROR,
00773 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00774 errmsg("cannot have more than 2^32-1 commands in a transaction")));
00775 }
00776 currentCommandIdUsed = false;
00777
00778
00779 SnapshotSetCommandId(currentCommandId);
00780
00781
00782
00783
00784
00785
00786
00787 AtCCI_LocalCache();
00788 }
00789 }
00790
00791
00792
00793
00794
00795
00796
00797 void
00798 ForceSyncCommit(void)
00799 {
00800 forceSyncCommit = true;
00801 }
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812 static void
00813 AtStart_Cache(void)
00814 {
00815 AcceptInvalidationMessages();
00816 }
00817
00818
00819
00820
00821 static void
00822 AtStart_Memory(void)
00823 {
00824 TransactionState s = CurrentTransactionState;
00825
00826
00827
00828
00829
00830
00831
00832
00833 if (TransactionAbortContext == NULL)
00834 TransactionAbortContext =
00835 AllocSetContextCreate(TopMemoryContext,
00836 "TransactionAbortContext",
00837 32 * 1024,
00838 32 * 1024,
00839 32 * 1024);
00840
00841
00842
00843
00844 Assert(TopTransactionContext == NULL);
00845
00846
00847
00848
00849 TopTransactionContext =
00850 AllocSetContextCreate(TopMemoryContext,
00851 "TopTransactionContext",
00852 ALLOCSET_DEFAULT_MINSIZE,
00853 ALLOCSET_DEFAULT_INITSIZE,
00854 ALLOCSET_DEFAULT_MAXSIZE);
00855
00856
00857
00858
00859
00860 CurTransactionContext = TopTransactionContext;
00861 s->curTransactionContext = CurTransactionContext;
00862
00863
00864 MemoryContextSwitchTo(CurTransactionContext);
00865 }
00866
00867
00868
00869
00870 static void
00871 AtStart_ResourceOwner(void)
00872 {
00873 TransactionState s = CurrentTransactionState;
00874
00875
00876
00877
00878 Assert(TopTransactionResourceOwner == NULL);
00879
00880
00881
00882
00883 s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
00884
00885 TopTransactionResourceOwner = s->curTransactionOwner;
00886 CurTransactionResourceOwner = s->curTransactionOwner;
00887 CurrentResourceOwner = s->curTransactionOwner;
00888 }
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898 static void
00899 AtSubStart_Memory(void)
00900 {
00901 TransactionState s = CurrentTransactionState;
00902
00903 Assert(CurTransactionContext != NULL);
00904
00905
00906
00907
00908
00909
00910 CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
00911 "CurTransactionContext",
00912 ALLOCSET_DEFAULT_MINSIZE,
00913 ALLOCSET_DEFAULT_INITSIZE,
00914 ALLOCSET_DEFAULT_MAXSIZE);
00915 s->curTransactionContext = CurTransactionContext;
00916
00917
00918 MemoryContextSwitchTo(CurTransactionContext);
00919 }
00920
00921
00922
00923
00924 static void
00925 AtSubStart_ResourceOwner(void)
00926 {
00927 TransactionState s = CurrentTransactionState;
00928
00929 Assert(s->parent != NULL);
00930
00931
00932
00933
00934
00935 s->curTransactionOwner =
00936 ResourceOwnerCreate(s->parent->curTransactionOwner,
00937 "SubTransaction");
00938
00939 CurTransactionResourceOwner = s->curTransactionOwner;
00940 CurrentResourceOwner = s->curTransactionOwner;
00941 }
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 static TransactionId
00955 RecordTransactionCommit(void)
00956 {
00957 TransactionId xid = GetTopTransactionIdIfAny();
00958 bool markXidCommitted = TransactionIdIsValid(xid);
00959 TransactionId latestXid = InvalidTransactionId;
00960 int nrels;
00961 RelFileNode *rels;
00962 int nchildren;
00963 TransactionId *children;
00964 int nmsgs = 0;
00965 SharedInvalidationMessage *invalMessages = NULL;
00966 bool RelcacheInitFileInval = false;
00967 bool wrote_xlog;
00968
00969
00970 nrels = smgrGetPendingDeletes(true, &rels);
00971 nchildren = xactGetCommittedChildren(&children);
00972 if (XLogStandbyInfoActive())
00973 nmsgs = xactGetCommittedInvalidationMessages(&invalMessages,
00974 &RelcacheInitFileInval);
00975 wrote_xlog = (XactLastRecEnd != 0);
00976
00977
00978
00979
00980
00981 if (!markXidCommitted)
00982 {
00983
00984
00985
00986
00987
00988
00989 if (nrels != 0)
00990 elog(ERROR, "cannot commit a transaction that deleted files but has no xid");
00991
00992
00993 Assert(nchildren == 0);
00994
00995
00996
00997
00998
00999
01000
01001
01002 if (!wrote_xlog)
01003 goto cleanup;
01004 }
01005 else
01006 {
01007
01008
01009
01010
01011 BufmgrCommit();
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 START_CRIT_SECTION();
01031 MyPgXact->delayChkpt = true;
01032
01033 SetCurrentTransactionStopTimestamp();
01034
01035
01036
01037
01038 if (nrels > 0 || nmsgs > 0 || RelcacheInitFileInval || forceSyncCommit)
01039 {
01040 XLogRecData rdata[4];
01041 int lastrdata = 0;
01042 xl_xact_commit xlrec;
01043
01044
01045
01046
01047 xlrec.xinfo = 0;
01048 if (RelcacheInitFileInval)
01049 xlrec.xinfo |= XACT_COMPLETION_UPDATE_RELCACHE_FILE;
01050 if (forceSyncCommit)
01051 xlrec.xinfo |= XACT_COMPLETION_FORCE_SYNC_COMMIT;
01052
01053 xlrec.dbId = MyDatabaseId;
01054 xlrec.tsId = MyDatabaseTableSpace;
01055
01056 xlrec.xact_time = xactStopTimestamp;
01057 xlrec.nrels = nrels;
01058 xlrec.nsubxacts = nchildren;
01059 xlrec.nmsgs = nmsgs;
01060 rdata[0].data = (char *) (&xlrec);
01061 rdata[0].len = MinSizeOfXactCommit;
01062 rdata[0].buffer = InvalidBuffer;
01063
01064 if (nrels > 0)
01065 {
01066 rdata[0].next = &(rdata[1]);
01067 rdata[1].data = (char *) rels;
01068 rdata[1].len = nrels * sizeof(RelFileNode);
01069 rdata[1].buffer = InvalidBuffer;
01070 lastrdata = 1;
01071 }
01072
01073 if (nchildren > 0)
01074 {
01075 rdata[lastrdata].next = &(rdata[2]);
01076 rdata[2].data = (char *) children;
01077 rdata[2].len = nchildren * sizeof(TransactionId);
01078 rdata[2].buffer = InvalidBuffer;
01079 lastrdata = 2;
01080 }
01081
01082 if (nmsgs > 0)
01083 {
01084 rdata[lastrdata].next = &(rdata[3]);
01085 rdata[3].data = (char *) invalMessages;
01086 rdata[3].len = nmsgs * sizeof(SharedInvalidationMessage);
01087 rdata[3].buffer = InvalidBuffer;
01088 lastrdata = 3;
01089 }
01090 rdata[lastrdata].next = NULL;
01091
01092 (void) XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
01093 }
01094 else
01095 {
01096 XLogRecData rdata[2];
01097 int lastrdata = 0;
01098 xl_xact_commit_compact xlrec;
01099
01100 xlrec.xact_time = xactStopTimestamp;
01101 xlrec.nsubxacts = nchildren;
01102 rdata[0].data = (char *) (&xlrec);
01103 rdata[0].len = MinSizeOfXactCommitCompact;
01104 rdata[0].buffer = InvalidBuffer;
01105
01106 if (nchildren > 0)
01107 {
01108 rdata[0].next = &(rdata[1]);
01109 rdata[1].data = (char *) children;
01110 rdata[1].len = nchildren * sizeof(TransactionId);
01111 rdata[1].buffer = InvalidBuffer;
01112 lastrdata = 1;
01113 }
01114 rdata[lastrdata].next = NULL;
01115
01116 (void) XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT_COMPACT, rdata);
01117 }
01118 }
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143 if ((wrote_xlog && synchronous_commit > SYNCHRONOUS_COMMIT_OFF) ||
01144 forceSyncCommit || nrels > 0)
01145 {
01146 XLogFlush(XactLastRecEnd);
01147
01148
01149
01150
01151 if (markXidCommitted)
01152 TransactionIdCommitTree(xid, nchildren, children);
01153 }
01154 else
01155 {
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167 XLogSetAsyncXactLSN(XactLastRecEnd);
01168
01169
01170
01171
01172
01173
01174 if (markXidCommitted)
01175 TransactionIdAsyncCommitTree(xid, nchildren, children, XactLastRecEnd);
01176 }
01177
01178
01179
01180
01181
01182 if (markXidCommitted)
01183 {
01184 MyPgXact->delayChkpt = false;
01185 END_CRIT_SECTION();
01186 }
01187
01188
01189 latestXid = TransactionIdLatest(xid, nchildren, children);
01190
01191
01192
01193
01194
01195
01196
01197 if (wrote_xlog)
01198 SyncRepWaitForLSN(XactLastRecEnd);
01199
01200
01201 XactLastRecEnd = 0;
01202
01203 cleanup:
01204
01205 if (rels)
01206 pfree(rels);
01207
01208 return latestXid;
01209 }
01210
01211
01212
01213
01214
01215 static void
01216 AtCCI_LocalCache(void)
01217 {
01218
01219
01220
01221
01222
01223 AtCCI_RelationMap();
01224
01225
01226
01227
01228 CommandEndInvalidationMessages();
01229 }
01230
01231
01232
01233
01234 static void
01235 AtCommit_Memory(void)
01236 {
01237
01238
01239
01240
01241 MemoryContextSwitchTo(TopMemoryContext);
01242
01243
01244
01245
01246 Assert(TopTransactionContext != NULL);
01247 MemoryContextDelete(TopTransactionContext);
01248 TopTransactionContext = NULL;
01249 CurTransactionContext = NULL;
01250 CurrentTransactionState->curTransactionContext = NULL;
01251 }
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261 static void
01262 AtSubCommit_Memory(void)
01263 {
01264 TransactionState s = CurrentTransactionState;
01265
01266 Assert(s->parent != NULL);
01267
01268
01269 CurTransactionContext = s->parent->curTransactionContext;
01270 MemoryContextSwitchTo(CurTransactionContext);
01271
01272
01273
01274
01275
01276
01277
01278 if (MemoryContextIsEmpty(s->curTransactionContext))
01279 {
01280 MemoryContextDelete(s->curTransactionContext);
01281 s->curTransactionContext = NULL;
01282 }
01283 }
01284
01285
01286
01287
01288
01289
01290 static void
01291 AtSubCommit_childXids(void)
01292 {
01293 TransactionState s = CurrentTransactionState;
01294 int new_nChildXids;
01295
01296 Assert(s->parent != NULL);
01297
01298
01299
01300
01301
01302 new_nChildXids = s->parent->nChildXids + s->nChildXids + 1;
01303
01304
01305 if (s->parent->maxChildXids < new_nChildXids)
01306 {
01307 int new_maxChildXids;
01308 TransactionId *new_childXids;
01309
01310
01311
01312
01313
01314
01315
01316 new_maxChildXids = Min(new_nChildXids * 2,
01317 (int) (MaxAllocSize / sizeof(TransactionId)));
01318
01319 if (new_maxChildXids < new_nChildXids)
01320 ereport(ERROR,
01321 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
01322 errmsg("maximum number of committed subtransactions (%d) exceeded",
01323 (int) (MaxAllocSize / sizeof(TransactionId)))));
01324
01325
01326
01327
01328
01329
01330 if (s->parent->childXids == NULL)
01331 new_childXids =
01332 MemoryContextAlloc(TopTransactionContext,
01333 new_maxChildXids * sizeof(TransactionId));
01334 else
01335 new_childXids = repalloc(s->parent->childXids,
01336 new_maxChildXids * sizeof(TransactionId));
01337
01338 s->parent->childXids = new_childXids;
01339 s->parent->maxChildXids = new_maxChildXids;
01340 }
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351 s->parent->childXids[s->parent->nChildXids] = s->transactionId;
01352
01353 if (s->nChildXids > 0)
01354 memcpy(&s->parent->childXids[s->parent->nChildXids + 1],
01355 s->childXids,
01356 s->nChildXids * sizeof(TransactionId));
01357
01358 s->parent->nChildXids = new_nChildXids;
01359
01360
01361 if (s->childXids != NULL)
01362 pfree(s->childXids);
01363
01364 s->childXids = NULL;
01365 s->nChildXids = 0;
01366 s->maxChildXids = 0;
01367 }
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380 static TransactionId
01381 RecordTransactionAbort(bool isSubXact)
01382 {
01383 TransactionId xid = GetCurrentTransactionIdIfAny();
01384 TransactionId latestXid;
01385 int nrels;
01386 RelFileNode *rels;
01387 int nchildren;
01388 TransactionId *children;
01389 XLogRecData rdata[3];
01390 int lastrdata = 0;
01391 xl_xact_abort xlrec;
01392
01393
01394
01395
01396
01397
01398
01399 if (!TransactionIdIsValid(xid))
01400 {
01401
01402 if (!isSubXact)
01403 XactLastRecEnd = 0;
01404 return InvalidTransactionId;
01405 }
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418 if (TransactionIdDidCommit(xid))
01419 elog(PANIC, "cannot abort transaction %u, it was already committed",
01420 xid);
01421
01422
01423 nrels = smgrGetPendingDeletes(false, &rels);
01424 nchildren = xactGetCommittedChildren(&children);
01425
01426
01427 START_CRIT_SECTION();
01428
01429
01430 if (isSubXact)
01431 xlrec.xact_time = GetCurrentTimestamp();
01432 else
01433 {
01434 SetCurrentTransactionStopTimestamp();
01435 xlrec.xact_time = xactStopTimestamp;
01436 }
01437 xlrec.nrels = nrels;
01438 xlrec.nsubxacts = nchildren;
01439 rdata[0].data = (char *) (&xlrec);
01440 rdata[0].len = MinSizeOfXactAbort;
01441 rdata[0].buffer = InvalidBuffer;
01442
01443 if (nrels > 0)
01444 {
01445 rdata[0].next = &(rdata[1]);
01446 rdata[1].data = (char *) rels;
01447 rdata[1].len = nrels * sizeof(RelFileNode);
01448 rdata[1].buffer = InvalidBuffer;
01449 lastrdata = 1;
01450 }
01451
01452 if (nchildren > 0)
01453 {
01454 rdata[lastrdata].next = &(rdata[2]);
01455 rdata[2].data = (char *) children;
01456 rdata[2].len = nchildren * sizeof(TransactionId);
01457 rdata[2].buffer = InvalidBuffer;
01458 lastrdata = 2;
01459 }
01460 rdata[lastrdata].next = NULL;
01461
01462 (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473 if (!isSubXact)
01474 XLogSetAsyncXactLSN(XactLastRecEnd);
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484 TransactionIdAbortTree(xid, nchildren, children);
01485
01486 END_CRIT_SECTION();
01487
01488
01489 latestXid = TransactionIdLatest(xid, nchildren, children);
01490
01491
01492
01493
01494
01495
01496
01497 if (isSubXact)
01498 XidCacheRemoveRunningXids(xid, nchildren, children, latestXid);
01499
01500
01501 if (!isSubXact)
01502 XactLastRecEnd = 0;
01503
01504
01505 if (rels)
01506 pfree(rels);
01507
01508 return latestXid;
01509 }
01510
01511
01512
01513
01514 static void
01515 AtAbort_Memory(void)
01516 {
01517
01518
01519
01520
01521
01522
01523
01524
01525 if (TransactionAbortContext != NULL)
01526 MemoryContextSwitchTo(TransactionAbortContext);
01527 else
01528 MemoryContextSwitchTo(TopMemoryContext);
01529 }
01530
01531
01532
01533
01534 static void
01535 AtSubAbort_Memory(void)
01536 {
01537 Assert(TransactionAbortContext != NULL);
01538
01539 MemoryContextSwitchTo(TransactionAbortContext);
01540 }
01541
01542
01543
01544
01545
01546 static void
01547 AtAbort_ResourceOwner(void)
01548 {
01549
01550
01551
01552
01553 CurrentResourceOwner = TopTransactionResourceOwner;
01554 }
01555
01556
01557
01558
01559 static void
01560 AtSubAbort_ResourceOwner(void)
01561 {
01562 TransactionState s = CurrentTransactionState;
01563
01564
01565 CurrentResourceOwner = s->curTransactionOwner;
01566 }
01567
01568
01569
01570
01571
01572 static void
01573 AtSubAbort_childXids(void)
01574 {
01575 TransactionState s = CurrentTransactionState;
01576
01577
01578
01579
01580
01581
01582 if (s->childXids != NULL)
01583 pfree(s->childXids);
01584 s->childXids = NULL;
01585 s->nChildXids = 0;
01586 s->maxChildXids = 0;
01587
01588
01589
01590
01591
01592
01593
01594 }
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604 static void
01605 AtCleanup_Memory(void)
01606 {
01607 Assert(CurrentTransactionState->parent == NULL);
01608
01609
01610
01611
01612
01613 MemoryContextSwitchTo(TopMemoryContext);
01614
01615
01616
01617
01618 if (TransactionAbortContext != NULL)
01619 MemoryContextResetAndDeleteChildren(TransactionAbortContext);
01620
01621
01622
01623
01624 if (TopTransactionContext != NULL)
01625 MemoryContextDelete(TopTransactionContext);
01626 TopTransactionContext = NULL;
01627 CurTransactionContext = NULL;
01628 CurrentTransactionState->curTransactionContext = NULL;
01629 }
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640 static void
01641 AtSubCleanup_Memory(void)
01642 {
01643 TransactionState s = CurrentTransactionState;
01644
01645 Assert(s->parent != NULL);
01646
01647
01648 MemoryContextSwitchTo(s->parent->curTransactionContext);
01649 CurTransactionContext = s->parent->curTransactionContext;
01650
01651
01652
01653
01654 if (TransactionAbortContext != NULL)
01655 MemoryContextResetAndDeleteChildren(TransactionAbortContext);
01656
01657
01658
01659
01660
01661
01662 if (s->curTransactionContext)
01663 MemoryContextDelete(s->curTransactionContext);
01664 s->curTransactionContext = NULL;
01665 }
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675 static void
01676 StartTransaction(void)
01677 {
01678 TransactionState s;
01679 VirtualTransactionId vxid;
01680
01681
01682
01683
01684 s = &TopTransactionStateData;
01685 CurrentTransactionState = s;
01686
01687
01688
01689
01690 if (s->state != TRANS_DEFAULT)
01691 elog(WARNING, "StartTransaction while in %s state",
01692 TransStateAsString(s->state));
01693
01694
01695
01696
01697
01698 s->state = TRANS_START;
01699 s->transactionId = InvalidTransactionId;
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709 if (RecoveryInProgress())
01710 {
01711 s->startedInRecovery = true;
01712 XactReadOnly = true;
01713 }
01714 else
01715 {
01716 s->startedInRecovery = false;
01717 XactReadOnly = DefaultXactReadOnly;
01718 }
01719 XactDeferrable = DefaultXactDeferrable;
01720 XactIsoLevel = DefaultXactIsoLevel;
01721 forceSyncCommit = false;
01722 MyXactAccessedTempRel = false;
01723
01724
01725
01726
01727 s->subTransactionId = TopSubTransactionId;
01728 currentSubTransactionId = TopSubTransactionId;
01729 currentCommandId = FirstCommandId;
01730 currentCommandIdUsed = false;
01731
01732
01733
01734
01735 nUnreportedXids = 0;
01736
01737
01738
01739
01740 AtStart_Memory();
01741 AtStart_ResourceOwner();
01742
01743
01744
01745
01746
01747 vxid.backendId = MyBackendId;
01748 vxid.localTransactionId = GetNextLocalTransactionId();
01749
01750
01751
01752
01753 VirtualXactLockTableInsert(vxid);
01754
01755
01756
01757
01758
01759 Assert(MyProc->backendId == vxid.backendId);
01760 MyProc->lxid = vxid.localTransactionId;
01761
01762 TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
01763
01764
01765
01766
01767
01768
01769
01770 xactStartTimestamp = stmtStartTimestamp;
01771 xactStopTimestamp = 0;
01772 pgstat_report_xact_timestamp(xactStartTimestamp);
01773
01774
01775
01776
01777
01778
01779 s->nestingLevel = 1;
01780 s->gucNestLevel = 1;
01781 s->childXids = NULL;
01782 s->nChildXids = 0;
01783 s->maxChildXids = 0;
01784 GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
01785
01786 Assert(s->prevSecContext == 0);
01787
01788
01789
01790
01791 AtStart_GUC();
01792 AtStart_Inval();
01793 AtStart_Cache();
01794 AfterTriggerBeginXact();
01795
01796
01797
01798
01799
01800 s->state = TRANS_INPROGRESS;
01801
01802 ShowTransactionState("StartTransaction");
01803 }
01804
01805
01806
01807
01808
01809
01810
01811 static void
01812 CommitTransaction(void)
01813 {
01814 TransactionState s = CurrentTransactionState;
01815 TransactionId latestXid;
01816
01817 ShowTransactionState("CommitTransaction");
01818
01819
01820
01821
01822 if (s->state != TRANS_INPROGRESS)
01823 elog(WARNING, "CommitTransaction while in %s state",
01824 TransStateAsString(s->state));
01825 Assert(s->parent == NULL);
01826
01827
01828
01829
01830
01831
01832
01833 for (;;)
01834 {
01835
01836
01837
01838 AfterTriggerFireDeferred();
01839
01840
01841
01842
01843
01844
01845 if (!PreCommit_Portals(false))
01846 break;
01847 }
01848
01849 CallXactCallbacks(XACT_EVENT_PRE_COMMIT);
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859 AfterTriggerEndXact(true);
01860
01861
01862
01863
01864
01865 PreCommit_on_commit_actions();
01866
01867
01868 AtEOXact_LargeObject(true);
01869
01870
01871
01872
01873
01874
01875 PreCommit_CheckForSerializationFailure();
01876
01877
01878
01879
01880
01881
01882 PreCommit_Notify();
01883
01884
01885 HOLD_INTERRUPTS();
01886
01887
01888 AtEOXact_RelationMap(true);
01889
01890
01891
01892
01893
01894 s->state = TRANS_COMMIT;
01895
01896
01897
01898
01899 latestXid = RecordTransactionCommit();
01900
01901 TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->lxid);
01902
01903
01904
01905
01906
01907
01908 ProcArrayEndTransaction(MyProc, latestXid);
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926 CallXactCallbacks(XACT_EVENT_COMMIT);
01927
01928 ResourceOwnerRelease(TopTransactionResourceOwner,
01929 RESOURCE_RELEASE_BEFORE_LOCKS,
01930 true, true);
01931
01932
01933 AtEOXact_Buffers(true);
01934
01935
01936 AtEOXact_RelationCache(true);
01937
01938
01939
01940
01941
01942
01943
01944
01945 AtEOXact_Inval(true);
01946
01947 AtEOXact_MultiXact();
01948
01949 ResourceOwnerRelease(TopTransactionResourceOwner,
01950 RESOURCE_RELEASE_LOCKS,
01951 true, true);
01952 ResourceOwnerRelease(TopTransactionResourceOwner,
01953 RESOURCE_RELEASE_AFTER_LOCKS,
01954 true, true);
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965 smgrDoPendingDeletes(true);
01966
01967
01968 AtEOXact_CatCache(true);
01969
01970 AtCommit_Notify();
01971 AtEOXact_GUC(true, 1);
01972 AtEOXact_SPI(true);
01973 AtEOXact_on_commit_actions(true);
01974 AtEOXact_Namespace(true);
01975 AtEOXact_SMgr();
01976 AtEOXact_Files();
01977 AtEOXact_ComboCid();
01978 AtEOXact_HashTables(true);
01979 AtEOXact_PgStat(true);
01980 AtEOXact_Snapshot(true);
01981 pgstat_report_xact_timestamp(0);
01982
01983 CurrentResourceOwner = NULL;
01984 ResourceOwnerDelete(TopTransactionResourceOwner);
01985 s->curTransactionOwner = NULL;
01986 CurTransactionResourceOwner = NULL;
01987 TopTransactionResourceOwner = NULL;
01988
01989 AtCommit_Memory();
01990
01991 s->transactionId = InvalidTransactionId;
01992 s->subTransactionId = InvalidSubTransactionId;
01993 s->nestingLevel = 0;
01994 s->gucNestLevel = 0;
01995 s->childXids = NULL;
01996 s->nChildXids = 0;
01997 s->maxChildXids = 0;
01998
01999
02000
02001
02002
02003 s->state = TRANS_DEFAULT;
02004
02005 RESUME_INTERRUPTS();
02006 }
02007
02008
02009
02010
02011
02012
02013
02014 static void
02015 PrepareTransaction(void)
02016 {
02017 TransactionState s = CurrentTransactionState;
02018 TransactionId xid = GetCurrentTransactionId();
02019 GlobalTransaction gxact;
02020 TimestampTz prepared_at;
02021
02022 ShowTransactionState("PrepareTransaction");
02023
02024
02025
02026
02027 if (s->state != TRANS_INPROGRESS)
02028 elog(WARNING, "PrepareTransaction while in %s state",
02029 TransStateAsString(s->state));
02030 Assert(s->parent == NULL);
02031
02032
02033
02034
02035
02036
02037
02038 for (;;)
02039 {
02040
02041
02042
02043 AfterTriggerFireDeferred();
02044
02045
02046
02047
02048
02049
02050 if (!PreCommit_Portals(true))
02051 break;
02052 }
02053
02054 CallXactCallbacks(XACT_EVENT_PRE_PREPARE);
02055
02056
02057
02058
02059
02060
02061
02062
02063
02064 AfterTriggerEndXact(true);
02065
02066
02067
02068
02069
02070 PreCommit_on_commit_actions();
02071
02072
02073 AtEOXact_LargeObject(true);
02074
02075
02076
02077
02078
02079
02080 PreCommit_CheckForSerializationFailure();
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099 if (MyXactAccessedTempRel)
02100 ereport(ERROR,
02101 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02102 errmsg("cannot PREPARE a transaction that has operated on temporary tables")));
02103
02104
02105
02106
02107
02108
02109 if (XactHasExportedSnapshots())
02110 ereport(ERROR,
02111 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02112 errmsg("cannot PREPARE a transaction that has exported snapshots")));
02113
02114
02115 HOLD_INTERRUPTS();
02116
02117
02118
02119
02120
02121 s->state = TRANS_PREPARE;
02122
02123 prepared_at = GetCurrentTimestamp();
02124
02125
02126 BufmgrCommit();
02127
02128
02129
02130
02131
02132 gxact = MarkAsPreparing(xid, prepareGID, prepared_at,
02133 GetUserId(), MyDatabaseId);
02134 prepareGID = NULL;
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152 StartPrepare(gxact);
02153
02154 AtPrepare_Notify();
02155 AtPrepare_Locks();
02156 AtPrepare_PredicateLocks();
02157 AtPrepare_PgStat();
02158 AtPrepare_MultiXact();
02159 AtPrepare_RelationMap();
02160
02161
02162
02163
02164
02165
02166
02167
02168 EndPrepare(gxact);
02169
02170
02171
02172
02173
02174
02175 XactLastRecEnd = 0;
02176
02177
02178
02179
02180
02181
02182 ProcArrayClearTransaction(MyProc);
02183
02184
02185
02186
02187
02188
02189
02190 CallXactCallbacks(XACT_EVENT_PREPARE);
02191
02192 ResourceOwnerRelease(TopTransactionResourceOwner,
02193 RESOURCE_RELEASE_BEFORE_LOCKS,
02194 true, true);
02195
02196
02197 AtEOXact_Buffers(true);
02198
02199
02200 AtEOXact_RelationCache(true);
02201
02202
02203
02204 PostPrepare_PgStat();
02205
02206 PostPrepare_Inval();
02207
02208 PostPrepare_smgr();
02209
02210 PostPrepare_MultiXact(xid);
02211
02212 PostPrepare_Locks(xid);
02213 PostPrepare_PredicateLocks(xid);
02214
02215 ResourceOwnerRelease(TopTransactionResourceOwner,
02216 RESOURCE_RELEASE_LOCKS,
02217 true, true);
02218 ResourceOwnerRelease(TopTransactionResourceOwner,
02219 RESOURCE_RELEASE_AFTER_LOCKS,
02220 true, true);
02221
02222
02223 AtEOXact_CatCache(true);
02224
02225
02226 AtEOXact_GUC(true, 1);
02227 AtEOXact_SPI(true);
02228 AtEOXact_on_commit_actions(true);
02229 AtEOXact_Namespace(true);
02230 AtEOXact_SMgr();
02231 AtEOXact_Files();
02232 AtEOXact_ComboCid();
02233 AtEOXact_HashTables(true);
02234
02235 AtEOXact_Snapshot(true);
02236
02237 CurrentResourceOwner = NULL;
02238 ResourceOwnerDelete(TopTransactionResourceOwner);
02239 s->curTransactionOwner = NULL;
02240 CurTransactionResourceOwner = NULL;
02241 TopTransactionResourceOwner = NULL;
02242
02243 AtCommit_Memory();
02244
02245 s->transactionId = InvalidTransactionId;
02246 s->subTransactionId = InvalidSubTransactionId;
02247 s->nestingLevel = 0;
02248 s->gucNestLevel = 0;
02249 s->childXids = NULL;
02250 s->nChildXids = 0;
02251 s->maxChildXids = 0;
02252
02253
02254
02255
02256
02257 s->state = TRANS_DEFAULT;
02258
02259 RESUME_INTERRUPTS();
02260 }
02261
02262
02263
02264
02265
02266 static void
02267 AbortTransaction(void)
02268 {
02269 TransactionState s = CurrentTransactionState;
02270 TransactionId latestXid;
02271
02272
02273 HOLD_INTERRUPTS();
02274
02275
02276 AtAbort_Memory();
02277 AtAbort_ResourceOwner();
02278
02279
02280
02281
02282
02283
02284
02285 LWLockReleaseAll();
02286
02287
02288 AbortBufferIO();
02289 UnlockBuffers();
02290
02291
02292
02293
02294
02295 LockErrorCleanup();
02296
02297
02298
02299
02300 if (s->state != TRANS_INPROGRESS && s->state != TRANS_PREPARE)
02301 elog(WARNING, "AbortTransaction while in %s state",
02302 TransStateAsString(s->state));
02303 Assert(s->parent == NULL);
02304
02305
02306
02307
02308
02309 s->state = TRANS_ABORT;
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321 SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
02322
02323
02324
02325
02326 AfterTriggerEndXact(false);
02327 AtAbort_Portals();
02328 AtEOXact_LargeObject(false);
02329 AtAbort_Notify();
02330 AtEOXact_RelationMap(false);
02331
02332
02333
02334
02335
02336 latestXid = RecordTransactionAbort(false);
02337
02338 TRACE_POSTGRESQL_TRANSACTION_ABORT(MyProc->lxid);
02339
02340
02341
02342
02343
02344
02345 ProcArrayEndTransaction(MyProc, latestXid);
02346
02347
02348
02349
02350
02351
02352 if (TopTransactionResourceOwner != NULL)
02353 {
02354 CallXactCallbacks(XACT_EVENT_ABORT);
02355
02356 ResourceOwnerRelease(TopTransactionResourceOwner,
02357 RESOURCE_RELEASE_BEFORE_LOCKS,
02358 false, true);
02359 AtEOXact_Buffers(false);
02360 AtEOXact_RelationCache(false);
02361 AtEOXact_Inval(false);
02362 AtEOXact_MultiXact();
02363 ResourceOwnerRelease(TopTransactionResourceOwner,
02364 RESOURCE_RELEASE_LOCKS,
02365 false, true);
02366 ResourceOwnerRelease(TopTransactionResourceOwner,
02367 RESOURCE_RELEASE_AFTER_LOCKS,
02368 false, true);
02369 smgrDoPendingDeletes(false);
02370 AtEOXact_CatCache(false);
02371
02372 AtEOXact_GUC(false, 1);
02373 AtEOXact_SPI(false);
02374 AtEOXact_on_commit_actions(false);
02375 AtEOXact_Namespace(false);
02376 AtEOXact_SMgr();
02377 AtEOXact_Files();
02378 AtEOXact_ComboCid();
02379 AtEOXact_HashTables(false);
02380 AtEOXact_PgStat(false);
02381 pgstat_report_xact_timestamp(0);
02382 }
02383
02384
02385
02386
02387 RESUME_INTERRUPTS();
02388 }
02389
02390
02391
02392
02393 static void
02394 CleanupTransaction(void)
02395 {
02396 TransactionState s = CurrentTransactionState;
02397
02398
02399
02400
02401 if (s->state != TRANS_ABORT)
02402 elog(FATAL, "CleanupTransaction: unexpected state %s",
02403 TransStateAsString(s->state));
02404
02405
02406
02407
02408 AtCleanup_Portals();
02409 AtEOXact_Snapshot(false);
02410
02411 CurrentResourceOwner = NULL;
02412 if (TopTransactionResourceOwner)
02413 ResourceOwnerDelete(TopTransactionResourceOwner);
02414 s->curTransactionOwner = NULL;
02415 CurTransactionResourceOwner = NULL;
02416 TopTransactionResourceOwner = NULL;
02417
02418 AtCleanup_Memory();
02419
02420 s->transactionId = InvalidTransactionId;
02421 s->subTransactionId = InvalidSubTransactionId;
02422 s->nestingLevel = 0;
02423 s->gucNestLevel = 0;
02424 s->childXids = NULL;
02425 s->nChildXids = 0;
02426 s->maxChildXids = 0;
02427
02428
02429
02430
02431
02432 s->state = TRANS_DEFAULT;
02433 }
02434
02435
02436
02437
02438 void
02439 StartTransactionCommand(void)
02440 {
02441 TransactionState s = CurrentTransactionState;
02442
02443 switch (s->blockState)
02444 {
02445
02446
02447
02448
02449 case TBLOCK_DEFAULT:
02450 StartTransaction();
02451 s->blockState = TBLOCK_STARTED;
02452 break;
02453
02454
02455
02456
02457
02458
02459
02460
02461 case TBLOCK_INPROGRESS:
02462 case TBLOCK_SUBINPROGRESS:
02463 break;
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473 case TBLOCK_ABORT:
02474 case TBLOCK_SUBABORT:
02475 break;
02476
02477
02478 case TBLOCK_STARTED:
02479 case TBLOCK_BEGIN:
02480 case TBLOCK_SUBBEGIN:
02481 case TBLOCK_END:
02482 case TBLOCK_SUBRELEASE:
02483 case TBLOCK_SUBCOMMIT:
02484 case TBLOCK_ABORT_END:
02485 case TBLOCK_SUBABORT_END:
02486 case TBLOCK_ABORT_PENDING:
02487 case TBLOCK_SUBABORT_PENDING:
02488 case TBLOCK_SUBRESTART:
02489 case TBLOCK_SUBABORT_RESTART:
02490 case TBLOCK_PREPARE:
02491 elog(ERROR, "StartTransactionCommand: unexpected state %s",
02492 BlockStateAsString(s->blockState));
02493 break;
02494 }
02495
02496
02497
02498
02499
02500 Assert(CurTransactionContext != NULL);
02501 MemoryContextSwitchTo(CurTransactionContext);
02502 }
02503
02504
02505
02506
02507 void
02508 CommitTransactionCommand(void)
02509 {
02510 TransactionState s = CurrentTransactionState;
02511
02512 switch (s->blockState)
02513 {
02514
02515
02516
02517
02518
02519 case TBLOCK_DEFAULT:
02520 elog(FATAL, "CommitTransactionCommand: unexpected state %s",
02521 BlockStateAsString(s->blockState));
02522 break;
02523
02524
02525
02526
02527
02528 case TBLOCK_STARTED:
02529 CommitTransaction();
02530 s->blockState = TBLOCK_DEFAULT;
02531 break;
02532
02533
02534
02535
02536
02537
02538
02539 case TBLOCK_BEGIN:
02540 s->blockState = TBLOCK_INPROGRESS;
02541 break;
02542
02543
02544
02545
02546
02547
02548 case TBLOCK_INPROGRESS:
02549 case TBLOCK_SUBINPROGRESS:
02550 CommandCounterIncrement();
02551 break;
02552
02553
02554
02555
02556
02557 case TBLOCK_END:
02558 CommitTransaction();
02559 s->blockState = TBLOCK_DEFAULT;
02560 break;
02561
02562
02563
02564
02565
02566
02567 case TBLOCK_ABORT:
02568 case TBLOCK_SUBABORT:
02569 break;
02570
02571
02572
02573
02574
02575
02576 case TBLOCK_ABORT_END:
02577 CleanupTransaction();
02578 s->blockState = TBLOCK_DEFAULT;
02579 break;
02580
02581
02582
02583
02584
02585
02586 case TBLOCK_ABORT_PENDING:
02587 AbortTransaction();
02588 CleanupTransaction();
02589 s->blockState = TBLOCK_DEFAULT;
02590 break;
02591
02592
02593
02594
02595
02596 case TBLOCK_PREPARE:
02597 PrepareTransaction();
02598 s->blockState = TBLOCK_DEFAULT;
02599 break;
02600
02601
02602
02603
02604
02605
02606
02607 case TBLOCK_SUBBEGIN:
02608 StartSubTransaction();
02609 s->blockState = TBLOCK_SUBINPROGRESS;
02610 break;
02611
02612
02613
02614
02615
02616
02617
02618 case TBLOCK_SUBRELEASE:
02619 do
02620 {
02621 CommitSubTransaction();
02622 s = CurrentTransactionState;
02623 } while (s->blockState == TBLOCK_SUBRELEASE);
02624
02625 Assert(s->blockState == TBLOCK_INPROGRESS ||
02626 s->blockState == TBLOCK_SUBINPROGRESS);
02627 break;
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638 case TBLOCK_SUBCOMMIT:
02639 do
02640 {
02641 CommitSubTransaction();
02642 s = CurrentTransactionState;
02643 } while (s->blockState == TBLOCK_SUBCOMMIT);
02644
02645 if (s->blockState == TBLOCK_END)
02646 {
02647 Assert(s->parent == NULL);
02648 CommitTransaction();
02649 s->blockState = TBLOCK_DEFAULT;
02650 }
02651 else if (s->blockState == TBLOCK_PREPARE)
02652 {
02653 Assert(s->parent == NULL);
02654 PrepareTransaction();
02655 s->blockState = TBLOCK_DEFAULT;
02656 }
02657 else
02658 elog(ERROR, "CommitTransactionCommand: unexpected state %s",
02659 BlockStateAsString(s->blockState));
02660 break;
02661
02662
02663
02664
02665
02666
02667 case TBLOCK_SUBABORT_END:
02668 CleanupSubTransaction();
02669 CommitTransactionCommand();
02670 break;
02671
02672
02673
02674
02675 case TBLOCK_SUBABORT_PENDING:
02676 AbortSubTransaction();
02677 CleanupSubTransaction();
02678 CommitTransactionCommand();
02679 break;
02680
02681
02682
02683
02684
02685
02686 case TBLOCK_SUBRESTART:
02687 {
02688 char *name;
02689 int savepointLevel;
02690
02691
02692 name = s->name;
02693 s->name = NULL;
02694 savepointLevel = s->savepointLevel;
02695
02696 AbortSubTransaction();
02697 CleanupSubTransaction();
02698
02699 DefineSavepoint(NULL);
02700 s = CurrentTransactionState;
02701 s->name = name;
02702 s->savepointLevel = savepointLevel;
02703
02704
02705 AssertState(s->blockState == TBLOCK_SUBBEGIN);
02706 StartSubTransaction();
02707 s->blockState = TBLOCK_SUBINPROGRESS;
02708 }
02709 break;
02710
02711
02712
02713
02714
02715 case TBLOCK_SUBABORT_RESTART:
02716 {
02717 char *name;
02718 int savepointLevel;
02719
02720
02721 name = s->name;
02722 s->name = NULL;
02723 savepointLevel = s->savepointLevel;
02724
02725 CleanupSubTransaction();
02726
02727 DefineSavepoint(NULL);
02728 s = CurrentTransactionState;
02729 s->name = name;
02730 s->savepointLevel = savepointLevel;
02731
02732
02733 AssertState(s->blockState == TBLOCK_SUBBEGIN);
02734 StartSubTransaction();
02735 s->blockState = TBLOCK_SUBINPROGRESS;
02736 }
02737 break;
02738 }
02739 }
02740
02741
02742
02743
02744 void
02745 AbortCurrentTransaction(void)
02746 {
02747 TransactionState s = CurrentTransactionState;
02748
02749 switch (s->blockState)
02750 {
02751 case TBLOCK_DEFAULT:
02752 if (s->state == TRANS_DEFAULT)
02753 {
02754
02755 }
02756 else
02757 {
02758
02759
02760
02761
02762
02763
02764
02765 if (s->state == TRANS_START)
02766 s->state = TRANS_INPROGRESS;
02767 AbortTransaction();
02768 CleanupTransaction();
02769 }
02770 break;
02771
02772
02773
02774
02775
02776 case TBLOCK_STARTED:
02777 AbortTransaction();
02778 CleanupTransaction();
02779 s->blockState = TBLOCK_DEFAULT;
02780 break;
02781
02782
02783
02784
02785
02786
02787
02788
02789 case TBLOCK_BEGIN:
02790 AbortTransaction();
02791 CleanupTransaction();
02792 s->blockState = TBLOCK_DEFAULT;
02793 break;
02794
02795
02796
02797
02798
02799
02800 case TBLOCK_INPROGRESS:
02801 AbortTransaction();
02802 s->blockState = TBLOCK_ABORT;
02803
02804 break;
02805
02806
02807
02808
02809
02810
02811 case TBLOCK_END:
02812 AbortTransaction();
02813 CleanupTransaction();
02814 s->blockState = TBLOCK_DEFAULT;
02815 break;
02816
02817
02818
02819
02820
02821
02822 case TBLOCK_ABORT:
02823 case TBLOCK_SUBABORT:
02824 break;
02825
02826
02827
02828
02829
02830
02831 case TBLOCK_ABORT_END:
02832 CleanupTransaction();
02833 s->blockState = TBLOCK_DEFAULT;
02834 break;
02835
02836
02837
02838
02839
02840 case TBLOCK_ABORT_PENDING:
02841 AbortTransaction();
02842 CleanupTransaction();
02843 s->blockState = TBLOCK_DEFAULT;
02844 break;
02845
02846
02847
02848
02849
02850
02851 case TBLOCK_PREPARE:
02852 AbortTransaction();
02853 CleanupTransaction();
02854 s->blockState = TBLOCK_DEFAULT;
02855 break;
02856
02857
02858
02859
02860
02861
02862 case TBLOCK_SUBINPROGRESS:
02863 AbortSubTransaction();
02864 s->blockState = TBLOCK_SUBABORT;
02865 break;
02866
02867
02868
02869
02870
02871
02872 case TBLOCK_SUBBEGIN:
02873 case TBLOCK_SUBRELEASE:
02874 case TBLOCK_SUBCOMMIT:
02875 case TBLOCK_SUBABORT_PENDING:
02876 case TBLOCK_SUBRESTART:
02877 AbortSubTransaction();
02878 CleanupSubTransaction();
02879 AbortCurrentTransaction();
02880 break;
02881
02882
02883
02884
02885 case TBLOCK_SUBABORT_END:
02886 case TBLOCK_SUBABORT_RESTART:
02887 CleanupSubTransaction();
02888 AbortCurrentTransaction();
02889 break;
02890 }
02891 }
02892
02893
02894
02895
02896
02897
02898
02899
02900
02901
02902
02903
02904
02905
02906
02907
02908
02909
02910
02911 void
02912 PreventTransactionChain(bool isTopLevel, const char *stmtType)
02913 {
02914
02915
02916
02917 if (IsTransactionBlock())
02918 ereport(ERROR,
02919 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
02920
02921 errmsg("%s cannot run inside a transaction block",
02922 stmtType)));
02923
02924
02925
02926
02927 if (IsSubTransaction())
02928 ereport(ERROR,
02929 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
02930
02931 errmsg("%s cannot run inside a subtransaction",
02932 stmtType)));
02933
02934
02935
02936
02937 if (!isTopLevel)
02938 ereport(ERROR,
02939 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
02940
02941 errmsg("%s cannot be executed from a function or multi-command string",
02942 stmtType)));
02943
02944
02945 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
02946 CurrentTransactionState->blockState != TBLOCK_STARTED)
02947 elog(FATAL, "cannot prevent transaction chain");
02948
02949 }
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968 void
02969 RequireTransactionChain(bool isTopLevel, const char *stmtType)
02970 {
02971
02972
02973
02974 if (IsTransactionBlock())
02975 return;
02976
02977
02978
02979
02980 if (IsSubTransaction())
02981 return;
02982
02983
02984
02985
02986 if (!isTopLevel)
02987 return;
02988
02989 ereport(ERROR,
02990 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
02991
02992 errmsg("%s can only be used in transaction blocks",
02993 stmtType)));
02994 }
02995
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005
03006 bool
03007 IsInTransactionChain(bool isTopLevel)
03008 {
03009
03010
03011
03012
03013 if (IsTransactionBlock())
03014 return true;
03015
03016 if (IsSubTransaction())
03017 return true;
03018
03019 if (!isTopLevel)
03020 return true;
03021
03022 if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
03023 CurrentTransactionState->blockState != TBLOCK_STARTED)
03024 return true;
03025
03026 return false;
03027 }
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039
03040
03041 void
03042 RegisterXactCallback(XactCallback callback, void *arg)
03043 {
03044 XactCallbackItem *item;
03045
03046 item = (XactCallbackItem *)
03047 MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
03048 item->callback = callback;
03049 item->arg = arg;
03050 item->next = Xact_callbacks;
03051 Xact_callbacks = item;
03052 }
03053
03054 void
03055 UnregisterXactCallback(XactCallback callback, void *arg)
03056 {
03057 XactCallbackItem *item;
03058 XactCallbackItem *prev;
03059
03060 prev = NULL;
03061 for (item = Xact_callbacks; item; prev = item, item = item->next)
03062 {
03063 if (item->callback == callback && item->arg == arg)
03064 {
03065 if (prev)
03066 prev->next = item->next;
03067 else
03068 Xact_callbacks = item->next;
03069 pfree(item);
03070 break;
03071 }
03072 }
03073 }
03074
03075 static void
03076 CallXactCallbacks(XactEvent event)
03077 {
03078 XactCallbackItem *item;
03079
03080 for (item = Xact_callbacks; item; item = item->next)
03081 (*item->callback) (event, item->arg);
03082 }
03083
03084
03085
03086
03087
03088
03089
03090
03091
03092
03093
03094
03095
03096 void
03097 RegisterSubXactCallback(SubXactCallback callback, void *arg)
03098 {
03099 SubXactCallbackItem *item;
03100
03101 item = (SubXactCallbackItem *)
03102 MemoryContextAlloc(TopMemoryContext, sizeof(SubXactCallbackItem));
03103 item->callback = callback;
03104 item->arg = arg;
03105 item->next = SubXact_callbacks;
03106 SubXact_callbacks = item;
03107 }
03108
03109 void
03110 UnregisterSubXactCallback(SubXactCallback callback, void *arg)
03111 {
03112 SubXactCallbackItem *item;
03113 SubXactCallbackItem *prev;
03114
03115 prev = NULL;
03116 for (item = SubXact_callbacks; item; prev = item, item = item->next)
03117 {
03118 if (item->callback == callback && item->arg == arg)
03119 {
03120 if (prev)
03121 prev->next = item->next;
03122 else
03123 SubXact_callbacks = item->next;
03124 pfree(item);
03125 break;
03126 }
03127 }
03128 }
03129
03130 static void
03131 CallSubXactCallbacks(SubXactEvent event,
03132 SubTransactionId mySubid,
03133 SubTransactionId parentSubid)
03134 {
03135 SubXactCallbackItem *item;
03136
03137 for (item = SubXact_callbacks; item; item = item->next)
03138 (*item->callback) (event, mySubid, parentSubid, item->arg);
03139 }
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151 void
03152 BeginTransactionBlock(void)
03153 {
03154 TransactionState s = CurrentTransactionState;
03155
03156 switch (s->blockState)
03157 {
03158
03159
03160
03161 case TBLOCK_STARTED:
03162 s->blockState = TBLOCK_BEGIN;
03163 break;
03164
03165
03166
03167
03168 case TBLOCK_INPROGRESS:
03169 case TBLOCK_SUBINPROGRESS:
03170 case TBLOCK_ABORT:
03171 case TBLOCK_SUBABORT:
03172 ereport(WARNING,
03173 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
03174 errmsg("there is already a transaction in progress")));
03175 break;
03176
03177
03178 case TBLOCK_DEFAULT:
03179 case TBLOCK_BEGIN:
03180 case TBLOCK_SUBBEGIN:
03181 case TBLOCK_END:
03182 case TBLOCK_SUBRELEASE:
03183 case TBLOCK_SUBCOMMIT:
03184 case TBLOCK_ABORT_END:
03185 case TBLOCK_SUBABORT_END:
03186 case TBLOCK_ABORT_PENDING:
03187 case TBLOCK_SUBABORT_PENDING:
03188 case TBLOCK_SUBRESTART:
03189 case TBLOCK_SUBABORT_RESTART:
03190 case TBLOCK_PREPARE:
03191 elog(FATAL, "BeginTransactionBlock: unexpected state %s",
03192 BlockStateAsString(s->blockState));
03193 break;
03194 }
03195 }
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209 bool
03210 PrepareTransactionBlock(char *gid)
03211 {
03212 TransactionState s;
03213 bool result;
03214
03215
03216 result = EndTransactionBlock();
03217
03218
03219 if (result)
03220 {
03221 s = CurrentTransactionState;
03222
03223 while (s->parent != NULL)
03224 s = s->parent;
03225
03226 if (s->blockState == TBLOCK_END)
03227 {
03228
03229 prepareGID = MemoryContextStrdup(TopTransactionContext, gid);
03230
03231 s->blockState = TBLOCK_PREPARE;
03232 }
03233 else
03234 {
03235
03236
03237
03238
03239 Assert(s->blockState == TBLOCK_STARTED);
03240
03241 result = false;
03242 }
03243 }
03244
03245 return result;
03246 }
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260 bool
03261 EndTransactionBlock(void)
03262 {
03263 TransactionState s = CurrentTransactionState;
03264 bool result = false;
03265
03266 switch (s->blockState)
03267 {
03268
03269
03270
03271
03272 case TBLOCK_INPROGRESS:
03273 s->blockState = TBLOCK_END;
03274 result = true;
03275 break;
03276
03277
03278
03279
03280
03281 case TBLOCK_ABORT:
03282 s->blockState = TBLOCK_ABORT_END;
03283 break;
03284
03285
03286
03287
03288
03289 case TBLOCK_SUBINPROGRESS:
03290 while (s->parent != NULL)
03291 {
03292 if (s->blockState == TBLOCK_SUBINPROGRESS)
03293 s->blockState = TBLOCK_SUBCOMMIT;
03294 else
03295 elog(FATAL, "EndTransactionBlock: unexpected state %s",
03296 BlockStateAsString(s->blockState));
03297 s = s->parent;
03298 }
03299 if (s->blockState == TBLOCK_INPROGRESS)
03300 s->blockState = TBLOCK_END;
03301 else
03302 elog(FATAL, "EndTransactionBlock: unexpected state %s",
03303 BlockStateAsString(s->blockState));
03304 result = true;
03305 break;
03306
03307
03308
03309
03310
03311
03312 case TBLOCK_SUBABORT:
03313 while (s->parent != NULL)
03314 {
03315 if (s->blockState == TBLOCK_SUBINPROGRESS)
03316 s->blockState = TBLOCK_SUBABORT_PENDING;
03317 else if (s->blockState == TBLOCK_SUBABORT)
03318 s->blockState = TBLOCK_SUBABORT_END;
03319 else
03320 elog(FATAL, "EndTransactionBlock: unexpected state %s",
03321 BlockStateAsString(s->blockState));
03322 s = s->parent;
03323 }
03324 if (s->blockState == TBLOCK_INPROGRESS)
03325 s->blockState = TBLOCK_ABORT_PENDING;
03326 else if (s->blockState == TBLOCK_ABORT)
03327 s->blockState = TBLOCK_ABORT_END;
03328 else
03329 elog(FATAL, "EndTransactionBlock: unexpected state %s",
03330 BlockStateAsString(s->blockState));
03331 break;
03332
03333
03334
03335
03336
03337
03338
03339 case TBLOCK_STARTED:
03340 ereport(WARNING,
03341 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
03342 errmsg("there is no transaction in progress")));
03343 result = true;
03344 break;
03345
03346
03347 case TBLOCK_DEFAULT:
03348 case TBLOCK_BEGIN:
03349 case TBLOCK_SUBBEGIN:
03350 case TBLOCK_END:
03351 case TBLOCK_SUBRELEASE:
03352 case TBLOCK_SUBCOMMIT:
03353 case TBLOCK_ABORT_END:
03354 case TBLOCK_SUBABORT_END:
03355 case TBLOCK_ABORT_PENDING:
03356 case TBLOCK_SUBABORT_PENDING:
03357 case TBLOCK_SUBRESTART:
03358 case TBLOCK_SUBABORT_RESTART:
03359 case TBLOCK_PREPARE:
03360 elog(FATAL, "EndTransactionBlock: unexpected state %s",
03361 BlockStateAsString(s->blockState));
03362 break;
03363 }
03364
03365 return result;
03366 }
03367
03368
03369
03370
03371
03372
03373
03374 void
03375 UserAbortTransactionBlock(void)
03376 {
03377 TransactionState s = CurrentTransactionState;
03378
03379 switch (s->blockState)
03380 {
03381
03382
03383
03384
03385
03386 case TBLOCK_INPROGRESS:
03387 s->blockState = TBLOCK_ABORT_PENDING;
03388 break;
03389
03390
03391
03392
03393
03394
03395
03396 case TBLOCK_ABORT:
03397 s->blockState = TBLOCK_ABORT_END;
03398 break;
03399
03400
03401
03402
03403
03404 case TBLOCK_SUBINPROGRESS:
03405 case TBLOCK_SUBABORT:
03406 while (s->parent != NULL)
03407 {
03408 if (s->blockState == TBLOCK_SUBINPROGRESS)
03409 s->blockState = TBLOCK_SUBABORT_PENDING;
03410 else if (s->blockState == TBLOCK_SUBABORT)
03411 s->blockState = TBLOCK_SUBABORT_END;
03412 else
03413 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
03414 BlockStateAsString(s->blockState));
03415 s = s->parent;
03416 }
03417 if (s->blockState == TBLOCK_INPROGRESS)
03418 s->blockState = TBLOCK_ABORT_PENDING;
03419 else if (s->blockState == TBLOCK_ABORT)
03420 s->blockState = TBLOCK_ABORT_END;
03421 else
03422 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
03423 BlockStateAsString(s->blockState));
03424 break;
03425
03426
03427
03428
03429
03430
03431
03432 case TBLOCK_STARTED:
03433 ereport(NOTICE,
03434 (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
03435 errmsg("there is no transaction in progress")));
03436 s->blockState = TBLOCK_ABORT_PENDING;
03437 break;
03438
03439
03440 case TBLOCK_DEFAULT:
03441 case TBLOCK_BEGIN:
03442 case TBLOCK_SUBBEGIN:
03443 case TBLOCK_END:
03444 case TBLOCK_SUBRELEASE:
03445 case TBLOCK_SUBCOMMIT:
03446 case TBLOCK_ABORT_END:
03447 case TBLOCK_SUBABORT_END:
03448 case TBLOCK_ABORT_PENDING:
03449 case TBLOCK_SUBABORT_PENDING:
03450 case TBLOCK_SUBRESTART:
03451 case TBLOCK_SUBABORT_RESTART:
03452 case TBLOCK_PREPARE:
03453 elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
03454 BlockStateAsString(s->blockState));
03455 break;
03456 }
03457 }
03458
03459
03460
03461
03462
03463 void
03464 DefineSavepoint(char *name)
03465 {
03466 TransactionState s = CurrentTransactionState;
03467
03468 switch (s->blockState)
03469 {
03470 case TBLOCK_INPROGRESS:
03471 case TBLOCK_SUBINPROGRESS:
03472
03473 PushTransaction();
03474 s = CurrentTransactionState;
03475
03476
03477
03478
03479
03480 if (name)
03481 s->name = MemoryContextStrdup(TopTransactionContext, name);
03482 break;
03483
03484
03485 case TBLOCK_DEFAULT:
03486 case TBLOCK_STARTED:
03487 case TBLOCK_BEGIN:
03488 case TBLOCK_SUBBEGIN:
03489 case TBLOCK_END:
03490 case TBLOCK_SUBRELEASE:
03491 case TBLOCK_SUBCOMMIT:
03492 case TBLOCK_ABORT:
03493 case TBLOCK_SUBABORT:
03494 case TBLOCK_ABORT_END:
03495 case TBLOCK_SUBABORT_END:
03496 case TBLOCK_ABORT_PENDING:
03497 case TBLOCK_SUBABORT_PENDING:
03498 case TBLOCK_SUBRESTART:
03499 case TBLOCK_SUBABORT_RESTART:
03500 case TBLOCK_PREPARE:
03501 elog(FATAL, "DefineSavepoint: unexpected state %s",
03502 BlockStateAsString(s->blockState));
03503 break;
03504 }
03505 }
03506
03507
03508
03509
03510
03511
03512
03513 void
03514 ReleaseSavepoint(List *options)
03515 {
03516 TransactionState s = CurrentTransactionState;
03517 TransactionState target,
03518 xact;
03519 ListCell *cell;
03520 char *name = NULL;
03521
03522 switch (s->blockState)
03523 {
03524
03525
03526
03527
03528 case TBLOCK_INPROGRESS:
03529 ereport(ERROR,
03530 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
03531 errmsg("no such savepoint")));
03532 break;
03533
03534
03535
03536
03537
03538 case TBLOCK_SUBINPROGRESS:
03539 break;
03540
03541
03542 case TBLOCK_DEFAULT:
03543 case TBLOCK_STARTED:
03544 case TBLOCK_BEGIN:
03545 case TBLOCK_SUBBEGIN:
03546 case TBLOCK_END:
03547 case TBLOCK_SUBRELEASE:
03548 case TBLOCK_SUBCOMMIT:
03549 case TBLOCK_ABORT:
03550 case TBLOCK_SUBABORT:
03551 case TBLOCK_ABORT_END:
03552 case TBLOCK_SUBABORT_END:
03553 case TBLOCK_ABORT_PENDING:
03554 case TBLOCK_SUBABORT_PENDING:
03555 case TBLOCK_SUBRESTART:
03556 case TBLOCK_SUBABORT_RESTART:
03557 case TBLOCK_PREPARE:
03558 elog(FATAL, "ReleaseSavepoint: unexpected state %s",
03559 BlockStateAsString(s->blockState));
03560 break;
03561 }
03562
03563 foreach(cell, options)
03564 {
03565 DefElem *elem = lfirst(cell);
03566
03567 if (strcmp(elem->defname, "savepoint_name") == 0)
03568 name = strVal(elem->arg);
03569 }
03570
03571 Assert(PointerIsValid(name));
03572
03573 for (target = s; PointerIsValid(target); target = target->parent)
03574 {
03575 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
03576 break;
03577 }
03578
03579 if (!PointerIsValid(target))
03580 ereport(ERROR,
03581 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
03582 errmsg("no such savepoint")));
03583
03584
03585 if (target->savepointLevel != s->savepointLevel)
03586 ereport(ERROR,
03587 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
03588 errmsg("no such savepoint")));
03589
03590
03591
03592
03593
03594
03595 xact = CurrentTransactionState;
03596 for (;;)
03597 {
03598 Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
03599 xact->blockState = TBLOCK_SUBRELEASE;
03600 if (xact == target)
03601 break;
03602 xact = xact->parent;
03603 Assert(PointerIsValid(xact));
03604 }
03605 }
03606
03607
03608
03609
03610
03611
03612
03613 void
03614 RollbackToSavepoint(List *options)
03615 {
03616 TransactionState s = CurrentTransactionState;
03617 TransactionState target,
03618 xact;
03619 ListCell *cell;
03620 char *name = NULL;
03621
03622 switch (s->blockState)
03623 {
03624
03625
03626
03627
03628 case TBLOCK_INPROGRESS:
03629 case TBLOCK_ABORT:
03630 ereport(ERROR,
03631 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
03632 errmsg("no such savepoint")));
03633 break;
03634
03635
03636
03637
03638 case TBLOCK_SUBINPROGRESS:
03639 case TBLOCK_SUBABORT:
03640 break;
03641
03642
03643 case TBLOCK_DEFAULT:
03644 case TBLOCK_STARTED:
03645 case TBLOCK_BEGIN:
03646 case TBLOCK_SUBBEGIN:
03647 case TBLOCK_END:
03648 case TBLOCK_SUBRELEASE:
03649 case TBLOCK_SUBCOMMIT:
03650 case TBLOCK_ABORT_END:
03651 case TBLOCK_SUBABORT_END:
03652 case TBLOCK_ABORT_PENDING:
03653 case TBLOCK_SUBABORT_PENDING:
03654 case TBLOCK_SUBRESTART:
03655 case TBLOCK_SUBABORT_RESTART:
03656 case TBLOCK_PREPARE:
03657 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
03658 BlockStateAsString(s->blockState));
03659 break;
03660 }
03661
03662 foreach(cell, options)
03663 {
03664 DefElem *elem = lfirst(cell);
03665
03666 if (strcmp(elem->defname, "savepoint_name") == 0)
03667 name = strVal(elem->arg);
03668 }
03669
03670 Assert(PointerIsValid(name));
03671
03672 for (target = s; PointerIsValid(target); target = target->parent)
03673 {
03674 if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
03675 break;
03676 }
03677
03678 if (!PointerIsValid(target))
03679 ereport(ERROR,
03680 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
03681 errmsg("no such savepoint")));
03682
03683
03684 if (target->savepointLevel != s->savepointLevel)
03685 ereport(ERROR,
03686 (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
03687 errmsg("no such savepoint")));
03688
03689
03690
03691
03692
03693
03694 xact = CurrentTransactionState;
03695 for (;;)
03696 {
03697 if (xact == target)
03698 break;
03699 if (xact->blockState == TBLOCK_SUBINPROGRESS)
03700 xact->blockState = TBLOCK_SUBABORT_PENDING;
03701 else if (xact->blockState == TBLOCK_SUBABORT)
03702 xact->blockState = TBLOCK_SUBABORT_END;
03703 else
03704 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
03705 BlockStateAsString(xact->blockState));
03706 xact = xact->parent;
03707 Assert(PointerIsValid(xact));
03708 }
03709
03710
03711 if (xact->blockState == TBLOCK_SUBINPROGRESS)
03712 xact->blockState = TBLOCK_SUBRESTART;
03713 else if (xact->blockState == TBLOCK_SUBABORT)
03714 xact->blockState = TBLOCK_SUBABORT_RESTART;
03715 else
03716 elog(FATAL, "RollbackToSavepoint: unexpected state %s",
03717 BlockStateAsString(xact->blockState));
03718 }
03719
03720
03721
03722
03723
03724
03725
03726
03727
03728
03729 void
03730 BeginInternalSubTransaction(char *name)
03731 {
03732 TransactionState s = CurrentTransactionState;
03733
03734 switch (s->blockState)
03735 {
03736 case TBLOCK_STARTED:
03737 case TBLOCK_INPROGRESS:
03738 case TBLOCK_END:
03739 case TBLOCK_PREPARE:
03740 case TBLOCK_SUBINPROGRESS:
03741
03742 PushTransaction();
03743 s = CurrentTransactionState;
03744
03745
03746
03747
03748
03749 if (name)
03750 s->name = MemoryContextStrdup(TopTransactionContext, name);
03751 break;
03752
03753
03754 case TBLOCK_DEFAULT:
03755 case TBLOCK_BEGIN:
03756 case TBLOCK_SUBBEGIN:
03757 case TBLOCK_SUBRELEASE:
03758 case TBLOCK_SUBCOMMIT:
03759 case TBLOCK_ABORT:
03760 case TBLOCK_SUBABORT:
03761 case TBLOCK_ABORT_END:
03762 case TBLOCK_SUBABORT_END:
03763 case TBLOCK_ABORT_PENDING:
03764 case TBLOCK_SUBABORT_PENDING:
03765 case TBLOCK_SUBRESTART:
03766 case TBLOCK_SUBABORT_RESTART:
03767 elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
03768 BlockStateAsString(s->blockState));
03769 break;
03770 }
03771
03772 CommitTransactionCommand();
03773 StartTransactionCommand();
03774 }
03775
03776
03777
03778
03779
03780
03781
03782
03783 void
03784 ReleaseCurrentSubTransaction(void)
03785 {
03786 TransactionState s = CurrentTransactionState;
03787
03788 if (s->blockState != TBLOCK_SUBINPROGRESS)
03789 elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
03790 BlockStateAsString(s->blockState));
03791 Assert(s->state == TRANS_INPROGRESS);
03792 MemoryContextSwitchTo(CurTransactionContext);
03793 CommitSubTransaction();
03794 s = CurrentTransactionState;
03795 Assert(s->state == TRANS_INPROGRESS);
03796 }
03797
03798
03799
03800
03801
03802
03803
03804
03805 void
03806 RollbackAndReleaseCurrentSubTransaction(void)
03807 {
03808 TransactionState s = CurrentTransactionState;
03809
03810 switch (s->blockState)
03811 {
03812
03813 case TBLOCK_SUBINPROGRESS:
03814 case TBLOCK_SUBABORT:
03815 break;
03816
03817
03818 case TBLOCK_DEFAULT:
03819 case TBLOCK_STARTED:
03820 case TBLOCK_BEGIN:
03821 case TBLOCK_SUBBEGIN:
03822 case TBLOCK_INPROGRESS:
03823 case TBLOCK_END:
03824 case TBLOCK_SUBRELEASE:
03825 case TBLOCK_SUBCOMMIT:
03826 case TBLOCK_ABORT:
03827 case TBLOCK_ABORT_END:
03828 case TBLOCK_SUBABORT_END:
03829 case TBLOCK_ABORT_PENDING:
03830 case TBLOCK_SUBABORT_PENDING:
03831 case TBLOCK_SUBRESTART:
03832 case TBLOCK_SUBABORT_RESTART:
03833 case TBLOCK_PREPARE:
03834 elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
03835 BlockStateAsString(s->blockState));
03836 break;
03837 }
03838
03839
03840
03841
03842 if (s->blockState == TBLOCK_SUBINPROGRESS)
03843 AbortSubTransaction();
03844
03845
03846 CleanupSubTransaction();
03847
03848 s = CurrentTransactionState;
03849 AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
03850 s->blockState == TBLOCK_INPROGRESS ||
03851 s->blockState == TBLOCK_STARTED);
03852 }
03853
03854
03855
03856
03857
03858
03859
03860
03861 void
03862 AbortOutOfAnyTransaction(void)
03863 {
03864 TransactionState s = CurrentTransactionState;
03865
03866
03867
03868
03869 do
03870 {
03871 switch (s->blockState)
03872 {
03873 case TBLOCK_DEFAULT:
03874 if (s->state == TRANS_DEFAULT)
03875 {
03876
03877 }
03878 else
03879 {
03880
03881
03882
03883
03884
03885
03886
03887 if (s->state == TRANS_START)
03888 s->state = TRANS_INPROGRESS;
03889 AbortTransaction();
03890 CleanupTransaction();
03891 }
03892 break;
03893 case TBLOCK_STARTED:
03894 case TBLOCK_BEGIN:
03895 case TBLOCK_INPROGRESS:
03896 case TBLOCK_END:
03897 case TBLOCK_ABORT_PENDING:
03898 case TBLOCK_PREPARE:
03899
03900 AbortTransaction();
03901 CleanupTransaction();
03902 s->blockState = TBLOCK_DEFAULT;
03903 break;
03904 case TBLOCK_ABORT:
03905 case TBLOCK_ABORT_END:
03906
03907 CleanupTransaction();
03908 s->blockState = TBLOCK_DEFAULT;
03909 break;
03910
03911
03912
03913
03914 case TBLOCK_SUBBEGIN:
03915 case TBLOCK_SUBINPROGRESS:
03916 case TBLOCK_SUBRELEASE:
03917 case TBLOCK_SUBCOMMIT:
03918 case TBLOCK_SUBABORT_PENDING:
03919 case TBLOCK_SUBRESTART:
03920 AbortSubTransaction();
03921 CleanupSubTransaction();
03922 s = CurrentTransactionState;
03923 break;
03924
03925 case TBLOCK_SUBABORT:
03926 case TBLOCK_SUBABORT_END:
03927 case TBLOCK_SUBABORT_RESTART:
03928
03929 CleanupSubTransaction();
03930 s = CurrentTransactionState;
03931 break;
03932 }
03933 } while (s->blockState != TBLOCK_DEFAULT);
03934
03935
03936 Assert(s->parent == NULL);
03937 }
03938
03939
03940
03941
03942 bool
03943 IsTransactionBlock(void)
03944 {
03945 TransactionState s = CurrentTransactionState;
03946
03947 if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
03948 return false;
03949
03950 return true;
03951 }
03952
03953
03954
03955
03956
03957
03958
03959
03960 bool
03961 IsTransactionOrTransactionBlock(void)
03962 {
03963 TransactionState s = CurrentTransactionState;
03964
03965 if (s->blockState == TBLOCK_DEFAULT)
03966 return false;
03967
03968 return true;
03969 }
03970
03971
03972
03973
03974 char
03975 TransactionBlockStatusCode(void)
03976 {
03977 TransactionState s = CurrentTransactionState;
03978
03979 switch (s->blockState)
03980 {
03981 case TBLOCK_DEFAULT:
03982 case TBLOCK_STARTED:
03983 return 'I';
03984 case TBLOCK_BEGIN:
03985 case TBLOCK_SUBBEGIN:
03986 case TBLOCK_INPROGRESS:
03987 case TBLOCK_SUBINPROGRESS:
03988 case TBLOCK_END:
03989 case TBLOCK_SUBRELEASE:
03990 case TBLOCK_SUBCOMMIT:
03991 case TBLOCK_PREPARE:
03992 return 'T';
03993 case TBLOCK_ABORT:
03994 case TBLOCK_SUBABORT:
03995 case TBLOCK_ABORT_END:
03996 case TBLOCK_SUBABORT_END:
03997 case TBLOCK_ABORT_PENDING:
03998 case TBLOCK_SUBABORT_PENDING:
03999 case TBLOCK_SUBRESTART:
04000 case TBLOCK_SUBABORT_RESTART:
04001 return 'E';
04002 }
04003
04004
04005 elog(FATAL, "invalid transaction block state: %s",
04006 BlockStateAsString(s->blockState));
04007 return 0;
04008 }
04009
04010
04011
04012
04013 bool
04014 IsSubTransaction(void)
04015 {
04016 TransactionState s = CurrentTransactionState;
04017
04018 if (s->nestingLevel >= 2)
04019 return true;
04020
04021 return false;
04022 }
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036 static void
04037 StartSubTransaction(void)
04038 {
04039 TransactionState s = CurrentTransactionState;
04040
04041 if (s->state != TRANS_DEFAULT)
04042 elog(WARNING, "StartSubTransaction while in %s state",
04043 TransStateAsString(s->state));
04044
04045 s->state = TRANS_START;
04046
04047
04048
04049
04050
04051
04052 AtSubStart_Memory();
04053 AtSubStart_ResourceOwner();
04054 AtSubStart_Inval();
04055 AtSubStart_Notify();
04056 AfterTriggerBeginSubXact();
04057
04058 s->state = TRANS_INPROGRESS;
04059
04060
04061
04062
04063 CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
04064 s->parent->subTransactionId);
04065
04066 ShowTransactionState("StartSubTransaction");
04067 }
04068
04069
04070
04071
04072
04073
04074
04075 static void
04076 CommitSubTransaction(void)
04077 {
04078 TransactionState s = CurrentTransactionState;
04079
04080 ShowTransactionState("CommitSubTransaction");
04081
04082 if (s->state != TRANS_INPROGRESS)
04083 elog(WARNING, "CommitSubTransaction while in %s state",
04084 TransStateAsString(s->state));
04085
04086
04087
04088 CallSubXactCallbacks(SUBXACT_EVENT_PRE_COMMIT_SUB, s->subTransactionId,
04089 s->parent->subTransactionId);
04090
04091
04092 s->state = TRANS_COMMIT;
04093
04094
04095 CommandCounterIncrement();
04096
04097
04098
04099
04100
04101
04102
04103
04104 if (TransactionIdIsValid(s->transactionId))
04105 AtSubCommit_childXids();
04106 AfterTriggerEndSubXact(true);
04107 AtSubCommit_Portals(s->subTransactionId,
04108 s->parent->subTransactionId,
04109 s->parent->curTransactionOwner);
04110 AtEOSubXact_LargeObject(true, s->subTransactionId,
04111 s->parent->subTransactionId);
04112 AtSubCommit_Notify();
04113
04114 CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
04115 s->parent->subTransactionId);
04116
04117 ResourceOwnerRelease(s->curTransactionOwner,
04118 RESOURCE_RELEASE_BEFORE_LOCKS,
04119 true, false);
04120 AtEOSubXact_RelationCache(true, s->subTransactionId,
04121 s->parent->subTransactionId);
04122 AtEOSubXact_Inval(true);
04123 AtSubCommit_smgr();
04124
04125
04126
04127
04128 CurrentResourceOwner = s->curTransactionOwner;
04129 if (TransactionIdIsValid(s->transactionId))
04130 XactLockTableDelete(s->transactionId);
04131
04132
04133
04134
04135 ResourceOwnerRelease(s->curTransactionOwner,
04136 RESOURCE_RELEASE_LOCKS,
04137 true, false);
04138 ResourceOwnerRelease(s->curTransactionOwner,
04139 RESOURCE_RELEASE_AFTER_LOCKS,
04140 true, false);
04141
04142 AtEOXact_GUC(true, s->gucNestLevel);
04143 AtEOSubXact_SPI(true, s->subTransactionId);
04144 AtEOSubXact_on_commit_actions(true, s->subTransactionId,
04145 s->parent->subTransactionId);
04146 AtEOSubXact_Namespace(true, s->subTransactionId,
04147 s->parent->subTransactionId);
04148 AtEOSubXact_Files(true, s->subTransactionId,
04149 s->parent->subTransactionId);
04150 AtEOSubXact_HashTables(true, s->nestingLevel);
04151 AtEOSubXact_PgStat(true, s->nestingLevel);
04152 AtSubCommit_Snapshot(s->nestingLevel);
04153
04154
04155
04156
04157
04158
04159 XactReadOnly = s->prevXactReadOnly;
04160
04161 CurrentResourceOwner = s->parent->curTransactionOwner;
04162 CurTransactionResourceOwner = s->parent->curTransactionOwner;
04163 ResourceOwnerDelete(s->curTransactionOwner);
04164 s->curTransactionOwner = NULL;
04165
04166 AtSubCommit_Memory();
04167
04168 s->state = TRANS_DEFAULT;
04169
04170 PopTransaction();
04171 }
04172
04173
04174
04175
04176 static void
04177 AbortSubTransaction(void)
04178 {
04179 TransactionState s = CurrentTransactionState;
04180
04181
04182 HOLD_INTERRUPTS();
04183
04184
04185 AtSubAbort_Memory();
04186 AtSubAbort_ResourceOwner();
04187
04188
04189
04190
04191
04192
04193
04194
04195
04196
04197 LWLockReleaseAll();
04198
04199 AbortBufferIO();
04200 UnlockBuffers();
04201
04202 LockErrorCleanup();
04203
04204
04205
04206
04207 ShowTransactionState("AbortSubTransaction");
04208
04209 if (s->state != TRANS_INPROGRESS)
04210 elog(WARNING, "AbortSubTransaction while in %s state",
04211 TransStateAsString(s->state));
04212
04213 s->state = TRANS_ABORT;
04214
04215
04216
04217
04218
04219 SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
04220
04221
04222
04223
04224
04225 if (s->curTransactionOwner)
04226 {
04227 AfterTriggerEndSubXact(false);
04228 AtSubAbort_Portals(s->subTransactionId,
04229 s->parent->subTransactionId,
04230 s->parent->curTransactionOwner);
04231 AtEOSubXact_LargeObject(false, s->subTransactionId,
04232 s->parent->subTransactionId);
04233 AtSubAbort_Notify();
04234
04235
04236 (void) RecordTransactionAbort(true);
04237
04238
04239 if (TransactionIdIsValid(s->transactionId))
04240 AtSubAbort_childXids();
04241
04242 CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
04243 s->parent->subTransactionId);
04244
04245 ResourceOwnerRelease(s->curTransactionOwner,
04246 RESOURCE_RELEASE_BEFORE_LOCKS,
04247 false, false);
04248 AtEOSubXact_RelationCache(false, s->subTransactionId,
04249 s->parent->subTransactionId);
04250 AtEOSubXact_Inval(false);
04251 ResourceOwnerRelease(s->curTransactionOwner,
04252 RESOURCE_RELEASE_LOCKS,
04253 false, false);
04254 ResourceOwnerRelease(s->curTransactionOwner,
04255 RESOURCE_RELEASE_AFTER_LOCKS,
04256 false, false);
04257 AtSubAbort_smgr();
04258
04259 AtEOXact_GUC(false, s->gucNestLevel);
04260 AtEOSubXact_SPI(false, s->subTransactionId);
04261 AtEOSubXact_on_commit_actions(false, s->subTransactionId,
04262 s->parent->subTransactionId);
04263 AtEOSubXact_Namespace(false, s->subTransactionId,
04264 s->parent->subTransactionId);
04265 AtEOSubXact_Files(false, s->subTransactionId,
04266 s->parent->subTransactionId);
04267 AtEOSubXact_HashTables(false, s->nestingLevel);
04268 AtEOSubXact_PgStat(false, s->nestingLevel);
04269 AtSubAbort_Snapshot(s->nestingLevel);
04270 }
04271
04272
04273
04274
04275
04276
04277 XactReadOnly = s->prevXactReadOnly;
04278
04279 RESUME_INTERRUPTS();
04280 }
04281
04282
04283
04284
04285
04286
04287
04288 static void
04289 CleanupSubTransaction(void)
04290 {
04291 TransactionState s = CurrentTransactionState;
04292
04293 ShowTransactionState("CleanupSubTransaction");
04294
04295 if (s->state != TRANS_ABORT)
04296 elog(WARNING, "CleanupSubTransaction while in %s state",
04297 TransStateAsString(s->state));
04298
04299 AtSubCleanup_Portals(s->subTransactionId);
04300
04301 CurrentResourceOwner = s->parent->curTransactionOwner;
04302 CurTransactionResourceOwner = s->parent->curTransactionOwner;
04303 if (s->curTransactionOwner)
04304 ResourceOwnerDelete(s->curTransactionOwner);
04305 s->curTransactionOwner = NULL;
04306
04307 AtSubCleanup_Memory();
04308
04309 s->state = TRANS_DEFAULT;
04310
04311 PopTransaction();
04312 }
04313
04314
04315
04316
04317
04318
04319
04320
04321 static void
04322 PushTransaction(void)
04323 {
04324 TransactionState p = CurrentTransactionState;
04325 TransactionState s;
04326
04327
04328
04329
04330 s = (TransactionState)
04331 MemoryContextAllocZero(TopTransactionContext,
04332 sizeof(TransactionStateData));
04333
04334
04335
04336
04337 currentSubTransactionId += 1;
04338 if (currentSubTransactionId == InvalidSubTransactionId)
04339 {
04340 currentSubTransactionId -= 1;
04341 pfree(s);
04342 ereport(ERROR,
04343 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
04344 errmsg("cannot have more than 2^32-1 subtransactions in a transaction")));
04345 }
04346
04347
04348
04349
04350
04351 s->transactionId = InvalidTransactionId;
04352 s->subTransactionId = currentSubTransactionId;
04353 s->parent = p;
04354 s->nestingLevel = p->nestingLevel + 1;
04355 s->gucNestLevel = NewGUCNestLevel();
04356 s->savepointLevel = p->savepointLevel;
04357 s->state = TRANS_DEFAULT;
04358 s->blockState = TBLOCK_SUBBEGIN;
04359 GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
04360 s->prevXactReadOnly = XactReadOnly;
04361
04362 CurrentTransactionState = s;
04363
04364
04365
04366
04367
04368
04369
04370 }
04371
04372
04373
04374
04375
04376
04377
04378
04379 static void
04380 PopTransaction(void)
04381 {
04382 TransactionState s = CurrentTransactionState;
04383
04384 if (s->state != TRANS_DEFAULT)
04385 elog(WARNING, "PopTransaction while in %s state",
04386 TransStateAsString(s->state));
04387
04388 if (s->parent == NULL)
04389 elog(FATAL, "PopTransaction with no parent");
04390
04391 CurrentTransactionState = s->parent;
04392
04393
04394 CurTransactionContext = s->parent->curTransactionContext;
04395 MemoryContextSwitchTo(CurTransactionContext);
04396
04397
04398 CurTransactionResourceOwner = s->parent->curTransactionOwner;
04399 CurrentResourceOwner = s->parent->curTransactionOwner;
04400
04401
04402 if (s->name)
04403 pfree(s->name);
04404 pfree(s);
04405 }
04406
04407
04408
04409
04410
04411 static void
04412 ShowTransactionState(const char *str)
04413 {
04414
04415 if (log_min_messages <= DEBUG3 || client_min_messages <= DEBUG3)
04416 {
04417 elog(DEBUG3, "%s", str);
04418 ShowTransactionStateRec(CurrentTransactionState);
04419 }
04420 }
04421
04422
04423
04424
04425
04426 static void
04427 ShowTransactionStateRec(TransactionState s)
04428 {
04429 StringInfoData buf;
04430
04431 initStringInfo(&buf);
04432
04433 if (s->nChildXids > 0)
04434 {
04435 int i;
04436
04437 appendStringInfo(&buf, "%u", s->childXids[0]);
04438 for (i = 1; i < s->nChildXids; i++)
04439 appendStringInfo(&buf, " %u", s->childXids[i]);
04440 }
04441
04442 if (s->parent)
04443 ShowTransactionStateRec(s->parent);
04444
04445
04446 ereport(DEBUG3,
04447 (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u%s, nestlvl: %d, children: %s",
04448 PointerIsValid(s->name) ? s->name : "unnamed",
04449 BlockStateAsString(s->blockState),
04450 TransStateAsString(s->state),
04451 (unsigned int) s->transactionId,
04452 (unsigned int) s->subTransactionId,
04453 (unsigned int) currentCommandId,
04454 currentCommandIdUsed ? " (used)" : "",
04455 s->nestingLevel, buf.data)));
04456
04457 pfree(buf.data);
04458 }
04459
04460
04461
04462
04463
04464 static const char *
04465 BlockStateAsString(TBlockState blockState)
04466 {
04467 switch (blockState)
04468 {
04469 case TBLOCK_DEFAULT:
04470 return "DEFAULT";
04471 case TBLOCK_STARTED:
04472 return "STARTED";
04473 case TBLOCK_BEGIN:
04474 return "BEGIN";
04475 case TBLOCK_INPROGRESS:
04476 return "INPROGRESS";
04477 case TBLOCK_END:
04478 return "END";
04479 case TBLOCK_ABORT:
04480 return "ABORT";
04481 case TBLOCK_ABORT_END:
04482 return "ABORT END";
04483 case TBLOCK_ABORT_PENDING:
04484 return "ABORT PEND";
04485 case TBLOCK_PREPARE:
04486 return "PREPARE";
04487 case TBLOCK_SUBBEGIN:
04488 return "SUB BEGIN";
04489 case TBLOCK_SUBINPROGRESS:
04490 return "SUB INPROGRS";
04491 case TBLOCK_SUBRELEASE:
04492 return "SUB RELEASE";
04493 case TBLOCK_SUBCOMMIT:
04494 return "SUB COMMIT";
04495 case TBLOCK_SUBABORT:
04496 return "SUB ABORT";
04497 case TBLOCK_SUBABORT_END:
04498 return "SUB ABORT END";
04499 case TBLOCK_SUBABORT_PENDING:
04500 return "SUB ABRT PEND";
04501 case TBLOCK_SUBRESTART:
04502 return "SUB RESTART";
04503 case TBLOCK_SUBABORT_RESTART:
04504 return "SUB AB RESTRT";
04505 }
04506 return "UNRECOGNIZED";
04507 }
04508
04509
04510
04511
04512
04513 static const char *
04514 TransStateAsString(TransState state)
04515 {
04516 switch (state)
04517 {
04518 case TRANS_DEFAULT:
04519 return "DEFAULT";
04520 case TRANS_START:
04521 return "START";
04522 case TRANS_INPROGRESS:
04523 return "INPROGR";
04524 case TRANS_COMMIT:
04525 return "COMMIT";
04526 case TRANS_ABORT:
04527 return "ABORT";
04528 case TRANS_PREPARE:
04529 return "PREPARE";
04530 }
04531 return "UNRECOGNIZED";
04532 }
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543 int
04544 xactGetCommittedChildren(TransactionId **ptr)
04545 {
04546 TransactionState s = CurrentTransactionState;
04547
04548 if (s->nChildXids == 0)
04549 *ptr = NULL;
04550 else
04551 *ptr = s->childXids;
04552
04553 return s->nChildXids;
04554 }
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564 static void
04565 xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
04566 TransactionId *sub_xids, int nsubxacts,
04567 SharedInvalidationMessage *inval_msgs, int nmsgs,
04568 RelFileNode *xnodes, int nrels,
04569 Oid dbId, Oid tsId,
04570 uint32 xinfo)
04571 {
04572 TransactionId max_xid;
04573 int i;
04574
04575 max_xid = TransactionIdLatest(xid, nsubxacts, sub_xids);
04576
04577
04578
04579
04580
04581
04582
04583
04584 if (TransactionIdFollowsOrEquals(max_xid,
04585 ShmemVariableCache->nextXid))
04586 {
04587 LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
04588 ShmemVariableCache->nextXid = max_xid;
04589 TransactionIdAdvance(ShmemVariableCache->nextXid);
04590 LWLockRelease(XidGenLock);
04591 }
04592
04593 if (standbyState == STANDBY_DISABLED)
04594 {
04595
04596
04597
04598 TransactionIdCommitTree(xid, nsubxacts, sub_xids);
04599 }
04600 else
04601 {
04602
04603
04604
04605
04606
04607
04608
04609
04610
04611 RecordKnownAssignedTransactionIds(max_xid);
04612
04613
04614
04615
04616
04617
04618
04619
04620
04621
04622 TransactionIdAsyncCommitTree(xid, nsubxacts, sub_xids, lsn);
04623
04624
04625
04626
04627 ExpireTreeKnownAssignedTransactionIds(xid, nsubxacts, sub_xids, max_xid);
04628
04629
04630
04631
04632
04633
04634 ProcessCommittedInvalidationMessages(inval_msgs, nmsgs,
04635 XactCompletionRelcacheInitFileInval(xinfo),
04636 dbId, tsId);
04637
04638
04639
04640
04641
04642
04643
04644
04645 StandbyReleaseLockTree(xid, 0, NULL);
04646 }
04647
04648
04649 if (nrels > 0)
04650 {
04651
04652
04653
04654
04655
04656
04657
04658
04659
04660
04661
04662
04663
04664
04665
04666 XLogFlush(lsn);
04667
04668 for (i = 0; i < nrels; i++)
04669 {
04670 SMgrRelation srel = smgropen(xnodes[i], InvalidBackendId);
04671 ForkNumber fork;
04672
04673 for (fork = 0; fork <= MAX_FORKNUM; fork++)
04674 XLogDropRelation(xnodes[i], fork);
04675 smgrdounlink(srel, true);
04676 smgrclose(srel);
04677 }
04678 }
04679
04680
04681
04682
04683
04684
04685
04686
04687
04688
04689
04690
04691
04692
04693 if (XactCompletionForceSyncCommit(xinfo))
04694 XLogFlush(lsn);
04695
04696 }
04697
04698
04699
04700
04701 static void
04702 xact_redo_commit(xl_xact_commit *xlrec,
04703 TransactionId xid, XLogRecPtr lsn)
04704 {
04705 TransactionId *subxacts;
04706 SharedInvalidationMessage *inval_msgs;
04707
04708
04709 subxacts = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
04710
04711 inval_msgs = (SharedInvalidationMessage *) &(subxacts[xlrec->nsubxacts]);
04712
04713 xact_redo_commit_internal(xid, lsn, subxacts, xlrec->nsubxacts,
04714 inval_msgs, xlrec->nmsgs,
04715 xlrec->xnodes, xlrec->nrels,
04716 xlrec->dbId,
04717 xlrec->tsId,
04718 xlrec->xinfo);
04719 }
04720
04721
04722
04723
04724 static void
04725 xact_redo_commit_compact(xl_xact_commit_compact *xlrec,
04726 TransactionId xid, XLogRecPtr lsn)
04727 {
04728 xact_redo_commit_internal(xid, lsn, xlrec->subxacts, xlrec->nsubxacts,
04729 NULL, 0,
04730 NULL, 0,
04731 InvalidOid,
04732 InvalidOid,
04733 0);
04734 }
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744
04745 static void
04746 xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
04747 {
04748 TransactionId *sub_xids;
04749 TransactionId max_xid;
04750 int i;
04751
04752 sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
04753 max_xid = TransactionIdLatest(xid, xlrec->nsubxacts, sub_xids);
04754
04755
04756
04757
04758
04759
04760
04761
04762 if (TransactionIdFollowsOrEquals(max_xid,
04763 ShmemVariableCache->nextXid))
04764 {
04765 LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
04766 ShmemVariableCache->nextXid = max_xid;
04767 TransactionIdAdvance(ShmemVariableCache->nextXid);
04768 LWLockRelease(XidGenLock);
04769 }
04770
04771 if (standbyState == STANDBY_DISABLED)
04772 {
04773
04774 TransactionIdAbortTree(xid, xlrec->nsubxacts, sub_xids);
04775 }
04776 else
04777 {
04778
04779
04780
04781
04782
04783
04784
04785
04786
04787 RecordKnownAssignedTransactionIds(max_xid);
04788
04789
04790 TransactionIdAbortTree(xid, xlrec->nsubxacts, sub_xids);
04791
04792
04793
04794
04795 ExpireTreeKnownAssignedTransactionIds(xid, xlrec->nsubxacts, sub_xids, max_xid);
04796
04797
04798
04799
04800
04801
04802
04803
04804
04805 StandbyReleaseLockTree(xid, xlrec->nsubxacts, sub_xids);
04806 }
04807
04808
04809 for (i = 0; i < xlrec->nrels; i++)
04810 {
04811 SMgrRelation srel = smgropen(xlrec->xnodes[i], InvalidBackendId);
04812 ForkNumber fork;
04813
04814 for (fork = 0; fork <= MAX_FORKNUM; fork++)
04815 XLogDropRelation(xlrec->xnodes[i], fork);
04816 smgrdounlink(srel, true);
04817 smgrclose(srel);
04818 }
04819 }
04820
04821 void
04822 xact_redo(XLogRecPtr lsn, XLogRecord *record)
04823 {
04824 uint8 info = record->xl_info & ~XLR_INFO_MASK;
04825
04826
04827 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
04828
04829 if (info == XLOG_XACT_COMMIT_COMPACT)
04830 {
04831 xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) XLogRecGetData(record);
04832
04833 xact_redo_commit_compact(xlrec, record->xl_xid, lsn);
04834 }
04835 else if (info == XLOG_XACT_COMMIT)
04836 {
04837 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
04838
04839 xact_redo_commit(xlrec, record->xl_xid, lsn);
04840 }
04841 else if (info == XLOG_XACT_ABORT)
04842 {
04843 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
04844
04845 xact_redo_abort(xlrec, record->xl_xid);
04846 }
04847 else if (info == XLOG_XACT_PREPARE)
04848 {
04849
04850 RecreateTwoPhaseFile(record->xl_xid,
04851 XLogRecGetData(record), record->xl_len);
04852 }
04853 else if (info == XLOG_XACT_COMMIT_PREPARED)
04854 {
04855 xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) XLogRecGetData(record);
04856
04857 xact_redo_commit(&xlrec->crec, xlrec->xid, lsn);
04858 RemoveTwoPhaseFile(xlrec->xid, false);
04859 }
04860 else if (info == XLOG_XACT_ABORT_PREPARED)
04861 {
04862 xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) XLogRecGetData(record);
04863
04864 xact_redo_abort(&xlrec->arec, xlrec->xid);
04865 RemoveTwoPhaseFile(xlrec->xid, false);
04866 }
04867 else if (info == XLOG_XACT_ASSIGNMENT)
04868 {
04869 xl_xact_assignment *xlrec = (xl_xact_assignment *) XLogRecGetData(record);
04870
04871 if (standbyState >= STANDBY_INITIALIZED)
04872 ProcArrayApplyXidAssignment(xlrec->xtop,
04873 xlrec->nsubxacts, xlrec->xsub);
04874 }
04875 else
04876 elog(PANIC, "xact_redo: unknown op code %u", info);
04877 }