Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * xact.c
4 : : * top level transaction system support routines
5 : : *
6 : : * See src/backend/access/transam/README for more information.
7 : : *
8 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
9 : : * Portions Copyright (c) 1994, Regents of the University of California
10 : : *
11 : : *
12 : : * IDENTIFICATION
13 : : * src/backend/access/transam/xact.c
14 : : *
15 : : *-------------------------------------------------------------------------
16 : : */
17 : :
18 : : #include "postgres.h"
19 : :
20 : : #include <time.h>
21 : : #include <unistd.h>
22 : :
23 : : #include "access/commit_ts.h"
24 : : #include "access/multixact.h"
25 : : #include "access/parallel.h"
26 : : #include "access/subtrans.h"
27 : : #include "access/transam.h"
28 : : #include "access/twophase.h"
29 : : #include "access/xact.h"
30 : : #include "access/xlog.h"
31 : : #include "access/xloginsert.h"
32 : : #include "access/xlogrecovery.h"
33 : : #include "access/xlogutils.h"
34 : : #include "access/xlogwait.h"
35 : : #include "catalog/index.h"
36 : : #include "catalog/namespace.h"
37 : : #include "catalog/pg_enum.h"
38 : : #include "catalog/storage.h"
39 : : #include "commands/async.h"
40 : : #include "commands/tablecmds.h"
41 : : #include "commands/trigger.h"
42 : : #include "common/pg_prng.h"
43 : : #include "executor/spi.h"
44 : : #include "libpq/be-fsstubs.h"
45 : : #include "libpq/pqsignal.h"
46 : : #include "miscadmin.h"
47 : : #include "pg_trace.h"
48 : : #include "pgstat.h"
49 : : #include "replication/logical.h"
50 : : #include "replication/logicallauncher.h"
51 : : #include "replication/logicalworker.h"
52 : : #include "replication/origin.h"
53 : : #include "replication/snapbuild.h"
54 : : #include "replication/syncrep.h"
55 : : #include "storage/aio_subsys.h"
56 : : #include "storage/condition_variable.h"
57 : : #include "storage/fd.h"
58 : : #include "storage/lmgr.h"
59 : : #include "storage/md.h"
60 : : #include "storage/predicate.h"
61 : : #include "storage/proc.h"
62 : : #include "storage/procarray.h"
63 : : #include "storage/sinvaladt.h"
64 : : #include "storage/smgr.h"
65 : : #include "utils/builtins.h"
66 : : #include "utils/combocid.h"
67 : : #include "utils/guc.h"
68 : : #include "utils/inval.h"
69 : : #include "utils/memutils.h"
70 : : #include "utils/relmapper.h"
71 : : #include "utils/snapmgr.h"
72 : : #include "utils/timeout.h"
73 : : #include "utils/timestamp.h"
74 : : #include "utils/typcache.h"
75 : :
76 : : /*
77 : : * User-tweakable parameters
78 : : */
79 : : int DefaultXactIsoLevel = XACT_READ_COMMITTED;
80 : : int XactIsoLevel = XACT_READ_COMMITTED;
81 : :
82 : : bool DefaultXactReadOnly = false;
83 : : bool XactReadOnly;
84 : :
85 : : bool DefaultXactDeferrable = false;
86 : : bool XactDeferrable;
87 : :
88 : : int synchronous_commit = SYNCHRONOUS_COMMIT_ON;
89 : :
90 : : /*
91 : : * CheckXidAlive is a xid value pointing to a possibly ongoing (sub)
92 : : * transaction. Currently, it is used in logical decoding. It's possible
93 : : * that such transactions can get aborted while the decoding is ongoing in
94 : : * which case we skip decoding that particular transaction. To ensure that we
95 : : * check whether the CheckXidAlive is aborted after fetching the tuple from
96 : : * system tables. We also ensure that during logical decoding we never
97 : : * directly access the tableam or heap APIs because we are checking for the
98 : : * concurrent aborts only in systable_* APIs.
99 : : */
100 : : TransactionId CheckXidAlive = InvalidTransactionId;
101 : : bool bsysscan = false;
102 : :
103 : : /*
104 : : * When running as a parallel worker, we place only a single
105 : : * TransactionStateData on the parallel worker's state stack, and the XID
106 : : * reflected there will be that of the *innermost* currently-active
107 : : * subtransaction in the backend that initiated parallelism. However,
108 : : * GetTopTransactionId() and TransactionIdIsCurrentTransactionId()
109 : : * need to return the same answers in the parallel worker as they would have
110 : : * in the user backend, so we need some additional bookkeeping.
111 : : *
112 : : * XactTopFullTransactionId stores the XID of our toplevel transaction, which
113 : : * will be the same as TopTransactionStateData.fullTransactionId in an
114 : : * ordinary backend; but in a parallel backend, which does not have the entire
115 : : * transaction state, it will instead be copied from the backend that started
116 : : * the parallel operation.
117 : : *
118 : : * nParallelCurrentXids will be 0 and ParallelCurrentXids NULL in an ordinary
119 : : * backend, but in a parallel backend, nParallelCurrentXids will contain the
120 : : * number of XIDs that need to be considered current, and ParallelCurrentXids
121 : : * will contain the XIDs themselves. This includes all XIDs that were current
122 : : * or sub-committed in the parent at the time the parallel operation began.
123 : : * The XIDs are stored sorted in numerical order (not logical order) to make
124 : : * lookups as fast as possible.
125 : : */
126 : : static FullTransactionId XactTopFullTransactionId = {InvalidTransactionId};
127 : : static int nParallelCurrentXids = 0;
128 : : static TransactionId *ParallelCurrentXids;
129 : :
130 : : /*
131 : : * Miscellaneous flag bits to record events which occur on the top level
132 : : * transaction. These flags are only persisted in MyXactFlags and are intended
133 : : * so we remember to do certain things later on in the transaction. This is
134 : : * globally accessible, so can be set from anywhere in the code that requires
135 : : * recording flags.
136 : : */
137 : : int MyXactFlags;
138 : :
139 : : /*
140 : : * transaction states - transaction state from server perspective
141 : : */
142 : : typedef enum TransState
143 : : {
144 : : TRANS_DEFAULT, /* idle */
145 : : TRANS_START, /* transaction starting */
146 : : TRANS_INPROGRESS, /* inside a valid transaction */
147 : : TRANS_COMMIT, /* commit in progress */
148 : : TRANS_ABORT, /* abort in progress */
149 : : TRANS_PREPARE, /* prepare in progress */
150 : : } TransState;
151 : :
152 : : /*
153 : : * transaction block states - transaction state of client queries
154 : : *
155 : : * Note: the subtransaction states are used only for non-topmost
156 : : * transactions; the others appear only in the topmost transaction.
157 : : */
158 : : typedef enum TBlockState
159 : : {
160 : : /* not-in-transaction-block states */
161 : : TBLOCK_DEFAULT, /* idle */
162 : : TBLOCK_STARTED, /* running single-query transaction */
163 : :
164 : : /* transaction block states */
165 : : TBLOCK_BEGIN, /* starting transaction block */
166 : : TBLOCK_INPROGRESS, /* live transaction */
167 : : TBLOCK_IMPLICIT_INPROGRESS, /* live transaction after implicit BEGIN */
168 : : TBLOCK_PARALLEL_INPROGRESS, /* live transaction inside parallel worker */
169 : : TBLOCK_END, /* COMMIT received */
170 : : TBLOCK_ABORT, /* failed xact, awaiting ROLLBACK */
171 : : TBLOCK_ABORT_END, /* failed xact, ROLLBACK received */
172 : : TBLOCK_ABORT_PENDING, /* live xact, ROLLBACK received */
173 : : TBLOCK_PREPARE, /* live xact, PREPARE received */
174 : :
175 : : /* subtransaction states */
176 : : TBLOCK_SUBBEGIN, /* starting a subtransaction */
177 : : TBLOCK_SUBINPROGRESS, /* live subtransaction */
178 : : TBLOCK_SUBRELEASE, /* RELEASE received */
179 : : TBLOCK_SUBCOMMIT, /* COMMIT received while TBLOCK_SUBINPROGRESS */
180 : : TBLOCK_SUBABORT, /* failed subxact, awaiting ROLLBACK */
181 : : TBLOCK_SUBABORT_END, /* failed subxact, ROLLBACK received */
182 : : TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received */
183 : : TBLOCK_SUBRESTART, /* live subxact, ROLLBACK TO received */
184 : : TBLOCK_SUBABORT_RESTART, /* failed subxact, ROLLBACK TO received */
185 : : } TBlockState;
186 : :
187 : : /*
188 : : * transaction state structure
189 : : *
190 : : * Note: parallelModeLevel counts the number of unmatched EnterParallelMode
191 : : * calls done at this transaction level. parallelChildXact is true if any
192 : : * upper transaction level has nonzero parallelModeLevel.
193 : : */
194 : : typedef struct TransactionStateData
195 : : {
196 : : FullTransactionId fullTransactionId; /* my FullTransactionId */
197 : : SubTransactionId subTransactionId; /* my subxact ID */
198 : : char *name; /* savepoint name, if any */
199 : : int savepointLevel; /* savepoint level */
200 : : TransState state; /* low-level state */
201 : : TBlockState blockState; /* high-level state */
202 : : int nestingLevel; /* transaction nesting depth */
203 : : int gucNestLevel; /* GUC context nesting depth */
204 : : MemoryContext curTransactionContext; /* my xact-lifetime context */
205 : : ResourceOwner curTransactionOwner; /* my query resources */
206 : : MemoryContext priorContext; /* CurrentMemoryContext before xact started */
207 : : TransactionId *childXids; /* subcommitted child XIDs, in XID order */
208 : : int nChildXids; /* # of subcommitted child XIDs */
209 : : int maxChildXids; /* allocated size of childXids[] */
210 : : Oid prevUser; /* previous CurrentUserId setting */
211 : : int prevSecContext; /* previous SecurityRestrictionContext */
212 : : bool prevXactReadOnly; /* entry-time xact r/o state */
213 : : bool startedInRecovery; /* did we start in recovery? */
214 : : bool didLogXid; /* has xid been included in WAL record? */
215 : : int parallelModeLevel; /* Enter/ExitParallelMode counter */
216 : : bool parallelChildXact; /* is any parent transaction parallel? */
217 : : bool chain; /* start a new block after this one */
218 : : bool topXidLogged; /* for a subxact: is top-level XID logged? */
219 : : struct TransactionStateData *parent; /* back link to parent */
220 : : } TransactionStateData;
221 : :
222 : : typedef TransactionStateData *TransactionState;
223 : :
224 : : /*
225 : : * Serialized representation used to transmit transaction state to parallel
226 : : * workers through shared memory.
227 : : */
228 : : typedef struct SerializedTransactionState
229 : : {
230 : : int xactIsoLevel;
231 : : bool xactDeferrable;
232 : : FullTransactionId topFullTransactionId;
233 : : FullTransactionId currentFullTransactionId;
234 : : CommandId currentCommandId;
235 : : int nParallelCurrentXids;
236 : : TransactionId parallelCurrentXids[FLEXIBLE_ARRAY_MEMBER];
237 : : } SerializedTransactionState;
238 : :
239 : : /* The size of SerializedTransactionState, not including the final array. */
240 : : #define SerializedTransactionStateHeaderSize \
241 : : offsetof(SerializedTransactionState, parallelCurrentXids)
242 : :
243 : : /*
244 : : * CurrentTransactionState always points to the current transaction state
245 : : * block. It will point to TopTransactionStateData when not in a
246 : : * transaction at all, or when in a top-level transaction.
247 : : */
248 : : static TransactionStateData TopTransactionStateData = {
249 : : .state = TRANS_DEFAULT,
250 : : .blockState = TBLOCK_DEFAULT,
251 : : .topXidLogged = false,
252 : : };
253 : :
254 : : /*
255 : : * unreportedXids holds XIDs of all subtransactions that have not yet been
256 : : * reported in an XLOG_XACT_ASSIGNMENT record.
257 : : */
258 : : static int nUnreportedXids;
259 : : static TransactionId unreportedXids[PGPROC_MAX_CACHED_SUBXIDS];
260 : :
261 : : static TransactionState CurrentTransactionState = &TopTransactionStateData;
262 : :
263 : : /*
264 : : * The subtransaction ID and command ID assignment counters are global
265 : : * to a whole transaction, so we do not keep them in the state stack.
266 : : */
267 : : static SubTransactionId currentSubTransactionId;
268 : : static CommandId currentCommandId;
269 : : static bool currentCommandIdUsed;
270 : :
271 : : /*
272 : : * xactStartTimestamp is the value of transaction_timestamp().
273 : : * stmtStartTimestamp is the value of statement_timestamp().
274 : : * xactStopTimestamp is the time at which we log a commit / abort WAL record,
275 : : * or if that was skipped, the time of the first subsequent
276 : : * GetCurrentTransactionStopTimestamp() call.
277 : : *
278 : : * These do not change as we enter and exit subtransactions, so we don't
279 : : * keep them inside the TransactionState stack.
280 : : */
281 : : static TimestampTz xactStartTimestamp;
282 : : static TimestampTz stmtStartTimestamp;
283 : : static TimestampTz xactStopTimestamp;
284 : :
285 : : /*
286 : : * GID to be used for preparing the current transaction. This is also
287 : : * global to a whole transaction, so we don't keep it in the state stack.
288 : : */
289 : : static char *prepareGID;
290 : :
291 : : /*
292 : : * Some commands want to force synchronous commit.
293 : : */
294 : : static bool forceSyncCommit = false;
295 : :
296 : : /* Flag for logging statements in a transaction. */
297 : : bool xact_is_sampled = false;
298 : :
299 : : /*
300 : : * Private context for transaction-abort work --- we reserve space for this
301 : : * at startup to ensure that AbortTransaction and AbortSubTransaction can work
302 : : * when we've run out of memory.
303 : : */
304 : : static MemoryContext TransactionAbortContext = NULL;
305 : :
306 : : /*
307 : : * List of add-on start- and end-of-xact callbacks
308 : : */
309 : : typedef struct XactCallbackItem
310 : : {
311 : : struct XactCallbackItem *next;
312 : : XactCallback callback;
313 : : void *arg;
314 : : } XactCallbackItem;
315 : :
316 : : static XactCallbackItem *Xact_callbacks = NULL;
317 : :
318 : : /*
319 : : * List of add-on start- and end-of-subxact callbacks
320 : : */
321 : : typedef struct SubXactCallbackItem
322 : : {
323 : : struct SubXactCallbackItem *next;
324 : : SubXactCallback callback;
325 : : void *arg;
326 : : } SubXactCallbackItem;
327 : :
328 : : static SubXactCallbackItem *SubXact_callbacks = NULL;
329 : :
330 : :
331 : : /* local function prototypes */
332 : : static void AssignTransactionId(TransactionState s);
333 : : static void AbortTransaction(void);
334 : : static void AtAbort_Memory(void);
335 : : static void AtCleanup_Memory(void);
336 : : static void AtAbort_ResourceOwner(void);
337 : : static void AtCCI_LocalCache(void);
338 : : static void AtCommit_Memory(void);
339 : : static void AtStart_Cache(void);
340 : : static void AtStart_Memory(void);
341 : : static void AtStart_ResourceOwner(void);
342 : : static void CallXactCallbacks(XactEvent event);
343 : : static void CallSubXactCallbacks(SubXactEvent event,
344 : : SubTransactionId mySubid,
345 : : SubTransactionId parentSubid);
346 : : static void CleanupTransaction(void);
347 : : static void CheckTransactionBlock(bool isTopLevel, bool throwError,
348 : : const char *stmtType);
349 : : static void CommitTransaction(void);
350 : : static TransactionId RecordTransactionAbort(bool isSubXact);
351 : : static void StartTransaction(void);
352 : :
353 : : static bool CommitTransactionCommandInternal(void);
354 : : static bool AbortCurrentTransactionInternal(void);
355 : :
356 : : static void StartSubTransaction(void);
357 : : static void CommitSubTransaction(void);
358 : : static void AbortSubTransaction(void);
359 : : static void CleanupSubTransaction(void);
360 : : static void PushTransaction(void);
361 : : static void PopTransaction(void);
362 : :
363 : : static void AtSubAbort_Memory(void);
364 : : static void AtSubCleanup_Memory(void);
365 : : static void AtSubAbort_ResourceOwner(void);
366 : : static void AtSubCommit_Memory(void);
367 : : static void AtSubStart_Memory(void);
368 : : static void AtSubStart_ResourceOwner(void);
369 : :
370 : : static void ShowTransactionState(const char *str);
371 : : static void ShowTransactionStateRec(const char *str, TransactionState s);
372 : : static const char *BlockStateAsString(TBlockState blockState);
373 : : static const char *TransStateAsString(TransState state);
374 : :
375 : :
376 : : /* ----------------------------------------------------------------
377 : : * transaction state accessors
378 : : * ----------------------------------------------------------------
379 : : */
380 : :
381 : : /*
382 : : * IsTransactionState
383 : : *
384 : : * This returns true if we are inside a valid transaction; that is,
385 : : * it is safe to initiate database access, take heavyweight locks, etc.
386 : : */
387 : : bool
10630 bruce@momjian.us 388 :CBC 147790340 : IsTransactionState(void)
389 : : {
10329 390 : 147790340 : TransactionState s = CurrentTransactionState;
391 : :
392 : : /*
393 : : * TRANS_DEFAULT and TRANS_ABORT are obviously unsafe states. However, we
394 : : * also reject the startup/shutdown states TRANS_START, TRANS_COMMIT,
395 : : * TRANS_PREPARE since it might be too soon or too late within those
396 : : * transition states to do anything interesting. Hence, the only "valid"
397 : : * state is TRANS_INPROGRESS.
398 : : */
6769 tgl@sss.pgh.pa.us 399 : 147790340 : return (s->state == TRANS_INPROGRESS);
400 : : }
401 : :
402 : : /*
403 : : * IsAbortedTransactionBlockState
404 : : *
405 : : * This returns true if we are within an aborted transaction block.
406 : : */
407 : : bool
9186 408 : 769651 : IsAbortedTransactionBlockState(void)
409 : : {
10329 bruce@momjian.us 410 : 769651 : TransactionState s = CurrentTransactionState;
411 : :
7781 412 [ + + ]: 769651 : if (s->blockState == TBLOCK_ABORT ||
7840 tgl@sss.pgh.pa.us 413 [ + + ]: 768113 : s->blockState == TBLOCK_SUBABORT)
10329 bruce@momjian.us 414 : 1844 : return true;
415 : :
416 : 767807 : return false;
417 : : }
418 : :
419 : :
420 : : /*
421 : : * GetTopTransactionId
422 : : *
423 : : * This will return the XID of the main transaction, assigning one if
424 : : * it's not yet set. Be careful to call this only inside a valid xact.
425 : : */
426 : : TransactionId
7840 tgl@sss.pgh.pa.us 427 : 26546 : GetTopTransactionId(void)
428 : : {
2457 tmunro@postgresql.or 429 [ + + ]: 26546 : if (!FullTransactionIdIsValid(XactTopFullTransactionId))
6679 tgl@sss.pgh.pa.us 430 : 459 : AssignTransactionId(&TopTransactionStateData);
2457 tmunro@postgresql.or 431 : 26546 : return XidFromFullTransactionId(XactTopFullTransactionId);
432 : : }
433 : :
434 : : /*
435 : : * GetTopTransactionIdIfAny
436 : : *
437 : : * This will return the XID of the main transaction, if one is assigned.
438 : : * It will return InvalidTransactionId if we are not currently inside a
439 : : * transaction, or inside a transaction that hasn't yet been assigned an XID.
440 : : */
441 : : TransactionId
6679 tgl@sss.pgh.pa.us 442 : 60813357 : GetTopTransactionIdIfAny(void)
443 : : {
2457 tmunro@postgresql.or 444 : 60813357 : return XidFromFullTransactionId(XactTopFullTransactionId);
445 : : }
446 : :
447 : : /*
448 : : * GetCurrentTransactionId
449 : : *
450 : : * This will return the XID of the current transaction (main or sub
451 : : * transaction), assigning one if it's not yet set. Be careful to call this
452 : : * only inside a valid xact.
453 : : */
454 : : TransactionId
9186 tgl@sss.pgh.pa.us 455 : 10953405 : GetCurrentTransactionId(void)
456 : : {
10329 bruce@momjian.us 457 : 10953405 : TransactionState s = CurrentTransactionState;
458 : :
2457 tmunro@postgresql.or 459 [ + + ]: 10953405 : if (!FullTransactionIdIsValid(s->fullTransactionId))
6679 tgl@sss.pgh.pa.us 460 : 134569 : AssignTransactionId(s);
2457 tmunro@postgresql.or 461 : 10953405 : return XidFromFullTransactionId(s->fullTransactionId);
462 : : }
463 : :
464 : : /*
465 : : * GetCurrentTransactionIdIfAny
466 : : *
467 : : * This will return the XID of the current sub xact, if one is assigned.
468 : : * It will return InvalidTransactionId if we are not currently inside a
469 : : * transaction, or inside a transaction that hasn't been assigned an XID yet.
470 : : */
471 : : TransactionId
6679 tgl@sss.pgh.pa.us 472 : 14202357 : GetCurrentTransactionIdIfAny(void)
473 : : {
2457 tmunro@postgresql.or 474 : 14202357 : return XidFromFullTransactionId(CurrentTransactionState->fullTransactionId);
475 : : }
476 : :
477 : : /*
478 : : * GetTopFullTransactionId
479 : : *
480 : : * This will return the FullTransactionId of the main transaction, assigning
481 : : * one if it's not yet set. Be careful to call this only inside a valid xact.
482 : : */
483 : : FullTransactionId
484 : 2900 : GetTopFullTransactionId(void)
485 : : {
486 [ + + ]: 2900 : if (!FullTransactionIdIsValid(XactTopFullTransactionId))
487 : 2077 : AssignTransactionId(&TopTransactionStateData);
488 : 2900 : return XactTopFullTransactionId;
489 : : }
490 : :
491 : : /*
492 : : * GetTopFullTransactionIdIfAny
493 : : *
494 : : * This will return the FullTransactionId of the main transaction, if one is
495 : : * assigned. It will return InvalidFullTransactionId if we are not currently
496 : : * inside a transaction, or inside a transaction that hasn't yet been assigned
497 : : * one.
498 : : */
499 : : FullTransactionId
500 : 12 : GetTopFullTransactionIdIfAny(void)
501 : : {
502 : 12 : return XactTopFullTransactionId;
503 : : }
504 : :
505 : : /*
506 : : * GetCurrentFullTransactionId
507 : : *
508 : : * This will return the FullTransactionId of the current transaction (main or
509 : : * sub transaction), assigning one if it's not yet set. Be careful to call
510 : : * this only inside a valid xact.
511 : : */
512 : : FullTransactionId
2457 tmunro@postgresql.or 513 :GBC 344 : GetCurrentFullTransactionId(void)
514 : : {
515 : 344 : TransactionState s = CurrentTransactionState;
516 : :
517 [ + + ]: 344 : if (!FullTransactionIdIsValid(s->fullTransactionId))
518 : 17 : AssignTransactionId(s);
519 : 344 : return s->fullTransactionId;
520 : : }
521 : :
522 : : /*
523 : : * GetCurrentFullTransactionIdIfAny
524 : : *
525 : : * This will return the FullTransactionId of the current sub xact, if one is
526 : : * assigned. It will return InvalidFullTransactionId if we are not currently
527 : : * inside a transaction, or inside a transaction that hasn't been assigned one
528 : : * yet.
529 : : */
530 : : FullTransactionId
2457 tmunro@postgresql.or 531 :UBC 0 : GetCurrentFullTransactionIdIfAny(void)
532 : : {
533 : 0 : return CurrentTransactionState->fullTransactionId;
534 : : }
535 : :
536 : : /*
537 : : * MarkCurrentTransactionIdLoggedIfAny
538 : : *
539 : : * Remember that the current xid - if it is assigned - now has been wal logged.
540 : : */
541 : : void
4391 rhaas@postgresql.org 542 :CBC 14162026 : MarkCurrentTransactionIdLoggedIfAny(void)
543 : : {
2457 tmunro@postgresql.or 544 [ + + ]: 14162026 : if (FullTransactionIdIsValid(CurrentTransactionState->fullTransactionId))
4391 rhaas@postgresql.org 545 : 13916727 : CurrentTransactionState->didLogXid = true;
546 : 14162026 : }
547 : :
548 : : /*
549 : : * IsSubxactTopXidLogPending
550 : : *
551 : : * This is used to decide whether we need to WAL log the top-level XID for
552 : : * operation in a subtransaction. We require that for logical decoding, see
553 : : * LogicalDecodingProcessRecord.
554 : : *
555 : : * This returns true if wal_level >= logical and we are inside a valid
556 : : * subtransaction, for which the assignment was not yet written to any WAL
557 : : * record.
558 : : */
559 : : bool
1507 akapila@postgresql.o 560 : 14169350 : IsSubxactTopXidLogPending(void)
561 : : {
562 : : /* check whether it is already logged */
563 [ + + ]: 14169350 : if (CurrentTransactionState->topXidLogged)
564 : 102126 : return false;
565 : :
566 : : /* wal_level has to be logical */
567 [ + + ]: 14067224 : if (!XLogLogicalInfoActive())
568 : 13536890 : return false;
569 : :
570 : : /* we need to be in a transaction state */
571 [ + + ]: 530334 : if (!IsTransactionState())
572 : 3805 : return false;
573 : :
574 : : /* it has to be a subtransaction */
575 [ + + ]: 526529 : if (!IsSubTransaction())
576 : 526082 : return false;
577 : :
578 : : /* the subtransaction has to have a XID assigned */
579 [ + + ]: 447 : if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
580 : 7 : return false;
581 : :
582 : 440 : return true;
583 : : }
584 : :
585 : : /*
586 : : * MarkSubxactTopXidLogged
587 : : *
588 : : * Remember that the top transaction id for the current subtransaction is WAL
589 : : * logged now.
590 : : */
591 : : void
592 : 219 : MarkSubxactTopXidLogged(void)
593 : : {
594 [ - + ]: 219 : Assert(IsSubxactTopXidLogPending());
595 : :
596 : 219 : CurrentTransactionState->topXidLogged = true;
597 : 219 : }
598 : :
599 : : /*
600 : : * GetStableLatestTransactionId
601 : : *
602 : : * Get the transaction's XID if it has one, else read the next-to-be-assigned
603 : : * XID. Once we have a value, return that same value for the remainder of the
604 : : * current transaction. This is meant to provide the reference point for the
605 : : * age(xid) function, but might be useful for other maintenance tasks as well.
606 : : */
607 : : TransactionId
4969 simon@2ndQuadrant.co 608 : 119 : GetStableLatestTransactionId(void)
609 : : {
610 : : static LocalTransactionId lxid = InvalidLocalTransactionId;
611 : : static TransactionId stablexid = InvalidTransactionId;
612 : :
655 heikki.linnakangas@i 613 [ + + ]: 119 : if (lxid != MyProc->vxid.lxid)
614 : : {
615 : 2 : lxid = MyProc->vxid.lxid;
4968 simon@2ndQuadrant.co 616 : 2 : stablexid = GetTopTransactionIdIfAny();
617 [ + - ]: 2 : if (!TransactionIdIsValid(stablexid))
1767 tmunro@postgresql.or 618 : 2 : stablexid = ReadNextTransactionId();
619 : : }
620 : :
4968 simon@2ndQuadrant.co 621 [ - + ]: 119 : Assert(TransactionIdIsValid(stablexid));
622 : :
4969 623 : 119 : return stablexid;
624 : : }
625 : :
626 : : /*
627 : : * AssignTransactionId
628 : : *
629 : : * Assigns a new permanent FullTransactionId to the given TransactionState.
630 : : * We do not assign XIDs to transactions until/unless this is called.
631 : : * Also, any parent TransactionStates that don't yet have XIDs are assigned
632 : : * one; this maintains the invariant that a child transaction has an XID
633 : : * following its parent's.
634 : : */
635 : : static void
6679 tgl@sss.pgh.pa.us 636 : 138252 : AssignTransactionId(TransactionState s)
637 : : {
6608 bruce@momjian.us 638 : 138252 : bool isSubXact = (s->parent != NULL);
639 : : ResourceOwner currentOwner;
4244 640 : 138252 : bool log_unknown_top = false;
641 : :
642 : : /* Assert that caller didn't screw up */
2457 tmunro@postgresql.or 643 [ - + ]: 138252 : Assert(!FullTransactionIdIsValid(s->fullTransactionId));
7763 tgl@sss.pgh.pa.us 644 [ - + ]: 138252 : Assert(s->state == TRANS_INPROGRESS);
645 : :
646 : : /*
647 : : * Workers synchronize transaction state at the beginning of each parallel
648 : : * operation, so we can't account for new XIDs at this point.
649 : : */
3716 rhaas@postgresql.org 650 [ + - - + ]: 138252 : if (IsInParallelMode() || IsParallelWorker())
630 tgl@sss.pgh.pa.us 651 [ # # ]:UBC 0 : ereport(ERROR,
652 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
653 : : errmsg("cannot assign transaction IDs during a parallel operation")));
654 : :
655 : : /*
656 : : * Ensure parent(s) have XIDs, so that a child always has an XID later
657 : : * than its parent. Mustn't recurse here, or we might get a stack
658 : : * overflow if we're at the bottom of a huge stack of subtransactions none
659 : : * of which have XIDs yet.
660 : : */
2457 tmunro@postgresql.or 661 [ + + + + ]:CBC 138252 : if (isSubXact && !FullTransactionIdIsValid(s->parent->fullTransactionId))
662 : : {
5366 bruce@momjian.us 663 : 561 : TransactionState p = s->parent;
664 : : TransactionState *parents;
665 : 561 : size_t parentOffset = 0;
666 : :
8 michael@paquier.xyz 667 :GNC 561 : parents = palloc_array(TransactionState, s->nestingLevel);
2457 tmunro@postgresql.or 668 [ + + + + ]:CBC 1691 : while (p != NULL && !FullTransactionIdIsValid(p->fullTransactionId))
669 : : {
5627 rhaas@postgresql.org 670 : 1130 : parents[parentOffset++] = p;
671 : 1130 : p = p->parent;
672 : : }
673 : :
674 : : /*
675 : : * This is technically a recursive call, but the recursion will never
676 : : * be more than one layer deep.
677 : : */
678 [ + + ]: 1691 : while (parentOffset != 0)
679 : 1130 : AssignTransactionId(parents[--parentOffset]);
680 : :
681 : 561 : pfree(parents);
682 : : }
683 : :
684 : : /*
685 : : * When wal_level=logical, guarantee that a subtransaction's xid can only
686 : : * be seen in the WAL stream if its toplevel xid has been logged before.
687 : : * If necessary we log an xact_assignment record with fewer than
688 : : * PGPROC_MAX_CACHED_SUBXIDS. Note that it is fine if didLogXid isn't set
689 : : * for a transaction even though it appears in a WAL record, we just might
690 : : * superfluously log something. That can happen when an xid is included
691 : : * somewhere inside a wal record, but not in XLogRecord->xl_xid, like in
692 : : * xl_standby_locks.
693 : : */
4391 694 [ + + + + ]: 138252 : if (isSubXact && XLogLogicalInfoActive() &&
695 [ + + ]: 300 : !TopTransactionStateData.didLogXid)
696 : 24 : log_unknown_top = true;
697 : :
698 : : /*
699 : : * Generate a new FullTransactionId and record its xid in PGPROC and
700 : : * pg_subtrans.
701 : : *
702 : : * NB: we must make the subtrans entry BEFORE the Xid appears anywhere in
703 : : * shared storage other than PGPROC; because if there's no room for it in
704 : : * PGPROC, the subtrans entry is needed to ensure that other backends see
705 : : * the Xid as "running". See GetNewTransactionId.
706 : : */
2457 tmunro@postgresql.or 707 : 138252 : s->fullTransactionId = GetNewTransactionId(isSubXact);
3885 rhaas@postgresql.org 708 [ + + ]: 138252 : if (!isSubXact)
2457 tmunro@postgresql.or 709 : 134842 : XactTopFullTransactionId = s->fullTransactionId;
710 : :
6679 tgl@sss.pgh.pa.us 711 [ + + ]: 138252 : if (isSubXact)
2457 tmunro@postgresql.or 712 : 3410 : SubTransSetParent(XidFromFullTransactionId(s->fullTransactionId),
713 : 3410 : XidFromFullTransactionId(s->parent->fullTransactionId));
714 : :
715 : : /*
716 : : * If it's a top-level transaction, the predicate locking system needs to
717 : : * be told about it too.
718 : : */
5340 tgl@sss.pgh.pa.us 719 [ + + ]: 138252 : if (!isSubXact)
2457 tmunro@postgresql.or 720 : 134842 : RegisterPredicateLockingXid(XidFromFullTransactionId(s->fullTransactionId));
721 : :
722 : : /*
723 : : * Acquire lock on the transaction XID. (We assume this cannot block.) We
724 : : * have to ensure that the lock is assigned to the transaction's own
725 : : * ResourceOwner.
726 : : */
7763 tgl@sss.pgh.pa.us 727 : 138252 : currentOwner = CurrentResourceOwner;
2990 728 : 138252 : CurrentResourceOwner = s->curTransactionOwner;
729 : :
2457 tmunro@postgresql.or 730 : 138252 : XactLockTableInsert(XidFromFullTransactionId(s->fullTransactionId));
731 : :
7763 tgl@sss.pgh.pa.us 732 : 138252 : CurrentResourceOwner = currentOwner;
733 : :
734 : : /*
735 : : * Every PGPROC_MAX_CACHED_SUBXIDS assigned transaction ids within each
736 : : * top-level transaction we issue a WAL record for the assignment. We
737 : : * include the top-level xid and all the subxids that have not yet been
738 : : * reported using XLOG_XACT_ASSIGNMENT records.
739 : : *
740 : : * This is required to limit the amount of shared memory required in a hot
741 : : * standby server to keep track of in-progress XIDs. See notes for
742 : : * RecordKnownAssignedTransactionIds().
743 : : *
744 : : * We don't keep track of the immediate parent of each subxid, only the
745 : : * top-level transaction that each subxact belongs to. This is correct in
746 : : * recovery only because aborted subtransactions are separately WAL
747 : : * logged.
748 : : *
749 : : * This is correct even for the case where several levels above us didn't
750 : : * have an xid assigned as we recursed up to them beforehand.
751 : : */
5843 simon@2ndQuadrant.co 752 [ + + + + ]: 138252 : if (isSubXact && XLogStandbyInfoActive())
753 : : {
2457 tmunro@postgresql.or 754 : 2926 : unreportedXids[nUnreportedXids] = XidFromFullTransactionId(s->fullTransactionId);
5843 simon@2ndQuadrant.co 755 : 2926 : nUnreportedXids++;
756 : :
757 : : /*
758 : : * ensure this test matches similar one in
759 : : * RecoverPreparedTransactions()
760 : : */
4391 rhaas@postgresql.org 761 [ + + + + ]: 2926 : if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS ||
762 : : log_unknown_top)
763 : : {
764 : : xl_xact_assignment xlrec;
765 : :
766 : : /*
767 : : * xtop is always set by now because we recurse up transaction
768 : : * stack to the highest unassigned xid and then come back down
769 : : */
5843 simon@2ndQuadrant.co 770 : 53 : xlrec.xtop = GetTopTransactionId();
771 [ - + ]: 53 : Assert(TransactionIdIsValid(xlrec.xtop));
772 : 53 : xlrec.nsubxacts = nUnreportedXids;
773 : :
4046 heikki.linnakangas@i 774 : 53 : XLogBeginInsert();
310 peter@eisentraut.org 775 : 53 : XLogRegisterData(&xlrec, MinSizeOfXactAssignment);
776 : 53 : XLogRegisterData(unreportedXids,
777 : : nUnreportedXids * sizeof(TransactionId));
778 : :
4046 heikki.linnakangas@i 779 : 53 : (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT);
780 : :
5843 simon@2ndQuadrant.co 781 : 53 : nUnreportedXids = 0;
782 : : /* mark top, not current xact as having been logged */
4391 rhaas@postgresql.org 783 : 53 : TopTransactionStateData.didLogXid = true;
784 : : }
785 : : }
5843 simon@2ndQuadrant.co 786 : 138252 : }
787 : :
788 : : /*
789 : : * GetCurrentSubTransactionId
790 : : */
791 : : SubTransactionId
7763 tgl@sss.pgh.pa.us 792 : 1622517 : GetCurrentSubTransactionId(void)
793 : : {
794 : 1622517 : TransactionState s = CurrentTransactionState;
795 : :
796 : 1622517 : return s->subTransactionId;
797 : : }
798 : :
799 : : /*
800 : : * SubTransactionIsActive
801 : : *
802 : : * Test if the specified subxact ID is still active. Note caller is
803 : : * responsible for checking whether this ID is relevant to the current xact.
804 : : */
805 : : bool
4673 tgl@sss.pgh.pa.us 806 :UBC 0 : SubTransactionIsActive(SubTransactionId subxid)
807 : : {
808 : : TransactionState s;
809 : :
810 [ # # ]: 0 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
811 : : {
812 [ # # ]: 0 : if (s->state == TRANS_ABORT)
813 : 0 : continue;
814 [ # # ]: 0 : if (s->subTransactionId == subxid)
815 : 0 : return true;
816 : : }
817 : 0 : return false;
818 : : }
819 : :
820 : :
821 : : /*
822 : : * GetCurrentCommandId
823 : : *
824 : : * "used" must be true if the caller intends to use the command ID to mark
825 : : * inserted/updated/deleted tuples. false means the ID is being fetched
826 : : * for read-only purposes (ie, as a snapshot validity cutoff). See
827 : : * CommandCounterIncrement() for discussion.
828 : : */
829 : : CommandId
6593 tgl@sss.pgh.pa.us 830 :CBC 5575268 : GetCurrentCommandId(bool used)
831 : : {
832 : : /* this is global to a transaction, not subtransaction-local */
833 [ + + ]: 5575268 : if (used)
834 : : {
835 : : /*
836 : : * Forbid setting currentCommandIdUsed in a parallel worker, because
837 : : * we have no provision for communicating this back to the leader. We
838 : : * could relax this restriction when currentCommandIdUsed was already
839 : : * true at the start of the parallel operation.
840 : : */
630 841 [ - + ]: 3491197 : if (IsParallelWorker())
630 tgl@sss.pgh.pa.us 842 [ # # ]:UBC 0 : ereport(ERROR,
843 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
844 : : errmsg("cannot modify data in a parallel worker")));
845 : :
6593 tgl@sss.pgh.pa.us 846 :CBC 3491197 : currentCommandIdUsed = true;
847 : : }
7763 848 : 5575268 : return currentCommandId;
849 : : }
850 : :
851 : : /*
852 : : * SetParallelStartTimestamps
853 : : *
854 : : * In a parallel worker, we should inherit the parent transaction's
855 : : * timestamps rather than setting our own. The parallel worker
856 : : * infrastructure must call this to provide those values before
857 : : * calling StartTransaction() or SetCurrentStatementStartTimestamp().
858 : : */
859 : : void
2630 860 : 1453 : SetParallelStartTimestamps(TimestampTz xact_ts, TimestampTz stmt_ts)
861 : : {
862 [ - + ]: 1453 : Assert(IsParallelWorker());
863 : 1453 : xactStartTimestamp = xact_ts;
864 : 1453 : stmtStartTimestamp = stmt_ts;
865 : 1453 : }
866 : :
867 : : /*
868 : : * GetCurrentTransactionStartTimestamp
869 : : */
870 : : TimestampTz
7477 871 : 43200 : GetCurrentTransactionStartTimestamp(void)
872 : : {
873 : 43200 : return xactStartTimestamp;
874 : : }
875 : :
876 : : /*
877 : : * GetCurrentStatementStartTimestamp
878 : : */
879 : : TimestampTz
7177 bruce@momjian.us 880 : 1125912 : GetCurrentStatementStartTimestamp(void)
881 : : {
882 : 1125912 : return stmtStartTimestamp;
883 : : }
884 : :
885 : : /*
886 : : * GetCurrentTransactionStopTimestamp
887 : : *
888 : : * If the transaction stop time hasn't already been set, which can happen if
889 : : * we decided we don't need to log an XLOG record, set xactStopTimestamp.
890 : : */
891 : : TimestampTz
6807 tgl@sss.pgh.pa.us 892 : 1033382 : GetCurrentTransactionStopTimestamp(void)
893 : : {
1161 andres@anarazel.de 894 : 1033382 : TransactionState s PG_USED_FOR_ASSERTS_ONLY = CurrentTransactionState;
895 : :
896 : : /* should only be called after commit / abort processing */
897 [ + + + + : 1033382 : Assert(s->state == TRANS_DEFAULT ||
- + - - ]
898 : : s->state == TRANS_COMMIT ||
899 : : s->state == TRANS_ABORT ||
900 : : s->state == TRANS_PREPARE);
901 : :
902 [ + + ]: 1033382 : if (xactStopTimestamp == 0)
903 : 294631 : xactStopTimestamp = GetCurrentTimestamp();
904 : :
905 : 1033382 : return xactStopTimestamp;
906 : : }
907 : :
908 : : /*
909 : : * SetCurrentStatementStartTimestamp
910 : : *
911 : : * In a parallel worker, this should already have been provided by a call
912 : : * to SetParallelStartTimestamps().
913 : : */
914 : : void
7177 bruce@momjian.us 915 : 542626 : SetCurrentStatementStartTimestamp(void)
916 : : {
2630 tgl@sss.pgh.pa.us 917 [ + + ]: 542626 : if (!IsParallelWorker())
918 : 541173 : stmtStartTimestamp = GetCurrentTimestamp();
919 : : else
920 [ - + ]: 1453 : Assert(stmtStartTimestamp != 0);
7177 bruce@momjian.us 921 : 542626 : }
922 : :
923 : : /*
924 : : * GetCurrentTransactionNestLevel
925 : : *
926 : : * Note: this will return zero when not inside any transaction, one when
927 : : * inside a top-level transaction, etc.
928 : : */
929 : : int
7840 tgl@sss.pgh.pa.us 930 : 17334898 : GetCurrentTransactionNestLevel(void)
931 : : {
932 : 17334898 : TransactionState s = CurrentTransactionState;
933 : :
934 : 17334898 : return s->nestingLevel;
935 : : }
936 : :
937 : :
938 : : /*
939 : : * TransactionIdIsCurrentTransactionId
940 : : */
941 : : bool
10754 scrappy@hub.org 942 : 61037194 : TransactionIdIsCurrentTransactionId(TransactionId xid)
943 : : {
944 : : TransactionState s;
945 : :
946 : : /*
947 : : * We always say that BootstrapTransactionId is "not my transaction ID"
948 : : * even when it is (ie, during bootstrap). Along with the fact that
949 : : * transam.c always treats BootstrapTransactionId as already committed,
950 : : * this causes the heapam_visibility.c routines to see all tuples as
951 : : * committed, which is what we need during bootstrap. (Bootstrap mode
952 : : * only inserts tuples, it never updates or deletes them, so all tuples
953 : : * can be presumed good immediately.)
954 : : *
955 : : * Likewise, InvalidTransactionId and FrozenTransactionId are certainly
956 : : * not my transaction ID, so we can just return "false" immediately for
957 : : * any non-normal XID.
958 : : */
6983 tgl@sss.pgh.pa.us 959 [ + + ]: 61037194 : if (!TransactionIdIsNormal(xid))
10329 bruce@momjian.us 960 : 652874 : return false;
961 : :
2229 tmunro@postgresql.or 962 [ + + ]: 60384320 : if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
963 : 43081057 : return true;
964 : :
965 : : /*
966 : : * In parallel workers, the XIDs we must consider as current are stored in
967 : : * ParallelCurrentXids rather than the transaction-state stack. Note that
968 : : * the XIDs in this array are sorted numerically rather than according to
969 : : * transactionIdPrecedes order.
970 : : */
3885 rhaas@postgresql.org 971 [ + + ]: 17303263 : if (nParallelCurrentXids > 0)
972 : : {
973 : : int low,
974 : : high;
975 : :
976 : 3703780 : low = 0;
977 : 3703780 : high = nParallelCurrentXids - 1;
978 [ + + ]: 14618030 : while (low <= high)
979 : : {
980 : : int middle;
981 : : TransactionId probe;
982 : :
983 : 14519572 : middle = low + (high - low) / 2;
984 : 14519572 : probe = ParallelCurrentXids[middle];
985 [ + + ]: 14519572 : if (probe == xid)
986 : 3605322 : return true;
987 [ + + ]: 10914250 : else if (probe < xid)
988 : 10815792 : low = middle + 1;
989 : : else
990 : 98458 : high = middle - 1;
991 : : }
992 : 98458 : return false;
993 : : }
994 : :
995 : : /*
996 : : * We will return true for the Xid of the current subtransaction, any of
997 : : * its subcommitted children, any of its parents, or any of their
998 : : * previously subcommitted children. However, a transaction being aborted
999 : : * is no longer "current", even though it may still have an entry on the
1000 : : * state stack.
1001 : : */
7782 tgl@sss.pgh.pa.us 1002 [ + + ]: 27188951 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
1003 : : {
1004 : : int low,
1005 : : high;
1006 : :
1007 [ - + ]: 13664164 : if (s->state == TRANS_ABORT)
7782 tgl@sss.pgh.pa.us 1008 :UBC 0 : continue;
2457 tmunro@postgresql.or 1009 [ + + ]:CBC 13664164 : if (!FullTransactionIdIsValid(s->fullTransactionId))
7763 tgl@sss.pgh.pa.us 1010 : 4800270 : continue; /* it can't have any child XIDs either */
2457 tmunro@postgresql.or 1011 [ + + ]: 8863894 : if (TransactionIdEquals(xid, XidFromFullTransactionId(s->fullTransactionId)))
7840 tgl@sss.pgh.pa.us 1012 : 71642 : return true;
1013 : : /* As the childXids array is ordered, we can use binary search */
6485 1014 : 8792252 : low = 0;
1015 : 8792252 : high = s->nChildXids - 1;
1016 [ + + ]: 8793132 : while (low <= high)
1017 : : {
1018 : : int middle;
1019 : : TransactionId probe;
1020 : :
1021 : 3934 : middle = low + (high - low) / 2;
1022 : 3934 : probe = s->childXids[middle];
1023 [ + + ]: 3934 : if (TransactionIdEquals(probe, xid))
7840 1024 : 3054 : return true;
6485 1025 [ + + ]: 880 : else if (TransactionIdPrecedes(probe, xid))
1026 : 807 : low = middle + 1;
1027 : : else
1028 : 73 : high = middle - 1;
1029 : : }
1030 : : }
1031 : :
7840 1032 : 13524787 : return false;
1033 : : }
1034 : :
1035 : : /*
1036 : : * TransactionStartedDuringRecovery
1037 : : *
1038 : : * Returns true if the current transaction started while recovery was still
1039 : : * in progress. Recovery might have ended since so RecoveryInProgress() might
1040 : : * return false already.
1041 : : */
1042 : : bool
5843 simon@2ndQuadrant.co 1043 : 7053195 : TransactionStartedDuringRecovery(void)
1044 : : {
1045 : 7053195 : return CurrentTransactionState->startedInRecovery;
1046 : : }
1047 : :
1048 : : /*
1049 : : * EnterParallelMode
1050 : : */
1051 : : void
3885 rhaas@postgresql.org 1052 : 3365 : EnterParallelMode(void)
1053 : : {
1054 : 3365 : TransactionState s = CurrentTransactionState;
1055 : :
1056 [ - + ]: 3365 : Assert(s->parallelModeLevel >= 0);
1057 : :
1058 : 3365 : ++s->parallelModeLevel;
1059 : 3365 : }
1060 : :
1061 : : /*
1062 : : * ExitParallelMode
1063 : : */
1064 : : void
1065 : 1906 : ExitParallelMode(void)
1066 : : {
1067 : 1906 : TransactionState s = CurrentTransactionState;
1068 : :
1069 [ - + ]: 1906 : Assert(s->parallelModeLevel > 0);
630 tgl@sss.pgh.pa.us 1070 [ + - + - : 1906 : Assert(s->parallelModeLevel > 1 || s->parallelChildXact ||
- + ]
1071 : : !ParallelContextActive());
1072 : :
3885 rhaas@postgresql.org 1073 : 1906 : --s->parallelModeLevel;
1074 : 1906 : }
1075 : :
1076 : : /*
1077 : : * IsInParallelMode
1078 : : *
1079 : : * Are we in a parallel operation, as either the leader or a worker? Check
1080 : : * this to prohibit operations that change backend-local state expected to
1081 : : * match across all workers. Mere caches usually don't require such a
1082 : : * restriction. State modified in a strict push/pop fashion, such as the
1083 : : * active snapshot stack, is often fine.
1084 : : *
1085 : : * We say we are in parallel mode if we are in a subxact of a transaction
1086 : : * that's initiated a parallel operation; for most purposes that context
1087 : : * has all the same restrictions.
1088 : : */
1089 : : bool
1090 : 4268978 : IsInParallelMode(void)
1091 : : {
630 tgl@sss.pgh.pa.us 1092 : 4268978 : TransactionState s = CurrentTransactionState;
1093 : :
1094 [ + + + + ]: 4268978 : return s->parallelModeLevel != 0 || s->parallelChildXact;
1095 : : }
1096 : :
1097 : : /*
1098 : : * CommandCounterIncrement
1099 : : */
1100 : : void
9186 1101 : 1114521 : CommandCounterIncrement(void)
1102 : : {
1103 : : /*
1104 : : * If the current value of the command counter hasn't been "used" to mark
1105 : : * tuples, we need not increment it, since there's no need to distinguish
1106 : : * a read-only command from others. This helps postpone command counter
1107 : : * overflow, and keeps no-op CommandCounterIncrement operations cheap.
1108 : : */
6593 1109 [ + + ]: 1114521 : if (currentCommandIdUsed)
1110 : : {
1111 : : /*
1112 : : * Workers synchronize transaction state at the beginning of each
1113 : : * parallel operation, so we can't account for new commands after that
1114 : : * point.
1115 : : */
3716 rhaas@postgresql.org 1116 [ + - - + ]: 615942 : if (IsInParallelMode() || IsParallelWorker())
630 tgl@sss.pgh.pa.us 1117 [ # # ]:UBC 0 : ereport(ERROR,
1118 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
1119 : : errmsg("cannot start commands during a parallel operation")));
1120 : :
6593 tgl@sss.pgh.pa.us 1121 :CBC 615942 : currentCommandId += 1;
4483 rhaas@postgresql.org 1122 [ - + ]: 615942 : if (currentCommandId == InvalidCommandId)
1123 : : {
6593 tgl@sss.pgh.pa.us 1124 :UBC 0 : currentCommandId -= 1;
1125 [ # # ]: 0 : ereport(ERROR,
1126 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1127 : : errmsg("cannot have more than 2^32-2 commands in a transaction")));
1128 : : }
6593 tgl@sss.pgh.pa.us 1129 :CBC 615942 : currentCommandIdUsed = false;
1130 : :
1131 : : /* Propagate new command ID into static snapshots */
6429 alvherre@alvh.no-ip. 1132 : 615942 : SnapshotSetCommandId(currentCommandId);
1133 : :
1134 : : /*
1135 : : * Make any catalog changes done by the just-completed command visible
1136 : : * in the local syscache. We obviously don't need to do this after a
1137 : : * read-only command. (But see hacks in inval.c to make real sure we
1138 : : * don't think a command that queued inval messages was read-only.)
1139 : : */
5793 tgl@sss.pgh.pa.us 1140 : 615942 : AtCCI_LocalCache();
1141 : : }
10754 scrappy@hub.org 1142 : 1114518 : }
1143 : :
1144 : : /*
1145 : : * ForceSyncCommit
1146 : : *
1147 : : * Interface routine to allow commands to force a synchronous commit of the
1148 : : * current top-level transaction. Currently, two-phase commit does not
1149 : : * persist and restore this variable. So long as all callers use
1150 : : * PreventInTransactionBlock(), that omission has no consequences.
1151 : : */
1152 : : void
6714 tgl@sss.pgh.pa.us 1153 : 512 : ForceSyncCommit(void)
1154 : : {
1155 : 512 : forceSyncCommit = true;
1156 : 512 : }
1157 : :
1158 : :
1159 : : /* ----------------------------------------------------------------
1160 : : * StartTransaction stuff
1161 : : * ----------------------------------------------------------------
1162 : : */
1163 : :
1164 : : /*
1165 : : * AtStart_Cache
1166 : : */
1167 : : static void
9186 1168 : 330412 : AtStart_Cache(void)
1169 : : {
8948 1170 : 330412 : AcceptInvalidationMessages();
10754 scrappy@hub.org 1171 : 330412 : }
1172 : :
1173 : : /*
1174 : : * AtStart_Memory
1175 : : */
1176 : : static void
9186 tgl@sss.pgh.pa.us 1177 : 330412 : AtStart_Memory(void)
1178 : : {
7840 1179 : 330412 : TransactionState s = CurrentTransactionState;
1180 : :
1181 : : /*
1182 : : * Remember the memory context that was active prior to transaction start.
1183 : : */
535 1184 : 330412 : s->priorContext = CurrentMemoryContext;
1185 : :
1186 : : /*
1187 : : * If this is the first time through, create a private context for
1188 : : * AbortTransaction to work in. By reserving some space now, we can
1189 : : * insulate AbortTransaction from out-of-memory scenarios. Like
1190 : : * ErrorContext, we set it up with slow growth rate and a nonzero minimum
1191 : : * size, so that space will be reserved immediately.
1192 : : */
6965 1193 [ + + ]: 330412 : if (TransactionAbortContext == NULL)
1194 : 15352 : TransactionAbortContext =
2624 1195 : 15352 : AllocSetContextCreate(TopMemoryContext,
1196 : : "TransactionAbortContext",
1197 : : 32 * 1024,
1198 : : 32 * 1024,
1199 : : 32 * 1024);
1200 : :
1201 : : /*
1202 : : * Likewise, if this is the first time through, create a top-level context
1203 : : * for transaction-local data. This context will be reset at transaction
1204 : : * end, and then re-used in later transactions.
1205 : : */
535 1206 [ + + ]: 330412 : if (TopTransactionContext == NULL)
1207 : 15352 : TopTransactionContext =
1208 : 15352 : AllocSetContextCreate(TopMemoryContext,
1209 : : "TopTransactionContext",
1210 : : ALLOCSET_DEFAULT_SIZES);
1211 : :
1212 : : /*
1213 : : * In a top-level transaction, CurTransactionContext is the same as
1214 : : * TopTransactionContext.
1215 : : */
7840 1216 : 330412 : CurTransactionContext = TopTransactionContext;
1217 : 330412 : s->curTransactionContext = CurTransactionContext;
1218 : :
1219 : : /* Make the CurTransactionContext active. */
1220 : 330412 : MemoryContextSwitchTo(CurTransactionContext);
10754 scrappy@hub.org 1221 : 330412 : }
1222 : :
1223 : : /*
1224 : : * AtStart_ResourceOwner
1225 : : */
1226 : : static void
7824 tgl@sss.pgh.pa.us 1227 : 330412 : AtStart_ResourceOwner(void)
1228 : : {
1229 : 330412 : TransactionState s = CurrentTransactionState;
1230 : :
1231 : : /*
1232 : : * We shouldn't have a transaction resource owner already.
1233 : : */
1234 [ - + ]: 330412 : Assert(TopTransactionResourceOwner == NULL);
1235 : :
1236 : : /*
1237 : : * Create a toplevel resource owner for the transaction.
1238 : : */
1239 : 330412 : s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
1240 : :
1241 : 330412 : TopTransactionResourceOwner = s->curTransactionOwner;
1242 : 330412 : CurTransactionResourceOwner = s->curTransactionOwner;
1243 : 330412 : CurrentResourceOwner = s->curTransactionOwner;
1244 : 330412 : }
1245 : :
1246 : : /* ----------------------------------------------------------------
1247 : : * StartSubTransaction stuff
1248 : : * ----------------------------------------------------------------
1249 : : */
1250 : :
1251 : : /*
1252 : : * AtSubStart_Memory
1253 : : */
1254 : : static void
7840 1255 : 9117 : AtSubStart_Memory(void)
1256 : : {
1257 : 9117 : TransactionState s = CurrentTransactionState;
1258 : :
1259 [ - + ]: 9117 : Assert(CurTransactionContext != NULL);
1260 : :
1261 : : /*
1262 : : * Remember the context that was active prior to subtransaction start.
1263 : : */
535 1264 : 9117 : s->priorContext = CurrentMemoryContext;
1265 : :
1266 : : /*
1267 : : * Create a CurTransactionContext, which will be used to hold data that
1268 : : * survives subtransaction commit but disappears on subtransaction abort.
1269 : : * We make it a child of the immediate parent's CurTransactionContext.
1270 : : */
7840 1271 : 9117 : CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
1272 : : "CurTransactionContext",
1273 : : ALLOCSET_DEFAULT_SIZES);
1274 : 9117 : s->curTransactionContext = CurTransactionContext;
1275 : :
1276 : : /* Make the CurTransactionContext active. */
1277 : 9117 : MemoryContextSwitchTo(CurTransactionContext);
1278 : 9117 : }
1279 : :
1280 : : /*
1281 : : * AtSubStart_ResourceOwner
1282 : : */
1283 : : static void
7824 1284 : 9117 : AtSubStart_ResourceOwner(void)
1285 : : {
1286 : 9117 : TransactionState s = CurrentTransactionState;
1287 : :
1288 [ - + ]: 9117 : Assert(s->parent != NULL);
1289 : :
1290 : : /*
1291 : : * Create a resource owner for the subtransaction. We make it a child of
1292 : : * the immediate parent's resource owner.
1293 : : */
1294 : 9117 : s->curTransactionOwner =
1295 : 9117 : ResourceOwnerCreate(s->parent->curTransactionOwner,
1296 : : "SubTransaction");
1297 : :
1298 : 9117 : CurTransactionResourceOwner = s->curTransactionOwner;
1299 : 9117 : CurrentResourceOwner = s->curTransactionOwner;
1300 : 9117 : }
1301 : :
1302 : : /* ----------------------------------------------------------------
1303 : : * CommitTransaction stuff
1304 : : * ----------------------------------------------------------------
1305 : : */
1306 : :
1307 : : /*
1308 : : * RecordTransactionCommit
1309 : : *
1310 : : * Returns latest XID among xact and its children, or InvalidTransactionId
1311 : : * if the xact has no XID. (We compute that here just because it's easier.)
1312 : : *
1313 : : * If you change this function, see RecordTransactionCommitPrepared also.
1314 : : */
1315 : : static TransactionId
5792 1316 : 302636 : RecordTransactionCommit(void)
1317 : : {
6679 1318 : 302636 : TransactionId xid = GetTopTransactionIdIfAny();
6608 bruce@momjian.us 1319 : 302636 : bool markXidCommitted = TransactionIdIsValid(xid);
6676 tgl@sss.pgh.pa.us 1320 : 302636 : TransactionId latestXid = InvalidTransactionId;
1321 : : int nrels;
1322 : : RelFileLocator *rels;
1323 : : int nchildren;
1324 : : TransactionId *children;
1352 andres@anarazel.de 1325 : 302636 : int ndroppedstats = 0;
1326 : 302636 : xl_xact_stats_item *droppedstats = NULL;
5606 rhaas@postgresql.org 1327 : 302636 : int nmsgs = 0;
5843 simon@2ndQuadrant.co 1328 : 302636 : SharedInvalidationMessage *invalMessages = NULL;
5606 rhaas@postgresql.org 1329 : 302636 : bool RelcacheInitFileInval = false;
1330 : : bool wrote_xlog;
1331 : :
1332 : : /*
1333 : : * Log pending invalidations for logical decoding of in-progress
1334 : : * transactions. Normally for DDLs, we log this at each command end,
1335 : : * however, for certain cases where we directly update the system table
1336 : : * without a transaction block, the invalidations are not logged till this
1337 : : * time.
1338 : : */
1974 akapila@postgresql.o 1339 [ + + ]: 302636 : if (XLogLogicalInfoActive())
1340 : 12178 : LogLogicalInvalidations();
1341 : :
1342 : : /* Get data needed for commit record */
5606 rhaas@postgresql.org 1343 : 302636 : nrels = smgrGetPendingDeletes(true, &rels);
7824 tgl@sss.pgh.pa.us 1344 : 302636 : nchildren = xactGetCommittedChildren(&children);
1352 andres@anarazel.de 1345 : 302636 : ndroppedstats = pgstat_get_transactional_drops(true, &droppedstats);
5606 rhaas@postgresql.org 1346 [ + + ]: 302636 : if (XLogStandbyInfoActive())
1347 : 201908 : nmsgs = xactGetCommittedInvalidationMessages(&invalMessages,
1348 : : &RelcacheInitFileInval);
4925 heikki.linnakangas@i 1349 : 302636 : wrote_xlog = (XactLastRecEnd != 0);
1350 : :
1351 : : /*
1352 : : * If we haven't been assigned an XID yet, we neither can, nor do we want
1353 : : * to write a COMMIT record.
1354 : : */
6679 tgl@sss.pgh.pa.us 1355 [ + + ]: 302636 : if (!markXidCommitted)
1356 : : {
1357 : : /*
1358 : : * We expect that every RelationDropStorage is followed by a catalog
1359 : : * update, and hence XID assignment, so we shouldn't get here with any
1360 : : * pending deletes. Same is true for dropping stats.
1361 : : *
1362 : : * Use a real test not just an Assert to check this, since it's a bit
1363 : : * fragile.
1364 : : */
1352 andres@anarazel.de 1365 [ + - - + ]: 173843 : if (nrels != 0 || ndroppedstats != 0)
6679 tgl@sss.pgh.pa.us 1366 [ # # ]:UBC 0 : elog(ERROR, "cannot commit a transaction that deleted files but has no xid");
1367 : :
1368 : : /* Can't have child XIDs either; AssignTransactionId enforces this */
6679 tgl@sss.pgh.pa.us 1369 [ - + ]:CBC 173843 : Assert(nchildren == 0);
1370 : :
1371 : : /*
1372 : : * Transactions without an assigned xid can contain invalidation
1373 : : * messages. While inplace updates do this, this is not known to be
1374 : : * necessary; see comment at inplace CacheInvalidateHeapTuple().
1375 : : * Extensions might still rely on this capability, and standbys may
1376 : : * need to process those invals. We can't emit a commit record
1377 : : * without an xid, and we don't want to force assigning an xid,
1378 : : * because that'd be problematic for e.g. vacuum. Hence we emit a
1379 : : * bespoke record for the invalidations. We don't want to use that in
1380 : : * case a commit record is emitted, so they happen synchronously with
1381 : : * commits (besides not wanting to emit more WAL records).
1382 : : *
1383 : : * XXX Every known use of this capability is a defect. Since an XID
1384 : : * isn't controlling visibility of the change that prompted invals,
1385 : : * other sessions need the inval even if this transactions aborts.
1386 : : *
1387 : : * ON COMMIT DELETE ROWS does a nontransactional index_build(), which
1388 : : * queues a relcache inval, including in transactions without an xid
1389 : : * that had read the (empty) table. Standbys don't need any ON COMMIT
1390 : : * DELETE ROWS invals, but we've not done the work to withhold them.
1391 : : */
3526 andres@anarazel.de 1392 [ + + ]: 173843 : if (nmsgs != 0)
1393 : : {
1394 : 9144 : LogStandbyInvalidations(nmsgs, invalMessages,
1395 : : RelcacheInitFileInval);
3479 rhaas@postgresql.org 1396 : 9144 : wrote_xlog = true; /* not strictly necessary */
1397 : : }
1398 : :
1399 : : /*
1400 : : * If we didn't create XLOG entries, we're done here; otherwise we
1401 : : * should trigger flushing those entries the same as a commit record
1402 : : * would. This will primarily happen for HOT pruning and the like; we
1403 : : * want these to be flushed to disk in due time.
1404 : : */
5477 1405 [ + + ]: 173843 : if (!wrote_xlog)
6679 tgl@sss.pgh.pa.us 1406 : 156674 : goto cleanup;
1407 : : }
1408 : : else
1409 : : {
1410 : : bool replorigin;
1411 : :
1412 : : /*
1413 : : * Are we using the replication origins feature? Or, in other words,
1414 : : * are we replaying remote actions?
1415 : : */
3733 alvherre@alvh.no-ip. 1416 [ + + ]: 129808 : replorigin = (replorigin_session_origin != InvalidRepOriginId &&
1417 [ + - ]: 1015 : replorigin_session_origin != DoNotReplicateId);
1418 : :
1419 : : /*
1420 : : * Mark ourselves as within our "commit critical section". This
1421 : : * forces any concurrent checkpoint to wait until we've updated
1422 : : * pg_xact. Without this, it is possible for the checkpoint to set
1423 : : * REDO after the XLOG record but fail to flush the pg_xact update to
1424 : : * disk, leading to loss of the transaction commit if the system
1425 : : * crashes a little later.
1426 : : *
1427 : : * Note: we could, but don't bother to, set this flag in
1428 : : * RecordTransactionAbort. That's because loss of a transaction abort
1429 : : * is noncritical; the presumption would be that it aborted, anyway.
1430 : : *
1431 : : * It's safe to change the delayChkptFlags flag of our own backend
1432 : : * without holding the ProcArrayLock, since we're the only one
1433 : : * modifying it. This makes checkpoint's determination of which xacts
1434 : : * are delaying the checkpoint a bit fuzzy, but it doesn't matter.
1435 : : *
1436 : : * Note, it is important to get the commit timestamp after marking the
1437 : : * transaction in the commit critical section. See
1438 : : * RecordTransactionCommitPrepared.
1439 : : */
148 akapila@postgresql.o 1440 [ - + ]:GNC 128793 : Assert((MyProc->delayChkptFlags & DELAY_CHKPT_IN_COMMIT) == 0);
6679 tgl@sss.pgh.pa.us 1441 :CBC 128793 : START_CRIT_SECTION();
148 akapila@postgresql.o 1442 :GNC 128793 : MyProc->delayChkptFlags |= DELAY_CHKPT_IN_COMMIT;
1443 : :
1444 [ - + ]: 128793 : Assert(xactStopTimestamp == 0);
1445 : :
1446 : : /*
1447 : : * Ensures the DELAY_CHKPT_IN_COMMIT flag write is globally visible
1448 : : * before commit time is written.
1449 : : */
1450 : 128793 : pg_write_barrier();
1451 : :
1452 : : /*
1453 : : * Insert the commit XLOG record.
1454 : : */
1161 andres@anarazel.de 1455 :CBC 128793 : XactLogCommitRecord(GetCurrentTransactionStopTimestamp(),
1456 : : nchildren, children, nrels, rels,
1457 : : ndroppedstats, droppedstats,
1458 : : nmsgs, invalMessages,
1459 : : RelcacheInitFileInval,
1460 : : MyXactFlags,
1461 : : InvalidTransactionId, NULL /* plain commit */ );
1462 : :
3733 alvherre@alvh.no-ip. 1463 [ + + ]: 128793 : if (replorigin)
1464 : : /* Move LSNs forward for this replication origin */
3734 1465 : 1015 : replorigin_session_advance(replorigin_session_origin_lsn,
1466 : : XactLastRecEnd);
1467 : :
1468 : : /*
1469 : : * Record commit timestamp. The value comes from plain commit
1470 : : * timestamp if there's no replication origin; otherwise, the
1471 : : * timestamp was already set in replorigin_session_origin_timestamp by
1472 : : * replication.
1473 : : *
1474 : : * We don't need to WAL-log anything here, as the commit record
1475 : : * written above already contains the data.
1476 : : */
1477 : :
3733 1478 [ + + + + ]: 128793 : if (!replorigin || replorigin_session_origin_timestamp == 0)
1161 andres@anarazel.de 1479 : 127877 : replorigin_session_origin_timestamp = GetCurrentTransactionStopTimestamp();
1480 : :
4033 alvherre@alvh.no-ip. 1481 : 128793 : TransactionTreeSetCommitTsData(xid, nchildren, children,
1482 : : replorigin_session_origin_timestamp,
1483 : : replorigin_session_origin);
1484 : : }
1485 : :
1486 : : /*
1487 : : * Check if we want to commit asynchronously. We can allow the XLOG flush
1488 : : * to happen asynchronously if synchronous_commit=off, or if the current
1489 : : * transaction has not performed any WAL-logged operation or didn't assign
1490 : : * an xid. The transaction can end up not writing any WAL, even if it has
1491 : : * an xid, if it only wrote to temporary and/or unlogged tables. It can
1492 : : * end up having written WAL without an xid if it did HOT pruning. In
1493 : : * case of a crash, the loss of such a transaction will be irrelevant;
1494 : : * temp tables will be lost anyway, unlogged tables will be truncated and
1495 : : * HOT pruning will be done again later. (Given the foregoing, you might
1496 : : * think that it would be unnecessary to emit the XLOG record at all in
1497 : : * this case, but we don't currently try to do that. It would certainly
1498 : : * cause problems at least in Hot Standby mode, where the
1499 : : * KnownAssignedXids machinery requires tracking every XID assignment. It
1500 : : * might be OK to skip it only when wal_level < replica, but for now we
1501 : : * don't.)
1502 : : *
1503 : : * However, if we're doing cleanup of any non-temp rels or committing any
1504 : : * command that wanted to force sync commit, then we must flush XLOG
1505 : : * immediately. (We must not allow asynchronous commit if there are any
1506 : : * non-temp tables to be deleted, because we might delete the files before
1507 : : * the COMMIT record is flushed to disk. We do allow asynchronous commit
1508 : : * if all to-be-deleted tables are temporary though, since they are lost
1509 : : * anyway if we crash.)
1510 : : */
3948 andres@anarazel.de 1511 [ + + + + ]: 145962 : if ((wrote_xlog && markXidCommitted &&
1512 [ + + + + ]: 145962 : synchronous_commit > SYNCHRONOUS_COMMIT_OFF) ||
5372 rhaas@postgresql.org 1513 [ + + ]: 23474 : forceSyncCommit || nrels > 0)
1514 : : {
6679 tgl@sss.pgh.pa.us 1515 : 122508 : XLogFlush(XactLastRecEnd);
1516 : :
1517 : : /*
1518 : : * Now we may update the CLOG, if we wrote a COMMIT record above
1519 : : */
1520 [ + - ]: 122508 : if (markXidCommitted)
6268 alvherre@alvh.no-ip. 1521 : 122508 : TransactionIdCommitTree(xid, nchildren, children);
1522 : : }
1523 : : else
1524 : : {
1525 : : /*
1526 : : * Asynchronous commit case:
1527 : : *
1528 : : * This enables possible committed transaction loss in the case of a
1529 : : * postmaster crash because WAL buffers are left unwritten. Ideally we
1530 : : * could issue the WAL write without the fsync, but some
1531 : : * wal_sync_methods do not allow separate write/fsync.
1532 : : *
1533 : : * Report the latest async commit LSN, so that the WAL writer knows to
1534 : : * flush this commit.
1535 : : */
5621 simon@2ndQuadrant.co 1536 : 23454 : XLogSetAsyncXactLSN(XactLastRecEnd);
1537 : :
1538 : : /*
1539 : : * We must not immediately update the CLOG, since we didn't flush the
1540 : : * XLOG. Instead, we store the LSN up to which the XLOG must be
1541 : : * flushed before the CLOG may be updated.
1542 : : */
6679 tgl@sss.pgh.pa.us 1543 [ + + ]: 23454 : if (markXidCommitted)
6268 alvherre@alvh.no-ip. 1544 : 6285 : TransactionIdAsyncCommitTree(xid, nchildren, children, XactLastRecEnd);
1545 : : }
1546 : :
1547 : : /*
1548 : : * If we entered a commit critical section, leave it now, and let
1549 : : * checkpoints proceed.
1550 : : */
6679 tgl@sss.pgh.pa.us 1551 [ + + ]: 145962 : if (markXidCommitted)
1552 : : {
148 akapila@postgresql.o 1553 :GNC 128793 : MyProc->delayChkptFlags &= ~DELAY_CHKPT_IN_COMMIT;
9106 tgl@sss.pgh.pa.us 1554 [ - + ]:CBC 128793 : END_CRIT_SECTION();
1555 : : }
1556 : :
1557 : : /* Compute latestXid while we have the child XIDs handy */
6676 1558 : 145962 : latestXid = TransactionIdLatest(xid, nchildren, children);
1559 : :
1560 : : /*
1561 : : * Wait for synchronous replication, if required. Similar to the decision
1562 : : * above about using committing asynchronously we only want to wait if
1563 : : * this backend assigned an xid and wrote WAL. No need to wait if an xid
1564 : : * was assigned due to temporary/unlogged tables or due to HOT pruning.
1565 : : *
1566 : : * Note that at this stage we have marked clog, but still show as running
1567 : : * in the procarray and continue to hold locks.
1568 : : */
3948 andres@anarazel.de 1569 [ + + + + ]: 145962 : if (wrote_xlog && markXidCommitted)
3551 rhaas@postgresql.org 1570 : 124796 : SyncRepWaitForLSN(XactLastRecEnd, true);
1571 : :
1572 : : /* remember end of last commit record */
3886 andres@anarazel.de 1573 : 145962 : XactLastCommitEnd = XactLastRecEnd;
1574 : :
1575 : : /* Reset XactLastRecEnd until the next transaction writes something */
4925 heikki.linnakangas@i 1576 : 145962 : XactLastRecEnd = 0;
6679 tgl@sss.pgh.pa.us 1577 : 302636 : cleanup:
1578 : : /* Clean up local data */
7489 1579 [ + + ]: 302636 : if (rels)
1580 : 9657 : pfree(rels);
1352 andres@anarazel.de 1581 [ + + ]: 302636 : if (ndroppedstats)
1582 : 11195 : pfree(droppedstats);
1583 : :
6676 tgl@sss.pgh.pa.us 1584 : 302636 : return latestXid;
1585 : : }
1586 : :
1587 : :
1588 : : /*
1589 : : * AtCCI_LocalCache
1590 : : */
1591 : : static void
5793 1592 : 615942 : AtCCI_LocalCache(void)
1593 : : {
1594 : : /*
1595 : : * Make any pending relation map changes visible. We must do this before
1596 : : * processing local sinval messages, so that the map changes will get
1597 : : * reflected into the relcache when relcache invals are processed.
1598 : : */
1599 : 615942 : AtCCI_RelationMap();
1600 : :
1601 : : /*
1602 : : * Make catalog changes visible to me for the next command.
1603 : : */
7840 1604 : 615942 : CommandEndInvalidationMessages();
9474 inoue@tpf.co.jp 1605 : 615939 : }
1606 : :
1607 : : /*
1608 : : * AtCommit_Memory
1609 : : */
1610 : : static void
9186 tgl@sss.pgh.pa.us 1611 : 304371 : AtCommit_Memory(void)
1612 : : {
535 1613 : 304371 : TransactionState s = CurrentTransactionState;
1614 : :
1615 : : /*
1616 : : * Return to the memory context that was current before we started the
1617 : : * transaction. (In principle, this could not be any of the contexts we
1618 : : * are about to delete. If it somehow is, assertions in mcxt.c will
1619 : : * complain.)
1620 : : */
1621 : 304371 : MemoryContextSwitchTo(s->priorContext);
1622 : :
1623 : : /*
1624 : : * Release all transaction-local memory. TopTransactionContext survives
1625 : : * but becomes empty; any sub-contexts go away.
1626 : : */
9300 1627 [ - + ]: 304371 : Assert(TopTransactionContext != NULL);
535 1628 : 304371 : MemoryContextReset(TopTransactionContext);
1629 : :
1630 : : /*
1631 : : * Clear these pointers as a pro-forma matter. (Notionally, while
1632 : : * TopTransactionContext still exists, it's currently not associated with
1633 : : * this TransactionState struct.)
1634 : : */
7840 1635 : 304371 : CurTransactionContext = NULL;
535 1636 : 304371 : s->curTransactionContext = NULL;
7840 1637 : 304371 : }
1638 : :
1639 : : /* ----------------------------------------------------------------
1640 : : * CommitSubTransaction stuff
1641 : : * ----------------------------------------------------------------
1642 : : */
1643 : :
1644 : : /*
1645 : : * AtSubCommit_Memory
1646 : : */
1647 : : static void
1648 : 4433 : AtSubCommit_Memory(void)
1649 : : {
1650 : 4433 : TransactionState s = CurrentTransactionState;
1651 : :
1652 [ - + ]: 4433 : Assert(s->parent != NULL);
1653 : :
1654 : : /* Return to parent transaction level's memory context. */
1655 : 4433 : CurTransactionContext = s->parent->curTransactionContext;
1656 : 4433 : MemoryContextSwitchTo(CurTransactionContext);
1657 : :
1658 : : /*
1659 : : * Ordinarily we cannot throw away the child's CurTransactionContext,
1660 : : * since the data it contains will be needed at upper commit. However, if
1661 : : * there isn't actually anything in it, we can throw it away. This avoids
1662 : : * a small memory leak in the common case of "trivial" subxacts.
1663 : : */
7763 1664 [ + + ]: 4433 : if (MemoryContextIsEmpty(s->curTransactionContext))
1665 : : {
1666 : 4419 : MemoryContextDelete(s->curTransactionContext);
1667 : 4419 : s->curTransactionContext = NULL;
1668 : : }
7840 1669 : 4433 : }
1670 : :
1671 : : /*
1672 : : * AtSubCommit_childXids
1673 : : *
1674 : : * Pass my own XID and my child XIDs up to my parent as committed children.
1675 : : */
1676 : : static void
1677 : 2745 : AtSubCommit_childXids(void)
1678 : : {
1679 : 2745 : TransactionState s = CurrentTransactionState;
1680 : : int new_nChildXids;
1681 : :
1682 [ - + ]: 2745 : Assert(s->parent != NULL);
1683 : :
1684 : : /*
1685 : : * The parent childXids array will need to hold my XID and all my
1686 : : * childXids, in addition to the XIDs already there.
1687 : : */
6485 1688 : 2745 : new_nChildXids = s->parent->nChildXids + s->nChildXids + 1;
1689 : :
1690 : : /* Allocate or enlarge the parent array if necessary */
1691 [ + + ]: 2745 : if (s->parent->maxChildXids < new_nChildXids)
1692 : : {
1693 : : int new_maxChildXids;
1694 : : TransactionId *new_childXids;
1695 : :
1696 : : /*
1697 : : * Make it 2x what's needed right now, to avoid having to enlarge it
1698 : : * repeatedly. But we can't go above MaxAllocSize. (The latter limit
1699 : : * is what ensures that we don't need to worry about integer overflow
1700 : : * here or in the calculation of new_nChildXids.)
1701 : : */
1702 : 1614 : new_maxChildXids = Min(new_nChildXids * 2,
1703 : : (int) (MaxAllocSize / sizeof(TransactionId)));
1704 : :
1705 [ - + ]: 1614 : if (new_maxChildXids < new_nChildXids)
6485 tgl@sss.pgh.pa.us 1706 [ # # ]:UBC 0 : ereport(ERROR,
1707 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1708 : : errmsg("maximum number of committed subtransactions (%d) exceeded",
1709 : : (int) (MaxAllocSize / sizeof(TransactionId)))));
1710 : :
1711 : : /*
1712 : : * We keep the child-XID arrays in TopTransactionContext; this avoids
1713 : : * setting up child-transaction contexts for what might be just a few
1714 : : * bytes of grandchild XIDs.
1715 : : */
6485 tgl@sss.pgh.pa.us 1716 [ + + ]:CBC 1614 : if (s->parent->childXids == NULL)
1717 : : new_childXids =
6034 bruce@momjian.us 1718 : 1583 : MemoryContextAlloc(TopTransactionContext,
1719 : : new_maxChildXids * sizeof(TransactionId));
1720 : : else
1721 : 31 : new_childXids = repalloc(s->parent->childXids,
1722 : : new_maxChildXids * sizeof(TransactionId));
1723 : :
1724 : 1614 : s->parent->childXids = new_childXids;
6485 tgl@sss.pgh.pa.us 1725 : 1614 : s->parent->maxChildXids = new_maxChildXids;
1726 : : }
1727 : :
1728 : : /*
1729 : : * Copy all my XIDs to parent's array.
1730 : : *
1731 : : * Note: We rely on the fact that the XID of a child always follows that
1732 : : * of its parent. By copying the XID of this subtransaction before the
1733 : : * XIDs of its children, we ensure that the array stays ordered. Likewise,
1734 : : * all XIDs already in the array belong to subtransactions started and
1735 : : * subcommitted before us, so their XIDs must precede ours.
1736 : : */
2457 tmunro@postgresql.or 1737 : 2745 : s->parent->childXids[s->parent->nChildXids] = XidFromFullTransactionId(s->fullTransactionId);
1738 : :
6485 tgl@sss.pgh.pa.us 1739 [ + + ]: 2745 : if (s->nChildXids > 0)
1740 : 1008 : memcpy(&s->parent->childXids[s->parent->nChildXids + 1],
1741 : 1008 : s->childXids,
1742 : 1008 : s->nChildXids * sizeof(TransactionId));
1743 : :
1744 : 2745 : s->parent->nChildXids = new_nChildXids;
1745 : :
1746 : : /* Release child's array to avoid leakage */
1747 [ + + ]: 2745 : if (s->childXids != NULL)
1748 : 1008 : pfree(s->childXids);
1749 : : /* We must reset these to avoid double-free if fail later in commit */
1750 : 2745 : s->childXids = NULL;
1751 : 2745 : s->nChildXids = 0;
1752 : 2745 : s->maxChildXids = 0;
7840 1753 : 2745 : }
1754 : :
1755 : : /* ----------------------------------------------------------------
1756 : : * AbortTransaction stuff
1757 : : * ----------------------------------------------------------------
1758 : : */
1759 : :
1760 : : /*
1761 : : * RecordTransactionAbort
1762 : : *
1763 : : * Returns latest XID among xact and its children, or InvalidTransactionId
1764 : : * if the xact has no XID. (We compute that here just because it's easier.)
1765 : : */
1766 : : static TransactionId
6679 1767 : 30719 : RecordTransactionAbort(bool isSubXact)
1768 : : {
1769 : 30719 : TransactionId xid = GetCurrentTransactionIdIfAny();
1770 : : TransactionId latestXid;
1771 : : int nrels;
1772 : : RelFileLocator *rels;
1352 andres@anarazel.de 1773 : 30719 : int ndroppedstats = 0;
1774 : 30719 : xl_xact_stats_item *droppedstats = NULL;
1775 : : int nchildren;
1776 : : TransactionId *children;
1777 : : TimestampTz xact_time;
1778 : : bool replorigin;
1779 : :
1780 : : /*
1781 : : * If we haven't been assigned an XID, nobody will care whether we aborted
1782 : : * or not. Hence, we're done in that case. It does not matter if we have
1783 : : * rels to delete (note that this routine is not responsible for actually
1784 : : * deleting 'em). We cannot have any child XIDs, either.
1785 : : */
6679 tgl@sss.pgh.pa.us 1786 [ + + ]: 30719 : if (!TransactionIdIsValid(xid))
1787 : : {
1788 : : /* Reset XactLastRecEnd until the next transaction writes something */
1789 [ + + ]: 24293 : if (!isSubXact)
4925 heikki.linnakangas@i 1790 : 20274 : XactLastRecEnd = 0;
6676 tgl@sss.pgh.pa.us 1791 : 24293 : return InvalidTransactionId;
1792 : : }
1793 : :
1794 : : /*
1795 : : * We have a valid XID, so we should write an ABORT record for it.
1796 : : *
1797 : : * We do not flush XLOG to disk here, since the default assumption after a
1798 : : * crash would be that we aborted, anyway. For the same reason, we don't
1799 : : * need to worry about interlocking against checkpoint start.
1800 : : */
1801 : :
1802 : : /*
1803 : : * Check that we haven't aborted halfway through RecordTransactionCommit.
1804 : : */
6679 1805 [ - + ]: 6426 : if (TransactionIdDidCommit(xid))
6679 tgl@sss.pgh.pa.us 1806 [ # # ]:UBC 0 : elog(PANIC, "cannot abort transaction %u, it was already committed",
1807 : : xid);
1808 : :
1809 : : /*
1810 : : * Are we using the replication origins feature? Or, in other words, are
1811 : : * we replaying remote actions?
1812 : : */
1074 akapila@postgresql.o 1813 [ + + ]:CBC 6456 : replorigin = (replorigin_session_origin != InvalidRepOriginId &&
1814 [ + - ]: 30 : replorigin_session_origin != DoNotReplicateId);
1815 : :
1816 : : /* Fetch the data we need for the abort record */
5606 rhaas@postgresql.org 1817 : 6426 : nrels = smgrGetPendingDeletes(false, &rels);
6679 tgl@sss.pgh.pa.us 1818 : 6426 : nchildren = xactGetCommittedChildren(&children);
1352 andres@anarazel.de 1819 : 6426 : ndroppedstats = pgstat_get_transactional_drops(false, &droppedstats);
1820 : :
1821 : : /* XXX do we really need a critical section here? */
6679 tgl@sss.pgh.pa.us 1822 : 6426 : START_CRIT_SECTION();
1823 : :
1824 : : /* Write the ABORT record */
1825 [ + + ]: 6426 : if (isSubXact)
3931 andres@anarazel.de 1826 : 665 : xact_time = GetCurrentTimestamp();
1827 : : else
1828 : : {
1161 1829 : 5761 : xact_time = GetCurrentTransactionStopTimestamp();
1830 : : }
1831 : :
3931 1832 : 6426 : XactLogAbortRecord(xact_time,
1833 : : nchildren, children,
1834 : : nrels, rels,
1835 : : ndroppedstats, droppedstats,
1836 : : MyXactFlags, InvalidTransactionId,
1837 : : NULL);
1838 : :
1074 akapila@postgresql.o 1839 [ + + ]: 6426 : if (replorigin)
1840 : : /* Move LSNs forward for this replication origin */
1841 : 30 : replorigin_session_advance(replorigin_session_origin_lsn,
1842 : : XactLastRecEnd);
1843 : :
1844 : : /*
1845 : : * Report the latest async abort LSN, so that the WAL writer knows to
1846 : : * flush this abort. There's nothing to be gained by delaying this, since
1847 : : * WALWriter may as well do this when it can. This is important with
1848 : : * streaming replication because if we don't flush WAL regularly we will
1849 : : * find that large aborts leave us with a long backlog for when commits
1850 : : * occur after the abort, increasing our window of data loss should
1851 : : * problems occur at that point.
1852 : : */
5698 simon@2ndQuadrant.co 1853 [ + + ]: 6426 : if (!isSubXact)
5621 1854 : 5761 : XLogSetAsyncXactLSN(XactLastRecEnd);
1855 : :
1856 : : /*
1857 : : * Mark the transaction aborted in clog. This is not absolutely necessary
1858 : : * but we may as well do it while we are here; also, in the subxact case
1859 : : * it is helpful because XactLockTableWait makes use of it to avoid
1860 : : * waiting for already-aborted subtransactions. It is OK to do it without
1861 : : * having flushed the ABORT record to disk, because in event of a crash
1862 : : * we'd be assumed to have aborted anyway.
1863 : : */
6268 alvherre@alvh.no-ip. 1864 : 6426 : TransactionIdAbortTree(xid, nchildren, children);
1865 : :
6679 tgl@sss.pgh.pa.us 1866 [ - + ]: 6426 : END_CRIT_SECTION();
1867 : :
1868 : : /* Compute latestXid while we have the child XIDs handy */
6676 1869 : 6426 : latestXid = TransactionIdLatest(xid, nchildren, children);
1870 : :
1871 : : /*
1872 : : * If we're aborting a subtransaction, we can immediately remove failed
1873 : : * XIDs from PGPROC's cache of running child XIDs. We do that here for
1874 : : * subxacts, because we already have the child XID array at hand. For
1875 : : * main xacts, the equivalent happens just after this function returns.
1876 : : */
6679 1877 [ + + ]: 6426 : if (isSubXact)
6676 1878 : 665 : XidCacheRemoveRunningXids(xid, nchildren, children, latestXid);
1879 : :
1880 : : /* Reset XactLastRecEnd until the next transaction writes something */
6679 1881 [ + + ]: 6426 : if (!isSubXact)
4925 heikki.linnakangas@i 1882 : 5761 : XactLastRecEnd = 0;
1883 : :
1884 : : /* And clean up local data */
7489 tgl@sss.pgh.pa.us 1885 [ + + ]: 6426 : if (rels)
1886 : 1009 : pfree(rels);
1352 andres@anarazel.de 1887 [ + + ]: 6426 : if (ndroppedstats)
1888 : 1415 : pfree(droppedstats);
1889 : :
6676 tgl@sss.pgh.pa.us 1890 : 6426 : return latestXid;
1891 : : }
1892 : :
1893 : : /*
1894 : : * AtAbort_Memory
1895 : : */
1896 : : static void
9186 1897 : 41809 : AtAbort_Memory(void)
1898 : : {
1899 : : /*
1900 : : * Switch into TransactionAbortContext, which should have some free space
1901 : : * even if nothing else does. We'll work in this context until we've
1902 : : * finished cleaning up.
1903 : : *
1904 : : * It is barely possible to get here when we've not been able to create
1905 : : * TransactionAbortContext yet; if so use TopMemoryContext.
1906 : : */
6965 1907 [ + - ]: 41809 : if (TransactionAbortContext != NULL)
1908 : 41809 : MemoryContextSwitchTo(TransactionAbortContext);
1909 : : else
9300 tgl@sss.pgh.pa.us 1910 :UBC 0 : MemoryContextSwitchTo(TopMemoryContext);
9304 tgl@sss.pgh.pa.us 1911 :CBC 41809 : }
1912 : :
1913 : : /*
1914 : : * AtSubAbort_Memory
1915 : : */
1916 : : static void
7840 1917 : 4684 : AtSubAbort_Memory(void)
1918 : : {
6965 1919 [ - + ]: 4684 : Assert(TransactionAbortContext != NULL);
1920 : :
1921 : 4684 : MemoryContextSwitchTo(TransactionAbortContext);
7840 1922 : 4684 : }
1923 : :
1924 : :
1925 : : /*
1926 : : * AtAbort_ResourceOwner
1927 : : */
1928 : : static void
7745 1929 : 26041 : AtAbort_ResourceOwner(void)
1930 : : {
1931 : : /*
1932 : : * Make sure we have a valid ResourceOwner, if possible (else it will be
1933 : : * NULL, which is OK)
1934 : : */
1935 : 26041 : CurrentResourceOwner = TopTransactionResourceOwner;
1936 : 26041 : }
1937 : :
1938 : : /*
1939 : : * AtSubAbort_ResourceOwner
1940 : : */
1941 : : static void
1942 : 4684 : AtSubAbort_ResourceOwner(void)
1943 : : {
1944 : 4684 : TransactionState s = CurrentTransactionState;
1945 : :
1946 : : /* Make sure we have a valid ResourceOwner */
1947 : 4684 : CurrentResourceOwner = s->curTransactionOwner;
1948 : 4684 : }
1949 : :
1950 : :
1951 : : /*
1952 : : * AtSubAbort_childXids
1953 : : */
1954 : : static void
7763 1955 : 665 : AtSubAbort_childXids(void)
1956 : : {
1957 : 665 : TransactionState s = CurrentTransactionState;
1958 : :
1959 : : /*
1960 : : * We keep the child-XID arrays in TopTransactionContext (see
1961 : : * AtSubCommit_childXids). This means we'd better free the array
1962 : : * explicitly at abort to avoid leakage.
1963 : : */
6485 1964 [ + + ]: 665 : if (s->childXids != NULL)
1965 : 25 : pfree(s->childXids);
1966 : 665 : s->childXids = NULL;
1967 : 665 : s->nChildXids = 0;
1968 : 665 : s->maxChildXids = 0;
1969 : :
1970 : : /*
1971 : : * We could prune the unreportedXids array here. But we don't bother. That
1972 : : * would potentially reduce number of XLOG_XACT_ASSIGNMENT records but it
1973 : : * would likely introduce more CPU time into the more common paths, so we
1974 : : * choose not to do that.
1975 : : */
7763 1976 : 665 : }
1977 : :
1978 : : /* ----------------------------------------------------------------
1979 : : * CleanupTransaction stuff
1980 : : * ----------------------------------------------------------------
1981 : : */
1982 : :
1983 : : /*
1984 : : * AtCleanup_Memory
1985 : : */
1986 : : static void
9186 1987 : 26041 : AtCleanup_Memory(void)
1988 : : {
535 1989 : 26041 : TransactionState s = CurrentTransactionState;
1990 : :
1991 : : /* Should be at top level */
1992 [ - + ]: 26041 : Assert(s->parent == NULL);
1993 : :
1994 : : /*
1995 : : * Return to the memory context that was current before we started the
1996 : : * transaction. (In principle, this could not be any of the contexts we
1997 : : * are about to delete. If it somehow is, assertions in mcxt.c will
1998 : : * complain.)
1999 : : */
2000 : 26041 : MemoryContextSwitchTo(s->priorContext);
2001 : :
2002 : : /*
2003 : : * Clear the special abort context for next time.
2004 : : */
6965 2005 [ + - ]: 26041 : if (TransactionAbortContext != NULL)
764 nathan@postgresql.or 2006 : 26041 : MemoryContextReset(TransactionAbortContext);
2007 : :
2008 : : /*
2009 : : * Release all transaction-local memory, the same as in AtCommit_Memory,
2010 : : * except we must cope with the possibility that we didn't get as far as
2011 : : * creating TopTransactionContext.
2012 : : */
9300 tgl@sss.pgh.pa.us 2013 [ + - ]: 26041 : if (TopTransactionContext != NULL)
535 2014 : 26041 : MemoryContextReset(TopTransactionContext);
2015 : :
2016 : : /*
2017 : : * Clear these pointers as a pro-forma matter. (Notionally, while
2018 : : * TopTransactionContext still exists, it's currently not associated with
2019 : : * this TransactionState struct.)
2020 : : */
7840 2021 : 26041 : CurTransactionContext = NULL;
535 2022 : 26041 : s->curTransactionContext = NULL;
10754 scrappy@hub.org 2023 : 26041 : }
2024 : :
2025 : :
2026 : : /* ----------------------------------------------------------------
2027 : : * CleanupSubTransaction stuff
2028 : : * ----------------------------------------------------------------
2029 : : */
2030 : :
2031 : : /*
2032 : : * AtSubCleanup_Memory
2033 : : */
2034 : : static void
7840 tgl@sss.pgh.pa.us 2035 : 4684 : AtSubCleanup_Memory(void)
2036 : : {
2037 : 4684 : TransactionState s = CurrentTransactionState;
2038 : :
2039 [ - + ]: 4684 : Assert(s->parent != NULL);
2040 : :
2041 : : /*
2042 : : * Return to the memory context that was current before we started the
2043 : : * subtransaction. (In principle, this could not be any of the contexts
2044 : : * we are about to delete. If it somehow is, assertions in mcxt.c will
2045 : : * complain.)
2046 : : */
535 2047 : 4684 : MemoryContextSwitchTo(s->priorContext);
2048 : :
2049 : : /* Update CurTransactionContext (might not be same as priorContext) */
7840 2050 : 4684 : CurTransactionContext = s->parent->curTransactionContext;
2051 : :
2052 : : /*
2053 : : * Clear the special abort context for next time.
2054 : : */
6965 2055 [ + - ]: 4684 : if (TransactionAbortContext != NULL)
764 nathan@postgresql.or 2056 : 4684 : MemoryContextReset(TransactionAbortContext);
2057 : :
2058 : : /*
2059 : : * Delete the subxact local memory contexts. Its CurTransactionContext can
2060 : : * go too (note this also kills CurTransactionContexts from any children
2061 : : * of the subxact).
2062 : : */
7763 tgl@sss.pgh.pa.us 2063 [ + - ]: 4684 : if (s->curTransactionContext)
2064 : 4684 : MemoryContextDelete(s->curTransactionContext);
2065 : 4684 : s->curTransactionContext = NULL;
7840 2066 : 4684 : }
2067 : :
2068 : : /* ----------------------------------------------------------------
2069 : : * interface routines
2070 : : * ----------------------------------------------------------------
2071 : : */
2072 : :
2073 : : /*
2074 : : * StartTransaction
2075 : : */
2076 : : static void
9186 2077 : 330412 : StartTransaction(void)
2078 : : {
2079 : : TransactionState s;
2080 : : VirtualTransactionId vxid;
2081 : :
2082 : : /*
2083 : : * Let's just make sure the state stack is empty
2084 : : */
7763 2085 : 330412 : s = &TopTransactionStateData;
2086 : 330412 : CurrentTransactionState = s;
2087 : :
2457 tmunro@postgresql.or 2088 [ - + ]: 330412 : Assert(!FullTransactionIdIsValid(XactTopFullTransactionId));
2089 : :
2090 : : /* check the current transaction state */
2591 michael@paquier.xyz 2091 [ - + ]: 330412 : Assert(s->state == TRANS_DEFAULT);
2092 : :
2093 : : /*
2094 : : * Set the current transaction state information appropriately during
2095 : : * start processing. Note that once the transaction status is switched
2096 : : * this process cannot fail until the user ID and the security context
2097 : : * flags are fetched below.
2098 : : */
10329 bruce@momjian.us 2099 : 330412 : s->state = TRANS_START;
2457 tmunro@postgresql.or 2100 : 330412 : s->fullTransactionId = InvalidFullTransactionId; /* until assigned */
2101 : :
2102 : : /* Determine if statements are logged in this transaction */
2451 alvherre@alvh.no-ip. 2103 [ - + ]: 330412 : xact_is_sampled = log_xact_sample_rate != 0 &&
2451 alvherre@alvh.no-ip. 2104 [ # # ]:UBC 0 : (log_xact_sample_rate == 1 ||
1481 tgl@sss.pgh.pa.us 2105 [ # # ]: 0 : pg_prng_double(&pg_global_prng_state) <= log_xact_sample_rate);
2106 : :
2107 : : /*
2108 : : * initialize current transaction state fields
2109 : : *
2110 : : * note: prevXactReadOnly is not used at the outermost level
2111 : : */
2591 michael@paquier.xyz 2112 :CBC 330412 : s->nestingLevel = 1;
2113 : 330412 : s->gucNestLevel = 1;
2114 : 330412 : s->childXids = NULL;
2115 : 330412 : s->nChildXids = 0;
2116 : 330412 : s->maxChildXids = 0;
2117 : :
2118 : : /*
2119 : : * Once the current user ID and the security context flags are fetched,
2120 : : * both will be properly reset even if transaction startup fails.
2121 : : */
2122 : 330412 : GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
2123 : :
2124 : : /* SecurityRestrictionContext should never be set outside a transaction */
2125 [ - + ]: 330412 : Assert(s->prevSecContext == 0);
2126 : :
2127 : : /*
2128 : : * Make sure we've reset xact state variables
2129 : : *
2130 : : * If recovery is still in progress, mark this transaction as read-only.
2131 : : * We have lower level defences in XLogInsert and elsewhere to stop us
2132 : : * from modifying data during recovery, but this gives the normal
2133 : : * indication to the user that the transaction is read-only.
2134 : : */
5843 simon@2ndQuadrant.co 2135 [ + + ]: 330412 : if (RecoveryInProgress())
2136 : : {
2137 : 1193 : s->startedInRecovery = true;
2138 : 1193 : XactReadOnly = true;
2139 : : }
2140 : : else
2141 : : {
2142 : 329219 : s->startedInRecovery = false;
2143 : 329219 : XactReadOnly = DefaultXactReadOnly;
2144 : : }
5428 heikki.linnakangas@i 2145 : 330412 : XactDeferrable = DefaultXactDeferrable;
8099 tgl@sss.pgh.pa.us 2146 : 330412 : XactIsoLevel = DefaultXactIsoLevel;
6714 2147 : 330412 : forceSyncCommit = false;
3193 simon@2ndQuadrant.co 2148 : 330412 : MyXactFlags = 0;
2149 : :
2150 : : /*
2151 : : * reinitialize within-transaction counters
2152 : : */
7763 tgl@sss.pgh.pa.us 2153 : 330412 : s->subTransactionId = TopSubTransactionId;
2154 : 330412 : currentSubTransactionId = TopSubTransactionId;
2155 : 330412 : currentCommandId = FirstCommandId;
6593 2156 : 330412 : currentCommandIdUsed = false;
2157 : :
2158 : : /*
2159 : : * initialize reported xid accounting
2160 : : */
5843 simon@2ndQuadrant.co 2161 : 330412 : nUnreportedXids = 0;
4391 rhaas@postgresql.org 2162 : 330412 : s->didLogXid = false;
2163 : :
2164 : : /*
2165 : : * must initialize resource-management stuff first
2166 : : */
7824 tgl@sss.pgh.pa.us 2167 : 330412 : AtStart_Memory();
2168 : 330412 : AtStart_ResourceOwner();
2169 : :
2170 : : /*
2171 : : * Assign a new LocalTransactionId, and combine it with the proc number to
2172 : : * form a virtual transaction id.
2173 : : */
655 heikki.linnakangas@i 2174 : 330412 : vxid.procNumber = MyProcNumber;
6679 tgl@sss.pgh.pa.us 2175 : 330412 : vxid.localTransactionId = GetNextLocalTransactionId();
2176 : :
2177 : : /*
2178 : : * Lock the virtual transaction id before we announce it in the proc array
2179 : : */
2180 : 330412 : VirtualXactLockTableInsert(vxid);
2181 : :
2182 : : /*
2183 : : * Advertise it in the proc array. We assume assignment of
2184 : : * localTransactionId is atomic, and the proc number should be set
2185 : : * already.
2186 : : */
655 heikki.linnakangas@i 2187 [ - + ]: 330412 : Assert(MyProc->vxid.procNumber == vxid.procNumber);
2188 : 330412 : MyProc->vxid.lxid = vxid.localTransactionId;
2189 : :
2190 : : TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
2191 : :
2192 : : /*
2193 : : * set transaction_timestamp() (a/k/a now()). Normally, we want this to
2194 : : * be the same as the first command's statement_timestamp(), so don't do a
2195 : : * fresh GetCurrentTimestamp() call (which'd be expensive anyway). But
2196 : : * for transactions started inside procedures (i.e., nonatomic SPI
2197 : : * contexts), we do need to advance the timestamp. Also, in a parallel
2198 : : * worker, the timestamp should already have been provided by a call to
2199 : : * SetParallelStartTimestamps().
2200 : : */
2630 tgl@sss.pgh.pa.us 2201 [ + + ]: 330412 : if (!IsParallelWorker())
2202 : : {
2628 2203 [ + + ]: 326053 : if (!SPI_inside_nonatomic_context())
2204 : 323846 : xactStartTimestamp = stmtStartTimestamp;
2205 : : else
2206 : 2207 : xactStartTimestamp = GetCurrentTimestamp();
2207 : : }
2208 : : else
2630 2209 [ - + ]: 4359 : Assert(xactStartTimestamp != 0);
6673 2210 : 330412 : pgstat_report_xact_timestamp(xactStartTimestamp);
2211 : : /* Mark xactStopTimestamp as unset. */
2628 2212 : 330412 : xactStopTimestamp = 0;
2213 : :
2214 : : /*
2215 : : * initialize other subsystems for new transaction
2216 : : */
6681 2217 : 330412 : AtStart_GUC();
10329 bruce@momjian.us 2218 : 330412 : AtStart_Cache();
7769 tgl@sss.pgh.pa.us 2219 : 330412 : AfterTriggerBeginXact();
2220 : :
2221 : : /*
2222 : : * done with start processing, set current transaction state to "in
2223 : : * progress"
2224 : : */
10329 bruce@momjian.us 2225 : 330412 : s->state = TRANS_INPROGRESS;
2226 : :
2227 : : /* Schedule transaction timeout */
672 akorotkov@postgresql 2228 [ - + ]: 330412 : if (TransactionTimeout > 0)
672 akorotkov@postgresql 2229 :UBC 0 : enable_timeout_after(TRANSACTION_TIMEOUT, TransactionTimeout);
2230 : :
7840 tgl@sss.pgh.pa.us 2231 :CBC 330412 : ShowTransactionState("StartTransaction");
10754 scrappy@hub.org 2232 : 330412 : }
2233 : :
2234 : :
2235 : : /*
2236 : : * CommitTransaction
2237 : : *
2238 : : * NB: if you change this routine, better look at PrepareTransaction too!
2239 : : */
2240 : : static void
9186 tgl@sss.pgh.pa.us 2241 : 304318 : CommitTransaction(void)
2242 : : {
10329 bruce@momjian.us 2243 : 304318 : TransactionState s = CurrentTransactionState;
2244 : : TransactionId latestXid;
2245 : : bool is_parallel_worker;
2246 : :
3885 rhaas@postgresql.org 2247 : 304318 : is_parallel_worker = (s->blockState == TBLOCK_PARALLEL_INPROGRESS);
2248 : :
2249 : : /* Enforce parallel mode restrictions during parallel worker commit. */
3716 2250 [ + + ]: 304318 : if (is_parallel_worker)
2251 : 1447 : EnterParallelMode();
2252 : :
7840 tgl@sss.pgh.pa.us 2253 : 304318 : ShowTransactionState("CommitTransaction");
2254 : :
2255 : : /*
2256 : : * check the current transaction state
2257 : : */
10329 bruce@momjian.us 2258 [ - + ]: 304318 : if (s->state != TRANS_INPROGRESS)
7813 tgl@sss.pgh.pa.us 2259 [ # # ]:UBC 0 : elog(WARNING, "CommitTransaction while in %s state",
2260 : : TransStateAsString(s->state));
7840 tgl@sss.pgh.pa.us 2261 [ + - ]:CBC 304318 : Assert(s->parent == NULL);
2262 : :
2263 : : /*
2264 : : * Do pre-commit processing that involves calling user-defined code, such
2265 : : * as triggers. SECURITY_RESTRICTED_OPERATION contexts must not queue an
2266 : : * action that would run here, because that would bypass the sandbox.
2267 : : * Since closing cursors could queue trigger actions, triggers could open
2268 : : * cursors, etc, we have to keep looping until there's nothing left to do.
2269 : : */
2270 : : for (;;)
2271 : : {
2272 : : /*
2273 : : * Fire all currently pending deferred triggers.
2274 : : */
7556 2275 : 309348 : AfterTriggerFireDeferred();
2276 : :
2277 : : /*
2278 : : * Close open portals (converting holdable ones into static portals).
2279 : : * If there weren't any, we are done ... otherwise loop back to check
2280 : : * if they queued deferred triggers. Lather, rinse, repeat.
2281 : : */
5408 2282 [ + + ]: 309271 : if (!PreCommit_Portals(false))
7556 2283 : 304241 : break;
2284 : : }
2285 : :
2286 : : /*
2287 : : * The remaining actions cannot call any user-defined code, so it's safe
2288 : : * to start shutting down within-transaction services. But note that most
2289 : : * of this stuff could still throw an error, which would switch us into
2290 : : * the transaction-abort path.
2291 : : */
2292 : :
1865 noah@leadboat.com 2293 [ + + ]: 304241 : CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_PRE_COMMIT
2294 : : : XACT_EVENT_PRE_COMMIT);
2295 : :
2296 : : /*
2297 : : * If this xact has started any unfinished parallel operation, clean up
2298 : : * its workers, warning about leaked resources. (But we don't actually
2299 : : * reset parallelModeLevel till entering TRANS_COMMIT, a bit below. This
2300 : : * keeps parallel mode restrictions active as long as possible in a
2301 : : * parallel worker.)
2302 : : */
630 tgl@sss.pgh.pa.us 2303 : 304241 : AtEOXact_Parallel(true);
2304 [ + + ]: 304241 : if (is_parallel_worker)
2305 : : {
2306 [ - + ]: 1447 : if (s->parallelModeLevel != 1)
630 tgl@sss.pgh.pa.us 2307 [ # # ]:UBC 0 : elog(WARNING, "parallelModeLevel is %d not 1 at end of parallel worker transaction",
2308 : : s->parallelModeLevel);
2309 : : }
2310 : : else
2311 : : {
630 tgl@sss.pgh.pa.us 2312 [ - + ]:CBC 302794 : if (s->parallelModeLevel != 0)
630 tgl@sss.pgh.pa.us 2313 [ # # ]:UBC 0 : elog(WARNING, "parallelModeLevel is %d not 0 at end of transaction",
2314 : : s->parallelModeLevel);
2315 : : }
2316 : :
2317 : : /* Shut down the deferred-trigger manager */
5408 tgl@sss.pgh.pa.us 2318 :CBC 304241 : AfterTriggerEndXact(true);
2319 : :
2320 : : /*
2321 : : * Let ON COMMIT management do its thing (must happen after closing
2322 : : * cursors, to avoid dangling-reference problems)
2323 : : */
7720 2324 : 304241 : PreCommit_on_commit_actions();
2325 : :
2326 : : /*
2327 : : * Synchronize files that are created and not WAL-logged during this
2328 : : * transaction. This must happen before AtEOXact_RelationMap(), so that we
2329 : : * don't see committed-but-broken files after a crash.
2330 : : */
2084 noah@leadboat.com 2331 : 304238 : smgrDoPendingSyncs(true, is_parallel_worker);
2332 : :
2333 : : /* close large objects before lower-level cleanup */
7813 tgl@sss.pgh.pa.us 2334 : 304238 : AtEOXact_LargeObject(true);
2335 : :
2336 : : /*
2337 : : * Insert notifications sent by NOTIFY commands into the queue. This
2338 : : * should be late in the pre-commit sequence to minimize time spent
2339 : : * holding the notify-insertion lock. However, this could result in
2340 : : * creating a snapshot, so we must do it before serializable cleanup.
2341 : : */
2216 2342 : 304238 : PreCommit_Notify();
2343 : :
2344 : : /*
2345 : : * Mark serializable transaction as complete for predicate locking
2346 : : * purposes. This should be done as late as we can put it and still allow
2347 : : * errors to be raised for failure patterns found at commit. This is not
2348 : : * appropriate in a parallel worker however, because we aren't committing
2349 : : * the leader's transaction and its serializable state will live on.
2350 : : */
2470 tmunro@postgresql.or 2351 [ + + ]: 304238 : if (!is_parallel_worker)
2352 : 302791 : PreCommit_CheckForSerializationFailure();
2353 : :
2354 : : /* Prevent cancel/die interrupt while cleaning up */
7720 tgl@sss.pgh.pa.us 2355 : 304083 : HOLD_INTERRUPTS();
2356 : :
2357 : : /* Commit updates to the relation map --- do this as late as possible */
2687 pg@bowt.ie 2358 : 304083 : AtEOXact_RelationMap(true, is_parallel_worker);
2359 : :
2360 : : /*
2361 : : * set the current transaction state information appropriately during
2362 : : * commit processing
2363 : : */
7720 tgl@sss.pgh.pa.us 2364 : 304083 : s->state = TRANS_COMMIT;
3716 rhaas@postgresql.org 2365 : 304083 : s->parallelModeLevel = 0;
630 tgl@sss.pgh.pa.us 2366 : 304083 : s->parallelChildXact = false; /* should be false already */
2367 : :
2368 : : /* Disable transaction timeout */
671 akorotkov@postgresql 2369 [ - + ]: 304083 : if (TransactionTimeout > 0)
671 akorotkov@postgresql 2370 :UBC 0 : disable_timeout(TRANSACTION_TIMEOUT, false);
2371 : :
3885 rhaas@postgresql.org 2372 [ + + ]:CBC 304083 : if (!is_parallel_worker)
2373 : : {
2374 : : /*
2375 : : * We need to mark our XIDs as committed in pg_xact. This is where we
2376 : : * durably commit.
2377 : : */
2378 : 302636 : latestXid = RecordTransactionCommit();
2379 : : }
2380 : : else
2381 : : {
2382 : : /*
2383 : : * We must not mark our XID committed; the parallel leader is
2384 : : * responsible for that.
2385 : : */
2386 : 1447 : latestXid = InvalidTransactionId;
2387 : :
2388 : : /*
2389 : : * Make sure the leader will know about any WAL we wrote before it
2390 : : * commits.
2391 : : */
2392 : 1447 : ParallelWorkerReportLastRecEnd(XactLastRecEnd);
2393 : : }
2394 : :
2395 : : TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->vxid.lxid);
2396 : :
2397 : : /*
2398 : : * Let others know about no transaction in progress by me. Note that this
2399 : : * must be done _before_ releasing locks we hold and _after_
2400 : : * RecordTransactionCommit.
2401 : : */
6676 tgl@sss.pgh.pa.us 2402 : 304083 : ProcArrayEndTransaction(MyProc, latestXid);
2403 : :
2404 : : /*
2405 : : * This is all post-commit cleanup. Note that if an error is raised here,
2406 : : * it's too late to abort the transaction. This should be just
2407 : : * noncritical resource releasing.
2408 : : *
2409 : : * The ordering of operations is not entirely random. The idea is:
2410 : : * release resources visible to other backends (eg, files, buffer pins);
2411 : : * then release locks; then release backend-local resources. We want to
2412 : : * release locks at the point where any backend waiting for us will see
2413 : : * our transaction as being fully cleaned up.
2414 : : *
2415 : : * Resources that can be associated with individual queries are handled by
2416 : : * the ResourceOwner mechanism. The other calls here are for backend-wide
2417 : : * state.
2418 : : */
2419 : :
3885 rhaas@postgresql.org 2420 : 304083 : CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_COMMIT
2421 : : : XACT_EVENT_COMMIT);
2422 : :
764 heikki.linnakangas@i 2423 : 304083 : CurrentResourceOwner = NULL;
7824 tgl@sss.pgh.pa.us 2424 : 304083 : ResourceOwnerRelease(TopTransactionResourceOwner,
2425 : : RESOURCE_RELEASE_BEFORE_LOCKS,
2426 : : true, true);
2427 : :
276 andres@anarazel.de 2428 : 304083 : AtEOXact_Aio(true);
2429 : :
2430 : : /* Check we've released all buffer pins */
7733 tgl@sss.pgh.pa.us 2431 : 304083 : AtEOXact_Buffers(true);
2432 : :
2433 : : /* Clean up the relation cache */
7437 2434 : 304083 : AtEOXact_RelationCache(true);
2435 : :
2436 : : /* Clean up the type cache */
420 akorotkov@postgresql 2437 : 304083 : AtEOXact_TypeCache();
2438 : :
2439 : : /*
2440 : : * Make catalog changes visible to all backends. This has to happen after
2441 : : * relcache references are dropped (see comments for
2442 : : * AtEOXact_RelationCache), but before locks are released (if anyone is
2443 : : * waiting for lock on a relation we've modified, we want them to know
2444 : : * about the catalog change before they start using the relation).
2445 : : */
7824 tgl@sss.pgh.pa.us 2446 : 304083 : AtEOXact_Inval(true);
2447 : :
7539 2448 : 304083 : AtEOXact_MultiXact();
2449 : :
7824 2450 : 304083 : ResourceOwnerRelease(TopTransactionResourceOwner,
2451 : : RESOURCE_RELEASE_LOCKS,
2452 : : true, true);
2453 : 304083 : ResourceOwnerRelease(TopTransactionResourceOwner,
2454 : : RESOURCE_RELEASE_AFTER_LOCKS,
2455 : : true, true);
2456 : :
2457 : : /*
2458 : : * Likewise, dropping of files deleted during the transaction is best done
2459 : : * after releasing relcache and buffer pins. (This is not strictly
2460 : : * necessary during commit, since such pins should have been released
2461 : : * already, but this ordering is definitely critical during abort.) Since
2462 : : * this may take many seconds, also delay until after releasing locks.
2463 : : * Other backends will observe the attendant catalog changes and not
2464 : : * attempt to access affected files.
2465 : : */
4935 rhaas@postgresql.org 2466 : 304083 : smgrDoPendingDeletes(true);
2467 : :
2468 : : /*
2469 : : * Send out notification signals to other backends (and do other
2470 : : * post-commit NOTIFY cleanup). This must not happen until after our
2471 : : * transaction is fully done from the viewpoint of other backends.
2472 : : */
5784 tgl@sss.pgh.pa.us 2473 : 304083 : AtCommit_Notify();
2474 : :
2475 : : /*
2476 : : * Everything after this should be purely internal-to-this-backend
2477 : : * cleanup.
2478 : : */
6681 2479 : 304083 : AtEOXact_GUC(true, 1);
8052 mail@joeconway.com 2480 : 304083 : AtEOXact_SPI(true);
2627 tmunro@postgresql.or 2481 : 304083 : AtEOXact_Enum();
7763 tgl@sss.pgh.pa.us 2482 : 304083 : AtEOXact_on_commit_actions(true);
3885 rhaas@postgresql.org 2483 : 304083 : AtEOXact_Namespace(true, is_parallel_worker);
4810 tgl@sss.pgh.pa.us 2484 : 304083 : AtEOXact_SMgr();
2791 2485 : 304083 : AtEOXact_Files(true);
6887 2486 : 304083 : AtEOXact_ComboCid();
6811 2487 : 304083 : AtEOXact_HashTables(true);
2444 akapila@postgresql.o 2488 : 304083 : AtEOXact_PgStat(true, is_parallel_worker);
3178 simon@2ndQuadrant.co 2489 : 304083 : AtEOXact_Snapshot(true, false);
3153 peter_e@gmx.net 2490 : 304083 : AtEOXact_ApplyLauncher(true);
1077 tgl@sss.pgh.pa.us 2491 : 304083 : AtEOXact_LogicalRepWorkers(true);
6673 2492 : 304083 : pgstat_report_xact_timestamp(0);
2493 : :
7824 2494 : 304083 : ResourceOwnerDelete(TopTransactionResourceOwner);
2495 : 304083 : s->curTransactionOwner = NULL;
2496 : 304083 : CurTransactionResourceOwner = NULL;
2497 : 304083 : TopTransactionResourceOwner = NULL;
2498 : :
8458 2499 : 304083 : AtCommit_Memory();
2500 : :
2457 tmunro@postgresql.or 2501 : 304083 : s->fullTransactionId = InvalidFullTransactionId;
7763 tgl@sss.pgh.pa.us 2502 : 304083 : s->subTransactionId = InvalidSubTransactionId;
7840 2503 : 304083 : s->nestingLevel = 0;
6681 2504 : 304083 : s->gucNestLevel = 0;
6485 2505 : 304083 : s->childXids = NULL;
2506 : 304083 : s->nChildXids = 0;
2507 : 304083 : s->maxChildXids = 0;
2508 : :
2457 tmunro@postgresql.or 2509 : 304083 : XactTopFullTransactionId = InvalidFullTransactionId;
3885 rhaas@postgresql.org 2510 : 304083 : nParallelCurrentXids = 0;
2511 : :
2512 : : /*
2513 : : * done with commit processing, set current transaction state back to
2514 : : * default
2515 : : */
10329 bruce@momjian.us 2516 : 304083 : s->state = TRANS_DEFAULT;
2517 : :
9099 tgl@sss.pgh.pa.us 2518 [ - + ]: 304083 : RESUME_INTERRUPTS();
10754 scrappy@hub.org 2519 : 304083 : }
2520 : :
2521 : :
2522 : : /*
2523 : : * PrepareTransaction
2524 : : *
2525 : : * NB: if you change this routine, better look at CommitTransaction too!
2526 : : */
2527 : : static void
7489 tgl@sss.pgh.pa.us 2528 : 344 : PrepareTransaction(void)
2529 : : {
7369 bruce@momjian.us 2530 : 344 : TransactionState s = CurrentTransactionState;
164 michael@paquier.xyz 2531 :GNC 344 : FullTransactionId fxid = GetCurrentFullTransactionId();
2532 : : GlobalTransaction gxact;
2533 : : TimestampTz prepared_at;
2534 : :
3885 rhaas@postgresql.org 2535 [ - + ]:CBC 344 : Assert(!IsInParallelMode());
2536 : :
7489 tgl@sss.pgh.pa.us 2537 : 344 : ShowTransactionState("PrepareTransaction");
2538 : :
2539 : : /*
2540 : : * check the current transaction state
2541 : : */
2542 [ - + ]: 344 : if (s->state != TRANS_INPROGRESS)
7489 tgl@sss.pgh.pa.us 2543 [ # # ]:UBC 0 : elog(WARNING, "PrepareTransaction while in %s state",
2544 : : TransStateAsString(s->state));
7489 tgl@sss.pgh.pa.us 2545 [ + - ]:CBC 344 : Assert(s->parent == NULL);
2546 : :
2547 : : /*
2548 : : * Do pre-commit processing that involves calling user-defined code, such
2549 : : * as triggers. Since closing cursors could queue trigger actions,
2550 : : * triggers could open cursors, etc, we have to keep looping until there's
2551 : : * nothing left to do.
2552 : : */
2553 : : for (;;)
2554 : : {
2555 : : /*
2556 : : * Fire all currently pending deferred triggers.
2557 : : */
2558 : 347 : AfterTriggerFireDeferred();
2559 : :
2560 : : /*
2561 : : * Close open portals (converting holdable ones into static portals).
2562 : : * If there weren't any, we are done ... otherwise loop back to check
2563 : : * if they queued deferred triggers. Lather, rinse, repeat.
2564 : : */
5408 2565 [ + + ]: 347 : if (!PreCommit_Portals(true))
7489 2566 : 344 : break;
2567 : : }
2568 : :
4690 2569 : 344 : CallXactCallbacks(XACT_EVENT_PRE_PREPARE);
2570 : :
2571 : : /*
2572 : : * The remaining actions cannot call any user-defined code, so it's safe
2573 : : * to start shutting down within-transaction services. But note that most
2574 : : * of this stuff could still throw an error, which would switch us into
2575 : : * the transaction-abort path.
2576 : : */
2577 : :
2578 : : /* Shut down the deferred-trigger manager */
5408 2579 : 343 : AfterTriggerEndXact(true);
2580 : :
2581 : : /*
2582 : : * Let ON COMMIT management do its thing (must happen after closing
2583 : : * cursors, to avoid dangling-reference problems)
2584 : : */
7489 2585 : 343 : PreCommit_on_commit_actions();
2586 : :
2587 : : /*
2588 : : * Synchronize files that are created and not WAL-logged during this
2589 : : * transaction. This must happen before EndPrepare(), so that we don't see
2590 : : * committed-but-broken files after a crash and COMMIT PREPARED.
2591 : : */
2084 noah@leadboat.com 2592 : 343 : smgrDoPendingSyncs(true, false);
2593 : :
2594 : : /* close large objects before lower-level cleanup */
7489 tgl@sss.pgh.pa.us 2595 : 343 : AtEOXact_LargeObject(true);
2596 : :
2597 : : /* NOTIFY requires no work at this point */
2598 : :
2599 : : /*
2600 : : * Mark serializable transaction as complete for predicate locking
2601 : : * purposes. This should be done as late as we can put it and still allow
2602 : : * errors to be raised for failure patterns found at commit.
2603 : : */
5428 heikki.linnakangas@i 2604 : 343 : PreCommit_CheckForSerializationFailure();
2605 : :
2606 : : /*
2607 : : * Don't allow PREPARE TRANSACTION if we've accessed a temporary table in
2608 : : * this transaction. Having the prepared xact hold locks on another
2609 : : * backend's temp table seems a bad idea --- for instance it would prevent
2610 : : * the backend from exiting. There are other problems too, such as how to
2611 : : * clean up the source backend's local buffers and ON COMMIT state if the
2612 : : * prepared xact includes a DROP of a temp table.
2613 : : *
2614 : : * Other objects types, like functions, operators or extensions, share the
2615 : : * same restriction as they should not be created, locked or dropped as
2616 : : * this can mess up with this session or even a follow-up session trying
2617 : : * to use the same temporary namespace.
2618 : : *
2619 : : * We must check this after executing any ON COMMIT actions, because they
2620 : : * might still access a temp relation.
2621 : : *
2622 : : * XXX In principle this could be relaxed to allow some useful special
2623 : : * cases, such as a temp table created and dropped all within the
2624 : : * transaction. That seems to require much more bookkeeping though.
2625 : : */
2526 michael@paquier.xyz 2626 [ + + ]: 343 : if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
2627 [ + - ]: 34 : ereport(ERROR,
2628 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2629 : : errmsg("cannot PREPARE a transaction that has operated on temporary objects")));
2630 : :
2631 : : /*
2632 : : * Likewise, don't allow PREPARE after pg_export_snapshot. This could be
2633 : : * supported if we added cleanup logic to twophase.c, but for now it
2634 : : * doesn't seem worth the trouble.
2635 : : */
5171 tgl@sss.pgh.pa.us 2636 [ - + ]: 309 : if (XactHasExportedSnapshots())
5171 tgl@sss.pgh.pa.us 2637 [ # # ]:UBC 0 : ereport(ERROR,
2638 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2639 : : errmsg("cannot PREPARE a transaction that has exported snapshots")));
2640 : :
2641 : : /* Prevent cancel/die interrupt while cleaning up */
7489 tgl@sss.pgh.pa.us 2642 :CBC 309 : HOLD_INTERRUPTS();
2643 : :
2644 : : /*
2645 : : * set the current transaction state information appropriately during
2646 : : * prepare processing
2647 : : */
2648 : 309 : s->state = TRANS_PREPARE;
2649 : :
2650 : : /* Disable transaction timeout */
671 akorotkov@postgresql 2651 [ - + ]: 309 : if (TransactionTimeout > 0)
671 akorotkov@postgresql 2652 :UBC 0 : disable_timeout(TRANSACTION_TIMEOUT, false);
2653 : :
7477 tgl@sss.pgh.pa.us 2654 :CBC 309 : prepared_at = GetCurrentTimestamp();
2655 : :
2656 : : /*
2657 : : * Reserve the GID for this transaction. This could fail if the requested
2658 : : * GID is invalid or already in use.
2659 : : */
164 michael@paquier.xyz 2660 :GNC 309 : gxact = MarkAsPreparing(fxid, prepareGID, prepared_at,
2661 : : GetUserId(), MyDatabaseId);
7489 tgl@sss.pgh.pa.us 2662 :CBC 290 : prepareGID = NULL;
2663 : :
2664 : : /*
2665 : : * Collect data for the 2PC state file. Note that in general, no actual
2666 : : * state change should happen in the called modules during this step,
2667 : : * since it's still possible to fail before commit, and in that case we
2668 : : * want transaction abort to be able to clean up. (In particular, the
2669 : : * AtPrepare routines may error out if they find cases they cannot
2670 : : * handle.) State cleanup should happen in the PostPrepare routines
2671 : : * below. However, some modules can go ahead and clear state here because
2672 : : * they wouldn't do anything with it during abort anyway.
2673 : : *
2674 : : * Note: because the 2PC state file records will be replayed in the same
2675 : : * order they are made, the order of these calls has to match the order in
2676 : : * which we want things to happen during COMMIT PREPARED or ROLLBACK
2677 : : * PREPARED; in particular, pay attention to whether things should happen
2678 : : * before or after releasing the transaction's locks.
2679 : : */
2680 : 290 : StartPrepare(gxact);
2681 : :
2682 : 290 : AtPrepare_Notify();
2683 : 290 : AtPrepare_Locks();
5428 heikki.linnakangas@i 2684 : 288 : AtPrepare_PredicateLocks();
6780 tgl@sss.pgh.pa.us 2685 : 288 : AtPrepare_PgStat();
5869 heikki.linnakangas@i 2686 : 288 : AtPrepare_MultiXact();
5793 tgl@sss.pgh.pa.us 2687 : 288 : AtPrepare_RelationMap();
2688 : :
2689 : : /*
2690 : : * Here is where we really truly prepare.
2691 : : *
2692 : : * We have to record transaction prepares even if we didn't make any
2693 : : * updates, because the transaction manager might get confused if we lose
2694 : : * a global transaction.
2695 : : */
7489 2696 : 288 : EndPrepare(gxact);
2697 : :
2698 : : /*
2699 : : * Now we clean up backend-internal state and release internal resources.
2700 : : */
2701 : :
2702 : : /* Reset XactLastRecEnd until the next transaction writes something */
4925 heikki.linnakangas@i 2703 : 288 : XactLastRecEnd = 0;
2704 : :
2705 : : /*
2706 : : * Transfer our locks to a dummy PGPROC. This has to be done before
2707 : : * ProcArrayClearTransaction(). Otherwise, a GetLockConflicts() would
2708 : : * conclude "xact already committed or aborted" for our locks.
2709 : : */
164 michael@paquier.xyz 2710 :GNC 288 : PostPrepare_Locks(fxid);
2711 : :
2712 : : /*
2713 : : * Let others know about no transaction in progress by me. This has to be
2714 : : * done *after* the prepared transaction has been marked valid, else
2715 : : * someone may think it is unlocked and recyclable.
2716 : : */
6676 tgl@sss.pgh.pa.us 2717 :CBC 288 : ProcArrayClearTransaction(MyProc);
2718 : :
2719 : : /*
2720 : : * In normal commit-processing, this is all non-critical post-transaction
2721 : : * cleanup. When the transaction is prepared, however, it's important
2722 : : * that the locks and other per-backend resources are transferred to the
2723 : : * prepared transaction's PGPROC entry. Note that if an error is raised
2724 : : * here, it's too late to abort the transaction. XXX: This probably should
2725 : : * be in a critical section, to force a PANIC if any of this fails, but
2726 : : * that cure could be worse than the disease.
2727 : : */
2728 : :
7489 2729 : 288 : CallXactCallbacks(XACT_EVENT_PREPARE);
2730 : :
2731 : 288 : ResourceOwnerRelease(TopTransactionResourceOwner,
2732 : : RESOURCE_RELEASE_BEFORE_LOCKS,
2733 : : true, true);
2734 : :
276 andres@anarazel.de 2735 : 288 : AtEOXact_Aio(true);
2736 : :
2737 : : /* Check we've released all buffer pins */
7489 tgl@sss.pgh.pa.us 2738 : 288 : AtEOXact_Buffers(true);
2739 : :
2740 : : /* Clean up the relation cache */
7437 2741 : 288 : AtEOXact_RelationCache(true);
2742 : :
2743 : : /* Clean up the type cache */
420 akorotkov@postgresql 2744 : 288 : AtEOXact_TypeCache();
2745 : :
2746 : : /* notify doesn't need a postprepare call */
2747 : :
6780 tgl@sss.pgh.pa.us 2748 : 288 : PostPrepare_PgStat();
2749 : :
7489 2750 : 288 : PostPrepare_Inval();
2751 : :
2752 : 288 : PostPrepare_smgr();
2753 : :
164 michael@paquier.xyz 2754 :GNC 288 : PostPrepare_MultiXact(fxid);
2755 : :
2756 : 288 : PostPrepare_PredicateLocks(fxid);
2757 : :
7489 tgl@sss.pgh.pa.us 2758 :CBC 288 : ResourceOwnerRelease(TopTransactionResourceOwner,
2759 : : RESOURCE_RELEASE_LOCKS,
2760 : : true, true);
2761 : 288 : ResourceOwnerRelease(TopTransactionResourceOwner,
2762 : : RESOURCE_RELEASE_AFTER_LOCKS,
2763 : : true, true);
2764 : :
2765 : : /*
2766 : : * Allow another backend to finish the transaction. After
2767 : : * PostPrepare_Twophase(), the transaction is completely detached from our
2768 : : * backend. The rest is just non-critical cleanup of backend-local state.
2769 : : */
4235 heikki.linnakangas@i 2770 : 288 : PostPrepare_Twophase();
2771 : :
2772 : : /* PREPARE acts the same as COMMIT as far as GUC is concerned */
6681 tgl@sss.pgh.pa.us 2773 : 288 : AtEOXact_GUC(true, 1);
7489 2774 : 288 : AtEOXact_SPI(true);
2627 tmunro@postgresql.or 2775 : 288 : AtEOXact_Enum();
7489 tgl@sss.pgh.pa.us 2776 : 288 : AtEOXact_on_commit_actions(true);
3885 rhaas@postgresql.org 2777 : 288 : AtEOXact_Namespace(true, false);
4810 tgl@sss.pgh.pa.us 2778 : 288 : AtEOXact_SMgr();
2791 2779 : 288 : AtEOXact_Files(true);
6887 2780 : 288 : AtEOXact_ComboCid();
6811 2781 : 288 : AtEOXact_HashTables(true);
2782 : : /* don't call AtEOXact_PgStat here; we fixed pgstat state above */
3178 simon@2ndQuadrant.co 2783 : 288 : AtEOXact_Snapshot(true, true);
2784 : : /* we treat PREPARE as ROLLBACK so far as waking workers goes */
1077 tgl@sss.pgh.pa.us 2785 : 288 : AtEOXact_ApplyLauncher(false);
2786 : 288 : AtEOXact_LogicalRepWorkers(false);
4256 2787 : 288 : pgstat_report_xact_timestamp(0);
2788 : :
7489 2789 : 288 : CurrentResourceOwner = NULL;
2790 : 288 : ResourceOwnerDelete(TopTransactionResourceOwner);
2791 : 288 : s->curTransactionOwner = NULL;
2792 : 288 : CurTransactionResourceOwner = NULL;
2793 : 288 : TopTransactionResourceOwner = NULL;
2794 : :
2795 : 288 : AtCommit_Memory();
2796 : :
2457 tmunro@postgresql.or 2797 : 288 : s->fullTransactionId = InvalidFullTransactionId;
7489 tgl@sss.pgh.pa.us 2798 : 288 : s->subTransactionId = InvalidSubTransactionId;
2799 : 288 : s->nestingLevel = 0;
6681 2800 : 288 : s->gucNestLevel = 0;
6485 2801 : 288 : s->childXids = NULL;
2802 : 288 : s->nChildXids = 0;
2803 : 288 : s->maxChildXids = 0;
2804 : :
2457 tmunro@postgresql.or 2805 : 288 : XactTopFullTransactionId = InvalidFullTransactionId;
3885 rhaas@postgresql.org 2806 : 288 : nParallelCurrentXids = 0;
2807 : :
2808 : : /*
2809 : : * done with 1st phase commit processing, set current transaction state
2810 : : * back to default
2811 : : */
7489 tgl@sss.pgh.pa.us 2812 : 288 : s->state = TRANS_DEFAULT;
2813 : :
2814 [ - + ]: 288 : RESUME_INTERRUPTS();
2815 : 288 : }
2816 : :
2817 : :
2818 : : /*
2819 : : * AbortTransaction
2820 : : */
2821 : : static void
9186 2822 : 26041 : AbortTransaction(void)
2823 : : {
10329 bruce@momjian.us 2824 : 26041 : TransactionState s = CurrentTransactionState;
2825 : : TransactionId latestXid;
2826 : : bool is_parallel_worker;
2827 : :
2828 : : /* Prevent cancel/die interrupt while cleaning up */
9099 tgl@sss.pgh.pa.us 2829 : 26041 : HOLD_INTERRUPTS();
2830 : :
2831 : : /* Disable transaction timeout */
671 akorotkov@postgresql 2832 [ - + ]: 26041 : if (TransactionTimeout > 0)
671 akorotkov@postgresql 2833 :UBC 0 : disable_timeout(TRANSACTION_TIMEOUT, false);
2834 : :
2835 : : /* Make sure we have a valid memory context and resource owner */
6965 tgl@sss.pgh.pa.us 2836 :CBC 26041 : AtAbort_Memory();
2837 : 26041 : AtAbort_ResourceOwner();
2838 : :
2839 : : /*
2840 : : * Release any LW locks we might be holding as quickly as possible.
2841 : : * (Regular locks, however, must be held till we finish aborting.)
2842 : : * Releasing LW locks is critical since we might try to grab them again
2843 : : * while cleaning up!
2844 : : */
8846 2845 : 26041 : LWLockReleaseAll();
2846 : :
2847 : : /*
2848 : : * Cleanup waiting for LSN if any.
2849 : : */
43 akorotkov@postgresql 2850 :GNC 26041 : WaitLSNCleanup();
2851 : :
2852 : : /* Clear wait information and command progress indicator */
3570 rhaas@postgresql.org 2853 :CBC 26041 : pgstat_report_wait_end();
2854 : 26041 : pgstat_progress_end_command();
2855 : :
276 andres@anarazel.de 2856 : 26041 : pgaio_error_cleanup();
2857 : :
2858 : : /* Clean up buffer content locks, too */
9131 tgl@sss.pgh.pa.us 2859 : 26041 : UnlockBuffers();
2860 : :
2861 : : /* Reset WAL record construction state */
4046 heikki.linnakangas@i 2862 : 26041 : XLogResetInsertion();
2863 : :
2864 : : /* Cancel condition variable sleep */
3313 rhaas@postgresql.org 2865 : 26041 : ConditionVariableCancelSleep();
2866 : :
2867 : : /*
2868 : : * Also clean up any open wait for lock, since the lock manager will choke
2869 : : * if we try to wait for another lock before doing this.
2870 : : */
4992 2871 : 26041 : LockErrorCleanup();
2872 : :
2873 : : /*
2874 : : * If any timeout events are still active, make sure the timeout interrupt
2875 : : * is scheduled. This covers possible loss of a timeout interrupt due to
2876 : : * longjmp'ing out of the SIGINT handler (see notes in handle_sig_alarm).
2877 : : * We delay this till after LockErrorCleanup so that we don't uselessly
2878 : : * reschedule lock or deadlock check timeouts.
2879 : : */
4402 tgl@sss.pgh.pa.us 2880 : 26041 : reschedule_timeouts();
2881 : :
2882 : : /*
2883 : : * Re-enable signals, in case we got here by longjmp'ing out of a signal
2884 : : * handler. We do this fairly early in the sequence so that the timeout
2885 : : * infrastructure will be functional if needed while aborting.
2886 : : */
1049 tmunro@postgresql.or 2887 : 26041 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
2888 : :
2889 : : /*
2890 : : * check the current transaction state
2891 : : */
3885 rhaas@postgresql.org 2892 : 26041 : is_parallel_worker = (s->blockState == TBLOCK_PARALLEL_INPROGRESS);
7489 tgl@sss.pgh.pa.us 2893 [ + + - + ]: 26041 : if (s->state != TRANS_INPROGRESS && s->state != TRANS_PREPARE)
7813 tgl@sss.pgh.pa.us 2894 [ # # ]:UBC 0 : elog(WARNING, "AbortTransaction while in %s state",
2895 : : TransStateAsString(s->state));
7840 tgl@sss.pgh.pa.us 2896 [ - + ]:CBC 26041 : Assert(s->parent == NULL);
2897 : :
2898 : : /*
2899 : : * set the current transaction state information appropriately during the
2900 : : * abort processing
2901 : : */
10329 bruce@momjian.us 2902 : 26041 : s->state = TRANS_ABORT;
2903 : :
2904 : : /*
2905 : : * Reset user ID which might have been changed transiently. We need this
2906 : : * to clean up in case control escaped out of a SECURITY DEFINER function
2907 : : * or other local change of CurrentUserId; therefore, the prior value of
2908 : : * SecurityRestrictionContext also needs to be restored.
2909 : : *
2910 : : * (Note: it is not necessary to restore session authorization or role
2911 : : * settings here because those can only be changed via GUC, and GUC will
2912 : : * take care of rolling them back if need be.)
2913 : : */
5853 tgl@sss.pgh.pa.us 2914 : 26041 : SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
2915 : :
2916 : : /* Forget about any active REINDEX. */
2067 2917 : 26041 : ResetReindexState(s->nestingLevel);
2918 : :
2919 : : /* Reset logical streaming state. */
1958 akapila@postgresql.o 2920 : 26041 : ResetLogicalStreamingState();
2921 : :
2922 : : /* Reset snapshot export state. */
1522 michael@paquier.xyz 2923 : 26041 : SnapBuildResetExportedSnapshotState();
2924 : :
2925 : : /*
2926 : : * If this xact has started any unfinished parallel operation, clean up
2927 : : * its workers and exit parallel mode. Don't warn about leaked resources.
2928 : : */
630 tgl@sss.pgh.pa.us 2929 : 26041 : AtEOXact_Parallel(false);
2930 : 26041 : s->parallelModeLevel = 0;
2931 : 26041 : s->parallelChildXact = false; /* should be false already */
2932 : :
2933 : : /*
2934 : : * do abort processing
2935 : : */
5774 bruce@momjian.us 2936 : 26041 : AfterTriggerEndXact(false); /* 'false' means it's abort */
8266 tgl@sss.pgh.pa.us 2937 : 26041 : AtAbort_Portals();
2084 noah@leadboat.com 2938 : 26041 : smgrDoPendingSyncs(false, is_parallel_worker);
5793 tgl@sss.pgh.pa.us 2939 : 26041 : AtEOXact_LargeObject(false);
9935 2940 : 26041 : AtAbort_Notify();
2687 pg@bowt.ie 2941 : 26041 : AtEOXact_RelationMap(false, is_parallel_worker);
4235 heikki.linnakangas@i 2942 : 26041 : AtAbort_Twophase();
2943 : :
2944 : : /*
2945 : : * Advertise the fact that we aborted in pg_xact (assuming that we got as
2946 : : * far as assigning an XID to advertise). But if we're inside a parallel
2947 : : * worker, skip this; the user backend must be the one to write the abort
2948 : : * record.
2949 : : */
3885 rhaas@postgresql.org 2950 [ + + ]: 26041 : if (!is_parallel_worker)
2951 : 26035 : latestXid = RecordTransactionAbort(false);
2952 : : else
2953 : : {
2954 : 6 : latestXid = InvalidTransactionId;
2955 : :
2956 : : /*
2957 : : * Since the parallel leader won't get our value of XactLastRecEnd in
2958 : : * this case, we nudge WAL-writer ourselves in this case. See related
2959 : : * comments in RecordTransactionAbort for why this matters.
2960 : : */
2961 : 6 : XLogSetAsyncXactLSN(XactLastRecEnd);
2962 : : }
2963 : :
2964 : : TRACE_POSTGRESQL_TRANSACTION_ABORT(MyProc->vxid.lxid);
2965 : :
2966 : : /*
2967 : : * Let others know about no transaction in progress by me. Note that this
2968 : : * must be done _before_ releasing locks we hold and _after_
2969 : : * RecordTransactionAbort.
2970 : : */
6676 tgl@sss.pgh.pa.us 2971 : 26041 : ProcArrayEndTransaction(MyProc, latestXid);
2972 : :
2973 : : /*
2974 : : * Post-abort cleanup. See notes in CommitTransaction() concerning
2975 : : * ordering. We can skip all of it if the transaction failed before
2976 : : * creating a resource owner.
2977 : : */
5807 2978 [ + - ]: 26041 : if (TopTransactionResourceOwner != NULL)
2979 : : {
3885 rhaas@postgresql.org 2980 [ + + ]: 26041 : if (is_parallel_worker)
2981 : 6 : CallXactCallbacks(XACT_EVENT_PARALLEL_ABORT);
2982 : : else
2983 : 26035 : CallXactCallbacks(XACT_EVENT_ABORT);
2984 : :
5807 tgl@sss.pgh.pa.us 2985 : 26041 : ResourceOwnerRelease(TopTransactionResourceOwner,
2986 : : RESOURCE_RELEASE_BEFORE_LOCKS,
2987 : : false, true);
276 andres@anarazel.de 2988 : 26041 : AtEOXact_Aio(false);
5807 tgl@sss.pgh.pa.us 2989 : 26041 : AtEOXact_Buffers(false);
2990 : 26041 : AtEOXact_RelationCache(false);
420 akorotkov@postgresql 2991 : 26041 : AtEOXact_TypeCache();
5807 tgl@sss.pgh.pa.us 2992 : 26041 : AtEOXact_Inval(false);
2993 : 26041 : AtEOXact_MultiXact();
2994 : 26041 : ResourceOwnerRelease(TopTransactionResourceOwner,
2995 : : RESOURCE_RELEASE_LOCKS,
2996 : : false, true);
2997 : 26041 : ResourceOwnerRelease(TopTransactionResourceOwner,
2998 : : RESOURCE_RELEASE_AFTER_LOCKS,
2999 : : false, true);
4935 rhaas@postgresql.org 3000 : 26041 : smgrDoPendingDeletes(false);
3001 : :
5807 tgl@sss.pgh.pa.us 3002 : 26041 : AtEOXact_GUC(false, 1);
3003 : 26041 : AtEOXact_SPI(false);
2627 tmunro@postgresql.or 3004 : 26041 : AtEOXact_Enum();
5807 tgl@sss.pgh.pa.us 3005 : 26041 : AtEOXact_on_commit_actions(false);
3885 rhaas@postgresql.org 3006 : 26041 : AtEOXact_Namespace(false, is_parallel_worker);
4810 tgl@sss.pgh.pa.us 3007 : 26041 : AtEOXact_SMgr();
2791 3008 : 26041 : AtEOXact_Files(false);
5807 3009 : 26041 : AtEOXact_ComboCid();
3010 : 26041 : AtEOXact_HashTables(false);
2444 akapila@postgresql.o 3011 : 26041 : AtEOXact_PgStat(false, is_parallel_worker);
3153 peter_e@gmx.net 3012 : 26041 : AtEOXact_ApplyLauncher(false);
1077 tgl@sss.pgh.pa.us 3013 : 26041 : AtEOXact_LogicalRepWorkers(false);
5807 3014 : 26041 : pgstat_report_xact_timestamp(0);
3015 : : }
3016 : :
3017 : : /*
3018 : : * State remains TRANS_ABORT until CleanupTransaction().
3019 : : */
9099 3020 [ - + ]: 26041 : RESUME_INTERRUPTS();
9304 3021 : 26041 : }
3022 : :
3023 : : /*
3024 : : * CleanupTransaction
3025 : : */
3026 : : static void
9186 3027 : 26041 : CleanupTransaction(void)
3028 : : {
9304 3029 : 26041 : TransactionState s = CurrentTransactionState;
3030 : :
3031 : : /*
3032 : : * State should still be TRANS_ABORT from AbortTransaction().
3033 : : */
3034 [ - + ]: 26041 : if (s->state != TRANS_ABORT)
7810 tgl@sss.pgh.pa.us 3035 [ # # ]:UBC 0 : elog(FATAL, "CleanupTransaction: unexpected state %s",
3036 : : TransStateAsString(s->state));
3037 : :
3038 : : /*
3039 : : * do abort cleanup processing
3040 : : */
8266 tgl@sss.pgh.pa.us 3041 :CBC 26041 : AtCleanup_Portals(); /* now safe to release portal memory */
3102 3042 : 26041 : AtEOXact_Snapshot(false, true); /* and release the transaction's snapshots */
3043 : :
7781 bruce@momjian.us 3044 : 26041 : CurrentResourceOwner = NULL; /* and resource owner */
7763 tgl@sss.pgh.pa.us 3045 [ + - ]: 26041 : if (TopTransactionResourceOwner)
3046 : 26041 : ResourceOwnerDelete(TopTransactionResourceOwner);
7824 3047 : 26041 : s->curTransactionOwner = NULL;
3048 : 26041 : CurTransactionResourceOwner = NULL;
3049 : 26041 : TopTransactionResourceOwner = NULL;
3050 : :
8266 3051 : 26041 : AtCleanup_Memory(); /* and transaction memory */
3052 : :
2457 tmunro@postgresql.or 3053 : 26041 : s->fullTransactionId = InvalidFullTransactionId;
7763 tgl@sss.pgh.pa.us 3054 : 26041 : s->subTransactionId = InvalidSubTransactionId;
7840 3055 : 26041 : s->nestingLevel = 0;
6681 3056 : 26041 : s->gucNestLevel = 0;
6485 3057 : 26041 : s->childXids = NULL;
3058 : 26041 : s->nChildXids = 0;
3059 : 26041 : s->maxChildXids = 0;
3885 rhaas@postgresql.org 3060 : 26041 : s->parallelModeLevel = 0;
630 tgl@sss.pgh.pa.us 3061 : 26041 : s->parallelChildXact = false;
3062 : :
2457 tmunro@postgresql.or 3063 : 26041 : XactTopFullTransactionId = InvalidFullTransactionId;
3885 rhaas@postgresql.org 3064 : 26041 : nParallelCurrentXids = 0;
3065 : :
3066 : : /*
3067 : : * done with abort processing, set current transaction state back to
3068 : : * default
3069 : : */
10329 bruce@momjian.us 3070 : 26041 : s->state = TRANS_DEFAULT;
3071 : 26041 : }
3072 : :
3073 : : /*
3074 : : * StartTransactionCommand
3075 : : */
3076 : : void
8254 tgl@sss.pgh.pa.us 3077 : 420000 : StartTransactionCommand(void)
3078 : : {
10329 bruce@momjian.us 3079 : 420000 : TransactionState s = CurrentTransactionState;
3080 : :
3081 [ + + + - : 420000 : switch (s->blockState)
- ]
3082 : : {
3083 : : /*
3084 : : * if we aren't in a transaction block, we just do our usual start
3085 : : * transaction.
3086 : : */
10328 3087 : 328929 : case TBLOCK_DEFAULT:
3088 : 328929 : StartTransaction();
7927 3089 : 328929 : s->blockState = TBLOCK_STARTED;
3090 : 328929 : break;
3091 : :
3092 : : /*
3093 : : * We are somewhere in a transaction block or subtransaction and
3094 : : * about to start a new command. For now we do nothing, but
3095 : : * someday we may do command-local resource initialization. (Note
3096 : : * that any needed CommandCounterIncrement was done by the
3097 : : * previous CommitTransactionCommand.)
3098 : : */
10328 3099 : 90153 : case TBLOCK_INPROGRESS:
3100 : : case TBLOCK_IMPLICIT_INPROGRESS:
3101 : : case TBLOCK_SUBINPROGRESS:
3102 : 90153 : break;
3103 : :
3104 : : /*
3105 : : * Here we are in a failed transaction block (one of the commands
3106 : : * caused an abort) so we do nothing but remain in the abort
3107 : : * state. Eventually we will get a ROLLBACK command which will
3108 : : * get us out of this state. (It is up to other code to ensure
3109 : : * that no commands other than ROLLBACK will be processed in these
3110 : : * states.)
3111 : : */
3112 : 918 : case TBLOCK_ABORT:
3113 : : case TBLOCK_SUBABORT:
3114 : 918 : break;
3115 : :
3116 : : /* These cases are invalid. */
7840 tgl@sss.pgh.pa.us 3117 :UBC 0 : case TBLOCK_STARTED:
3118 : : case TBLOCK_BEGIN:
3119 : : case TBLOCK_PARALLEL_INPROGRESS:
3120 : : case TBLOCK_SUBBEGIN:
3121 : : case TBLOCK_END:
3122 : : case TBLOCK_SUBRELEASE:
3123 : : case TBLOCK_SUBCOMMIT:
3124 : : case TBLOCK_ABORT_END:
3125 : : case TBLOCK_SUBABORT_END:
3126 : : case TBLOCK_ABORT_PENDING:
3127 : : case TBLOCK_SUBABORT_PENDING:
3128 : : case TBLOCK_SUBRESTART:
3129 : : case TBLOCK_SUBABORT_RESTART:
3130 : : case TBLOCK_PREPARE:
7763 3131 [ # # ]: 0 : elog(ERROR, "StartTransactionCommand: unexpected state %s",
3132 : : BlockStateAsString(s->blockState));
3133 : : break;
3134 : : }
3135 : :
3136 : : /*
3137 : : * We must switch to CurTransactionContext before returning. This is
3138 : : * already done if we called StartTransaction, otherwise not.
3139 : : */
7840 tgl@sss.pgh.pa.us 3140 [ - + ]:CBC 420000 : Assert(CurTransactionContext != NULL);
3141 : 420000 : MemoryContextSwitchTo(CurTransactionContext);
10329 bruce@momjian.us 3142 : 420000 : }
3143 : :
3144 : :
3145 : : /*
3146 : : * Simple system for saving and restoring transaction characteristics
3147 : : * (isolation level, read only, deferrable). We need this for transaction
3148 : : * chaining, so that we can set the characteristics of the new transaction to
3149 : : * be the same as the previous one. (We need something like this because the
3150 : : * GUC system resets the characteristics at transaction end, so for example
3151 : : * just skipping the reset in StartTransaction() won't work.)
3152 : : */
3153 : : void
1389 tgl@sss.pgh.pa.us 3154 : 396066 : SaveTransactionCharacteristics(SavedTransactionCharacteristics *s)
3155 : : {
3156 : 396066 : s->save_XactIsoLevel = XactIsoLevel;
3157 : 396066 : s->save_XactReadOnly = XactReadOnly;
3158 : 396066 : s->save_XactDeferrable = XactDeferrable;
2461 peter@eisentraut.org 3159 : 396066 : }
3160 : :
3161 : : void
1389 tgl@sss.pgh.pa.us 3162 : 34 : RestoreTransactionCharacteristics(const SavedTransactionCharacteristics *s)
3163 : : {
3164 : 34 : XactIsoLevel = s->save_XactIsoLevel;
3165 : 34 : XactReadOnly = s->save_XactReadOnly;
3166 : 34 : XactDeferrable = s->save_XactDeferrable;
2461 peter@eisentraut.org 3167 : 34 : }
3168 : :
3169 : : /*
3170 : : * CommitTransactionCommand -- a wrapper function handling the
3171 : : * loop over subtransactions to avoid a potentially dangerous recursion
3172 : : * in CommitTransactionCommandInternal().
3173 : : */
3174 : : void
8254 tgl@sss.pgh.pa.us 3175 : 395835 : CommitTransactionCommand(void)
3176 : : {
3177 : : /*
3178 : : * Repeatedly call CommitTransactionCommandInternal() until all the work
3179 : : * is done.
3180 : : */
609 akorotkov@postgresql 3181 [ + + ]: 396062 : while (!CommitTransactionCommandInternal())
3182 : : {
3183 : : }
650 3184 : 395544 : }
3185 : :
3186 : : /*
3187 : : * CommitTransactionCommandInternal - a function doing an iteration of work
3188 : : * regarding handling the commit transaction command. In the case of
3189 : : * subtransactions more than one iterations could be required. Returns
3190 : : * true when no more iterations required, false otherwise.
3191 : : */
3192 : : static bool
3193 : 396062 : CommitTransactionCommandInternal(void)
3194 : : {
10329 bruce@momjian.us 3195 : 396062 : TransactionState s = CurrentTransactionState;
3196 : : SavedTransactionCharacteristics savetc;
3197 : :
3198 : : /* Must save in case we need to restore below */
1389 tgl@sss.pgh.pa.us 3199 : 396062 : SaveTransactionCharacteristics(&savetc);
3200 : :
10329 bruce@momjian.us 3201 [ - + + + : 396062 : switch (s->blockState)
+ + + + +
+ + + + +
+ + - ]
3202 : : {
3203 : : /*
3204 : : * These shouldn't happen. TBLOCK_DEFAULT means the previous
3205 : : * StartTransactionCommand didn't set the STARTED state
3206 : : * appropriately, while TBLOCK_PARALLEL_INPROGRESS should be ended
3207 : : * by EndParallelWorkerTransaction(), not this function.
3208 : : */
7927 bruce@momjian.us 3209 :UBC 0 : case TBLOCK_DEFAULT:
3210 : : case TBLOCK_PARALLEL_INPROGRESS:
7814 tgl@sss.pgh.pa.us 3211 [ # # ]: 0 : elog(FATAL, "CommitTransactionCommand: unexpected state %s",
3212 : : BlockStateAsString(s->blockState));
3213 : : break;
3214 : :
3215 : : /*
3216 : : * If we aren't in a transaction block, just do our usual
3217 : : * transaction commit, and return to the idle state.
3218 : : */
7927 bruce@momjian.us 3219 :CBC 294246 : case TBLOCK_STARTED:
8254 tgl@sss.pgh.pa.us 3220 : 294246 : CommitTransaction();
7927 bruce@momjian.us 3221 : 294236 : s->blockState = TBLOCK_DEFAULT;
10328 3222 : 294236 : break;
3223 : :
3224 : : /*
3225 : : * We are completing a "BEGIN TRANSACTION" command, so we change
3226 : : * to the "transaction block in progress" state and return. (We
3227 : : * assume the BEGIN did nothing to the database, so we need no
3228 : : * CommandCounterIncrement.)
3229 : : */
3230 : 11344 : case TBLOCK_BEGIN:
3231 : 11344 : s->blockState = TBLOCK_INPROGRESS;
3232 : 11344 : break;
3233 : :
3234 : : /*
3235 : : * This is the case when we have finished executing a command
3236 : : * someplace within a transaction block. We increment the command
3237 : : * counter and return.
3238 : : */
3239 : 69873 : case TBLOCK_INPROGRESS:
3240 : : case TBLOCK_IMPLICIT_INPROGRESS:
3241 : : case TBLOCK_SUBINPROGRESS:
3242 : 69873 : CommandCounterIncrement();
3243 : 69873 : break;
3244 : :
3245 : : /*
3246 : : * We are completing a "COMMIT" command. Do it and return to the
3247 : : * idle state.
3248 : : */
3249 : 8273 : case TBLOCK_END:
3250 : 8273 : CommitTransaction();
9304 tgl@sss.pgh.pa.us 3251 : 8061 : s->blockState = TBLOCK_DEFAULT;
2461 peter@eisentraut.org 3252 [ + + ]: 8061 : if (s->chain)
3253 : : {
3254 : 6 : StartTransaction();
3255 : 6 : s->blockState = TBLOCK_INPROGRESS;
3256 : 6 : s->chain = false;
1389 tgl@sss.pgh.pa.us 3257 : 6 : RestoreTransactionCharacteristics(&savetc);
3258 : : }
10328 bruce@momjian.us 3259 : 8061 : break;
3260 : :
3261 : : /*
3262 : : * Here we are in the middle of a transaction block but one of the
3263 : : * commands caused an abort so we do nothing but remain in the
3264 : : * abort state. Eventually we will get a ROLLBACK command.
3265 : : */
3266 : 9 : case TBLOCK_ABORT:
3267 : : case TBLOCK_SUBABORT:
3268 : 9 : break;
3269 : :
3270 : : /*
3271 : : * Here we were in an aborted transaction block and we just got
3272 : : * the ROLLBACK command from the user, so clean up the
3273 : : * already-aborted transaction and return to the idle state.
3274 : : */
7763 tgl@sss.pgh.pa.us 3275 : 711 : case TBLOCK_ABORT_END:
9304 3276 : 711 : CleanupTransaction();
10328 bruce@momjian.us 3277 : 711 : s->blockState = TBLOCK_DEFAULT;
2461 peter@eisentraut.org 3278 [ + + ]: 711 : if (s->chain)
3279 : : {
3280 : 6 : StartTransaction();
3281 : 6 : s->blockState = TBLOCK_INPROGRESS;
3282 : 6 : s->chain = false;
1389 tgl@sss.pgh.pa.us 3283 : 6 : RestoreTransactionCharacteristics(&savetc);
3284 : : }
10328 bruce@momjian.us 3285 : 711 : break;
3286 : :
3287 : : /*
3288 : : * Here we were in a perfectly good transaction block but the user
3289 : : * told us to ROLLBACK anyway. We have to abort the transaction
3290 : : * and then clean up.
3291 : : */
7763 tgl@sss.pgh.pa.us 3292 : 1428 : case TBLOCK_ABORT_PENDING:
3293 : 1428 : AbortTransaction();
3294 : 1428 : CleanupTransaction();
3295 : 1428 : s->blockState = TBLOCK_DEFAULT;
2461 peter@eisentraut.org 3296 [ + + ]: 1428 : if (s->chain)
3297 : : {
3298 : 9 : StartTransaction();
3299 : 9 : s->blockState = TBLOCK_INPROGRESS;
3300 : 9 : s->chain = false;
1389 tgl@sss.pgh.pa.us 3301 : 9 : RestoreTransactionCharacteristics(&savetc);
3302 : : }
7814 3303 : 1428 : break;
3304 : :
3305 : : /*
3306 : : * We are completing a "PREPARE TRANSACTION" command. Do it and
3307 : : * return to the idle state.
3308 : : */
7489 3309 : 246 : case TBLOCK_PREPARE:
3310 : 246 : PrepareTransaction();
3311 : 192 : s->blockState = TBLOCK_DEFAULT;
3312 : 192 : break;
3313 : :
3314 : : /*
3315 : : * The user issued a SAVEPOINT inside a transaction block. Start a
3316 : : * subtransaction. (DefineSavepoint already did PushTransaction,
3317 : : * so as to have someplace to put the SUBBEGIN state.)
3318 : : */
7840 3319 : 8746 : case TBLOCK_SUBBEGIN:
3320 : 8746 : StartSubTransaction();
3321 : 8746 : s->blockState = TBLOCK_SUBINPROGRESS;
3322 : 8746 : break;
3323 : :
3324 : : /*
3325 : : * The user issued a RELEASE command, so we end the current
3326 : : * subtransaction and return to the parent transaction. The parent
3327 : : * might be ended too, so repeat till we find an INPROGRESS
3328 : : * transaction or subtransaction.
3329 : : */
5266 simon@2ndQuadrant.co 3330 : 224 : case TBLOCK_SUBRELEASE:
3331 : : do
3332 : : {
5216 3333 : 224 : CommitSubTransaction();
7781 bruce@momjian.us 3334 : 224 : s = CurrentTransactionState; /* changed by pop */
5266 simon@2ndQuadrant.co 3335 [ + + ]: 224 : } while (s->blockState == TBLOCK_SUBRELEASE);
3336 : :
3337 [ + + - + ]: 138 : Assert(s->blockState == TBLOCK_INPROGRESS ||
3338 : : s->blockState == TBLOCK_SUBINPROGRESS);
3339 : 138 : break;
3340 : :
3341 : : /*
3342 : : * The user issued a COMMIT, so we end the current subtransaction
3343 : : * hierarchy and perform final commit. We do this by rolling up
3344 : : * any subtransactions into their parent, which leads to O(N^2)
3345 : : * operations with respect to resource owners - this isn't that
3346 : : * bad until we approach a thousands of savepoints but is
3347 : : * necessary for correctness should after triggers create new
3348 : : * resource owners.
3349 : : */
3350 : 523 : case TBLOCK_SUBCOMMIT:
3351 : : do
3352 : : {
5216 3353 : 523 : CommitSubTransaction();
5266 3354 : 523 : s = CurrentTransactionState; /* changed by pop */
3355 [ + + ]: 523 : } while (s->blockState == TBLOCK_SUBCOMMIT);
3356 : : /* If we had a COMMIT command, finish off the main xact too */
7769 tgl@sss.pgh.pa.us 3357 [ + + ]: 450 : if (s->blockState == TBLOCK_END)
3358 : : {
3359 [ - + ]: 352 : Assert(s->parent == NULL);
3360 : 352 : CommitTransaction();
3361 : 339 : s->blockState = TBLOCK_DEFAULT;
1763 fujii@postgresql.org 3362 [ + + ]: 339 : if (s->chain)
3363 : : {
3364 : 9 : StartTransaction();
3365 : 9 : s->blockState = TBLOCK_INPROGRESS;
3366 : 9 : s->chain = false;
1389 tgl@sss.pgh.pa.us 3367 : 9 : RestoreTransactionCharacteristics(&savetc);
3368 : : }
3369 : : }
7489 3370 [ + - ]: 98 : else if (s->blockState == TBLOCK_PREPARE)
3371 : : {
3372 [ - + ]: 98 : Assert(s->parent == NULL);
3373 : 98 : PrepareTransaction();
3374 : 96 : s->blockState = TBLOCK_DEFAULT;
3375 : : }
3376 : : else
5266 simon@2ndQuadrant.co 3377 [ # # ]:UBC 0 : elog(ERROR, "CommitTransactionCommand: unexpected state %s",
3378 : : BlockStateAsString(s->blockState));
7840 tgl@sss.pgh.pa.us 3379 :CBC 435 : break;
3380 : :
3381 : : /*
3382 : : * The current already-failed subtransaction is ending due to a
3383 : : * ROLLBACK or ROLLBACK TO command, so pop it and recursively
3384 : : * examine the parent (which could be in any of several states).
3385 : : * As we need to examine the parent, return false to request the
3386 : : * caller to do the next iteration.
3387 : : */
609 akorotkov@postgresql 3388 : 43 : case TBLOCK_SUBABORT_END:
3389 : 43 : CleanupSubTransaction();
3390 : 43 : return false;
3391 : :
3392 : : /*
3393 : : * As above, but it's not dead yet, so abort first.
3394 : : */
3395 : 184 : case TBLOCK_SUBABORT_PENDING:
3396 : 184 : AbortSubTransaction();
3397 : 184 : CleanupSubTransaction();
3398 : 184 : return false;
3399 : :
3400 : : /*
3401 : : * The current subtransaction is the target of a ROLLBACK TO
3402 : : * command. Abort and pop it, then start a new subtransaction
3403 : : * with the same name.
3404 : : */
7763 tgl@sss.pgh.pa.us 3405 : 266 : case TBLOCK_SUBRESTART:
3406 : : {
3407 : : char *name;
3408 : : int savepointLevel;
3409 : :
3410 : : /* save name and keep Cleanup from freeing it */
3411 : 266 : name = s->name;
3412 : 266 : s->name = NULL;
3413 : 266 : savepointLevel = s->savepointLevel;
3414 : :
3415 : 266 : AbortSubTransaction();
3416 : 266 : CleanupSubTransaction();
3417 : :
3418 : 266 : DefineSavepoint(NULL);
3419 : 266 : s = CurrentTransactionState; /* changed by push */
3420 : 266 : s->name = name;
3421 : 266 : s->savepointLevel = savepointLevel;
3422 : :
3423 : : /* This is the same as TBLOCK_SUBBEGIN case */
1147 peter@eisentraut.org 3424 [ - + ]: 266 : Assert(s->blockState == TBLOCK_SUBBEGIN);
7814 tgl@sss.pgh.pa.us 3425 : 266 : StartSubTransaction();
3426 : 266 : s->blockState = TBLOCK_SUBINPROGRESS;
3427 : : }
7840 3428 : 266 : break;
3429 : :
3430 : : /*
3431 : : * Same as above, but the subtransaction had already failed, so we
3432 : : * don't need AbortSubTransaction.
3433 : : */
7763 3434 : 105 : case TBLOCK_SUBABORT_RESTART:
3435 : : {
3436 : : char *name;
3437 : : int savepointLevel;
3438 : :
3439 : : /* save name and keep Cleanup from freeing it */
3440 : 105 : name = s->name;
3441 : 105 : s->name = NULL;
3442 : 105 : savepointLevel = s->savepointLevel;
3443 : :
3444 : 105 : CleanupSubTransaction();
3445 : :
3446 : 105 : DefineSavepoint(NULL);
3447 : 105 : s = CurrentTransactionState; /* changed by push */
3448 : 105 : s->name = name;
3449 : 105 : s->savepointLevel = savepointLevel;
3450 : :
3451 : : /* This is the same as TBLOCK_SUBBEGIN case */
1147 peter@eisentraut.org 3452 [ - + ]: 105 : Assert(s->blockState == TBLOCK_SUBBEGIN);
7763 tgl@sss.pgh.pa.us 3453 : 105 : StartSubTransaction();
3454 : 105 : s->blockState = TBLOCK_SUBINPROGRESS;
3455 : : }
3456 : 105 : break;
3457 : : }
3458 : :
3459 : : /* Done, no more iterations required */
609 akorotkov@postgresql 3460 : 395544 : return true;
3461 : : }
3462 : :
3463 : : /*
3464 : : * AbortCurrentTransaction -- a wrapper function handling the
3465 : : * loop over subtransactions to avoid potentially dangerous recursion in
3466 : : * AbortCurrentTransactionInternal().
3467 : : */
3468 : : void
7840 tgl@sss.pgh.pa.us 3469 : 25080 : AbortCurrentTransaction(void)
3470 : : {
3471 : : /*
3472 : : * Repeatedly call AbortCurrentTransactionInternal() until all the work is
3473 : : * done.
3474 : : */
609 akorotkov@postgresql 3475 [ - + ]: 25080 : while (!AbortCurrentTransactionInternal())
3476 : : {
3477 : : }
650 3478 : 25080 : }
3479 : :
3480 : : /*
3481 : : * AbortCurrentTransactionInternal - a function doing an iteration of work
3482 : : * regarding handling the current transaction abort. In the case of
3483 : : * subtransactions more than one iterations could be required. Returns
3484 : : * true when no more iterations required, false otherwise.
3485 : : */
3486 : : static bool
3487 : 25080 : AbortCurrentTransactionInternal(void)
3488 : : {
7840 tgl@sss.pgh.pa.us 3489 : 25080 : TransactionState s = CurrentTransactionState;
3490 : :
3491 [ + + - + : 25080 : switch (s->blockState)
+ + - - +
+ - - - ]
3492 : : {
7927 bruce@momjian.us 3493 : 37 : case TBLOCK_DEFAULT:
7606 tgl@sss.pgh.pa.us 3494 [ - + ]: 37 : if (s->state == TRANS_DEFAULT)
3495 : : {
3496 : : /* we are idle, so nothing to do */
3497 : : }
3498 : : else
3499 : : {
3500 : : /*
3501 : : * We can get here after an error during transaction start
3502 : : * (state will be TRANS_START). Need to clean up the
3503 : : * incompletely started transaction. First, adjust the
3504 : : * low-level state to suppress warning message from
3505 : : * AbortTransaction.
3506 : : */
7606 tgl@sss.pgh.pa.us 3507 [ # # ]:UBC 0 : if (s->state == TRANS_START)
3508 : 0 : s->state = TRANS_INPROGRESS;
3509 : 0 : AbortTransaction();
3510 : 0 : CleanupTransaction();
3511 : : }
7927 bruce@momjian.us 3512 :CBC 37 : break;
3513 : :
3514 : : /*
3515 : : * If we aren't in a transaction block, we just do the basic abort
3516 : : * & cleanup transaction. For this purpose, we treat an implicit
3517 : : * transaction block as if it were a simple statement.
3518 : : */
3519 : 22928 : case TBLOCK_STARTED:
3520 : : case TBLOCK_IMPLICIT_INPROGRESS:
10328 3521 : 22928 : AbortTransaction();
8254 tgl@sss.pgh.pa.us 3522 : 22928 : CleanupTransaction();
7927 bruce@momjian.us 3523 : 22928 : s->blockState = TBLOCK_DEFAULT;
10328 3524 : 22928 : break;
3525 : :
3526 : : /*
3527 : : * If we are in TBLOCK_BEGIN it means something screwed up right
3528 : : * after reading "BEGIN TRANSACTION". We assume that the user
3529 : : * will interpret the error as meaning the BEGIN failed to get him
3530 : : * into a transaction block, so we should abort and return to idle
3531 : : * state.
3532 : : */
10328 bruce@momjian.us 3533 :UBC 0 : case TBLOCK_BEGIN:
3534 : 0 : AbortTransaction();
7763 tgl@sss.pgh.pa.us 3535 : 0 : CleanupTransaction();
3536 : 0 : s->blockState = TBLOCK_DEFAULT;
10328 bruce@momjian.us 3537 : 0 : break;
3538 : :
3539 : : /*
3540 : : * We are somewhere in a transaction block and we've gotten a
3541 : : * failure, so we abort the transaction and set up the persistent
3542 : : * ABORT state. We will stay in ABORT until we get a ROLLBACK.
3543 : : */
10328 bruce@momjian.us 3544 :CBC 723 : case TBLOCK_INPROGRESS:
3545 : : case TBLOCK_PARALLEL_INPROGRESS:
3546 : 723 : AbortTransaction();
7927 3547 : 723 : s->blockState = TBLOCK_ABORT;
3548 : : /* CleanupTransaction happens when we exit TBLOCK_ABORT_END */
10328 3549 : 723 : break;
3550 : :
3551 : : /*
3552 : : * Here, we failed while trying to COMMIT. Clean up the
3553 : : * transaction and return to idle state (we do not want to stay in
3554 : : * the transaction).
3555 : : */
3556 : 225 : case TBLOCK_END:
3557 : 225 : AbortTransaction();
9304 tgl@sss.pgh.pa.us 3558 : 225 : CleanupTransaction();
7927 bruce@momjian.us 3559 : 225 : s->blockState = TBLOCK_DEFAULT;
10328 3560 : 225 : break;
3561 : :
3562 : : /*
3563 : : * Here, we are already in an aborted transaction state and are
3564 : : * waiting for a ROLLBACK, but for some reason we failed again! So
3565 : : * we just remain in the abort state.
3566 : : */
3567 : 51 : case TBLOCK_ABORT:
3568 : : case TBLOCK_SUBABORT:
3569 : 51 : break;
3570 : :
3571 : : /*
3572 : : * We are in a failed transaction and we got the ROLLBACK command.
3573 : : * We have already aborted, we just need to cleanup and go to idle
3574 : : * state.
3575 : : */
7763 tgl@sss.pgh.pa.us 3576 :UBC 0 : case TBLOCK_ABORT_END:
9304 3577 : 0 : CleanupTransaction();
10328 bruce@momjian.us 3578 : 0 : s->blockState = TBLOCK_DEFAULT;
3579 : 0 : break;
3580 : :
3581 : : /*
3582 : : * We are in a live transaction and we got a ROLLBACK command.
3583 : : * Abort, cleanup, go to idle state.
3584 : : */
7763 tgl@sss.pgh.pa.us 3585 : 0 : case TBLOCK_ABORT_PENDING:
3586 : 0 : AbortTransaction();
3587 : 0 : CleanupTransaction();
3588 : 0 : s->blockState = TBLOCK_DEFAULT;
7840 3589 : 0 : break;
3590 : :
3591 : : /*
3592 : : * Here, we failed while trying to PREPARE. Clean up the
3593 : : * transaction and return to idle state (we do not want to stay in
3594 : : * the transaction).
3595 : : */
7489 tgl@sss.pgh.pa.us 3596 :CBC 55 : case TBLOCK_PREPARE:
3597 : 55 : AbortTransaction();
3598 : 55 : CleanupTransaction();
3599 : 55 : s->blockState = TBLOCK_DEFAULT;
3600 : 55 : break;
3601 : :
3602 : : /*
3603 : : * We got an error inside a subtransaction. Abort just the
3604 : : * subtransaction, and go to the persistent SUBABORT state until
3605 : : * we get ROLLBACK.
3606 : : */
7840 3607 : 1061 : case TBLOCK_SUBINPROGRESS:
3608 : 1061 : AbortSubTransaction();
3609 : 1061 : s->blockState = TBLOCK_SUBABORT;
3610 : 1061 : break;
3611 : :
3612 : : /*
3613 : : * If we failed while trying to create a subtransaction, clean up
3614 : : * the broken subtransaction and abort the parent. The same
3615 : : * applies if we get a failure while ending a subtransaction. As
3616 : : * we need to abort the parent, return false to request the caller
3617 : : * to do the next iteration.
3618 : : */
609 akorotkov@postgresql 3619 :UBC 0 : case TBLOCK_SUBBEGIN:
3620 : : case TBLOCK_SUBRELEASE:
3621 : : case TBLOCK_SUBCOMMIT:
3622 : : case TBLOCK_SUBABORT_PENDING:
3623 : : case TBLOCK_SUBRESTART:
3624 : 0 : AbortSubTransaction();
3625 : 0 : CleanupSubTransaction();
3626 : 0 : return false;
3627 : :
3628 : : /*
3629 : : * Same as above, except the Abort() was already done.
3630 : : */
3631 : 0 : case TBLOCK_SUBABORT_END:
3632 : : case TBLOCK_SUBABORT_RESTART:
3633 : 0 : CleanupSubTransaction();
3634 : 0 : return false;
3635 : : }
3636 : :
3637 : : /* Done, no more iterations required */
609 akorotkov@postgresql 3638 :CBC 25080 : return true;
3639 : : }
3640 : :
3641 : : /*
3642 : : * PreventInTransactionBlock
3643 : : *
3644 : : * This routine is to be called by statements that must not run inside
3645 : : * a transaction block, typically because they have non-rollback-able
3646 : : * side effects or do internal commits.
3647 : : *
3648 : : * If this routine completes successfully, then the calling statement is
3649 : : * guaranteed that if it completes without error, its results will be
3650 : : * committed immediately.
3651 : : *
3652 : : * If we have already started a transaction block, issue an error; also issue
3653 : : * an error if we appear to be running inside a user-defined function (which
3654 : : * could issue more commands and possibly cause a failure after the statement
3655 : : * completes). Subtransactions are verboten too.
3656 : : *
3657 : : * We must also set XACT_FLAGS_NEEDIMMEDIATECOMMIT in MyXactFlags, to ensure
3658 : : * that postgres.c follows through by committing after the statement is done.
3659 : : *
3660 : : * isTopLevel: passed down from ProcessUtility to determine whether we are
3661 : : * inside a function. (We will always fail if this is false, but it's
3662 : : * convenient to centralize the check here instead of making callers do it.)
3663 : : * stmtType: statement type name, for error messages.
3664 : : */
3665 : : void
2862 peter_e@gmx.net 3666 : 7645 : PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
3667 : : {
3668 : : /*
3669 : : * xact block already started?
3670 : : */
8459 tgl@sss.pgh.pa.us 3671 [ + + ]: 7645 : if (IsTransactionBlock())
8186 3672 [ + - ]: 59 : ereport(ERROR,
3673 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
3674 : : /* translator: %s represents an SQL statement name */
3675 : : errmsg("%s cannot run inside a transaction block",
3676 : : stmtType)));
3677 : :
3678 : : /*
3679 : : * subtransaction?
3680 : : */
7840 3681 [ - + ]: 7586 : if (IsSubTransaction())
7840 tgl@sss.pgh.pa.us 3682 [ # # ]:UBC 0 : ereport(ERROR,
3683 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
3684 : : /* translator: %s represents an SQL statement name */
3685 : : errmsg("%s cannot run inside a subtransaction",
3686 : : stmtType)));
3687 : :
3688 : : /*
3689 : : * inside a function call?
3690 : : */
6855 tgl@sss.pgh.pa.us 3691 [ + + ]:CBC 7586 : if (!isTopLevel)
8186 3692 [ + - ]: 3 : ereport(ERROR,
3693 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
3694 : : /* translator: %s represents an SQL statement name */
3695 : : errmsg("%s cannot be executed from a function", stmtType)));
3696 : :
3697 : : /* If we got past IsTransactionBlock test, should be in default state */
7927 bruce@momjian.us 3698 [ + + ]: 7583 : if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
7880 tgl@sss.pgh.pa.us 3699 [ - + ]: 6730 : CurrentTransactionState->blockState != TBLOCK_STARTED)
7840 tgl@sss.pgh.pa.us 3700 [ # # ]:UBC 0 : elog(FATAL, "cannot prevent transaction chain");
3701 : :
3702 : : /* All okay. Set the flag to make sure the right thing happens later. */
1241 tgl@sss.pgh.pa.us 3703 :CBC 7583 : MyXactFlags |= XACT_FLAGS_NEEDIMMEDIATECOMMIT;
8459 3704 : 7583 : }
3705 : :
3706 : : /*
3707 : : * WarnNoTransactionBlock
3708 : : * RequireTransactionBlock
3709 : : *
3710 : : * These two functions allow for warnings or errors if a command is executed
3711 : : * outside of a transaction block. This is useful for commands that have no
3712 : : * effects that persist past transaction end (and so calling them outside a
3713 : : * transaction block is presumably an error). DECLARE CURSOR is an example.
3714 : : * While top-level transaction control commands (BEGIN/COMMIT/ABORT) and SET
3715 : : * that have no effect issue warnings, all other no-effect commands generate
3716 : : * errors.
3717 : : *
3718 : : * If we appear to be running inside a user-defined function, we do not
3719 : : * issue anything, since the function could issue more commands that make
3720 : : * use of the current statement's results. Likewise subtransactions.
3721 : : * Thus these are inverses for PreventInTransactionBlock.
3722 : : *
3723 : : * isTopLevel: passed down from ProcessUtility to determine whether we are
3724 : : * inside a function.
3725 : : * stmtType: statement type name, for warning or error messages.
3726 : : */
3727 : : void
2862 peter_e@gmx.net 3728 : 1050 : WarnNoTransactionBlock(bool isTopLevel, const char *stmtType)
3729 : : {
3730 : 1050 : CheckTransactionBlock(isTopLevel, false, stmtType);
4406 bruce@momjian.us 3731 : 1050 : }
3732 : :
3733 : : void
2862 peter_e@gmx.net 3734 : 4189 : RequireTransactionBlock(bool isTopLevel, const char *stmtType)
3735 : : {
3736 : 4189 : CheckTransactionBlock(isTopLevel, true, stmtType);
4406 bruce@momjian.us 3737 : 4171 : }
3738 : :
3739 : : /*
3740 : : * This is the implementation of the above two.
3741 : : */
3742 : : static void
2862 peter_e@gmx.net 3743 : 5239 : CheckTransactionBlock(bool isTopLevel, bool throwError, const char *stmtType)
3744 : : {
3745 : : /*
3746 : : * xact block already started?
3747 : : */
8431 tgl@sss.pgh.pa.us 3748 [ + + ]: 5239 : if (IsTransactionBlock())
3749 : 5152 : return;
3750 : :
3751 : : /*
3752 : : * subtransaction?
3753 : : */
7840 3754 [ - + ]: 87 : if (IsSubTransaction())
7840 tgl@sss.pgh.pa.us 3755 :UBC 0 : return;
3756 : :
3757 : : /*
3758 : : * inside a function call?
3759 : : */
6855 tgl@sss.pgh.pa.us 3760 [ + + ]:CBC 87 : if (!isTopLevel)
8431 3761 : 58 : return;
3762 : :
4406 bruce@momjian.us 3763 [ + + + - ]: 29 : ereport(throwError ? ERROR : WARNING,
3764 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
3765 : : /* translator: %s represents an SQL statement name */
3766 : : errmsg("%s can only be used in transaction blocks",
3767 : : stmtType)));
3768 : : }
3769 : :
3770 : : /*
3771 : : * IsInTransactionBlock
3772 : : *
3773 : : * This routine is for statements that need to behave differently inside
3774 : : * a transaction block than when running as single commands. ANALYZE is
3775 : : * currently the only example.
3776 : : *
3777 : : * If this routine returns "false", then the calling statement is allowed
3778 : : * to perform internal transaction-commit-and-start cycles; there is not a
3779 : : * risk of messing up any transaction already in progress. (Note that this
3780 : : * is not the identical guarantee provided by PreventInTransactionBlock,
3781 : : * since we will not force a post-statement commit.)
3782 : : *
3783 : : * isTopLevel: passed down from ProcessUtility to determine whether we are
3784 : : * inside a function.
3785 : : */
3786 : : bool
2862 peter_e@gmx.net 3787 : 2622 : IsInTransactionBlock(bool isTopLevel)
3788 : : {
3789 : : /*
3790 : : * Return true on same conditions that would make
3791 : : * PreventInTransactionBlock error out
3792 : : */
7880 tgl@sss.pgh.pa.us 3793 [ + + ]: 2622 : if (IsTransactionBlock())
3794 : 77 : return true;
3795 : :
7840 3796 [ - + ]: 2545 : if (IsSubTransaction())
7840 tgl@sss.pgh.pa.us 3797 :UBC 0 : return true;
3798 : :
6855 tgl@sss.pgh.pa.us 3799 [ + + ]:CBC 2545 : if (!isTopLevel)
7880 3800 : 56 : return true;
3801 : :
3802 [ + - ]: 2489 : if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
3803 [ - + ]: 2489 : CurrentTransactionState->blockState != TBLOCK_STARTED)
7880 tgl@sss.pgh.pa.us 3804 :UBC 0 : return true;
3805 : :
7880 tgl@sss.pgh.pa.us 3806 :CBC 2489 : return false;
3807 : : }
3808 : :
3809 : :
3810 : : /*
3811 : : * Register or deregister callback functions for start- and end-of-xact
3812 : : * operations.
3813 : : *
3814 : : * These functions are intended for use by dynamically loaded modules.
3815 : : * For built-in modules we generally just hardwire the appropriate calls
3816 : : * (mainly because it's easier to control the order that way, where needed).
3817 : : *
3818 : : * At transaction end, the callback occurs post-commit or post-abort, so the
3819 : : * callback functions can only do noncritical cleanup.
3820 : : */
3821 : : void
7809 3822 : 1892 : RegisterXactCallback(XactCallback callback, void *arg)
3823 : : {
3824 : : XactCallbackItem *item;
3825 : :
3826 : : item = (XactCallbackItem *)
3827 : 1892 : MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
8117 3828 : 1892 : item->callback = callback;
3829 : 1892 : item->arg = arg;
7809 3830 : 1892 : item->next = Xact_callbacks;
3831 : 1892 : Xact_callbacks = item;
8117 3832 : 1892 : }
3833 : :
3834 : : void
7809 tgl@sss.pgh.pa.us 3835 :UBC 0 : UnregisterXactCallback(XactCallback callback, void *arg)
3836 : : {
3837 : : XactCallbackItem *item;
3838 : : XactCallbackItem *prev;
3839 : :
8117 3840 : 0 : prev = NULL;
7809 3841 [ # # ]: 0 : for (item = Xact_callbacks; item; prev = item, item = item->next)
3842 : : {
8117 3843 [ # # # # ]: 0 : if (item->callback == callback && item->arg == arg)
3844 : : {
3845 [ # # ]: 0 : if (prev)
3846 : 0 : prev->next = item->next;
3847 : : else
7809 3848 : 0 : Xact_callbacks = item->next;
8117 3849 : 0 : pfree(item);
3850 : 0 : break;
3851 : : }
3852 : : }
3853 : 0 : }
3854 : :
3855 : : static void
7763 tgl@sss.pgh.pa.us 3856 :CBC 634997 : CallXactCallbacks(XactEvent event)
3857 : : {
3858 : : XactCallbackItem *item;
3859 : : XactCallbackItem *next;
3860 : :
1177 3861 [ + + ]: 792603 : for (item = Xact_callbacks; item; item = next)
3862 : : {
3863 : : /* allow callbacks to unregister themselves when called */
3864 : 157607 : next = item->next;
3024 peter_e@gmx.net 3865 : 157607 : item->callback(event, item->arg);
3866 : : }
7763 tgl@sss.pgh.pa.us 3867 : 634996 : }
3868 : :
3869 : :
3870 : : /*
3871 : : * Register or deregister callback functions for start- and end-of-subxact
3872 : : * operations.
3873 : : *
3874 : : * Pretty much same as above, but for subtransaction events.
3875 : : *
3876 : : * At subtransaction end, the callback occurs post-subcommit or post-subabort,
3877 : : * so the callback functions can only do noncritical cleanup. At
3878 : : * subtransaction start, the callback is called when the subtransaction has
3879 : : * finished initializing.
3880 : : */
3881 : : void
3882 : 1892 : RegisterSubXactCallback(SubXactCallback callback, void *arg)
3883 : : {
3884 : : SubXactCallbackItem *item;
3885 : :
3886 : : item = (SubXactCallbackItem *)
3887 : 1892 : MemoryContextAlloc(TopMemoryContext, sizeof(SubXactCallbackItem));
3888 : 1892 : item->callback = callback;
3889 : 1892 : item->arg = arg;
3890 : 1892 : item->next = SubXact_callbacks;
3891 : 1892 : SubXact_callbacks = item;
3892 : 1892 : }
3893 : :
3894 : : void
7763 tgl@sss.pgh.pa.us 3895 :UBC 0 : UnregisterSubXactCallback(SubXactCallback callback, void *arg)
3896 : : {
3897 : : SubXactCallbackItem *item;
3898 : : SubXactCallbackItem *prev;
3899 : :
3900 : 0 : prev = NULL;
3901 [ # # ]: 0 : for (item = SubXact_callbacks; item; prev = item, item = item->next)
3902 : : {
3903 [ # # # # ]: 0 : if (item->callback == callback && item->arg == arg)
3904 : : {
3905 [ # # ]: 0 : if (prev)
3906 : 0 : prev->next = item->next;
3907 : : else
3908 : 0 : SubXact_callbacks = item->next;
3909 : 0 : pfree(item);
3910 : 0 : break;
3911 : : }
3912 : : }
3913 : 0 : }
3914 : :
3915 : : static void
7763 tgl@sss.pgh.pa.us 3916 :CBC 22667 : CallSubXactCallbacks(SubXactEvent event,
3917 : : SubTransactionId mySubid,
3918 : : SubTransactionId parentSubid)
3919 : : {
3920 : : SubXactCallbackItem *item;
3921 : : SubXactCallbackItem *next;
3922 : :
1177 3923 [ + + ]: 39847 : for (item = SubXact_callbacks; item; item = next)
3924 : : {
3925 : : /* allow callbacks to unregister themselves when called */
3926 : 17180 : next = item->next;
3024 peter_e@gmx.net 3927 : 17180 : item->callback(event, mySubid, parentSubid, item->arg);
3928 : : }
8117 tgl@sss.pgh.pa.us 3929 : 22667 : }
3930 : :
3931 : :
3932 : : /* ----------------------------------------------------------------
3933 : : * transaction block support
3934 : : * ----------------------------------------------------------------
3935 : : */
3936 : :
3937 : : /*
3938 : : * BeginTransactionBlock
3939 : : * This executes a BEGIN command.
3940 : : */
3941 : : void
10329 bruce@momjian.us 3942 : 11344 : BeginTransactionBlock(void)
3943 : : {
3944 : 11344 : TransactionState s = CurrentTransactionState;
3945 : :
7814 tgl@sss.pgh.pa.us 3946 [ + + - - : 11344 : switch (s->blockState)
- ]
3947 : : {
3948 : : /*
3949 : : * We are not inside a transaction block, so allow one to begin.
3950 : : */
7927 bruce@momjian.us 3951 : 10863 : case TBLOCK_STARTED:
3952 : 10863 : s->blockState = TBLOCK_BEGIN;
3953 : 10863 : break;
3954 : :
3955 : : /*
3956 : : * BEGIN converts an implicit transaction block to a regular one.
3957 : : * (Note that we allow this even if we've already done some
3958 : : * commands, which is a bit odd but matches historical practice.)
3959 : : */
3024 tgl@sss.pgh.pa.us 3960 : 481 : case TBLOCK_IMPLICIT_INPROGRESS:
3961 : 481 : s->blockState = TBLOCK_BEGIN;
3962 : 481 : break;
3963 : :
3964 : : /*
3965 : : * Already a transaction block in progress.
3966 : : */
7927 bruce@momjian.us 3967 :UBC 0 : case TBLOCK_INPROGRESS:
3968 : : case TBLOCK_PARALLEL_INPROGRESS:
3969 : : case TBLOCK_SUBINPROGRESS:
3970 : : case TBLOCK_ABORT:
3971 : : case TBLOCK_SUBABORT:
7814 tgl@sss.pgh.pa.us 3972 [ # # ]: 0 : ereport(WARNING,
3973 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
3974 : : errmsg("there is already a transaction in progress")));
7927 bruce@momjian.us 3975 : 0 : break;
3976 : :
3977 : : /* These cases are invalid. */
3978 : 0 : case TBLOCK_DEFAULT:
3979 : : case TBLOCK_BEGIN:
3980 : : case TBLOCK_SUBBEGIN:
3981 : : case TBLOCK_END:
3982 : : case TBLOCK_SUBRELEASE:
3983 : : case TBLOCK_SUBCOMMIT:
3984 : : case TBLOCK_ABORT_END:
3985 : : case TBLOCK_SUBABORT_END:
3986 : : case TBLOCK_ABORT_PENDING:
3987 : : case TBLOCK_SUBABORT_PENDING:
3988 : : case TBLOCK_SUBRESTART:
3989 : : case TBLOCK_SUBABORT_RESTART:
3990 : : case TBLOCK_PREPARE:
7840 tgl@sss.pgh.pa.us 3991 [ # # ]: 0 : elog(FATAL, "BeginTransactionBlock: unexpected state %s",
3992 : : BlockStateAsString(s->blockState));
3993 : : break;
3994 : : }
10754 scrappy@hub.org 3995 :CBC 11344 : }
3996 : :
3997 : : /*
3998 : : * PrepareTransactionBlock
3999 : : * This executes a PREPARE command.
4000 : : *
4001 : : * Since PREPARE may actually do a ROLLBACK, the result indicates what
4002 : : * happened: true for PREPARE, false for ROLLBACK.
4003 : : *
4004 : : * Note that we don't actually do anything here except change blockState.
4005 : : * The real work will be done in the upcoming PrepareTransaction().
4006 : : * We do it this way because it's not convenient to change memory context,
4007 : : * resource owner, etc while executing inside a Portal.
4008 : : */
4009 : : bool
2970 peter_e@gmx.net 4010 : 346 : PrepareTransactionBlock(const char *gid)
4011 : : {
4012 : : TransactionState s;
4013 : : bool result;
4014 : :
4015 : : /* Set up to commit the current transaction */
2461 peter@eisentraut.org 4016 : 346 : result = EndTransactionBlock(false);
4017 : :
4018 : : /* If successful, change outer tblock state to PREPARE */
7489 tgl@sss.pgh.pa.us 4019 [ + + ]: 346 : if (result)
4020 : : {
4021 : 344 : s = CurrentTransactionState;
4022 : :
4023 [ + + ]: 452 : while (s->parent != NULL)
4024 : 108 : s = s->parent;
4025 : :
4026 [ + - ]: 344 : if (s->blockState == TBLOCK_END)
4027 : : {
4028 : : /* Save GID where PrepareTransaction can find it again */
4029 : 344 : prepareGID = MemoryContextStrdup(TopTransactionContext, gid);
4030 : :
4031 : 344 : s->blockState = TBLOCK_PREPARE;
4032 : : }
4033 : : else
4034 : : {
4035 : : /*
4036 : : * ignore case where we are not in a transaction;
4037 : : * EndTransactionBlock already issued a warning.
4038 : : */
3024 tgl@sss.pgh.pa.us 4039 [ # # # # ]:UBC 0 : Assert(s->blockState == TBLOCK_STARTED ||
4040 : : s->blockState == TBLOCK_IMPLICIT_INPROGRESS);
4041 : : /* Don't send back a PREPARE result tag... */
7489 4042 : 0 : result = false;
4043 : : }
4044 : : }
4045 : :
7489 tgl@sss.pgh.pa.us 4046 :CBC 346 : return result;
4047 : : }
4048 : :
4049 : : /*
4050 : : * EndTransactionBlock
4051 : : * This executes a COMMIT command.
4052 : : *
4053 : : * Since COMMIT may actually do a ROLLBACK, the result indicates what
4054 : : * happened: true for COMMIT, false for ROLLBACK.
4055 : : *
4056 : : * Note that we don't actually do anything here except change blockState.
4057 : : * The real work will be done in the upcoming CommitTransactionCommand().
4058 : : * We do it this way because it's not convenient to change memory context,
4059 : : * resource owner, etc while executing inside a Portal.
4060 : : */
4061 : : bool
2461 peter@eisentraut.org 4062 : 9403 : EndTransactionBlock(bool chain)
4063 : : {
10329 bruce@momjian.us 4064 : 9403 : TransactionState s = CurrentTransactionState;
7814 tgl@sss.pgh.pa.us 4065 : 9403 : bool result = false;
4066 : :
4067 [ + + + + : 9403 : switch (s->blockState)
+ + - -
- ]
4068 : : {
4069 : : /*
4070 : : * We are in a transaction block, so tell CommitTransactionCommand
4071 : : * to COMMIT.
4072 : : */
7927 bruce@momjian.us 4073 : 8507 : case TBLOCK_INPROGRESS:
7814 tgl@sss.pgh.pa.us 4074 : 8507 : s->blockState = TBLOCK_END;
4075 : 8507 : result = true;
7840 4076 : 8507 : break;
4077 : :
4078 : : /*
4079 : : * We are in an implicit transaction block. If AND CHAIN was
4080 : : * specified, error. Otherwise commit, but issue a warning
4081 : : * because there was no explicit BEGIN before this.
4082 : : */
3024 4083 : 24 : case TBLOCK_IMPLICIT_INPROGRESS:
2293 peter@eisentraut.org 4084 [ + + ]: 24 : if (chain)
4085 [ + - ]: 12 : ereport(ERROR,
4086 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4087 : : /* translator: %s represents an SQL statement name */
4088 : : errmsg("%s can only be used in transaction blocks",
4089 : : "COMMIT AND CHAIN")));
4090 : : else
4091 [ + - ]: 12 : ereport(WARNING,
4092 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4093 : : errmsg("there is no transaction in progress")));
3024 tgl@sss.pgh.pa.us 4094 : 12 : s->blockState = TBLOCK_END;
4095 : 12 : result = true;
4096 : 12 : break;
4097 : :
4098 : : /*
4099 : : * We are in a failed transaction block. Tell
4100 : : * CommitTransactionCommand it's time to exit the block.
4101 : : */
7927 bruce@momjian.us 4102 : 380 : case TBLOCK_ABORT:
7763 tgl@sss.pgh.pa.us 4103 : 380 : s->blockState = TBLOCK_ABORT_END;
7927 bruce@momjian.us 4104 : 380 : break;
4105 : :
4106 : : /*
4107 : : * We are in a live subtransaction block. Set up to subcommit all
4108 : : * open subtransactions and then commit the main transaction.
4109 : : */
7769 tgl@sss.pgh.pa.us 4110 : 450 : case TBLOCK_SUBINPROGRESS:
4111 [ + + ]: 973 : while (s->parent != NULL)
4112 : : {
7763 4113 [ + - ]: 523 : if (s->blockState == TBLOCK_SUBINPROGRESS)
5266 simon@2ndQuadrant.co 4114 : 523 : s->blockState = TBLOCK_SUBCOMMIT;
4115 : : else
7763 tgl@sss.pgh.pa.us 4116 [ # # ]:UBC 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4117 : : BlockStateAsString(s->blockState));
7769 tgl@sss.pgh.pa.us 4118 :CBC 523 : s = s->parent;
4119 : : }
7763 4120 [ + - ]: 450 : if (s->blockState == TBLOCK_INPROGRESS)
4121 : 450 : s->blockState = TBLOCK_END;
4122 : : else
7763 tgl@sss.pgh.pa.us 4123 [ # # ]:UBC 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4124 : : BlockStateAsString(s->blockState));
7769 tgl@sss.pgh.pa.us 4125 :CBC 450 : result = true;
4126 : 450 : break;
4127 : :
4128 : : /*
4129 : : * Here we are inside an aborted subtransaction. Treat the COMMIT
4130 : : * as ROLLBACK: set up to abort everything and exit the main
4131 : : * transaction.
4132 : : */
7840 4133 : 30 : case TBLOCK_SUBABORT:
7763 4134 [ + + ]: 60 : while (s->parent != NULL)
4135 : : {
4136 [ - + ]: 30 : if (s->blockState == TBLOCK_SUBINPROGRESS)
7763 tgl@sss.pgh.pa.us 4137 :UBC 0 : s->blockState = TBLOCK_SUBABORT_PENDING;
7763 tgl@sss.pgh.pa.us 4138 [ + - ]:CBC 30 : else if (s->blockState == TBLOCK_SUBABORT)
4139 : 30 : s->blockState = TBLOCK_SUBABORT_END;
4140 : : else
7763 tgl@sss.pgh.pa.us 4141 [ # # ]:UBC 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4142 : : BlockStateAsString(s->blockState));
7763 tgl@sss.pgh.pa.us 4143 :CBC 30 : s = s->parent;
4144 : : }
4145 [ + - ]: 30 : if (s->blockState == TBLOCK_INPROGRESS)
4146 : 30 : s->blockState = TBLOCK_ABORT_PENDING;
7763 tgl@sss.pgh.pa.us 4147 [ # # ]:UBC 0 : else if (s->blockState == TBLOCK_ABORT)
4148 : 0 : s->blockState = TBLOCK_ABORT_END;
4149 : : else
4150 [ # # ]: 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4151 : : BlockStateAsString(s->blockState));
7840 tgl@sss.pgh.pa.us 4152 :CBC 30 : break;
4153 : :
4154 : : /*
4155 : : * The user issued COMMIT when not inside a transaction. For
4156 : : * COMMIT without CHAIN, issue a WARNING, staying in
4157 : : * TBLOCK_STARTED state. The upcoming call to
4158 : : * CommitTransactionCommand() will then close the transaction and
4159 : : * put us back into the default state. For COMMIT AND CHAIN,
4160 : : * error.
4161 : : */
7763 4162 : 12 : case TBLOCK_STARTED:
2293 peter@eisentraut.org 4163 [ + + ]: 12 : if (chain)
4164 [ + - ]: 3 : ereport(ERROR,
4165 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4166 : : /* translator: %s represents an SQL statement name */
4167 : : errmsg("%s can only be used in transaction blocks",
4168 : : "COMMIT AND CHAIN")));
4169 : : else
4170 [ + - ]: 9 : ereport(WARNING,
4171 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4172 : : errmsg("there is no transaction in progress")));
7719 tgl@sss.pgh.pa.us 4173 : 9 : result = true;
7927 bruce@momjian.us 4174 : 9 : break;
4175 : :
4176 : : /*
4177 : : * The user issued a COMMIT that somehow ran inside a parallel
4178 : : * worker. We can't cope with that.
4179 : : */
3885 rhaas@postgresql.org 4180 :UBC 0 : case TBLOCK_PARALLEL_INPROGRESS:
4181 [ # # ]: 0 : ereport(FATAL,
4182 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4183 : : errmsg("cannot commit during a parallel operation")));
4184 : : break;
4185 : :
4186 : : /* These cases are invalid. */
7927 bruce@momjian.us 4187 : 0 : case TBLOCK_DEFAULT:
4188 : : case TBLOCK_BEGIN:
4189 : : case TBLOCK_SUBBEGIN:
4190 : : case TBLOCK_END:
4191 : : case TBLOCK_SUBRELEASE:
4192 : : case TBLOCK_SUBCOMMIT:
4193 : : case TBLOCK_ABORT_END:
4194 : : case TBLOCK_SUBABORT_END:
4195 : : case TBLOCK_ABORT_PENDING:
4196 : : case TBLOCK_SUBABORT_PENDING:
4197 : : case TBLOCK_SUBRESTART:
4198 : : case TBLOCK_SUBABORT_RESTART:
4199 : : case TBLOCK_PREPARE:
7840 tgl@sss.pgh.pa.us 4200 [ # # ]: 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4201 : : BlockStateAsString(s->blockState));
4202 : : break;
4203 : : }
4204 : :
2461 peter@eisentraut.org 4205 [ + + + + :CBC 9388 : Assert(s->blockState == TBLOCK_STARTED ||
+ + - + ]
4206 : : s->blockState == TBLOCK_END ||
4207 : : s->blockState == TBLOCK_ABORT_END ||
4208 : : s->blockState == TBLOCK_ABORT_PENDING);
4209 : :
4210 : 9388 : s->chain = chain;
4211 : :
7814 tgl@sss.pgh.pa.us 4212 : 9388 : return result;
4213 : : }
4214 : :
4215 : : /*
4216 : : * UserAbortTransactionBlock
4217 : : * This executes a ROLLBACK command.
4218 : : *
4219 : : * As above, we don't actually do anything here except change blockState.
4220 : : */
4221 : : void
2461 peter@eisentraut.org 4222 : 1744 : UserAbortTransactionBlock(bool chain)
4223 : : {
10329 bruce@momjian.us 4224 : 1744 : TransactionState s = CurrentTransactionState;
4225 : :
7814 tgl@sss.pgh.pa.us 4226 [ + + + + : 1744 : switch (s->blockState)
- - - ]
4227 : : {
4228 : : /*
4229 : : * We are inside a transaction block and we got a ROLLBACK command
4230 : : * from the user, so tell CommitTransactionCommand to abort and
4231 : : * exit the transaction block.
4232 : : */
7763 4233 : 1315 : case TBLOCK_INPROGRESS:
4234 : 1315 : s->blockState = TBLOCK_ABORT_PENDING;
7840 4235 : 1315 : break;
4236 : :
4237 : : /*
4238 : : * We are inside a failed transaction block and we got a ROLLBACK
4239 : : * command from the user. Abort processing is already done, so
4240 : : * CommitTransactionCommand just has to cleanup and go back to
4241 : : * idle state.
4242 : : */
7763 4243 : 331 : case TBLOCK_ABORT:
4244 : 331 : s->blockState = TBLOCK_ABORT_END;
7840 4245 : 331 : break;
4246 : :
4247 : : /*
4248 : : * We are inside a subtransaction. Mark everything up to top
4249 : : * level as exitable.
4250 : : */
4251 : 59 : case TBLOCK_SUBINPROGRESS:
4252 : : case TBLOCK_SUBABORT:
7763 4253 [ + + ]: 224 : while (s->parent != NULL)
4254 : : {
4255 [ + + ]: 165 : if (s->blockState == TBLOCK_SUBINPROGRESS)
4256 : 152 : s->blockState = TBLOCK_SUBABORT_PENDING;
4257 [ + - ]: 13 : else if (s->blockState == TBLOCK_SUBABORT)
4258 : 13 : s->blockState = TBLOCK_SUBABORT_END;
4259 : : else
7763 tgl@sss.pgh.pa.us 4260 [ # # ]:UBC 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
4261 : : BlockStateAsString(s->blockState));
7763 tgl@sss.pgh.pa.us 4262 :CBC 165 : s = s->parent;
4263 : : }
4264 [ + - ]: 59 : if (s->blockState == TBLOCK_INPROGRESS)
4265 : 59 : s->blockState = TBLOCK_ABORT_PENDING;
7763 tgl@sss.pgh.pa.us 4266 [ # # ]:UBC 0 : else if (s->blockState == TBLOCK_ABORT)
4267 : 0 : s->blockState = TBLOCK_ABORT_END;
4268 : : else
4269 [ # # ]: 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
4270 : : BlockStateAsString(s->blockState));
7840 tgl@sss.pgh.pa.us 4271 :CBC 59 : break;
4272 : :
4273 : : /*
4274 : : * The user issued ABORT when not inside a transaction. For
4275 : : * ROLLBACK without CHAIN, issue a WARNING and go to abort state.
4276 : : * The upcoming call to CommitTransactionCommand() will then put
4277 : : * us back into the default state. For ROLLBACK AND CHAIN, error.
4278 : : *
4279 : : * We do the same thing with ABORT inside an implicit transaction,
4280 : : * although in this case we might be rolling back actual database
4281 : : * state changes. (It's debatable whether we should issue a
4282 : : * WARNING in this case, but we have done so historically.)
4283 : : */
4284 : 39 : case TBLOCK_STARTED:
4285 : : case TBLOCK_IMPLICIT_INPROGRESS:
2293 peter@eisentraut.org 4286 [ + + ]: 39 : if (chain)
4287 [ + - ]: 15 : ereport(ERROR,
4288 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4289 : : /* translator: %s represents an SQL statement name */
4290 : : errmsg("%s can only be used in transaction blocks",
4291 : : "ROLLBACK AND CHAIN")));
4292 : : else
4293 [ + - ]: 24 : ereport(WARNING,
4294 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4295 : : errmsg("there is no transaction in progress")));
7763 tgl@sss.pgh.pa.us 4296 : 24 : s->blockState = TBLOCK_ABORT_PENDING;
7840 4297 : 24 : break;
4298 : :
4299 : : /*
4300 : : * The user issued an ABORT that somehow ran inside a parallel
4301 : : * worker. We can't cope with that.
4302 : : */
3885 rhaas@postgresql.org 4303 :UBC 0 : case TBLOCK_PARALLEL_INPROGRESS:
4304 [ # # ]: 0 : ereport(FATAL,
4305 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4306 : : errmsg("cannot abort during a parallel operation")));
4307 : : break;
4308 : :
4309 : : /* These cases are invalid. */
7840 tgl@sss.pgh.pa.us 4310 : 0 : case TBLOCK_DEFAULT:
4311 : : case TBLOCK_BEGIN:
4312 : : case TBLOCK_SUBBEGIN:
4313 : : case TBLOCK_END:
4314 : : case TBLOCK_SUBRELEASE:
4315 : : case TBLOCK_SUBCOMMIT:
4316 : : case TBLOCK_ABORT_END:
4317 : : case TBLOCK_SUBABORT_END:
4318 : : case TBLOCK_ABORT_PENDING:
4319 : : case TBLOCK_SUBABORT_PENDING:
4320 : : case TBLOCK_SUBRESTART:
4321 : : case TBLOCK_SUBABORT_RESTART:
4322 : : case TBLOCK_PREPARE:
4323 [ # # ]: 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
4324 : : BlockStateAsString(s->blockState));
4325 : : break;
4326 : : }
4327 : :
2461 peter@eisentraut.org 4328 [ + + - + ]:CBC 1729 : Assert(s->blockState == TBLOCK_ABORT_END ||
4329 : : s->blockState == TBLOCK_ABORT_PENDING);
4330 : :
4331 : 1729 : s->chain = chain;
7814 tgl@sss.pgh.pa.us 4332 : 1729 : }
4333 : :
4334 : : /*
4335 : : * BeginImplicitTransactionBlock
4336 : : * Start an implicit transaction block if we're not already in one.
4337 : : *
4338 : : * Unlike BeginTransactionBlock, this is called directly from the main loop
4339 : : * in postgres.c, not within a Portal. So we can just change blockState
4340 : : * without a lot of ceremony. We do not expect caller to do
4341 : : * CommitTransactionCommand/StartTransactionCommand.
4342 : : */
4343 : : void
3024 4344 : 44464 : BeginImplicitTransactionBlock(void)
4345 : : {
4346 : 44464 : TransactionState s = CurrentTransactionState;
4347 : :
4348 : : /*
4349 : : * If we are in STARTED state (that is, no transaction block is open),
4350 : : * switch to IMPLICIT_INPROGRESS state, creating an implicit transaction
4351 : : * block.
4352 : : *
4353 : : * For caller convenience, we consider all other transaction states as
4354 : : * legal here; otherwise the caller would need its own state check, which
4355 : : * seems rather pointless.
4356 : : */
4357 [ + + ]: 44464 : if (s->blockState == TBLOCK_STARTED)
4358 : 5442 : s->blockState = TBLOCK_IMPLICIT_INPROGRESS;
4359 : 44464 : }
4360 : :
4361 : : /*
4362 : : * EndImplicitTransactionBlock
4363 : : * End an implicit transaction block, if we're in one.
4364 : : *
4365 : : * Like EndTransactionBlock, we just make any needed blockState change here.
4366 : : * The real work will be done in the upcoming CommitTransactionCommand().
4367 : : */
4368 : : void
4369 : 16388 : EndImplicitTransactionBlock(void)
4370 : : {
4371 : 16388 : TransactionState s = CurrentTransactionState;
4372 : :
4373 : : /*
4374 : : * If we are in IMPLICIT_INPROGRESS state, switch back to STARTED state,
4375 : : * allowing CommitTransactionCommand to commit whatever happened during
4376 : : * the implicit transaction block as though it were a single statement.
4377 : : *
4378 : : * For caller convenience, we consider all other transaction states as
4379 : : * legal here; otherwise the caller would need its own state check, which
4380 : : * seems rather pointless.
4381 : : */
4382 [ + + ]: 16388 : if (s->blockState == TBLOCK_IMPLICIT_INPROGRESS)
4383 : 4875 : s->blockState = TBLOCK_STARTED;
4384 : 16388 : }
4385 : :
4386 : : /*
4387 : : * DefineSavepoint
4388 : : * This executes a SAVEPOINT command.
4389 : : */
4390 : : void
2970 peter_e@gmx.net 4391 : 1351 : DefineSavepoint(const char *name)
4392 : : {
7781 bruce@momjian.us 4393 : 1351 : TransactionState s = CurrentTransactionState;
4394 : :
4395 : : /*
4396 : : * Workers synchronize transaction state at the beginning of each parallel
4397 : : * operation, so we can't account for new subtransactions after that
4398 : : * point. (Note that this check will certainly error out if s->blockState
4399 : : * is TBLOCK_PARALLEL_INPROGRESS, so we can treat that as an invalid case
4400 : : * below.)
4401 : : */
630 tgl@sss.pgh.pa.us 4402 [ + - - + ]: 1351 : if (IsInParallelMode() || IsParallelWorker())
3885 rhaas@postgresql.org 4403 [ # # ]:UBC 0 : ereport(ERROR,
4404 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4405 : : errmsg("cannot define savepoints during a parallel operation")));
4406 : :
7814 tgl@sss.pgh.pa.us 4407 [ + + - - ]:CBC 1351 : switch (s->blockState)
4408 : : {
4409 : 1345 : case TBLOCK_INPROGRESS:
4410 : : case TBLOCK_SUBINPROGRESS:
4411 : : /* Normal subtransaction start */
4412 : 1345 : PushTransaction();
3102 4413 : 1345 : s = CurrentTransactionState; /* changed by push */
4414 : :
4415 : : /*
4416 : : * Savepoint names, like the TransactionState block itself, live
4417 : : * in TopTransactionContext.
4418 : : */
7763 4419 [ + + ]: 1345 : if (name)
4420 : 974 : s->name = MemoryContextStrdup(TopTransactionContext, name);
7814 4421 : 1345 : break;
4422 : :
4423 : : /*
4424 : : * We disallow savepoint commands in implicit transaction blocks.
4425 : : * There would be no great difficulty in allowing them so far as
4426 : : * this module is concerned, but a savepoint seems inconsistent
4427 : : * with exec_simple_query's behavior of abandoning the whole query
4428 : : * string upon error. Also, the point of an implicit transaction
4429 : : * block (as opposed to a regular one) is to automatically close
4430 : : * after an error, so it's hard to see how a savepoint would fit
4431 : : * into that.
4432 : : *
4433 : : * The error messages for this are phrased as if there were no
4434 : : * active transaction block at all, which is historical but
4435 : : * perhaps could be improved.
4436 : : */
3024 4437 : 6 : case TBLOCK_IMPLICIT_INPROGRESS:
4438 [ + - ]: 6 : ereport(ERROR,
4439 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4440 : : /* translator: %s represents an SQL statement name */
4441 : : errmsg("%s can only be used in transaction blocks",
4442 : : "SAVEPOINT")));
4443 : : break;
4444 : :
4445 : : /* These cases are invalid. */
7814 tgl@sss.pgh.pa.us 4446 :UBC 0 : case TBLOCK_DEFAULT:
4447 : : case TBLOCK_STARTED:
4448 : : case TBLOCK_BEGIN:
4449 : : case TBLOCK_PARALLEL_INPROGRESS:
4450 : : case TBLOCK_SUBBEGIN:
4451 : : case TBLOCK_END:
4452 : : case TBLOCK_SUBRELEASE:
4453 : : case TBLOCK_SUBCOMMIT:
4454 : : case TBLOCK_ABORT:
4455 : : case TBLOCK_SUBABORT:
4456 : : case TBLOCK_ABORT_END:
4457 : : case TBLOCK_SUBABORT_END:
4458 : : case TBLOCK_ABORT_PENDING:
4459 : : case TBLOCK_SUBABORT_PENDING:
4460 : : case TBLOCK_SUBRESTART:
4461 : : case TBLOCK_SUBABORT_RESTART:
4462 : : case TBLOCK_PREPARE:
7810 4463 [ # # ]: 0 : elog(FATAL, "DefineSavepoint: unexpected state %s",
4464 : : BlockStateAsString(s->blockState));
4465 : : break;
4466 : : }
7814 tgl@sss.pgh.pa.us 4467 :CBC 1345 : }
4468 : :
4469 : : /*
4470 : : * ReleaseSavepoint
4471 : : * This executes a RELEASE command.
4472 : : *
4473 : : * As above, we don't actually do anything here except change blockState.
4474 : : */
4475 : : void
2862 peter_e@gmx.net 4476 : 141 : ReleaseSavepoint(const char *name)
4477 : : {
7781 bruce@momjian.us 4478 : 141 : TransactionState s = CurrentTransactionState;
4479 : : TransactionState target,
4480 : : xact;
4481 : :
4482 : : /*
4483 : : * Workers synchronize transaction state at the beginning of each parallel
4484 : : * operation, so we can't account for transaction state change after that
4485 : : * point. (Note that this check will certainly error out if s->blockState
4486 : : * is TBLOCK_PARALLEL_INPROGRESS, so we can treat that as an invalid case
4487 : : * below.)
4488 : : */
630 tgl@sss.pgh.pa.us 4489 [ + - - + ]: 141 : if (IsInParallelMode() || IsParallelWorker())
3885 rhaas@postgresql.org 4490 [ # # ]:UBC 0 : ereport(ERROR,
4491 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4492 : : errmsg("cannot release savepoints during a parallel operation")));
4493 : :
7814 tgl@sss.pgh.pa.us 4494 [ - + + - :CBC 141 : switch (s->blockState)
- ]
4495 : : {
4496 : : /*
4497 : : * We can't release a savepoint if there is no savepoint defined.
4498 : : */
7814 tgl@sss.pgh.pa.us 4499 :UBC 0 : case TBLOCK_INPROGRESS:
4500 [ # # ]: 0 : ereport(ERROR,
4501 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4502 : : errmsg("savepoint \"%s\" does not exist", name)));
4503 : : break;
4504 : :
3024 tgl@sss.pgh.pa.us 4505 :CBC 3 : case TBLOCK_IMPLICIT_INPROGRESS:
4506 : : /* See comment about implicit transactions in DefineSavepoint */
4507 [ + - ]: 3 : ereport(ERROR,
4508 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4509 : : /* translator: %s represents an SQL statement name */
4510 : : errmsg("%s can only be used in transaction blocks",
4511 : : "RELEASE SAVEPOINT")));
4512 : : break;
4513 : :
4514 : : /*
4515 : : * We are in a non-aborted subtransaction. This is the only valid
4516 : : * case.
4517 : : */
7814 4518 : 138 : case TBLOCK_SUBINPROGRESS:
4519 : 138 : break;
4520 : :
4521 : : /* These cases are invalid. */
7814 tgl@sss.pgh.pa.us 4522 :UBC 0 : case TBLOCK_DEFAULT:
4523 : : case TBLOCK_STARTED:
4524 : : case TBLOCK_BEGIN:
4525 : : case TBLOCK_PARALLEL_INPROGRESS:
4526 : : case TBLOCK_SUBBEGIN:
4527 : : case TBLOCK_END:
4528 : : case TBLOCK_SUBRELEASE:
4529 : : case TBLOCK_SUBCOMMIT:
4530 : : case TBLOCK_ABORT:
4531 : : case TBLOCK_SUBABORT:
4532 : : case TBLOCK_ABORT_END:
4533 : : case TBLOCK_SUBABORT_END:
4534 : : case TBLOCK_ABORT_PENDING:
4535 : : case TBLOCK_SUBABORT_PENDING:
4536 : : case TBLOCK_SUBRESTART:
4537 : : case TBLOCK_SUBABORT_RESTART:
4538 : : case TBLOCK_PREPARE:
4539 [ # # ]: 0 : elog(FATAL, "ReleaseSavepoint: unexpected state %s",
4540 : : BlockStateAsString(s->blockState));
4541 : : break;
4542 : : }
4543 : :
85 peter@eisentraut.org 4544 [ + - ]:GNC 224 : for (target = s; target; target = target->parent)
4545 : : {
4546 [ + - + + ]: 224 : if (target->name && strcmp(target->name, name) == 0)
7814 tgl@sss.pgh.pa.us 4547 :CBC 138 : break;
4548 : : }
4549 : :
85 peter@eisentraut.org 4550 [ - + ]:GNC 138 : if (!target)
7814 tgl@sss.pgh.pa.us 4551 [ # # ]:UBC 0 : ereport(ERROR,
4552 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4553 : : errmsg("savepoint \"%s\" does not exist", name)));
4554 : :
4555 : : /* disallow crossing savepoint level boundaries */
7785 tgl@sss.pgh.pa.us 4556 [ - + ]:CBC 138 : if (target->savepointLevel != s->savepointLevel)
7785 tgl@sss.pgh.pa.us 4557 [ # # ]:UBC 0 : ereport(ERROR,
4558 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4559 : : errmsg("savepoint \"%s\" does not exist within current savepoint level", name)));
4560 : :
4561 : : /*
4562 : : * Mark "commit pending" all subtransactions up to the target
4563 : : * subtransaction. The actual commits will happen when control gets to
4564 : : * CommitTransactionCommand.
4565 : : */
7785 tgl@sss.pgh.pa.us 4566 :CBC 138 : xact = CurrentTransactionState;
4567 : : for (;;)
4568 : : {
4569 [ - + ]: 224 : Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
5266 simon@2ndQuadrant.co 4570 : 224 : xact->blockState = TBLOCK_SUBRELEASE;
7785 tgl@sss.pgh.pa.us 4571 [ + + ]: 224 : if (xact == target)
4572 : 138 : break;
4573 : 86 : xact = xact->parent;
85 peter@eisentraut.org 4574 [ - + ]:GNC 86 : Assert(xact);
4575 : : }
7814 tgl@sss.pgh.pa.us 4576 :CBC 138 : }
4577 : :
4578 : : /*
4579 : : * RollbackToSavepoint
4580 : : * This executes a ROLLBACK TO <savepoint> command.
4581 : : *
4582 : : * As above, we don't actually do anything here except change blockState.
4583 : : */
4584 : : void
2862 peter_e@gmx.net 4585 : 377 : RollbackToSavepoint(const char *name)
4586 : : {
7814 tgl@sss.pgh.pa.us 4587 : 377 : TransactionState s = CurrentTransactionState;
4588 : : TransactionState target,
4589 : : xact;
4590 : :
4591 : : /*
4592 : : * Workers synchronize transaction state at the beginning of each parallel
4593 : : * operation, so we can't account for transaction state change after that
4594 : : * point. (Note that this check will certainly error out if s->blockState
4595 : : * is TBLOCK_PARALLEL_INPROGRESS, so we can treat that as an invalid case
4596 : : * below.)
4597 : : */
630 4598 [ + - - + ]: 377 : if (IsInParallelMode() || IsParallelWorker())
3885 rhaas@postgresql.org 4599 [ # # ]:UBC 0 : ereport(ERROR,
4600 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4601 : : errmsg("cannot rollback to savepoints during a parallel operation")));
4602 : :
7814 tgl@sss.pgh.pa.us 4603 [ + + + - :CBC 377 : switch (s->blockState)
- ]
4604 : : {
4605 : : /*
4606 : : * We can't rollback to a savepoint if there is no savepoint
4607 : : * defined.
4608 : : */
4609 : 3 : case TBLOCK_INPROGRESS:
4610 : : case TBLOCK_ABORT:
4611 [ + - ]: 3 : ereport(ERROR,
4612 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4613 : : errmsg("savepoint \"%s\" does not exist", name)));
4614 : : break;
4615 : :
3024 4616 : 3 : case TBLOCK_IMPLICIT_INPROGRESS:
4617 : : /* See comment about implicit transactions in DefineSavepoint */
4618 [ + - ]: 3 : ereport(ERROR,
4619 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4620 : : /* translator: %s represents an SQL statement name */
4621 : : errmsg("%s can only be used in transaction blocks",
4622 : : "ROLLBACK TO SAVEPOINT")));
4623 : : break;
4624 : :
4625 : : /*
4626 : : * There is at least one savepoint, so proceed.
4627 : : */
7814 4628 : 371 : case TBLOCK_SUBINPROGRESS:
4629 : : case TBLOCK_SUBABORT:
4630 : 371 : break;
4631 : :
4632 : : /* These cases are invalid. */
7814 tgl@sss.pgh.pa.us 4633 :UBC 0 : case TBLOCK_DEFAULT:
4634 : : case TBLOCK_STARTED:
4635 : : case TBLOCK_BEGIN:
4636 : : case TBLOCK_PARALLEL_INPROGRESS:
4637 : : case TBLOCK_SUBBEGIN:
4638 : : case TBLOCK_END:
4639 : : case TBLOCK_SUBRELEASE:
4640 : : case TBLOCK_SUBCOMMIT:
4641 : : case TBLOCK_ABORT_END:
4642 : : case TBLOCK_SUBABORT_END:
4643 : : case TBLOCK_ABORT_PENDING:
4644 : : case TBLOCK_SUBABORT_PENDING:
4645 : : case TBLOCK_SUBRESTART:
4646 : : case TBLOCK_SUBABORT_RESTART:
4647 : : case TBLOCK_PREPARE:
4648 [ # # ]: 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
4649 : : BlockStateAsString(s->blockState));
4650 : : break;
4651 : : }
4652 : :
85 peter@eisentraut.org 4653 [ + - ]:GNC 403 : for (target = s; target; target = target->parent)
4654 : : {
4655 [ + - + + ]: 403 : if (target->name && strcmp(target->name, name) == 0)
7814 tgl@sss.pgh.pa.us 4656 :CBC 371 : break;
4657 : : }
4658 : :
85 peter@eisentraut.org 4659 [ - + ]:GNC 371 : if (!target)
7814 tgl@sss.pgh.pa.us 4660 [ # # ]:UBC 0 : ereport(ERROR,
4661 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4662 : : errmsg("savepoint \"%s\" does not exist", name)));
4663 : :
4664 : : /* disallow crossing savepoint level boundaries */
7807 tgl@sss.pgh.pa.us 4665 [ - + ]:CBC 371 : if (target->savepointLevel != s->savepointLevel)
7807 tgl@sss.pgh.pa.us 4666 [ # # ]:UBC 0 : ereport(ERROR,
4667 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4668 : : errmsg("savepoint \"%s\" does not exist within current savepoint level", name)));
4669 : :
4670 : : /*
4671 : : * Mark "abort pending" all subtransactions up to the target
4672 : : * subtransaction. The actual aborts will happen when control gets to
4673 : : * CommitTransactionCommand.
4674 : : */
7814 tgl@sss.pgh.pa.us 4675 :CBC 371 : xact = CurrentTransactionState;
4676 : : for (;;)
4677 : : {
7763 4678 [ + + ]: 403 : if (xact == target)
4679 : 371 : break;
4680 [ + - ]: 32 : if (xact->blockState == TBLOCK_SUBINPROGRESS)
4681 : 32 : xact->blockState = TBLOCK_SUBABORT_PENDING;
7763 tgl@sss.pgh.pa.us 4682 [ # # ]:UBC 0 : else if (xact->blockState == TBLOCK_SUBABORT)
4683 : 0 : xact->blockState = TBLOCK_SUBABORT_END;
4684 : : else
4685 [ # # ]: 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
4686 : : BlockStateAsString(xact->blockState));
7814 tgl@sss.pgh.pa.us 4687 :CBC 32 : xact = xact->parent;
85 peter@eisentraut.org 4688 [ - + ]:GNC 32 : Assert(xact);
4689 : : }
4690 : :
4691 : : /* And mark the target as "restart pending" */
7763 tgl@sss.pgh.pa.us 4692 [ + + ]:CBC 371 : if (xact->blockState == TBLOCK_SUBINPROGRESS)
4693 : 266 : xact->blockState = TBLOCK_SUBRESTART;
4694 [ + - ]: 105 : else if (xact->blockState == TBLOCK_SUBABORT)
4695 : 105 : xact->blockState = TBLOCK_SUBABORT_RESTART;
4696 : : else
7763 tgl@sss.pgh.pa.us 4697 [ # # ]:UBC 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
4698 : : BlockStateAsString(xact->blockState));
7814 tgl@sss.pgh.pa.us 4699 :CBC 371 : }
4700 : :
4701 : : /*
4702 : : * BeginInternalSubTransaction
4703 : : * This is the same as DefineSavepoint except it allows TBLOCK_STARTED,
4704 : : * TBLOCK_IMPLICIT_INPROGRESS, TBLOCK_PARALLEL_INPROGRESS, TBLOCK_END,
4705 : : * and TBLOCK_PREPARE states, and therefore it can safely be used in
4706 : : * functions that might be called when not inside a BEGIN block or when
4707 : : * running deferred triggers at COMMIT/PREPARE time. Also, it
4708 : : * automatically does CommitTransactionCommand/StartTransactionCommand
4709 : : * instead of expecting the caller to do it.
4710 : : */
4711 : : void
2970 peter_e@gmx.net 4712 : 7772 : BeginInternalSubTransaction(const char *name)
4713 : : {
7781 bruce@momjian.us 4714 : 7772 : TransactionState s = CurrentTransactionState;
630 tgl@sss.pgh.pa.us 4715 : 7772 : bool save_ExitOnAnyError = ExitOnAnyError;
4716 : :
4717 : : /*
4718 : : * Errors within this function are improbable, but if one does happen we
4719 : : * force a FATAL exit. Callers generally aren't prepared to handle losing
4720 : : * control, and moreover our transaction state is probably corrupted if we
4721 : : * fail partway through; so an ordinary ERROR longjmp isn't okay.
4722 : : */
4723 : 7772 : ExitOnAnyError = true;
4724 : :
4725 : : /*
4726 : : * We do not check for parallel mode here. It's permissible to start and
4727 : : * end "internal" subtransactions while in parallel mode, so long as no
4728 : : * new XIDs or command IDs are assigned. Enforcement of that occurs in
4729 : : * AssignTransactionId() and CommandCounterIncrement().
4730 : : */
4731 : :
7810 4732 [ + - - ]: 7772 : switch (s->blockState)
4733 : : {
4734 : 7772 : case TBLOCK_STARTED:
4735 : : case TBLOCK_INPROGRESS:
4736 : : case TBLOCK_IMPLICIT_INPROGRESS:
4737 : : case TBLOCK_PARALLEL_INPROGRESS:
4738 : : case TBLOCK_END:
4739 : : case TBLOCK_PREPARE:
4740 : : case TBLOCK_SUBINPROGRESS:
4741 : : /* Normal subtransaction start */
4742 : 7772 : PushTransaction();
3102 4743 : 7772 : s = CurrentTransactionState; /* changed by push */
4744 : :
4745 : : /*
4746 : : * Savepoint names, like the TransactionState block itself, live
4747 : : * in TopTransactionContext.
4748 : : */
7810 4749 [ + + ]: 7772 : if (name)
7763 4750 : 913 : s->name = MemoryContextStrdup(TopTransactionContext, name);
7810 4751 : 7772 : break;
4752 : :
4753 : : /* These cases are invalid. */
7810 tgl@sss.pgh.pa.us 4754 :UBC 0 : case TBLOCK_DEFAULT:
4755 : : case TBLOCK_BEGIN:
4756 : : case TBLOCK_SUBBEGIN:
4757 : : case TBLOCK_SUBRELEASE:
4758 : : case TBLOCK_SUBCOMMIT:
4759 : : case TBLOCK_ABORT:
4760 : : case TBLOCK_SUBABORT:
4761 : : case TBLOCK_ABORT_END:
4762 : : case TBLOCK_SUBABORT_END:
4763 : : case TBLOCK_ABORT_PENDING:
4764 : : case TBLOCK_SUBABORT_PENDING:
4765 : : case TBLOCK_SUBRESTART:
4766 : : case TBLOCK_SUBABORT_RESTART:
4767 [ # # ]: 0 : elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
4768 : : BlockStateAsString(s->blockState));
4769 : : break;
4770 : : }
4771 : :
7810 tgl@sss.pgh.pa.us 4772 :CBC 7772 : CommitTransactionCommand();
4773 : 7772 : StartTransactionCommand();
4774 : :
630 4775 : 7772 : ExitOnAnyError = save_ExitOnAnyError;
7810 4776 : 7772 : }
4777 : :
4778 : : /*
4779 : : * ReleaseCurrentSubTransaction
4780 : : *
4781 : : * RELEASE (ie, commit) the innermost subtransaction, regardless of its
4782 : : * savepoint name (if any).
4783 : : * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
4784 : : */
4785 : : void
4786 : 3686 : ReleaseCurrentSubTransaction(void)
4787 : : {
4788 : 3686 : TransactionState s = CurrentTransactionState;
4789 : :
4790 : : /*
4791 : : * We do not check for parallel mode here. It's permissible to start and
4792 : : * end "internal" subtransactions while in parallel mode, so long as no
4793 : : * new XIDs or command IDs are assigned.
4794 : : */
4795 : :
4796 [ - + ]: 3686 : if (s->blockState != TBLOCK_SUBINPROGRESS)
7810 tgl@sss.pgh.pa.us 4797 [ # # ]:UBC 0 : elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
4798 : : BlockStateAsString(s->blockState));
7769 tgl@sss.pgh.pa.us 4799 [ - + ]:CBC 3686 : Assert(s->state == TRANS_INPROGRESS);
7810 4800 : 3686 : MemoryContextSwitchTo(CurTransactionContext);
5216 simon@2ndQuadrant.co 4801 : 3686 : CommitSubTransaction();
7369 bruce@momjian.us 4802 : 3686 : s = CurrentTransactionState; /* changed by pop */
7769 tgl@sss.pgh.pa.us 4803 [ - + ]: 3686 : Assert(s->state == TRANS_INPROGRESS);
7810 4804 : 3686 : }
4805 : :
4806 : : /*
4807 : : * RollbackAndReleaseCurrentSubTransaction
4808 : : *
4809 : : * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
4810 : : * of its savepoint name (if any).
4811 : : * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
4812 : : */
4813 : : void
4814 : 4086 : RollbackAndReleaseCurrentSubTransaction(void)
4815 : : {
4816 : 4086 : TransactionState s = CurrentTransactionState;
4817 : :
4818 : : /*
4819 : : * We do not check for parallel mode here. It's permissible to start and
4820 : : * end "internal" subtransactions while in parallel mode, so long as no
4821 : : * new XIDs or command IDs are assigned.
4822 : : */
4823 : :
4824 [ + - - ]: 4086 : switch (s->blockState)
4825 : : {
4826 : : /* Must be in a subtransaction */
4827 : 4086 : case TBLOCK_SUBINPROGRESS:
4828 : : case TBLOCK_SUBABORT:
4829 : 4086 : break;
4830 : :
4831 : : /* These cases are invalid. */
7810 tgl@sss.pgh.pa.us 4832 :UBC 0 : case TBLOCK_DEFAULT:
4833 : : case TBLOCK_STARTED:
4834 : : case TBLOCK_BEGIN:
4835 : : case TBLOCK_IMPLICIT_INPROGRESS:
4836 : : case TBLOCK_PARALLEL_INPROGRESS:
4837 : : case TBLOCK_SUBBEGIN:
4838 : : case TBLOCK_INPROGRESS:
4839 : : case TBLOCK_END:
4840 : : case TBLOCK_SUBRELEASE:
4841 : : case TBLOCK_SUBCOMMIT:
4842 : : case TBLOCK_ABORT:
4843 : : case TBLOCK_ABORT_END:
4844 : : case TBLOCK_SUBABORT_END:
4845 : : case TBLOCK_ABORT_PENDING:
4846 : : case TBLOCK_SUBABORT_PENDING:
4847 : : case TBLOCK_SUBRESTART:
4848 : : case TBLOCK_SUBABORT_RESTART:
4849 : : case TBLOCK_PREPARE:
4850 [ # # ]: 0 : elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
4851 : : BlockStateAsString(s->blockState));
4852 : : break;
4853 : : }
4854 : :
4855 : : /*
4856 : : * Abort the current subtransaction, if needed.
4857 : : */
7810 tgl@sss.pgh.pa.us 4858 [ + + ]:CBC 4086 : if (s->blockState == TBLOCK_SUBINPROGRESS)
4859 : 3173 : AbortSubTransaction();
4860 : :
4861 : : /* And clean it up, too */
7763 4862 : 4086 : CleanupSubTransaction();
4863 : :
4864 : 4086 : s = CurrentTransactionState; /* changed by pop */
1147 peter@eisentraut.org 4865 [ + + + + : 4086 : Assert(s->blockState == TBLOCK_SUBINPROGRESS ||
+ - + + -
+ ]
4866 : : s->blockState == TBLOCK_INPROGRESS ||
4867 : : s->blockState == TBLOCK_IMPLICIT_INPROGRESS ||
4868 : : s->blockState == TBLOCK_PARALLEL_INPROGRESS ||
4869 : : s->blockState == TBLOCK_STARTED);
10754 scrappy@hub.org 4870 : 4086 : }
4871 : :
4872 : : /*
4873 : : * AbortOutOfAnyTransaction
4874 : : *
4875 : : * This routine is provided for error recovery purposes. It aborts any
4876 : : * active transaction or transaction block, leaving the system in a known
4877 : : * idle state.
4878 : : */
4879 : : void
9186 tgl@sss.pgh.pa.us 4880 : 15768 : AbortOutOfAnyTransaction(void)
4881 : : {
9935 4882 : 15768 : TransactionState s = CurrentTransactionState;
4883 : :
4884 : : /* Ensure we're not running in a doomed memory context */
3048 4885 : 15768 : AtAbort_Memory();
4886 : :
4887 : : /*
4888 : : * Get out of any transaction or nested transaction
4889 : : */
4890 : : do
4891 : : {
7840 4892 [ + + + - : 15768 : switch (s->blockState)
- - ]
4893 : : {
4894 : 15074 : case TBLOCK_DEFAULT:
4952 4895 [ - + ]: 15074 : if (s->state == TRANS_DEFAULT)
4896 : : {
4897 : : /* Not in a transaction, do nothing */
4898 : : }
4899 : : else
4900 : : {
4901 : : /*
4902 : : * We can get here after an error during transaction start
4903 : : * (state will be TRANS_START). Need to clean up the
4904 : : * incompletely started transaction. First, adjust the
4905 : : * low-level state to suppress warning message from
4906 : : * AbortTransaction.
4907 : : */
4952 tgl@sss.pgh.pa.us 4908 [ # # ]:UBC 0 : if (s->state == TRANS_START)
4909 : 0 : s->state = TRANS_INPROGRESS;
4910 : 0 : AbortTransaction();
4911 : 0 : CleanupTransaction();
4912 : : }
7840 tgl@sss.pgh.pa.us 4913 :CBC 15074 : break;
4914 : 682 : case TBLOCK_STARTED:
4915 : : case TBLOCK_BEGIN:
4916 : : case TBLOCK_INPROGRESS:
4917 : : case TBLOCK_IMPLICIT_INPROGRESS:
4918 : : case TBLOCK_PARALLEL_INPROGRESS:
4919 : : case TBLOCK_END:
4920 : : case TBLOCK_ABORT_PENDING:
4921 : : case TBLOCK_PREPARE:
4922 : : /* In a transaction, so clean up */
4923 : 682 : AbortTransaction();
4924 : 682 : CleanupTransaction();
4925 : 682 : s->blockState = TBLOCK_DEFAULT;
4926 : 682 : break;
4927 : 12 : case TBLOCK_ABORT:
4928 : : case TBLOCK_ABORT_END:
4929 : :
4930 : : /*
4931 : : * AbortTransaction is already done, still need Cleanup.
4932 : : * However, if we failed partway through running ROLLBACK,
4933 : : * there will be an active portal running that command, which
4934 : : * we need to shut down before doing CleanupTransaction.
4935 : : */
3048 4936 : 12 : AtAbort_Portals();
7840 4937 : 12 : CleanupTransaction();
4938 : 12 : s->blockState = TBLOCK_DEFAULT;
4939 : 12 : break;
4940 : :
4941 : : /*
4942 : : * In a subtransaction, so clean it up and abort parent too
4943 : : */
7763 tgl@sss.pgh.pa.us 4944 :UBC 0 : case TBLOCK_SUBBEGIN:
4945 : : case TBLOCK_SUBINPROGRESS:
4946 : : case TBLOCK_SUBRELEASE:
4947 : : case TBLOCK_SUBCOMMIT:
4948 : : case TBLOCK_SUBABORT_PENDING:
4949 : : case TBLOCK_SUBRESTART:
7840 4950 : 0 : AbortSubTransaction();
4951 : 0 : CleanupSubTransaction();
7781 bruce@momjian.us 4952 : 0 : s = CurrentTransactionState; /* changed by pop */
7840 tgl@sss.pgh.pa.us 4953 : 0 : break;
4954 : :
4955 : 0 : case TBLOCK_SUBABORT:
4956 : : case TBLOCK_SUBABORT_END:
4957 : : case TBLOCK_SUBABORT_RESTART:
4958 : : /* As above, but AbortSubTransaction already done */
3048 4959 [ # # ]: 0 : if (s->curTransactionOwner)
4960 : : {
4961 : : /* As in TBLOCK_ABORT, might have a live portal to zap */
4962 : 0 : AtSubAbort_Portals(s->subTransactionId,
4963 : 0 : s->parent->subTransactionId,
4964 : : s->curTransactionOwner,
4965 : 0 : s->parent->curTransactionOwner);
4966 : : }
7840 4967 : 0 : CleanupSubTransaction();
7781 bruce@momjian.us 4968 : 0 : s = CurrentTransactionState; /* changed by pop */
7840 tgl@sss.pgh.pa.us 4969 : 0 : break;
4970 : : }
7840 tgl@sss.pgh.pa.us 4971 [ - + ]:CBC 15768 : } while (s->blockState != TBLOCK_DEFAULT);
4972 : :
4973 : : /* Should be out of all subxacts now */
4974 [ - + ]: 15768 : Assert(s->parent == NULL);
4975 : :
4976 : : /*
4977 : : * Revert to TopMemoryContext, to ensure we exit in a well-defined state
4978 : : * whether there were any transactions to close or not. (Callers that
4979 : : * don't intend to exit soon should switch to some other context to avoid
4980 : : * long-term memory leaks.)
4981 : : */
535 4982 : 15768 : MemoryContextSwitchTo(TopMemoryContext);
9935 4983 : 15768 : }
4984 : :
4985 : : /*
4986 : : * IsTransactionBlock --- are we within a transaction block?
4987 : : */
4988 : : bool
9186 4989 : 202366 : IsTransactionBlock(void)
4990 : : {
10329 bruce@momjian.us 4991 : 202366 : TransactionState s = CurrentTransactionState;
4992 : :
7927 4993 [ + + + + ]: 202366 : if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
8272 tgl@sss.pgh.pa.us 4994 : 141219 : return false;
4995 : :
4996 : 61147 : return true;
4997 : : }
4998 : :
4999 : : /*
5000 : : * IsTransactionOrTransactionBlock --- are we within either a transaction
5001 : : * or a transaction block? (The backend is only really "idle" when this
5002 : : * returns false.)
5003 : : *
5004 : : * This should match up with IsTransactionBlock and IsTransactionState.
5005 : : */
5006 : : bool
8099 5007 : 678877 : IsTransactionOrTransactionBlock(void)
5008 : : {
5009 : 678877 : TransactionState s = CurrentTransactionState;
5010 : :
7927 bruce@momjian.us 5011 [ + + ]: 678877 : if (s->blockState == TBLOCK_DEFAULT)
8099 tgl@sss.pgh.pa.us 5012 : 594753 : return false;
5013 : :
5014 : 84124 : return true;
5015 : : }
5016 : :
5017 : : /*
5018 : : * TransactionBlockStatusCode - return status code to send in ReadyForQuery
5019 : : */
5020 : : char
8272 5021 : 331071 : TransactionBlockStatusCode(void)
5022 : : {
5023 : 331071 : TransactionState s = CurrentTransactionState;
5024 : :
5025 [ + + + - ]: 331071 : switch (s->blockState)
5026 : : {
5027 : 247824 : case TBLOCK_DEFAULT:
5028 : : case TBLOCK_STARTED:
5029 : 247824 : return 'I'; /* idle --- not in transaction */
5030 : 82317 : case TBLOCK_BEGIN:
5031 : : case TBLOCK_SUBBEGIN:
5032 : : case TBLOCK_INPROGRESS:
5033 : : case TBLOCK_IMPLICIT_INPROGRESS:
5034 : : case TBLOCK_PARALLEL_INPROGRESS:
5035 : : case TBLOCK_SUBINPROGRESS:
5036 : : case TBLOCK_END:
5037 : : case TBLOCK_SUBRELEASE:
5038 : : case TBLOCK_SUBCOMMIT:
5039 : : case TBLOCK_PREPARE:
5040 : 82317 : return 'T'; /* in transaction */
5041 : 930 : case TBLOCK_ABORT:
5042 : : case TBLOCK_SUBABORT:
5043 : : case TBLOCK_ABORT_END:
5044 : : case TBLOCK_SUBABORT_END:
5045 : : case TBLOCK_ABORT_PENDING:
5046 : : case TBLOCK_SUBABORT_PENDING:
5047 : : case TBLOCK_SUBRESTART:
5048 : : case TBLOCK_SUBABORT_RESTART:
5049 : 930 : return 'E'; /* in failed transaction */
5050 : : }
5051 : :
5052 : : /* should never get here */
7840 tgl@sss.pgh.pa.us 5053 [ # # ]:UBC 0 : elog(FATAL, "invalid transaction block state: %s",
5054 : : BlockStateAsString(s->blockState));
5055 : : return 0; /* keep compiler quiet */
5056 : : }
5057 : :
5058 : : /*
5059 : : * IsSubTransaction
5060 : : */
5061 : : bool
7840 tgl@sss.pgh.pa.us 5062 :CBC 548327 : IsSubTransaction(void)
5063 : : {
5064 : 548327 : TransactionState s = CurrentTransactionState;
5065 : :
7809 5066 [ + + ]: 548327 : if (s->nestingLevel >= 2)
5067 : 462 : return true;
5068 : :
5069 : 547865 : return false;
5070 : : }
5071 : :
5072 : : /*
5073 : : * StartSubTransaction
5074 : : *
5075 : : * If you're wondering why this is separate from PushTransaction: it's because
5076 : : * we can't conveniently do this stuff right inside DefineSavepoint. The
5077 : : * SAVEPOINT utility command will be executed inside a Portal, and if we
5078 : : * muck with CurrentMemoryContext or CurrentResourceOwner then exit from
5079 : : * the Portal will undo those settings. So we make DefineSavepoint just
5080 : : * push a dummy transaction block, and when control returns to the main
5081 : : * idle loop, CommitTransactionCommand will be called, and we'll come here
5082 : : * to finish starting the subtransaction.
5083 : : */
5084 : : static void
7840 5085 : 9117 : StartSubTransaction(void)
5086 : : {
5087 : 9117 : TransactionState s = CurrentTransactionState;
5088 : :
5089 [ - + ]: 9117 : if (s->state != TRANS_DEFAULT)
7813 tgl@sss.pgh.pa.us 5090 [ # # ]:UBC 0 : elog(WARNING, "StartSubTransaction while in %s state",
5091 : : TransStateAsString(s->state));
5092 : :
7840 tgl@sss.pgh.pa.us 5093 :CBC 9117 : s->state = TRANS_START;
5094 : :
5095 : : /*
5096 : : * Initialize subsystems for new subtransaction
5097 : : *
5098 : : * must initialize resource-management stuff first
5099 : : */
7824 5100 : 9117 : AtSubStart_Memory();
5101 : 9117 : AtSubStart_ResourceOwner();
7769 5102 : 9117 : AfterTriggerBeginSubXact();
5103 : :
7840 5104 : 9117 : s->state = TRANS_INPROGRESS;
5105 : :
5106 : : /*
5107 : : * Call start-of-subxact callbacks
5108 : : */
7763 5109 : 9117 : CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
5110 : 9117 : s->parent->subTransactionId);
5111 : :
7840 5112 : 9117 : ShowTransactionState("StartSubTransaction");
5113 : 9117 : }
5114 : :
5115 : : /*
5116 : : * CommitSubTransaction
5117 : : *
5118 : : * The caller has to make sure to always reassign CurrentTransactionState
5119 : : * if it has a local pointer to it after calling this function.
5120 : : */
5121 : : static void
5216 simon@2ndQuadrant.co 5122 : 4433 : CommitSubTransaction(void)
5123 : : {
7840 tgl@sss.pgh.pa.us 5124 : 4433 : TransactionState s = CurrentTransactionState;
5125 : :
5126 : 4433 : ShowTransactionState("CommitSubTransaction");
5127 : :
5128 [ - + ]: 4433 : if (s->state != TRANS_INPROGRESS)
7813 tgl@sss.pgh.pa.us 5129 [ # # ]:UBC 0 : elog(WARNING, "CommitSubTransaction while in %s state",
5130 : : TransStateAsString(s->state));
5131 : :
5132 : : /* Pre-commit processing goes here */
5133 : :
4690 tgl@sss.pgh.pa.us 5134 :CBC 4433 : CallSubXactCallbacks(SUBXACT_EVENT_PRE_COMMIT_SUB, s->subTransactionId,
5135 : 4433 : s->parent->subTransactionId);
5136 : :
5137 : : /*
5138 : : * If this subxact has started any unfinished parallel operation, clean up
5139 : : * its workers and exit parallel mode. Warn about leaked resources.
5140 : : */
630 5141 : 4433 : AtEOSubXact_Parallel(true, s->subTransactionId);
5142 [ - + ]: 4433 : if (s->parallelModeLevel != 0)
5143 : : {
630 tgl@sss.pgh.pa.us 5144 [ # # ]:UBC 0 : elog(WARNING, "parallelModeLevel is %d not 0 at end of subtransaction",
5145 : : s->parallelModeLevel);
3885 rhaas@postgresql.org 5146 : 0 : s->parallelModeLevel = 0;
5147 : : }
5148 : :
5149 : : /* Do the actual "commit", such as it is */
7840 tgl@sss.pgh.pa.us 5150 :CBC 4433 : s->state = TRANS_COMMIT;
5151 : :
5152 : : /* Must CCI to ensure commands of subtransaction are seen as done */
5153 : 4433 : CommandCounterIncrement();
5154 : :
5155 : : /*
5156 : : * Prior to 8.4 we marked subcommit in clog at this point. We now only
5157 : : * perform that step, if required, as part of the atomic update of the
5158 : : * whole transaction tree at top level commit or abort.
5159 : : */
5160 : :
5161 : : /* Post-commit cleanup */
2457 tmunro@postgresql.or 5162 [ + + ]: 4433 : if (FullTransactionIdIsValid(s->fullTransactionId))
6679 tgl@sss.pgh.pa.us 5163 : 2745 : AtSubCommit_childXids();
7769 5164 : 4433 : AfterTriggerEndSubXact(true);
7763 5165 : 4433 : AtSubCommit_Portals(s->subTransactionId,
5166 : 4433 : s->parent->subTransactionId,
1539 5167 : 4433 : s->parent->nestingLevel,
7809 5168 : 4433 : s->parent->curTransactionOwner);
7763 5169 : 4433 : AtEOSubXact_LargeObject(true, s->subTransactionId,
5170 : 4433 : s->parent->subTransactionId);
7809 5171 : 4433 : AtSubCommit_Notify();
5172 : :
7763 5173 : 4433 : CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
5174 : 4433 : s->parent->subTransactionId);
5175 : :
7824 5176 : 4433 : ResourceOwnerRelease(s->curTransactionOwner,
5177 : : RESOURCE_RELEASE_BEFORE_LOCKS,
5178 : : true, false);
7763 5179 : 4433 : AtEOSubXact_RelationCache(true, s->subTransactionId,
5180 : 4433 : s->parent->subTransactionId);
420 akorotkov@postgresql 5181 : 4433 : AtEOSubXact_TypeCache();
7809 tgl@sss.pgh.pa.us 5182 : 4433 : AtEOSubXact_Inval(true);
7773 5183 : 4433 : AtSubCommit_smgr();
5184 : :
5185 : : /*
5186 : : * The only lock we actually release here is the subtransaction XID lock.
5187 : : */
7763 5188 : 4433 : CurrentResourceOwner = s->curTransactionOwner;
2457 tmunro@postgresql.or 5189 [ + + ]: 4433 : if (FullTransactionIdIsValid(s->fullTransactionId))
5190 : 2745 : XactLockTableDelete(XidFromFullTransactionId(s->fullTransactionId));
5191 : :
5192 : : /*
5193 : : * Other locks should get transferred to their parent resource owner.
5194 : : */
7785 tgl@sss.pgh.pa.us 5195 : 4433 : ResourceOwnerRelease(s->curTransactionOwner,
5196 : : RESOURCE_RELEASE_LOCKS,
5197 : : true, false);
7824 5198 : 4433 : ResourceOwnerRelease(s->curTransactionOwner,
5199 : : RESOURCE_RELEASE_AFTER_LOCKS,
5200 : : true, false);
5201 : :
6681 5202 : 4433 : AtEOXact_GUC(true, s->gucNestLevel);
7763 5203 : 4433 : AtEOSubXact_SPI(true, s->subTransactionId);
5204 : 4433 : AtEOSubXact_on_commit_actions(true, s->subTransactionId,
5205 : 4433 : s->parent->subTransactionId);
5206 : 4433 : AtEOSubXact_Namespace(true, s->subTransactionId,
5207 : 4433 : s->parent->subTransactionId);
5208 : 4433 : AtEOSubXact_Files(true, s->subTransactionId,
5209 : 4433 : s->parent->subTransactionId);
6811 5210 : 4433 : AtEOSubXact_HashTables(true, s->nestingLevel);
6780 5211 : 4433 : AtEOSubXact_PgStat(true, s->nestingLevel);
6429 alvherre@alvh.no-ip. 5212 : 4433 : AtSubCommit_Snapshot(s->nestingLevel);
5213 : :
5214 : : /*
5215 : : * We need to restore the upper transaction's read-only state, in case the
5216 : : * upper is read-write while the child is read-only; GUC will incorrectly
5217 : : * think it should leave the child state in place.
5218 : : */
7813 tgl@sss.pgh.pa.us 5219 : 4433 : XactReadOnly = s->prevXactReadOnly;
5220 : :
7824 5221 : 4433 : CurrentResourceOwner = s->parent->curTransactionOwner;
5222 : 4433 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
7785 5223 : 4433 : ResourceOwnerDelete(s->curTransactionOwner);
7824 5224 : 4433 : s->curTransactionOwner = NULL;
5225 : :
7840 5226 : 4433 : AtSubCommit_Memory();
5227 : :
5228 : 4433 : s->state = TRANS_DEFAULT;
5229 : :
7763 5230 : 4433 : PopTransaction();
7840 5231 : 4433 : }
5232 : :
5233 : : /*
5234 : : * AbortSubTransaction
5235 : : */
5236 : : static void
5237 : 4684 : AbortSubTransaction(void)
5238 : : {
5239 : 4684 : TransactionState s = CurrentTransactionState;
5240 : :
5241 : : /* Prevent cancel/die interrupt while cleaning up */
5242 : 4684 : HOLD_INTERRUPTS();
5243 : :
5244 : : /* Make sure we have a valid memory context and resource owner */
6965 5245 : 4684 : AtSubAbort_Memory();
5246 : 4684 : AtSubAbort_ResourceOwner();
5247 : :
5248 : : /*
5249 : : * Release any LW locks we might be holding as quickly as possible.
5250 : : * (Regular locks, however, must be held till we finish aborting.)
5251 : : * Releasing LW locks is critical since we might try to grab them again
5252 : : * while cleaning up!
5253 : : *
5254 : : * FIXME This may be incorrect --- Are there some locks we should keep?
5255 : : * Buffer locks, for example? I don't think so but I'm not sure.
5256 : : */
7840 5257 : 4684 : LWLockReleaseAll();
5258 : :
3570 rhaas@postgresql.org 5259 : 4684 : pgstat_report_wait_end();
5260 : 4684 : pgstat_progress_end_command();
5261 : :
276 andres@anarazel.de 5262 : 4684 : pgaio_error_cleanup();
5263 : :
7840 tgl@sss.pgh.pa.us 5264 : 4684 : UnlockBuffers();
5265 : :
5266 : : /* Reset WAL record construction state */
4046 heikki.linnakangas@i 5267 : 4684 : XLogResetInsertion();
5268 : :
5269 : : /* Cancel condition variable sleep */
2919 rhaas@postgresql.org 5270 : 4684 : ConditionVariableCancelSleep();
5271 : :
5272 : : /*
5273 : : * Also clean up any open wait for lock, since the lock manager will choke
5274 : : * if we try to wait for another lock before doing this.
5275 : : */
4992 5276 : 4684 : LockErrorCleanup();
5277 : :
5278 : : /*
5279 : : * If any timeout events are still active, make sure the timeout interrupt
5280 : : * is scheduled. This covers possible loss of a timeout interrupt due to
5281 : : * longjmp'ing out of the SIGINT handler (see notes in handle_sig_alarm).
5282 : : * We delay this till after LockErrorCleanup so that we don't uselessly
5283 : : * reschedule lock or deadlock check timeouts.
5284 : : */
4402 tgl@sss.pgh.pa.us 5285 : 4684 : reschedule_timeouts();
5286 : :
5287 : : /*
5288 : : * Re-enable signals, in case we got here by longjmp'ing out of a signal
5289 : : * handler. We do this fairly early in the sequence so that the timeout
5290 : : * infrastructure will be functional if needed while aborting.
5291 : : */
1049 tmunro@postgresql.or 5292 : 4684 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
5293 : :
5294 : : /*
5295 : : * check the current transaction state
5296 : : */
6965 tgl@sss.pgh.pa.us 5297 : 4684 : ShowTransactionState("AbortSubTransaction");
5298 : :
5299 [ - + ]: 4684 : if (s->state != TRANS_INPROGRESS)
6965 tgl@sss.pgh.pa.us 5300 [ # # ]:UBC 0 : elog(WARNING, "AbortSubTransaction while in %s state",
5301 : : TransStateAsString(s->state));
5302 : :
6965 tgl@sss.pgh.pa.us 5303 :CBC 4684 : s->state = TRANS_ABORT;
5304 : :
5305 : : /*
5306 : : * Reset user ID which might have been changed transiently. (See notes in
5307 : : * AbortTransaction.)
5308 : : */
5853 5309 : 4684 : SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
5310 : :
5311 : : /* Forget about any active REINDEX. */
2067 5312 : 4684 : ResetReindexState(s->nestingLevel);
5313 : :
5314 : : /* Reset logical streaming state. */
1958 akapila@postgresql.o 5315 : 4684 : ResetLogicalStreamingState();
5316 : :
5317 : : /*
5318 : : * No need for SnapBuildResetExportedSnapshotState() here, snapshot
5319 : : * exports are not supported in subtransactions.
5320 : : */
5321 : :
5322 : : /*
5323 : : * If this subxact has started any unfinished parallel operation, clean up
5324 : : * its workers and exit parallel mode. Don't warn about leaked resources.
5325 : : */
630 tgl@sss.pgh.pa.us 5326 : 4684 : AtEOSubXact_Parallel(false, s->subTransactionId);
5327 : 4684 : s->parallelModeLevel = 0;
5328 : :
5329 : : /*
5330 : : * We can skip all this stuff if the subxact failed before creating a
5331 : : * ResourceOwner...
5332 : : */
7763 5333 [ + - ]: 4684 : if (s->curTransactionOwner)
5334 : : {
5335 : 4684 : AfterTriggerEndSubXact(false);
5336 : 4684 : AtSubAbort_Portals(s->subTransactionId,
5337 : 4684 : s->parent->subTransactionId,
5338 : : s->curTransactionOwner,
5339 : 4684 : s->parent->curTransactionOwner);
5340 : 4684 : AtEOSubXact_LargeObject(false, s->subTransactionId,
5341 : 4684 : s->parent->subTransactionId);
5342 : 4684 : AtSubAbort_Notify();
5343 : :
5344 : : /* Advertise the fact that we aborted in pg_xact. */
6676 5345 : 4684 : (void) RecordTransactionAbort(true);
5346 : :
5347 : : /* Post-abort cleanup */
2457 tmunro@postgresql.or 5348 [ + + ]: 4684 : if (FullTransactionIdIsValid(s->fullTransactionId))
7763 tgl@sss.pgh.pa.us 5349 : 665 : AtSubAbort_childXids();
5350 : :
5351 : 4684 : CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
5352 : 4684 : s->parent->subTransactionId);
5353 : :
5354 : 4684 : ResourceOwnerRelease(s->curTransactionOwner,
5355 : : RESOURCE_RELEASE_BEFORE_LOCKS,
5356 : : false, false);
5357 : :
276 andres@anarazel.de 5358 : 4684 : AtEOXact_Aio(false);
7763 tgl@sss.pgh.pa.us 5359 : 4684 : AtEOSubXact_RelationCache(false, s->subTransactionId,
5360 : 4684 : s->parent->subTransactionId);
420 akorotkov@postgresql 5361 : 4684 : AtEOSubXact_TypeCache();
7763 tgl@sss.pgh.pa.us 5362 : 4684 : AtEOSubXact_Inval(false);
5363 : 4684 : ResourceOwnerRelease(s->curTransactionOwner,
5364 : : RESOURCE_RELEASE_LOCKS,
5365 : : false, false);
5366 : 4684 : ResourceOwnerRelease(s->curTransactionOwner,
5367 : : RESOURCE_RELEASE_AFTER_LOCKS,
5368 : : false, false);
4935 rhaas@postgresql.org 5369 : 4684 : AtSubAbort_smgr();
5370 : :
6681 tgl@sss.pgh.pa.us 5371 : 4684 : AtEOXact_GUC(false, s->gucNestLevel);
7763 5372 : 4684 : AtEOSubXact_SPI(false, s->subTransactionId);
5373 : 4684 : AtEOSubXact_on_commit_actions(false, s->subTransactionId,
5374 : 4684 : s->parent->subTransactionId);
5375 : 4684 : AtEOSubXact_Namespace(false, s->subTransactionId,
5376 : 4684 : s->parent->subTransactionId);
5377 : 4684 : AtEOSubXact_Files(false, s->subTransactionId,
5378 : 4684 : s->parent->subTransactionId);
6811 5379 : 4684 : AtEOSubXact_HashTables(false, s->nestingLevel);
6780 5380 : 4684 : AtEOSubXact_PgStat(false, s->nestingLevel);
6429 alvherre@alvh.no-ip. 5381 : 4684 : AtSubAbort_Snapshot(s->nestingLevel);
5382 : : }
5383 : :
5384 : : /*
5385 : : * Restore the upper transaction's read-only state, too. This should be
5386 : : * redundant with GUC's cleanup but we may as well do it for consistency
5387 : : * with the commit case.
5388 : : */
7813 tgl@sss.pgh.pa.us 5389 : 4684 : XactReadOnly = s->prevXactReadOnly;
5390 : :
7840 5391 [ - + ]: 4684 : RESUME_INTERRUPTS();
5392 : 4684 : }
5393 : :
5394 : : /*
5395 : : * CleanupSubTransaction
5396 : : *
5397 : : * The caller has to make sure to always reassign CurrentTransactionState
5398 : : * if it has a local pointer to it after calling this function.
5399 : : */
5400 : : static void
5401 : 4684 : CleanupSubTransaction(void)
5402 : : {
5403 : 4684 : TransactionState s = CurrentTransactionState;
5404 : :
5405 : 4684 : ShowTransactionState("CleanupSubTransaction");
5406 : :
5407 [ - + ]: 4684 : if (s->state != TRANS_ABORT)
7813 tgl@sss.pgh.pa.us 5408 [ # # ]:UBC 0 : elog(WARNING, "CleanupSubTransaction while in %s state",
5409 : : TransStateAsString(s->state));
5410 : :
7763 tgl@sss.pgh.pa.us 5411 :CBC 4684 : AtSubCleanup_Portals(s->subTransactionId);
5412 : :
7824 5413 : 4684 : CurrentResourceOwner = s->parent->curTransactionOwner;
5414 : 4684 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
7763 5415 [ + - ]: 4684 : if (s->curTransactionOwner)
5416 : 4684 : ResourceOwnerDelete(s->curTransactionOwner);
7824 5417 : 4684 : s->curTransactionOwner = NULL;
5418 : :
7840 5419 : 4684 : AtSubCleanup_Memory();
5420 : :
5421 : 4684 : s->state = TRANS_DEFAULT;
5422 : :
7763 5423 : 4684 : PopTransaction();
7840 5424 : 4684 : }
5425 : :
5426 : : /*
5427 : : * PushTransaction
5428 : : * Create transaction state stack entry for a subtransaction
5429 : : *
5430 : : * The caller has to make sure to always reassign CurrentTransactionState
5431 : : * if it has a local pointer to it after calling this function.
5432 : : */
5433 : : static void
5434 : 9117 : PushTransaction(void)
5435 : : {
7781 bruce@momjian.us 5436 : 9117 : TransactionState p = CurrentTransactionState;
5437 : : TransactionState s;
5438 : :
5439 : : /*
5440 : : * We keep subtransaction state nodes in TopTransactionContext.
5441 : : */
5442 : : s = (TransactionState)
7840 tgl@sss.pgh.pa.us 5443 : 9117 : MemoryContextAllocZero(TopTransactionContext,
5444 : : sizeof(TransactionStateData));
5445 : :
5446 : : /*
5447 : : * Assign a subtransaction ID, watching out for counter wraparound.
5448 : : */
7763 5449 : 9117 : currentSubTransactionId += 1;
5450 [ - + ]: 9117 : if (currentSubTransactionId == InvalidSubTransactionId)
5451 : : {
7763 tgl@sss.pgh.pa.us 5452 :UBC 0 : currentSubTransactionId -= 1;
5453 : 0 : pfree(s);
5454 [ # # ]: 0 : ereport(ERROR,
5455 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5456 : : errmsg("cannot have more than 2^32-1 subtransactions in a transaction")));
5457 : : }
5458 : :
5459 : : /*
5460 : : * We can now stack a minimally valid subtransaction without fear of
5461 : : * failure.
5462 : : */
2457 tmunro@postgresql.or 5463 :CBC 9117 : s->fullTransactionId = InvalidFullTransactionId; /* until assigned */
7763 tgl@sss.pgh.pa.us 5464 : 9117 : s->subTransactionId = currentSubTransactionId;
7840 5465 : 9117 : s->parent = p;
5466 : 9117 : s->nestingLevel = p->nestingLevel + 1;
6681 5467 : 9117 : s->gucNestLevel = NewGUCNestLevel();
7814 5468 : 9117 : s->savepointLevel = p->savepointLevel;
7840 5469 : 9117 : s->state = TRANS_DEFAULT;
5470 : 9117 : s->blockState = TBLOCK_SUBBEGIN;
5853 5471 : 9117 : GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
7763 5472 : 9117 : s->prevXactReadOnly = XactReadOnly;
737 michael@paquier.xyz 5473 : 9117 : s->startedInRecovery = p->startedInRecovery;
3885 rhaas@postgresql.org 5474 : 9117 : s->parallelModeLevel = 0;
630 tgl@sss.pgh.pa.us 5475 [ + + - + ]: 9117 : s->parallelChildXact = (p->parallelModeLevel != 0 || p->parallelChildXact);
1507 akapila@postgresql.o 5476 : 9117 : s->topXidLogged = false;
5477 : :
7763 tgl@sss.pgh.pa.us 5478 : 9117 : CurrentTransactionState = s;
5479 : :
5480 : : /*
5481 : : * AbortSubTransaction and CleanupSubTransaction have to be able to cope
5482 : : * with the subtransaction from here on out; in particular they should not
5483 : : * assume that it necessarily has a transaction context, resource owner,
5484 : : * or XID.
5485 : : */
7840 5486 : 9117 : }
5487 : :
5488 : : /*
5489 : : * PopTransaction
5490 : : * Pop back to parent transaction state
5491 : : *
5492 : : * The caller has to make sure to always reassign CurrentTransactionState
5493 : : * if it has a local pointer to it after calling this function.
5494 : : */
5495 : : static void
5496 : 9117 : PopTransaction(void)
5497 : : {
5498 : 9117 : TransactionState s = CurrentTransactionState;
5499 : :
5500 [ - + ]: 9117 : if (s->state != TRANS_DEFAULT)
7813 tgl@sss.pgh.pa.us 5501 [ # # ]:UBC 0 : elog(WARNING, "PopTransaction while in %s state",
5502 : : TransStateAsString(s->state));
5503 : :
7840 tgl@sss.pgh.pa.us 5504 [ - + ]:CBC 9117 : if (s->parent == NULL)
7840 tgl@sss.pgh.pa.us 5505 [ # # ]:UBC 0 : elog(FATAL, "PopTransaction with no parent");
5506 : :
7840 tgl@sss.pgh.pa.us 5507 :CBC 9117 : CurrentTransactionState = s->parent;
5508 : :
5509 : : /* Let's just make sure CurTransactionContext is good */
5510 : 9117 : CurTransactionContext = s->parent->curTransactionContext;
5511 : 9117 : MemoryContextSwitchTo(CurTransactionContext);
5512 : :
5513 : : /* Ditto for ResourceOwner links */
7824 5514 : 9117 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
5515 : 9117 : CurrentResourceOwner = s->parent->curTransactionOwner;
5516 : :
5517 : : /* Free the old child structure */
7814 5518 [ + + ]: 9117 : if (s->name)
5519 : 1887 : pfree(s->name);
7840 5520 : 9117 : pfree(s);
5521 : 9117 : }
5522 : :
5523 : : /*
5524 : : * EstimateTransactionStateSpace
5525 : : * Estimate the amount of space that will be needed by
5526 : : * SerializeTransactionState. It would be OK to overestimate slightly,
5527 : : * but it's simple for us to work out the precise value, so we do.
5528 : : */
5529 : : Size
3885 rhaas@postgresql.org 5530 : 477 : EstimateTransactionStateSpace(void)
5531 : : {
5532 : : TransactionState s;
2457 tmunro@postgresql.or 5533 : 477 : Size nxids = 0;
5534 : 477 : Size size = SerializedTransactionStateHeaderSize;
5535 : :
3885 rhaas@postgresql.org 5536 [ + + ]: 2223 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
5537 : : {
2457 tmunro@postgresql.or 5538 [ + + ]: 1746 : if (FullTransactionIdIsValid(s->fullTransactionId))
3885 rhaas@postgresql.org 5539 : 1006 : nxids = add_size(nxids, 1);
5540 : 1746 : nxids = add_size(nxids, s->nChildXids);
5541 : : }
5542 : :
2442 tmunro@postgresql.or 5543 : 477 : return add_size(size, mul_size(sizeof(TransactionId), nxids));
5544 : : }
5545 : :
5546 : : /*
5547 : : * SerializeTransactionState
5548 : : * Write out relevant details of our transaction state that will be
5549 : : * needed by a parallel worker.
5550 : : *
5551 : : * We need to save and restore XactDeferrable, XactIsoLevel, and the XIDs
5552 : : * associated with this transaction. These are serialized into a
5553 : : * caller-supplied buffer big enough to hold the number of bytes reported by
5554 : : * EstimateTransactionStateSpace(). We emit the XIDs in sorted order for the
5555 : : * convenience of the receiving process.
5556 : : */
5557 : : void
3885 rhaas@postgresql.org 5558 : 477 : SerializeTransactionState(Size maxsize, char *start_address)
5559 : : {
5560 : : TransactionState s;
3862 bruce@momjian.us 5561 : 477 : Size nxids = 0;
5562 : 477 : Size i = 0;
5563 : : TransactionId *workspace;
5564 : : SerializedTransactionState *result;
5565 : :
2457 tmunro@postgresql.or 5566 : 477 : result = (SerializedTransactionState *) start_address;
5567 : :
5568 : 477 : result->xactIsoLevel = XactIsoLevel;
5569 : 477 : result->xactDeferrable = XactDeferrable;
5570 : 477 : result->topFullTransactionId = XactTopFullTransactionId;
5571 : 477 : result->currentFullTransactionId =
5572 : 477 : CurrentTransactionState->fullTransactionId;
5573 : 477 : result->currentCommandId = currentCommandId;
5574 : :
5575 : : /*
5576 : : * If we're running in a parallel worker and launching a parallel worker
5577 : : * of our own, we can just pass along the information that was passed to
5578 : : * us.
5579 : : */
3885 rhaas@postgresql.org 5580 [ - + ]: 477 : if (nParallelCurrentXids > 0)
5581 : : {
2457 tmunro@postgresql.or 5582 :UBC 0 : result->nParallelCurrentXids = nParallelCurrentXids;
5583 : 0 : memcpy(&result->parallelCurrentXids[0], ParallelCurrentXids,
5584 : : nParallelCurrentXids * sizeof(TransactionId));
3885 rhaas@postgresql.org 5585 : 0 : return;
5586 : : }
5587 : :
5588 : : /*
5589 : : * OK, we need to generate a sorted list of XIDs that our workers should
5590 : : * view as current. First, figure out how many there are.
5591 : : */
3885 rhaas@postgresql.org 5592 [ + + ]:CBC 2223 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
5593 : : {
2457 tmunro@postgresql.or 5594 [ + + ]: 1746 : if (FullTransactionIdIsValid(s->fullTransactionId))
3885 rhaas@postgresql.org 5595 : 1006 : nxids = add_size(nxids, 1);
5596 : 1746 : nxids = add_size(nxids, s->nChildXids);
5597 : : }
2457 tmunro@postgresql.or 5598 [ - + ]: 477 : Assert(SerializedTransactionStateHeaderSize + nxids * sizeof(TransactionId)
5599 : : <= maxsize);
5600 : :
5601 : : /* Copy them to our scratch space. */
3885 rhaas@postgresql.org 5602 : 477 : workspace = palloc(nxids * sizeof(TransactionId));
5603 [ + + ]: 2223 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
5604 : : {
2457 tmunro@postgresql.or 5605 [ + + ]: 1746 : if (FullTransactionIdIsValid(s->fullTransactionId))
5606 : 1006 : workspace[i++] = XidFromFullTransactionId(s->fullTransactionId);
1386 tgl@sss.pgh.pa.us 5607 [ - + ]: 1746 : if (s->nChildXids > 0)
1386 tgl@sss.pgh.pa.us 5608 :UBC 0 : memcpy(&workspace[i], s->childXids,
5609 : 0 : s->nChildXids * sizeof(TransactionId));
3885 rhaas@postgresql.org 5610 :CBC 1746 : i += s->nChildXids;
5611 : : }
5612 [ - + ]: 477 : Assert(i == nxids);
5613 : :
5614 : : /* Sort them. */
5615 : 477 : qsort(workspace, nxids, sizeof(TransactionId), xidComparator);
5616 : :
5617 : : /* Copy data into output area. */
2457 tmunro@postgresql.or 5618 : 477 : result->nParallelCurrentXids = nxids;
5619 : 477 : memcpy(&result->parallelCurrentXids[0], workspace,
5620 : : nxids * sizeof(TransactionId));
5621 : : }
5622 : :
5623 : : /*
5624 : : * StartParallelWorkerTransaction
5625 : : * Start a parallel worker transaction, restoring the relevant
5626 : : * transaction state serialized by SerializeTransactionState.
5627 : : */
5628 : : void
3885 rhaas@postgresql.org 5629 : 1453 : StartParallelWorkerTransaction(char *tstatespace)
5630 : : {
5631 : : SerializedTransactionState *tstate;
5632 : :
5633 [ - + ]: 1453 : Assert(CurrentTransactionState->blockState == TBLOCK_DEFAULT);
5634 : 1453 : StartTransaction();
5635 : :
2457 tmunro@postgresql.or 5636 : 1453 : tstate = (SerializedTransactionState *) tstatespace;
5637 : 1453 : XactIsoLevel = tstate->xactIsoLevel;
5638 : 1453 : XactDeferrable = tstate->xactDeferrable;
5639 : 1453 : XactTopFullTransactionId = tstate->topFullTransactionId;
5640 : 1453 : CurrentTransactionState->fullTransactionId =
5641 : : tstate->currentFullTransactionId;
5642 : 1453 : currentCommandId = tstate->currentCommandId;
5643 : 1453 : nParallelCurrentXids = tstate->nParallelCurrentXids;
5644 : 1453 : ParallelCurrentXids = &tstate->parallelCurrentXids[0];
5645 : :
3885 rhaas@postgresql.org 5646 : 1453 : CurrentTransactionState->blockState = TBLOCK_PARALLEL_INPROGRESS;
5647 : 1453 : }
5648 : :
5649 : : /*
5650 : : * EndParallelWorkerTransaction
5651 : : * End a parallel worker transaction.
5652 : : */
5653 : : void
5654 : 1447 : EndParallelWorkerTransaction(void)
5655 : : {
5656 [ - + ]: 1447 : Assert(CurrentTransactionState->blockState == TBLOCK_PARALLEL_INPROGRESS);
5657 : 1447 : CommitTransaction();
5658 : 1447 : CurrentTransactionState->blockState = TBLOCK_DEFAULT;
5659 : 1447 : }
5660 : :
5661 : : /*
5662 : : * ShowTransactionState
5663 : : * Debug support
5664 : : */
5665 : : static void
7840 tgl@sss.pgh.pa.us 5666 : 657992 : ShowTransactionState(const char *str)
5667 : : {
5668 : : /* skip work if message will definitely not be printed */
1851 5669 [ - + ]: 657992 : if (message_level_is_interesting(DEBUG5))
3318 rhaas@postgresql.org 5670 :UBC 0 : ShowTransactionStateRec(str, CurrentTransactionState);
7840 tgl@sss.pgh.pa.us 5671 :CBC 657992 : }
5672 : :
5673 : : /*
5674 : : * ShowTransactionStateRec
5675 : : * Recursive subroutine for ShowTransactionState
5676 : : */
5677 : : static void
3318 rhaas@postgresql.org 5678 :UBC 0 : ShowTransactionStateRec(const char *str, TransactionState s)
5679 : : {
5680 : : StringInfoData buf;
5681 : :
650 akorotkov@postgresql 5682 [ # # ]: 0 : if (s->parent)
5683 : : {
5684 : : /*
5685 : : * Since this function recurses, it could be driven to stack overflow.
5686 : : * This is just a debugging aid, so we can leave out some details
5687 : : * instead of erroring out with check_stack_depth().
5688 : : */
5689 [ # # ]: 0 : if (stack_is_too_deep())
5690 [ # # ]: 0 : ereport(DEBUG5,
5691 : : (errmsg_internal("%s(%d): parent omitted to avoid stack overflow",
5692 : : str, s->nestingLevel)));
5693 : : else
5694 : 0 : ShowTransactionStateRec(str, s->parent);
5695 : : }
5696 : :
5697 : 0 : initStringInfo(&buf);
6485 tgl@sss.pgh.pa.us 5698 [ # # ]: 0 : if (s->nChildXids > 0)
5699 : : {
5700 : : int i;
5701 : :
3318 rhaas@postgresql.org 5702 : 0 : appendStringInfo(&buf, ", children: %u", s->childXids[0]);
6485 tgl@sss.pgh.pa.us 5703 [ # # ]: 0 : for (i = 1; i < s->nChildXids; i++)
5704 : 0 : appendStringInfo(&buf, " %u", s->childXids[i]);
5705 : : }
3318 rhaas@postgresql.org 5706 [ # # # # : 0 : ereport(DEBUG5,
# # ]
5707 : : (errmsg_internal("%s(%d) name: %s; blockState: %s; state: %s, xid/subid/cid: %u/%u/%u%s%s",
5708 : : str, s->nestingLevel,
5709 : : s->name ? s->name : "unnamed",
5710 : : BlockStateAsString(s->blockState),
5711 : : TransStateAsString(s->state),
5712 : : XidFromFullTransactionId(s->fullTransactionId),
5713 : : s->subTransactionId,
5714 : : currentCommandId,
5715 : : currentCommandIdUsed ? " (used)" : "",
5716 : : buf.data)));
6485 tgl@sss.pgh.pa.us 5717 : 0 : pfree(buf.data);
7840 5718 : 0 : }
5719 : :
5720 : : /*
5721 : : * BlockStateAsString
5722 : : * Debug support
5723 : : */
5724 : : static const char *
5725 : 0 : BlockStateAsString(TBlockState blockState)
5726 : : {
7814 5727 [ # # # # : 0 : switch (blockState)
# # # # #
# # # # #
# # # # #
# # ]
5728 : : {
7840 5729 : 0 : case TBLOCK_DEFAULT:
5730 : 0 : return "DEFAULT";
5731 : 0 : case TBLOCK_STARTED:
5732 : 0 : return "STARTED";
5733 : 0 : case TBLOCK_BEGIN:
5734 : 0 : return "BEGIN";
5735 : 0 : case TBLOCK_INPROGRESS:
5736 : 0 : return "INPROGRESS";
3024 5737 : 0 : case TBLOCK_IMPLICIT_INPROGRESS:
5738 : 0 : return "IMPLICIT_INPROGRESS";
3885 rhaas@postgresql.org 5739 : 0 : case TBLOCK_PARALLEL_INPROGRESS:
5740 : 0 : return "PARALLEL_INPROGRESS";
7840 tgl@sss.pgh.pa.us 5741 : 0 : case TBLOCK_END:
5742 : 0 : return "END";
5743 : 0 : case TBLOCK_ABORT:
5744 : 0 : return "ABORT";
7763 5745 : 0 : case TBLOCK_ABORT_END:
2861 peter_e@gmx.net 5746 : 0 : return "ABORT_END";
7763 tgl@sss.pgh.pa.us 5747 : 0 : case TBLOCK_ABORT_PENDING:
2861 peter_e@gmx.net 5748 : 0 : return "ABORT_PENDING";
7489 tgl@sss.pgh.pa.us 5749 : 0 : case TBLOCK_PREPARE:
5750 : 0 : return "PREPARE";
7840 5751 : 0 : case TBLOCK_SUBBEGIN:
2861 peter_e@gmx.net 5752 : 0 : return "SUBBEGIN";
7840 tgl@sss.pgh.pa.us 5753 : 0 : case TBLOCK_SUBINPROGRESS:
2861 peter_e@gmx.net 5754 : 0 : return "SUBINPROGRESS";
5266 simon@2ndQuadrant.co 5755 : 0 : case TBLOCK_SUBRELEASE:
2861 peter_e@gmx.net 5756 : 0 : return "SUBRELEASE";
5266 simon@2ndQuadrant.co 5757 : 0 : case TBLOCK_SUBCOMMIT:
2861 peter_e@gmx.net 5758 : 0 : return "SUBCOMMIT";
7840 tgl@sss.pgh.pa.us 5759 : 0 : case TBLOCK_SUBABORT:
2861 peter_e@gmx.net 5760 : 0 : return "SUBABORT";
7763 tgl@sss.pgh.pa.us 5761 : 0 : case TBLOCK_SUBABORT_END:
2861 peter_e@gmx.net 5762 : 0 : return "SUBABORT_END";
7814 tgl@sss.pgh.pa.us 5763 : 0 : case TBLOCK_SUBABORT_PENDING:
2861 peter_e@gmx.net 5764 : 0 : return "SUBABORT_PENDING";
7763 tgl@sss.pgh.pa.us 5765 : 0 : case TBLOCK_SUBRESTART:
2861 peter_e@gmx.net 5766 : 0 : return "SUBRESTART";
7763 tgl@sss.pgh.pa.us 5767 : 0 : case TBLOCK_SUBABORT_RESTART:
2861 peter_e@gmx.net 5768 : 0 : return "SUBABORT_RESTART";
5769 : : }
7840 tgl@sss.pgh.pa.us 5770 : 0 : return "UNRECOGNIZED";
5771 : : }
5772 : :
5773 : : /*
5774 : : * TransStateAsString
5775 : : * Debug support
5776 : : */
5777 : : static const char *
5778 : 0 : TransStateAsString(TransState state)
5779 : : {
7814 5780 [ # # # # : 0 : switch (state)
# # # ]
5781 : : {
7840 5782 : 0 : case TRANS_DEFAULT:
5783 : 0 : return "DEFAULT";
5784 : 0 : case TRANS_START:
5785 : 0 : return "START";
7489 5786 : 0 : case TRANS_INPROGRESS:
2861 peter_e@gmx.net 5787 : 0 : return "INPROGRESS";
7840 tgl@sss.pgh.pa.us 5788 : 0 : case TRANS_COMMIT:
5789 : 0 : return "COMMIT";
5790 : 0 : case TRANS_ABORT:
5791 : 0 : return "ABORT";
7489 5792 : 0 : case TRANS_PREPARE:
5793 : 0 : return "PREPARE";
5794 : : }
7840 5795 : 0 : return "UNRECOGNIZED";
5796 : : }
5797 : :
5798 : : /*
5799 : : * xactGetCommittedChildren
5800 : : *
5801 : : * Gets the list of committed children of the current transaction. The return
5802 : : * value is the number of child transactions. *ptr is set to point to an
5803 : : * array of TransactionIds. The array is allocated in TopTransactionContext;
5804 : : * the caller should *not* pfree() it (this is a change from pre-8.4 code!).
5805 : : * If there are no subxacts, *ptr is set to NULL.
5806 : : */
5807 : : int
7824 tgl@sss.pgh.pa.us 5808 :CBC 309362 : xactGetCommittedChildren(TransactionId **ptr)
5809 : : {
7781 bruce@momjian.us 5810 : 309362 : TransactionState s = CurrentTransactionState;
5811 : :
6485 tgl@sss.pgh.pa.us 5812 [ + + ]: 309362 : if (s->nChildXids == 0)
7840 5813 : 308787 : *ptr = NULL;
5814 : : else
6485 5815 : 575 : *ptr = s->childXids;
5816 : :
5817 : 309362 : return s->nChildXids;
5818 : : }
5819 : :
5820 : : /*
5821 : : * XLOG support routines
5822 : : */
5823 : :
5824 : :
5825 : : /*
5826 : : * Log the commit record for a plain or twophase transaction commit.
5827 : : *
5828 : : * A 2pc commit will be emitted when twophase_xid is valid, a plain one
5829 : : * otherwise.
5830 : : */
5831 : : XLogRecPtr
3931 andres@anarazel.de 5832 : 129045 : XactLogCommitRecord(TimestampTz commit_time,
5833 : : int nsubxacts, TransactionId *subxacts,
5834 : : int nrels, RelFileLocator *rels,
5835 : : int ndroppedstats, xl_xact_stats_item *droppedstats,
5836 : : int nmsgs, SharedInvalidationMessage *msgs,
5837 : : bool relcacheInval,
5838 : : int xactflags, TransactionId twophase_xid,
5839 : : const char *twophase_gid)
5840 : : {
5841 : : xl_xact_commit xlrec;
5842 : : xl_xact_xinfo xl_xinfo;
5843 : : xl_xact_dbinfo xl_dbinfo;
5844 : : xl_xact_subxacts xl_subxacts;
5845 : : xl_xact_relfilelocators xl_relfilelocators;
5846 : : xl_xact_stats_items xl_dropped_stats;
5847 : : xl_xact_invals xl_invals;
5848 : : xl_xact_twophase xl_twophase;
5849 : : xl_xact_origin xl_origin;
5850 : : uint8 info;
5851 : :
5852 [ - + ]: 129045 : Assert(CritSectionCount > 0);
5853 : :
5854 : 129045 : xl_xinfo.xinfo = 0;
5855 : :
5856 : : /* decide between a plain and 2pc commit */
5857 [ + + ]: 129045 : if (!TransactionIdIsValid(twophase_xid))
5858 : 128793 : info = XLOG_XACT_COMMIT;
5859 : : else
5860 : 252 : info = XLOG_XACT_COMMIT_PREPARED;
5861 : :
5862 : : /* First figure out and collect all the information needed */
5863 : :
5864 : 129045 : xlrec.xact_time = commit_time;
5865 : :
5866 [ + + ]: 129045 : if (relcacheInval)
5867 : 3841 : xl_xinfo.xinfo |= XACT_COMPLETION_UPDATE_RELCACHE_FILE;
5868 [ + + ]: 129045 : if (forceSyncCommit)
5869 : 512 : xl_xinfo.xinfo |= XACT_COMPLETION_FORCE_SYNC_COMMIT;
3193 simon@2ndQuadrant.co 5870 [ + + ]: 129045 : if ((xactflags & XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK))
5871 : 39137 : xl_xinfo.xinfo |= XACT_XINFO_HAS_AE_LOCKS;
5872 : :
5873 : : /*
5874 : : * Check if the caller would like to ask standbys for immediate feedback
5875 : : * once this commit is applied.
5876 : : */
3551 rhaas@postgresql.org 5877 [ + + ]: 129045 : if (synchronous_commit >= SYNCHRONOUS_COMMIT_REMOTE_APPLY)
5878 : 2 : xl_xinfo.xinfo |= XACT_COMPLETION_APPLY_FEEDBACK;
5879 : :
5880 : : /*
5881 : : * Relcache invalidations requires information about the current database
5882 : : * and so does logical decoding.
5883 : : */
3931 andres@anarazel.de 5884 [ + + + + ]: 129045 : if (nmsgs > 0 || XLogLogicalInfoActive())
5885 : : {
5886 : 77184 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DBINFO;
5887 : 77184 : xl_dbinfo.dbId = MyDatabaseId;
5888 : 77184 : xl_dbinfo.tsId = MyDatabaseTableSpace;
5889 : : }
5890 : :
5891 [ + + ]: 129045 : if (nsubxacts > 0)
5892 : : {
5893 : 478 : xl_xinfo.xinfo |= XACT_XINFO_HAS_SUBXACTS;
5894 : 478 : xl_subxacts.nsubxacts = nsubxacts;
5895 : : }
5896 : :
5897 [ + + ]: 129045 : if (nrels > 0)
5898 : : {
1261 rhaas@postgresql.org 5899 : 9670 : xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
5900 : 9670 : xl_relfilelocators.nrels = nrels;
1949 heikki.linnakangas@i 5901 : 9670 : info |= XLR_SPECIAL_REL_UPDATE;
5902 : : }
5903 : :
1352 andres@anarazel.de 5904 [ + + ]: 129045 : if (ndroppedstats > 0)
5905 : : {
5906 : 11208 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DROPPED_STATS;
5907 : 11208 : xl_dropped_stats.nitems = ndroppedstats;
5908 : : }
5909 : :
3931 5910 [ + + ]: 129045 : if (nmsgs > 0)
5911 : : {
5912 : 76325 : xl_xinfo.xinfo |= XACT_XINFO_HAS_INVALS;
5913 : 76325 : xl_invals.nmsgs = nmsgs;
5914 : : }
5915 : :
5916 [ + + ]: 129045 : if (TransactionIdIsValid(twophase_xid))
5917 : : {
5918 : 252 : xl_xinfo.xinfo |= XACT_XINFO_HAS_TWOPHASE;
5919 : 252 : xl_twophase.xid = twophase_xid;
2822 simon@2ndQuadrant.co 5920 [ - + ]: 252 : Assert(twophase_gid != NULL);
5921 : :
5922 [ + + ]: 252 : if (XLogLogicalInfoActive())
5923 : 39 : xl_xinfo.xinfo |= XACT_XINFO_HAS_GID;
5924 : : }
5925 : :
5926 : : /* dump transaction origin information */
3734 alvherre@alvh.no-ip. 5927 [ + + ]: 129045 : if (replorigin_session_origin != InvalidRepOriginId)
5928 : : {
3886 andres@anarazel.de 5929 : 1037 : xl_xinfo.xinfo |= XACT_XINFO_HAS_ORIGIN;
5930 : :
3734 alvherre@alvh.no-ip. 5931 : 1037 : xl_origin.origin_lsn = replorigin_session_origin_lsn;
5932 : 1037 : xl_origin.origin_timestamp = replorigin_session_origin_timestamp;
5933 : : }
5934 : :
3931 andres@anarazel.de 5935 [ + + ]: 129045 : if (xl_xinfo.xinfo != 0)
5936 : 82904 : info |= XLOG_XACT_HAS_INFO;
5937 : :
5938 : : /* Then include all the collected data into the commit record. */
5939 : :
5940 : 129045 : XLogBeginInsert();
5941 : :
310 peter@eisentraut.org 5942 : 129045 : XLogRegisterData(&xlrec, sizeof(xl_xact_commit));
5943 : :
3931 andres@anarazel.de 5944 [ + + ]: 129045 : if (xl_xinfo.xinfo != 0)
310 peter@eisentraut.org 5945 : 82904 : XLogRegisterData(&xl_xinfo.xinfo, sizeof(xl_xinfo.xinfo));
5946 : :
3931 andres@anarazel.de 5947 [ + + ]: 129045 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DBINFO)
310 peter@eisentraut.org 5948 : 77184 : XLogRegisterData(&xl_dbinfo, sizeof(xl_dbinfo));
5949 : :
3931 andres@anarazel.de 5950 [ + + ]: 129045 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_SUBXACTS)
5951 : : {
310 peter@eisentraut.org 5952 : 478 : XLogRegisterData(&xl_subxacts,
5953 : : MinSizeOfXactSubxacts);
5954 : 478 : XLogRegisterData(subxacts,
5955 : : nsubxacts * sizeof(TransactionId));
5956 : : }
5957 : :
1261 rhaas@postgresql.org 5958 [ + + ]: 129045 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_RELFILELOCATORS)
5959 : : {
310 peter@eisentraut.org 5960 : 9670 : XLogRegisterData(&xl_relfilelocators,
5961 : : MinSizeOfXactRelfileLocators);
5962 : 9670 : XLogRegisterData(rels,
5963 : : nrels * sizeof(RelFileLocator));
5964 : : }
5965 : :
1352 andres@anarazel.de 5966 [ + + ]: 129045 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DROPPED_STATS)
5967 : : {
310 peter@eisentraut.org 5968 : 11208 : XLogRegisterData(&xl_dropped_stats,
5969 : : MinSizeOfXactStatsItems);
5970 : 11208 : XLogRegisterData(droppedstats,
5971 : : ndroppedstats * sizeof(xl_xact_stats_item));
5972 : : }
5973 : :
3931 andres@anarazel.de 5974 [ + + ]: 129045 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_INVALS)
5975 : : {
310 peter@eisentraut.org 5976 : 76325 : XLogRegisterData(&xl_invals, MinSizeOfXactInvals);
5977 : 76325 : XLogRegisterData(msgs,
5978 : : nmsgs * sizeof(SharedInvalidationMessage));
5979 : : }
5980 : :
3931 andres@anarazel.de 5981 [ + + ]: 129045 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_TWOPHASE)
5982 : : {
310 peter@eisentraut.org 5983 : 252 : XLogRegisterData(&xl_twophase, sizeof(xl_xact_twophase));
2822 simon@2ndQuadrant.co 5984 [ + + ]: 252 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_GID)
471 peter@eisentraut.org 5985 : 39 : XLogRegisterData(twophase_gid, strlen(twophase_gid) + 1);
5986 : : }
5987 : :
3886 andres@anarazel.de 5988 [ + + ]: 129045 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN)
310 peter@eisentraut.org 5989 : 1037 : XLogRegisterData(&xl_origin, sizeof(xl_xact_origin));
5990 : :
5991 : : /* we allow filtering by xacts */
3283 andres@anarazel.de 5992 : 129045 : XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
5993 : :
3931 5994 : 129045 : return XLogInsert(RM_XACT_ID, info);
5995 : : }
5996 : :
5997 : : /*
5998 : : * Log the commit record for a plain or twophase transaction abort.
5999 : : *
6000 : : * A 2pc abort will be emitted when twophase_xid is valid, a plain one
6001 : : * otherwise.
6002 : : */
6003 : : XLogRecPtr
6004 : 6469 : XactLogAbortRecord(TimestampTz abort_time,
6005 : : int nsubxacts, TransactionId *subxacts,
6006 : : int nrels, RelFileLocator *rels,
6007 : : int ndroppedstats, xl_xact_stats_item *droppedstats,
6008 : : int xactflags, TransactionId twophase_xid,
6009 : : const char *twophase_gid)
6010 : : {
6011 : : xl_xact_abort xlrec;
6012 : : xl_xact_xinfo xl_xinfo;
6013 : : xl_xact_subxacts xl_subxacts;
6014 : : xl_xact_relfilelocators xl_relfilelocators;
6015 : : xl_xact_stats_items xl_dropped_stats;
6016 : : xl_xact_twophase xl_twophase;
6017 : : xl_xact_dbinfo xl_dbinfo;
6018 : : xl_xact_origin xl_origin;
6019 : :
6020 : : uint8 info;
6021 : :
6022 [ - + ]: 6469 : Assert(CritSectionCount > 0);
6023 : :
6024 : 6469 : xl_xinfo.xinfo = 0;
6025 : :
6026 : : /* decide between a plain and 2pc abort */
6027 [ + + ]: 6469 : if (!TransactionIdIsValid(twophase_xid))
6028 : 6426 : info = XLOG_XACT_ABORT;
6029 : : else
6030 : 43 : info = XLOG_XACT_ABORT_PREPARED;
6031 : :
6032 : :
6033 : : /* First figure out and collect all the information needed */
6034 : :
6035 : 6469 : xlrec.xact_time = abort_time;
6036 : :
3193 simon@2ndQuadrant.co 6037 [ + + ]: 6469 : if ((xactflags & XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK))
6038 : 2567 : xl_xinfo.xinfo |= XACT_XINFO_HAS_AE_LOCKS;
6039 : :
3931 andres@anarazel.de 6040 [ + + ]: 6469 : if (nsubxacts > 0)
6041 : : {
6042 : 101 : xl_xinfo.xinfo |= XACT_XINFO_HAS_SUBXACTS;
6043 : 101 : xl_subxacts.nsubxacts = nsubxacts;
6044 : : }
6045 : :
6046 [ + + ]: 6469 : if (nrels > 0)
6047 : : {
1261 rhaas@postgresql.org 6048 : 1017 : xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
6049 : 1017 : xl_relfilelocators.nrels = nrels;
1949 heikki.linnakangas@i 6050 : 1017 : info |= XLR_SPECIAL_REL_UPDATE;
6051 : : }
6052 : :
1352 andres@anarazel.de 6053 [ + + ]: 6469 : if (ndroppedstats > 0)
6054 : : {
6055 : 1421 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DROPPED_STATS;
6056 : 1421 : xl_dropped_stats.nitems = ndroppedstats;
6057 : : }
6058 : :
3931 6059 [ + + ]: 6469 : if (TransactionIdIsValid(twophase_xid))
6060 : : {
6061 : 43 : xl_xinfo.xinfo |= XACT_XINFO_HAS_TWOPHASE;
6062 : 43 : xl_twophase.xid = twophase_xid;
2822 simon@2ndQuadrant.co 6063 [ - + ]: 43 : Assert(twophase_gid != NULL);
6064 : :
6065 [ + + ]: 43 : if (XLogLogicalInfoActive())
6066 : 13 : xl_xinfo.xinfo |= XACT_XINFO_HAS_GID;
6067 : : }
6068 : :
6069 [ + + + + ]: 6469 : if (TransactionIdIsValid(twophase_xid) && XLogLogicalInfoActive())
6070 : : {
6071 : 13 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DBINFO;
6072 : 13 : xl_dbinfo.dbId = MyDatabaseId;
6073 : 13 : xl_dbinfo.tsId = MyDatabaseTableSpace;
6074 : : }
6075 : :
6076 : : /*
6077 : : * Dump transaction origin information. We need this during recovery to
6078 : : * update the replication origin progress.
6079 : : */
1074 akapila@postgresql.o 6080 [ + + ]: 6469 : if (replorigin_session_origin != InvalidRepOriginId)
6081 : : {
2822 simon@2ndQuadrant.co 6082 : 36 : xl_xinfo.xinfo |= XACT_XINFO_HAS_ORIGIN;
6083 : :
6084 : 36 : xl_origin.origin_lsn = replorigin_session_origin_lsn;
6085 : 36 : xl_origin.origin_timestamp = replorigin_session_origin_timestamp;
6086 : : }
6087 : :
3931 andres@anarazel.de 6088 [ + + ]: 6469 : if (xl_xinfo.xinfo != 0)
6089 : 3221 : info |= XLOG_XACT_HAS_INFO;
6090 : :
6091 : : /* Then include all the collected data into the abort record. */
6092 : :
6093 : 6469 : XLogBeginInsert();
6094 : :
310 peter@eisentraut.org 6095 : 6469 : XLogRegisterData(&xlrec, MinSizeOfXactAbort);
6096 : :
3931 andres@anarazel.de 6097 [ + + ]: 6469 : if (xl_xinfo.xinfo != 0)
310 peter@eisentraut.org 6098 : 3221 : XLogRegisterData(&xl_xinfo, sizeof(xl_xinfo));
6099 : :
2822 simon@2ndQuadrant.co 6100 [ + + ]: 6469 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DBINFO)
310 peter@eisentraut.org 6101 : 13 : XLogRegisterData(&xl_dbinfo, sizeof(xl_dbinfo));
6102 : :
3931 andres@anarazel.de 6103 [ + + ]: 6469 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_SUBXACTS)
6104 : : {
310 peter@eisentraut.org 6105 : 101 : XLogRegisterData(&xl_subxacts,
6106 : : MinSizeOfXactSubxacts);
6107 : 101 : XLogRegisterData(subxacts,
6108 : : nsubxacts * sizeof(TransactionId));
6109 : : }
6110 : :
1261 rhaas@postgresql.org 6111 [ + + ]: 6469 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_RELFILELOCATORS)
6112 : : {
310 peter@eisentraut.org 6113 : 1017 : XLogRegisterData(&xl_relfilelocators,
6114 : : MinSizeOfXactRelfileLocators);
6115 : 1017 : XLogRegisterData(rels,
6116 : : nrels * sizeof(RelFileLocator));
6117 : : }
6118 : :
1352 andres@anarazel.de 6119 [ + + ]: 6469 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DROPPED_STATS)
6120 : : {
310 peter@eisentraut.org 6121 : 1421 : XLogRegisterData(&xl_dropped_stats,
6122 : : MinSizeOfXactStatsItems);
6123 : 1421 : XLogRegisterData(droppedstats,
6124 : : ndroppedstats * sizeof(xl_xact_stats_item));
6125 : : }
6126 : :
3931 andres@anarazel.de 6127 [ + + ]: 6469 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_TWOPHASE)
6128 : : {
310 peter@eisentraut.org 6129 : 43 : XLogRegisterData(&xl_twophase, sizeof(xl_xact_twophase));
2822 simon@2ndQuadrant.co 6130 [ + + ]: 43 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_GID)
471 peter@eisentraut.org 6131 : 13 : XLogRegisterData(twophase_gid, strlen(twophase_gid) + 1);
6132 : : }
6133 : :
2822 simon@2ndQuadrant.co 6134 [ + + ]: 6469 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN)
310 peter@eisentraut.org 6135 : 36 : XLogRegisterData(&xl_origin, sizeof(xl_xact_origin));
6136 : :
6137 : : /* Include the replication origin */
1074 akapila@postgresql.o 6138 : 6469 : XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
6139 : :
3931 andres@anarazel.de 6140 : 6469 : return XLogInsert(RM_XACT_ID, info);
6141 : : }
6142 : :
6143 : : /*
6144 : : * Before 9.0 this was a fairly short function, but now it performs many
6145 : : * actions for which the order of execution is critical.
6146 : : */
6147 : : static void
6148 : 22453 : xact_redo_commit(xl_xact_parsed_commit *parsed,
6149 : : TransactionId xid,
6150 : : XLogRecPtr lsn,
6151 : : RepOriginId origin_id)
6152 : : {
6153 : : TransactionId max_xid;
6154 : : TimestampTz commit_time;
6155 : :
3109 alvherre@alvh.no-ip. 6156 [ - + ]: 22453 : Assert(TransactionIdIsValid(xid));
6157 : :
3931 andres@anarazel.de 6158 : 22453 : max_xid = TransactionIdLatest(xid, parsed->nsubxacts, parsed->subxacts);
6159 : :
6160 : : /* Make sure nextXid is beyond any XID mentioned in the record. */
2457 tmunro@postgresql.or 6161 : 22453 : AdvanceNextFullTransactionIdPastXid(max_xid);
6162 : :
3553 andres@anarazel.de 6163 [ - + ]: 22453 : Assert(((parsed->xinfo & XACT_XINFO_HAS_ORIGIN) == 0) ==
6164 : : (origin_id == InvalidRepOriginId));
6165 : :
3886 6166 [ + + ]: 22453 : if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
6167 : 20 : commit_time = parsed->origin_timestamp;
6168 : : else
6169 : 22433 : commit_time = parsed->xact_time;
6170 : :
6171 : : /* Set the transaction commit timestamp and metadata */
3931 6172 : 22453 : TransactionTreeSetCommitTsData(xid, parsed->nsubxacts, parsed->subxacts,
6173 : : commit_time, origin_id);
6174 : :
5698 simon@2ndQuadrant.co 6175 [ + + ]: 22453 : if (standbyState == STANDBY_DISABLED)
6176 : : {
6177 : : /*
6178 : : * Mark the transaction committed in pg_xact.
6179 : : */
3931 andres@anarazel.de 6180 : 2225 : TransactionIdCommitTree(xid, parsed->nsubxacts, parsed->subxacts);
6181 : : }
6182 : : else
6183 : : {
6184 : : /*
6185 : : * If a transaction completion record arrives that has as-yet
6186 : : * unobserved subtransactions then this will not have been fully
6187 : : * handled by the call to RecordKnownAssignedTransactionIds() in the
6188 : : * main recovery loop in xlog.c. So we need to do bookkeeping again to
6189 : : * cover that case. This is confusing and it is easy to think this
6190 : : * call is irrelevant, which has happened three times in development
6191 : : * already. Leave it in.
6192 : : */
5843 simon@2ndQuadrant.co 6193 : 20228 : RecordKnownAssignedTransactionIds(max_xid);
6194 : :
6195 : : /*
6196 : : * Mark the transaction committed in pg_xact. We use async commit
6197 : : * protocol during recovery to provide information on database
6198 : : * consistency for when users try to set hint bits. It is important
6199 : : * that we do not set hint bits until the minRecoveryPoint is past
6200 : : * this commit record. This ensures that if we crash we don't see hint
6201 : : * bits set on changes made by transactions that haven't yet
6202 : : * recovered. It's unlikely but it's good to be safe.
6203 : : */
2149 alvherre@alvh.no-ip. 6204 : 20228 : TransactionIdAsyncCommitTree(xid, parsed->nsubxacts, parsed->subxacts, lsn);
6205 : :
6206 : : /*
6207 : : * We must mark clog before we update the ProcArray.
6208 : : */
6209 : 20228 : ExpireTreeKnownAssignedTransactionIds(xid, parsed->nsubxacts, parsed->subxacts, max_xid);
6210 : :
6211 : : /*
6212 : : * Send any cache invalidations attached to the commit. We must
6213 : : * maintain the same order of invalidation then release locks as
6214 : : * occurs in CommitTransaction().
6215 : : */
6216 : 20228 : ProcessCommittedInvalidationMessages(parsed->msgs, parsed->nmsgs,
3102 tgl@sss.pgh.pa.us 6217 : 20228 : XactCompletionRelcacheInitFileInval(parsed->xinfo),
6218 : : parsed->dbId, parsed->tsId);
6219 : :
6220 : : /*
6221 : : * Release locks, if any. We do this for both two phase and normal one
6222 : : * phase transactions. In effect we are ignoring the prepare phase and
6223 : : * just going straight to lock release.
6224 : : */
3193 simon@2ndQuadrant.co 6225 [ + + ]: 20228 : if (parsed->xinfo & XACT_XINFO_HAS_AE_LOCKS)
2742 6226 : 9982 : StandbyReleaseLockTree(xid, parsed->nsubxacts, parsed->subxacts);
6227 : : }
6228 : :
3886 andres@anarazel.de 6229 [ + + ]: 22453 : if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
6230 : : {
6231 : : /* recover apply progress */
6232 : 20 : replorigin_advance(origin_id, parsed->origin_lsn, lsn,
6233 : : false /* backward */ , false /* WAL */ );
6234 : : }
6235 : :
6236 : : /* Make sure files supposed to be dropped are dropped */
3931 6237 [ + + ]: 22453 : if (parsed->nrels > 0)
6238 : : {
6239 : : /*
6240 : : * First update minimum recovery point to cover this WAL record. Once
6241 : : * a relation is deleted, there's no going back. The buffer manager
6242 : : * enforces the WAL-first rule for normal updates to relation files,
6243 : : * so that the minimum recovery point is always updated before the
6244 : : * corresponding change in the data file is flushed to disk, but we
6245 : : * have to do the same here since we're bypassing the buffer manager.
6246 : : *
6247 : : * Doing this before deleting the files means that if a deletion fails
6248 : : * for some reason, you cannot start up the system even after restart,
6249 : : * until you fix the underlying situation so that the deletion will
6250 : : * succeed. Alternatively, we could update the minimum recovery point
6251 : : * after deletion, but that would leave a small window where the
6252 : : * WAL-first rule would be violated.
6253 : : */
4756 heikki.linnakangas@i 6254 : 2157 : XLogFlush(lsn);
6255 : :
6256 : : /* Make sure files supposed to be dropped are dropped */
1261 rhaas@postgresql.org 6257 : 2157 : DropRelationFiles(parsed->xlocators, parsed->nrels, true);
6258 : : }
6259 : :
1352 andres@anarazel.de 6260 [ + + ]: 22453 : if (parsed->nstats > 0)
6261 : : {
6262 : : /* see equivalent call for relations above */
6263 : 2789 : XLogFlush(lsn);
6264 : :
6265 : 2789 : pgstat_execute_transactional_drops(parsed->nstats, parsed->stats, true);
6266 : : }
6267 : :
6268 : : /*
6269 : : * We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
6270 : : * in normal operation. For example, in CREATE DATABASE, we copy all files
6271 : : * from the template database, and then commit the transaction. If we
6272 : : * crash after all the files have been copied but before the commit, you
6273 : : * have files in the data directory without an entry in pg_database. To
6274 : : * minimize the window for that, we use ForceSyncCommit() to rush the
6275 : : * commit record to disk as quick as possible. We have the same window
6276 : : * during recovery, and forcing an XLogFlush() (which updates
6277 : : * minRecoveryPoint during recovery) helps to reduce that problem window,
6278 : : * for any user that requested ForceSyncCommit().
6279 : : */
3931 6280 [ + + ]: 22453 : if (XactCompletionForceSyncCommit(parsed->xinfo))
5843 simon@2ndQuadrant.co 6281 : 45 : XLogFlush(lsn);
6282 : :
6283 : : /*
6284 : : * If asked by the primary (because someone is waiting for a synchronous
6285 : : * commit = remote_apply), we will need to ask walreceiver to send a reply
6286 : : * immediately.
6287 : : */
3551 rhaas@postgresql.org 6288 [ + + ]: 22453 : if (XactCompletionApplyFeedback(parsed->xinfo))
6289 : 2 : XLogRequestWalReceiverReply();
5287 simon@2ndQuadrant.co 6290 : 22453 : }
6291 : :
6292 : : /*
6293 : : * Be careful with the order of execution, as with xact_redo_commit().
6294 : : * The two functions are similar but differ in key places.
6295 : : *
6296 : : * Note also that an abort can be for a subtransaction and its children,
6297 : : * not just for a top level abort. That means we have to consider
6298 : : * topxid != xid, whereas in commit we would find topxid == xid always
6299 : : * because subtransaction commit is never WAL logged.
6300 : : */
6301 : : static void
1746 akapila@postgresql.o 6302 : 1880 : xact_redo_abort(xl_xact_parsed_abort *parsed, TransactionId xid,
6303 : : XLogRecPtr lsn, RepOriginId origin_id)
6304 : : {
6305 : : TransactionId max_xid;
6306 : :
3109 alvherre@alvh.no-ip. 6307 [ - + ]: 1880 : Assert(TransactionIdIsValid(xid));
6308 : :
6309 : : /* Make sure nextXid is beyond any XID mentioned in the record. */
3931 andres@anarazel.de 6310 : 1880 : max_xid = TransactionIdLatest(xid,
6311 : : parsed->nsubxacts,
6312 : 1880 : parsed->subxacts);
2457 tmunro@postgresql.or 6313 : 1880 : AdvanceNextFullTransactionIdPastXid(max_xid);
6314 : :
5698 simon@2ndQuadrant.co 6315 [ + + ]: 1880 : if (standbyState == STANDBY_DISABLED)
6316 : : {
6317 : : /* Mark the transaction aborted in pg_xact, no need for async stuff */
3931 andres@anarazel.de 6318 : 20 : TransactionIdAbortTree(xid, parsed->nsubxacts, parsed->subxacts);
6319 : : }
6320 : : else
6321 : : {
6322 : : /*
6323 : : * If a transaction completion record arrives that has as-yet
6324 : : * unobserved subtransactions then this will not have been fully
6325 : : * handled by the call to RecordKnownAssignedTransactionIds() in the
6326 : : * main recovery loop in xlog.c. So we need to do bookkeeping again to
6327 : : * cover that case. This is confusing and it is easy to think this
6328 : : * call is irrelevant, which has happened three times in development
6329 : : * already. Leave it in.
6330 : : */
5843 simon@2ndQuadrant.co 6331 : 1860 : RecordKnownAssignedTransactionIds(max_xid);
6332 : :
6333 : : /* Mark the transaction aborted in pg_xact, no need for async stuff */
3931 andres@anarazel.de 6334 : 1860 : TransactionIdAbortTree(xid, parsed->nsubxacts, parsed->subxacts);
6335 : :
6336 : : /*
6337 : : * We must update the ProcArray after we have marked clog.
6338 : : */
2149 alvherre@alvh.no-ip. 6339 : 1860 : ExpireTreeKnownAssignedTransactionIds(xid, parsed->nsubxacts, parsed->subxacts, max_xid);
6340 : :
6341 : : /*
6342 : : * There are no invalidation messages to send or undo.
6343 : : */
6344 : :
6345 : : /*
6346 : : * Release locks, if any. There are no invalidations to send.
6347 : : */
3193 simon@2ndQuadrant.co 6348 [ + + ]: 1860 : if (parsed->xinfo & XACT_XINFO_HAS_AE_LOCKS)
6349 : 1188 : StandbyReleaseLockTree(xid, parsed->nsubxacts, parsed->subxacts);
6350 : : }
6351 : :
1746 akapila@postgresql.o 6352 [ + + ]: 1880 : if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
6353 : : {
6354 : : /* recover apply progress */
6355 : 5 : replorigin_advance(origin_id, parsed->origin_lsn, lsn,
6356 : : false /* backward */ , false /* WAL */ );
6357 : : }
6358 : :
6359 : : /* Make sure files supposed to be dropped are dropped */
1603 fujii@postgresql.org 6360 [ + + ]: 1880 : if (parsed->nrels > 0)
6361 : : {
6362 : : /*
6363 : : * See comments about update of minimum recovery point on truncation,
6364 : : * in xact_redo_commit().
6365 : : */
6366 : 325 : XLogFlush(lsn);
6367 : :
1261 rhaas@postgresql.org 6368 : 325 : DropRelationFiles(parsed->xlocators, parsed->nrels, true);
6369 : : }
6370 : :
1352 andres@anarazel.de 6371 [ + + ]: 1880 : if (parsed->nstats > 0)
6372 : : {
6373 : : /* see equivalent call for relations above */
6374 : 439 : XLogFlush(lsn);
6375 : :
6376 : 439 : pgstat_execute_transactional_drops(parsed->nstats, parsed->stats, true);
6377 : : }
7489 tgl@sss.pgh.pa.us 6378 : 1880 : }
6379 : :
6380 : : void
4046 heikki.linnakangas@i 6381 : 24532 : xact_redo(XLogReaderState *record)
6382 : : {
3931 andres@anarazel.de 6383 : 24532 : uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
6384 : :
6385 : : /* Backup blocks are not used in xact records */
4046 heikki.linnakangas@i 6386 [ - + ]: 24532 : Assert(!XLogRecHasAnyBlockRefs(record));
6387 : :
3109 alvherre@alvh.no-ip. 6388 [ + + ]: 24532 : if (info == XLOG_XACT_COMMIT)
6389 : : {
7981 tgl@sss.pgh.pa.us 6390 : 22404 : xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
6391 : : xl_xact_parsed_commit parsed;
6392 : :
3109 alvherre@alvh.no-ip. 6393 : 22404 : ParseCommitRecord(XLogRecGetInfo(record), xlrec, &parsed);
6394 : 22404 : xact_redo_commit(&parsed, XLogRecGetXid(record),
6395 : 22404 : record->EndRecPtr, XLogRecGetOrigin(record));
6396 : : }
6397 [ + + ]: 2128 : else if (info == XLOG_XACT_COMMIT_PREPARED)
6398 : : {
6399 : 49 : xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
6400 : : xl_xact_parsed_commit parsed;
6401 : :
6402 : 49 : ParseCommitRecord(XLogRecGetInfo(record), xlrec, &parsed);
6403 : 49 : xact_redo_commit(&parsed, parsed.twophase_xid,
6404 : 49 : record->EndRecPtr, XLogRecGetOrigin(record));
6405 : :
6406 : : /* Delete TwoPhaseState gxact entry and/or 2PC file. */
6407 : 49 : LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
6408 : 49 : PrepareRedoRemove(parsed.twophase_xid, false);
6409 : 49 : LWLockRelease(TwoPhaseStateLock);
6410 : : }
6411 [ + + ]: 2079 : else if (info == XLOG_XACT_ABORT)
6412 : : {
7489 tgl@sss.pgh.pa.us 6413 : 1857 : xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
6414 : : xl_xact_parsed_abort parsed;
6415 : :
3109 alvherre@alvh.no-ip. 6416 : 1857 : ParseAbortRecord(XLogRecGetInfo(record), xlrec, &parsed);
1746 akapila@postgresql.o 6417 : 1857 : xact_redo_abort(&parsed, XLogRecGetXid(record),
6418 : 1857 : record->EndRecPtr, XLogRecGetOrigin(record));
6419 : : }
3109 alvherre@alvh.no-ip. 6420 [ + + ]: 222 : else if (info == XLOG_XACT_ABORT_PREPARED)
6421 : : {
6422 : 23 : xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
6423 : : xl_xact_parsed_abort parsed;
6424 : :
6425 : 23 : ParseAbortRecord(XLogRecGetInfo(record), xlrec, &parsed);
1746 akapila@postgresql.o 6426 : 23 : xact_redo_abort(&parsed, parsed.twophase_xid,
6427 : 23 : record->EndRecPtr, XLogRecGetOrigin(record));
6428 : :
6429 : : /* Delete TwoPhaseState gxact entry and/or 2PC file. */
3109 alvherre@alvh.no-ip. 6430 : 23 : LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
6431 : 23 : PrepareRedoRemove(parsed.twophase_xid, false);
6432 : 23 : LWLockRelease(TwoPhaseStateLock);
6433 : : }
7489 tgl@sss.pgh.pa.us 6434 [ + + ]: 199 : else if (info == XLOG_XACT_PREPARE)
6435 : : {
6436 : : /*
6437 : : * Store xid and start/end pointers of the WAL record in TwoPhaseState
6438 : : * gxact entry.
6439 : : */
3109 alvherre@alvh.no-ip. 6440 : 83 : LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
164 michael@paquier.xyz 6441 :GNC 83 : PrepareRedoAdd(InvalidFullTransactionId,
6442 : 83 : XLogRecGetData(record),
6443 : : record->ReadRecPtr,
6444 : : record->EndRecPtr,
2822 simon@2ndQuadrant.co 6445 :CBC 83 : XLogRecGetOrigin(record));
3109 alvherre@alvh.no-ip. 6446 : 83 : LWLockRelease(TwoPhaseStateLock);
6447 : : }
5843 simon@2ndQuadrant.co 6448 [ + + ]: 116 : else if (info == XLOG_XACT_ASSIGNMENT)
6449 : : {
6450 : 21 : xl_xact_assignment *xlrec = (xl_xact_assignment *) XLogRecGetData(record);
6451 : :
5698 6452 [ + - ]: 21 : if (standbyState >= STANDBY_INITIALIZED)
5843 6453 : 21 : ProcArrayApplyXidAssignment(xlrec->xtop,
6454 : 21 : xlrec->nsubxacts, xlrec->xsub);
6455 : : }
1974 akapila@postgresql.o 6456 [ - + ]: 95 : else if (info == XLOG_XACT_INVALIDATIONS)
6457 : : {
6458 : : /*
6459 : : * XXX we do ignore this for now, what matters are invalidations
6460 : : * written into the commit record.
6461 : : */
6462 : : }
6463 : : else
7489 tgl@sss.pgh.pa.us 6464 [ # # ]:UBC 0 : elog(PANIC, "xact_redo: unknown op code %u", info);
7489 tgl@sss.pgh.pa.us 6465 :CBC 24532 : }
|