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