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