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