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-2008, PostgreSQL Global Development Group
9 : * Portions Copyright (c) 1994, Regents of the University of California
10 : *
11 : *
12 : * IDENTIFICATION
13 : * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.256 2008/01/03 21:23:15 tgl Exp $
14 : *
15 : *-------------------------------------------------------------------------
16 : */
17 :
18 : #include "postgres.h"
19 :
20 : #include <time.h>
21 : #include <unistd.h>
22 :
23 : #include "access/multixact.h"
24 : #include "access/subtrans.h"
25 : #include "access/transam.h"
26 : #include "access/twophase.h"
27 : #include "access/xact.h"
28 : #include "access/xlogutils.h"
29 : #include "catalog/namespace.h"
30 : #include "commands/async.h"
31 : #include "commands/tablecmds.h"
32 : #include "commands/trigger.h"
33 : #include "executor/spi.h"
34 : #include "libpq/be-fsstubs.h"
35 : #include "miscadmin.h"
36 : #include "pgstat.h"
37 : #include "storage/fd.h"
38 : #include "storage/lmgr.h"
39 : #include "storage/procarray.h"
40 : #include "storage/sinvaladt.h"
41 : #include "storage/smgr.h"
42 : #include "utils/combocid.h"
43 : #include "utils/flatfiles.h"
44 : #include "utils/guc.h"
45 : #include "utils/inval.h"
46 : #include "utils/memutils.h"
47 : #include "utils/relcache.h"
48 : #include "utils/xml.h"
49 :
50 :
51 : /*
52 : * User-tweakable parameters
53 : */
54 : int DefaultXactIsoLevel = XACT_READ_COMMITTED;
55 : int XactIsoLevel;
56 :
57 : bool DefaultXactReadOnly = false;
58 : bool XactReadOnly;
59 :
60 : bool XactSyncCommit = true;
61 :
62 : int CommitDelay = 0; /* precommit delay in microseconds */
63 : int CommitSiblings = 5; /* # concurrent xacts needed to sleep */
64 :
65 :
66 : /*
67 : * transaction states - transaction state from server perspective
68 : */
69 : typedef enum TransState
70 : {
71 : TRANS_DEFAULT, /* idle */
72 : TRANS_START, /* transaction starting */
73 : TRANS_INPROGRESS, /* inside a valid transaction */
74 : TRANS_COMMIT, /* commit in progress */
75 : TRANS_ABORT, /* abort in progress */
76 : TRANS_PREPARE /* prepare in progress */
77 : } TransState;
78 :
79 : /*
80 : * transaction block states - transaction state of client queries
81 : *
82 : * Note: the subtransaction states are used only for non-topmost
83 : * transactions; the others appear only in the topmost transaction.
84 : */
85 : typedef enum TBlockState
86 : {
87 : /* not-in-transaction-block states */
88 : TBLOCK_DEFAULT, /* idle */
89 : TBLOCK_STARTED, /* running single-query transaction */
90 :
91 : /* transaction block states */
92 : TBLOCK_BEGIN, /* starting transaction block */
93 : TBLOCK_INPROGRESS, /* live transaction */
94 : TBLOCK_END, /* COMMIT received */
95 : TBLOCK_ABORT, /* failed xact, awaiting ROLLBACK */
96 : TBLOCK_ABORT_END, /* failed xact, ROLLBACK received */
97 : TBLOCK_ABORT_PENDING, /* live xact, ROLLBACK received */
98 : TBLOCK_PREPARE, /* live xact, PREPARE received */
99 :
100 : /* subtransaction states */
101 : TBLOCK_SUBBEGIN, /* starting a subtransaction */
102 : TBLOCK_SUBINPROGRESS, /* live subtransaction */
103 : TBLOCK_SUBEND, /* RELEASE received */
104 : TBLOCK_SUBABORT, /* failed subxact, awaiting ROLLBACK */
105 : TBLOCK_SUBABORT_END, /* failed subxact, ROLLBACK received */
106 : TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received */
107 : TBLOCK_SUBRESTART, /* live subxact, ROLLBACK TO received */
108 : TBLOCK_SUBABORT_RESTART /* failed subxact, ROLLBACK TO received */
109 : } TBlockState;
110 :
111 : /*
112 : * transaction state structure
113 : */
114 : typedef struct TransactionStateData
115 : {
116 : TransactionId transactionId; /* my XID, or Invalid if none */
117 : SubTransactionId subTransactionId; /* my subxact ID */
118 : char *name; /* savepoint name, if any */
119 : int savepointLevel; /* savepoint level */
120 : TransState state; /* low-level state */
121 : TBlockState blockState; /* high-level state */
122 : int nestingLevel; /* transaction nesting depth */
123 : int gucNestLevel; /* GUC context nesting depth */
124 : MemoryContext curTransactionContext; /* my xact-lifetime context */
125 : ResourceOwner curTransactionOwner; /* my query resources */
126 : List *childXids; /* subcommitted child XIDs */
127 : Oid prevUser; /* previous CurrentUserId setting */
128 : bool prevSecDefCxt; /* previous SecurityDefinerContext setting */
129 : bool prevXactReadOnly; /* entry-time xact r/o state */
130 : struct TransactionStateData *parent; /* back link to parent */
131 : } TransactionStateData;
132 :
133 : typedef TransactionStateData *TransactionState;
134 :
135 : /*
136 : * CurrentTransactionState always points to the current transaction state
137 : * block. It will point to TopTransactionStateData when not in a
138 : * transaction at all, or when in a top-level transaction.
139 : */
140 : static TransactionStateData TopTransactionStateData = {
141 : 0, /* transaction id */
142 : 0, /* subtransaction id */
143 : NULL, /* savepoint name */
144 : 0, /* savepoint level */
145 : TRANS_DEFAULT, /* transaction state */
146 : TBLOCK_DEFAULT, /* transaction block state from the client
147 : * perspective */
148 : 0, /* transaction nesting depth */
149 : 0, /* GUC context nesting depth */
150 : NULL, /* cur transaction context */
151 : NULL, /* cur transaction resource owner */
152 : NIL, /* subcommitted child Xids */
153 : InvalidOid, /* previous CurrentUserId setting */
154 : false, /* previous SecurityDefinerContext setting */
155 : false, /* entry-time xact r/o state */
156 : NULL /* link to parent state block */
157 : };
158 :
159 : static TransactionState CurrentTransactionState = &TopTransactionStateData;
160 :
161 : /*
162 : * The subtransaction ID and command ID assignment counters are global
163 : * to a whole transaction, so we do not keep them in the state stack.
164 : */
165 : static SubTransactionId currentSubTransactionId;
166 : static CommandId currentCommandId;
167 : static bool currentCommandIdUsed;
168 :
169 : /*
170 : * xactStartTimestamp is the value of transaction_timestamp().
171 : * stmtStartTimestamp is the value of statement_timestamp().
172 : * xactStopTimestamp is the time at which we log a commit or abort WAL record.
173 : * These do not change as we enter and exit subtransactions, so we don't
174 : * keep them inside the TransactionState stack.
175 : */
176 : static TimestampTz xactStartTimestamp;
177 : static TimestampTz stmtStartTimestamp;
178 : static TimestampTz xactStopTimestamp;
179 :
180 : /*
181 : * GID to be used for preparing the current transaction. This is also
182 : * global to a whole transaction, so we don't keep it in the state stack.
183 : */
184 : static char *prepareGID;
185 :
186 : /*
187 : * Some commands want to force synchronous commit.
188 : */
189 : static bool forceSyncCommit = false;
190 :
191 : /*
192 : * Private context for transaction-abort work --- we reserve space for this
193 : * at startup to ensure that AbortTransaction and AbortSubTransaction can work
194 : * when we've run out of memory.
195 : */
196 : static MemoryContext TransactionAbortContext = NULL;
197 :
198 : /*
199 : * List of add-on start- and end-of-xact callbacks
200 : */
201 : typedef struct XactCallbackItem
202 : {
203 : struct XactCallbackItem *next;
204 : XactCallback callback;
205 : void *arg;
206 : } XactCallbackItem;
207 :
208 : static XactCallbackItem *Xact_callbacks = NULL;
209 :
210 : /*
211 : * List of add-on start- and end-of-subxact callbacks
212 : */
213 : typedef struct SubXactCallbackItem
214 : {
215 : struct SubXactCallbackItem *next;
216 : SubXactCallback callback;
217 : void *arg;
218 : } SubXactCallbackItem;
219 :
220 : static SubXactCallbackItem *SubXact_callbacks = NULL;
221 :
222 :
223 : /* local function prototypes */
224 : static void AssignTransactionId(TransactionState s);
225 : static void AbortTransaction(void);
226 : static void AtAbort_Memory(void);
227 : static void AtCleanup_Memory(void);
228 : static void AtAbort_ResourceOwner(void);
229 : static void AtCommit_LocalCache(void);
230 : static void AtCommit_Memory(void);
231 : static void AtStart_Cache(void);
232 : static void AtStart_Memory(void);
233 : static void AtStart_ResourceOwner(void);
234 : static void CallXactCallbacks(XactEvent event);
235 : static void CallSubXactCallbacks(SubXactEvent event,
236 : SubTransactionId mySubid,
237 : SubTransactionId parentSubid);
238 : static void CleanupTransaction(void);
239 : static void CommitTransaction(void);
240 : static TransactionId RecordTransactionAbort(bool isSubXact);
241 : static void StartTransaction(void);
242 :
243 : static void RecordSubTransactionCommit(void);
244 : static void StartSubTransaction(void);
245 : static void CommitSubTransaction(void);
246 : static void AbortSubTransaction(void);
247 : static void CleanupSubTransaction(void);
248 : static void PushTransaction(void);
249 : static void PopTransaction(void);
250 :
251 : static void AtSubAbort_Memory(void);
252 : static void AtSubCleanup_Memory(void);
253 : static void AtSubAbort_ResourceOwner(void);
254 : static void AtSubCommit_Memory(void);
255 : static void AtSubStart_Memory(void);
256 : static void AtSubStart_ResourceOwner(void);
257 :
258 : static void ShowTransactionState(const char *str);
259 : static void ShowTransactionStateRec(TransactionState state);
260 : static const char *BlockStateAsString(TBlockState blockState);
261 : static const char *TransStateAsString(TransState state);
262 :
263 :
264 : /* ----------------------------------------------------------------
265 : * transaction state accessors
266 : * ----------------------------------------------------------------
267 : */
268 :
269 : /*
270 : * IsTransactionState
271 : *
272 : * This returns true if we are inside a valid transaction; that is,
273 : * it is safe to initiate database access, take heavyweight locks, etc.
274 : */
275 : bool
276 : IsTransactionState(void)
277 1229 : {
278 1229 : TransactionState s = CurrentTransactionState;
279 :
280 : /*
281 : * TRANS_DEFAULT and TRANS_ABORT are obviously unsafe states. However, we
282 : * also reject the startup/shutdown states TRANS_START, TRANS_COMMIT,
283 : * TRANS_PREPARE since it might be too soon or too late within those
284 : * transition states to do anything interesting. Hence, the only "valid"
285 : * state is TRANS_INPROGRESS.
286 : */
287 1229 : return (s->state == TRANS_INPROGRESS);
288 : }
289 :
290 : /*
291 : * IsAbortedTransactionBlockState
292 : *
293 : * This returns true if we are currently running a query
294 : * within an aborted transaction block.
295 : */
296 : bool
297 : IsAbortedTransactionBlockState(void)
298 10161 : {
299 10161 : TransactionState s = CurrentTransactionState;
300 :
301 10161 : if (s->blockState == TBLOCK_ABORT ||
302 : s->blockState == TBLOCK_SUBABORT)
303 28 : return true;
304 :
305 10133 : return false;
306 : }
307 :
308 :
309 : /*
310 : * GetTopTransactionId
311 : *
312 : * This will return the XID of the main transaction, assigning one if
313 : * it's not yet set. Be careful to call this only inside a valid xact.
314 : */
315 : TransactionId
316 : GetTopTransactionId(void)
317 7 : {
318 7 : if (!TransactionIdIsValid(TopTransactionStateData.transactionId))
319 7 : AssignTransactionId(&TopTransactionStateData);
320 7 : return TopTransactionStateData.transactionId;
321 : }
322 :
323 : /*
324 : * GetTopTransactionIdIfAny
325 : *
326 : * This will return the XID of the main transaction, if one is assigned.
327 : * It will return InvalidTransactionId if we are not currently inside a
328 : * transaction, or inside a transaction that hasn't yet been assigned an XID.
329 : */
330 : TransactionId
331 : GetTopTransactionIdIfAny(void)
332 12586 : {
333 12586 : return TopTransactionStateData.transactionId;
334 : }
335 :
336 : /*
337 : * GetCurrentTransactionId
338 : *
339 : * This will return the XID of the current transaction (main or sub
340 : * transaction), assigning one if it's not yet set. Be careful to call this
341 : * only inside a valid xact.
342 : */
343 : TransactionId
344 : GetCurrentTransactionId(void)
345 228037 : {
346 228037 : TransactionState s = CurrentTransactionState;
347 :
348 228037 : if (!TransactionIdIsValid(s->transactionId))
349 8653 : AssignTransactionId(s);
350 228037 : return s->transactionId;
351 : }
352 :
353 : /*
354 : * GetCurrentTransactionIdIfAny
355 : *
356 : * This will return the XID of the current sub xact, if one is assigned.
357 : * It will return InvalidTransactionId if we are not currently inside a
358 : * transaction, or inside a transaction that hasn't been assigned an XID yet.
359 : */
360 : TransactionId
361 : GetCurrentTransactionIdIfAny(void)
362 288642 : {
363 288642 : return CurrentTransactionState->transactionId;
364 : }
365 :
366 :
367 : /*
368 : * AssignTransactionId
369 : *
370 : * Assigns a new permanent XID to the given TransactionState.
371 : * We do not assign XIDs to transactions until/unless this is called.
372 : * Also, any parent TransactionStates that don't yet have XIDs are assigned
373 : * one; this maintains the invariant that a child transaction has an XID
374 : * following its parent's.
375 : */
376 : static void
377 : AssignTransactionId(TransactionState s)
378 8671 : {
379 8671 : bool isSubXact = (s->parent != NULL);
380 : ResourceOwner currentOwner;
381 :
382 : /* Assert that caller didn't screw up */
383 : Assert(!TransactionIdIsValid(s->transactionId));
384 : Assert(s->state == TRANS_INPROGRESS);
385 :
386 : /*
387 : * Ensure parent(s) have XIDs, so that a child always has an XID later
388 : * than its parent.
389 : */
390 8671 : if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
391 11 : AssignTransactionId(s->parent);
392 :
393 : /*
394 : * Generate a new Xid and record it in PG_PROC and pg_subtrans.
395 : *
396 : * NB: we must make the subtrans entry BEFORE the Xid appears anywhere in
397 : * shared storage other than PG_PROC; because if there's no room for it in
398 : * PG_PROC, the subtrans entry is needed to ensure that other backends see
399 : * the Xid as "running". See GetNewTransactionId.
400 : */
401 8671 : s->transactionId = GetNewTransactionId(isSubXact);
402 :
403 8671 : if (isSubXact)
404 40 : SubTransSetParent(s->transactionId, s->parent->transactionId);
405 :
406 : /*
407 : * Acquire lock on the transaction XID. (We assume this cannot block.) We
408 : * have to ensure that the lock is assigned to the transaction's own
409 : * ResourceOwner.
410 : */
411 8671 : currentOwner = CurrentResourceOwner;
412 8671 : PG_TRY();
413 : {
414 8671 : CurrentResourceOwner = s->curTransactionOwner;
415 8671 : XactLockTableInsert(s->transactionId);
416 : }
417 0 : PG_CATCH();
418 : {
419 : /* Ensure CurrentResourceOwner is restored on error */
420 0 : CurrentResourceOwner = currentOwner;
421 0 : PG_RE_THROW();
422 : }
423 8671 : PG_END_TRY();
424 8671 : CurrentResourceOwner = currentOwner;
425 8671 : }
426 :
427 :
428 : /*
429 : * GetCurrentSubTransactionId
430 : */
431 : SubTransactionId
432 : GetCurrentSubTransactionId(void)
433 47297 : {
434 47297 : TransactionState s = CurrentTransactionState;
435 :
436 47297 : return s->subTransactionId;
437 : }
438 :
439 :
440 : /*
441 : * GetCurrentCommandId
442 : *
443 : * "used" must be TRUE if the caller intends to use the command ID to mark
444 : * inserted/updated/deleted tuples. FALSE means the ID is being fetched
445 : * for read-only purposes (ie, as a snapshot validity cutoff). See
446 : * CommandCounterIncrement() for discussion.
447 : */
448 : CommandId
449 : GetCurrentCommandId(bool used)
450 136888 : {
451 : /* this is global to a transaction, not subtransaction-local */
452 136888 : if (used)
453 79800 : currentCommandIdUsed = true;
454 136888 : return currentCommandId;
455 : }
456 :
457 : /*
458 : * GetCurrentTransactionStartTimestamp
459 : */
460 : TimestampTz
461 : GetCurrentTransactionStartTimestamp(void)
462 108 : {
463 108 : return xactStartTimestamp;
464 : }
465 :
466 : /*
467 : * GetCurrentStatementStartTimestamp
468 : */
469 : TimestampTz
470 : GetCurrentStatementStartTimestamp(void)
471 29980 : {
472 29980 : return stmtStartTimestamp;
473 : }
474 :
475 : /*
476 : * GetCurrentTransactionStopTimestamp
477 : *
478 : * We return current time if the transaction stop time hasn't been set
479 : * (which can happen if we decide we don't need to log an XLOG record).
480 : */
481 : TimestampTz
482 : GetCurrentTransactionStopTimestamp(void)
483 8476 : {
484 8476 : if (xactStopTimestamp != 0)
485 4010 : return xactStopTimestamp;
486 4466 : return GetCurrentTimestamp();
487 : }
488 :
489 : /*
490 : * SetCurrentStatementStartTimestamp
491 : */
492 : void
493 : SetCurrentStatementStartTimestamp(void)
494 10019 : {
495 10019 : stmtStartTimestamp = GetCurrentTimestamp();
496 10019 : }
497 :
498 : /*
499 : * SetCurrentTransactionStopTimestamp
500 : */
501 : static inline void
502 : SetCurrentTransactionStopTimestamp(void)
503 8634 : {
504 8634 : xactStopTimestamp = GetCurrentTimestamp();
505 8634 : }
506 :
507 : /*
508 : * GetCurrentTransactionNestLevel
509 : *
510 : * Note: this will return zero when not inside any transaction, one when
511 : * inside a top-level transaction, etc.
512 : */
513 : int
514 : GetCurrentTransactionNestLevel(void)
515 307051 : {
516 307051 : TransactionState s = CurrentTransactionState;
517 :
518 307051 : return s->nestingLevel;
519 : }
520 :
521 :
522 : /*
523 : * TransactionIdIsCurrentTransactionId
524 : */
525 : bool
526 : TransactionIdIsCurrentTransactionId(TransactionId xid)
527 143862 : {
528 : TransactionState s;
529 :
530 : /*
531 : * We always say that BootstrapTransactionId is "not my transaction ID"
532 : * even when it is (ie, during bootstrap). Along with the fact that
533 : * transam.c always treats BootstrapTransactionId as already committed,
534 : * this causes the tqual.c routines to see all tuples as committed, which
535 : * is what we need during bootstrap. (Bootstrap mode only inserts tuples,
536 : * it never updates or deletes them, so all tuples can be presumed good
537 : * immediately.)
538 : *
539 : * Likewise, InvalidTransactionId and FrozenTransactionId are certainly
540 : * not my transaction ID, so we can just return "false" immediately for
541 : * any non-normal XID.
542 : */
543 143862 : if (!TransactionIdIsNormal(xid))
544 5110 : return false;
545 :
546 : /*
547 : * We will return true for the Xid of the current subtransaction, any of
548 : * its subcommitted children, any of its parents, or any of their
549 : * previously subcommitted children. However, a transaction being aborted
550 : * is no longer "current", even though it may still have an entry on the
551 : * state stack.
552 : */
553 226998 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
554 : {
555 : ListCell *cell;
556 :
557 138876 : if (s->state == TRANS_ABORT)
558 0 : continue;
559 138876 : if (!TransactionIdIsValid(s->transactionId))
560 35137 : continue; /* it can't have any child XIDs either */
561 103739 : if (TransactionIdEquals(xid, s->transactionId))
562 50617 : return true;
563 53127 : foreach(cell, s->childXids)
564 : {
565 18 : if (TransactionIdEquals(xid, lfirst_xid(cell)))
566 13 : return true;
567 : }
568 : }
569 :
570 88122 : return false;
571 : }
572 :
573 :
574 : /*
575 : * CommandCounterIncrement
576 : */
577 : void
578 : CommandCounterIncrement(void)
579 21043 : {
580 : /*
581 : * If the current value of the command counter hasn't been "used" to
582 : * mark tuples, we need not increment it, since there's no need to
583 : * distinguish a read-only command from others. This helps postpone
584 : * command counter overflow, and keeps no-op CommandCounterIncrement
585 : * operations cheap.
586 : */
587 21043 : if (currentCommandIdUsed)
588 : {
589 10947 : currentCommandId += 1;
590 10947 : if (currentCommandId == FirstCommandId) /* check for overflow */
591 : {
592 0 : currentCommandId -= 1;
593 0 : ereport(ERROR,
594 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
595 : errmsg("cannot have more than 2^32-1 commands in a transaction")));
596 : }
597 10947 : currentCommandIdUsed = false;
598 :
599 : /* Propagate new command ID into static snapshots, if set */
600 10947 : if (SerializableSnapshot)
601 9862 : SerializableSnapshot->curcid = currentCommandId;
602 10947 : if (LatestSnapshot)
603 2194 : LatestSnapshot->curcid = currentCommandId;
604 :
605 : /*
606 : * Make any catalog changes done by the just-completed command
607 : * visible in the local syscache. We obviously don't need to do
608 : * this after a read-only command. (But see hacks in inval.c
609 : * to make real sure we don't think a command that queued inval
610 : * messages was read-only.)
611 : */
612 10947 : AtCommit_LocalCache();
613 : }
614 :
615 : /*
616 : * Make any other backends' catalog changes visible to me.
617 : *
618 : * XXX this is probably in the wrong place: CommandCounterIncrement
619 : * should be purely a local operation, most likely. However fooling
620 : * with this will affect asynchronous cross-backend interactions,
621 : * which doesn't seem like a wise thing to do in late beta, so save
622 : * improving this for another day - tgl 2007-11-30
623 : */
624 21043 : AtStart_Cache();
625 21043 : }
626 :
627 : /*
628 : * ForceSyncCommit
629 : *
630 : * Interface routine to allow commands to force a synchronous commit of the
631 : * current top-level transaction
632 : */
633 : void
634 : ForceSyncCommit(void)
635 67 : {
636 67 : forceSyncCommit = true;
637 67 : }
638 :
639 :
640 : /* ----------------------------------------------------------------
641 : * StartTransaction stuff
642 : * ----------------------------------------------------------------
643 : */
644 :
645 : /*
646 : * AtStart_Cache
647 : */
648 : static void
649 : AtStart_Cache(void)
650 34716 : {
651 34716 : AcceptInvalidationMessages();
652 34716 : }
653 :
654 : /*
655 : * AtStart_Memory
656 : */
657 : static void
658 : AtStart_Memory(void)
659 13673 : {
660 13673 : TransactionState s = CurrentTransactionState;
661 :
662 : /*
663 : * If this is the first time through, create a private context for
664 : * AbortTransaction to work in. By reserving some space now, we can
665 : * insulate AbortTransaction from out-of-memory scenarios. Like
666 : * ErrorContext, we set it up with slow growth rate and a nonzero minimum
667 : * size, so that space will be reserved immediately.
668 : */
669 13673 : if (TransactionAbortContext == NULL)
670 138 : TransactionAbortContext =
671 : AllocSetContextCreate(TopMemoryContext,
672 : "TransactionAbortContext",
673 : 32 * 1024,
674 : 32 * 1024,
675 : 32 * 1024);
676 :
677 : /*
678 : * We shouldn't have a transaction context already.
679 : */
680 : Assert(TopTransactionContext == NULL);
681 :
682 : /*
683 : * Create a toplevel context for the transaction.
684 : */
685 13673 : TopTransactionContext =
686 : AllocSetContextCreate(TopMemoryContext,
687 : "TopTransactionContext",
688 : ALLOCSET_DEFAULT_MINSIZE,
689 : ALLOCSET_DEFAULT_INITSIZE,
690 : ALLOCSET_DEFAULT_MAXSIZE);
691 :
692 : /*
693 : * In a top-level transaction, CurTransactionContext is the same as
694 : * TopTransactionContext.
695 : */
696 13673 : CurTransactionContext = TopTransactionContext;
697 13673 : s->curTransactionContext = CurTransactionContext;
698 :
699 : /* Make the CurTransactionContext active. */
700 13673 : MemoryContextSwitchTo(CurTransactionContext);
701 13673 : }
702 :
703 : /*
704 : * AtStart_ResourceOwner
705 : */
706 : static void
707 : AtStart_ResourceOwner(void)
708 13673 : {
709 13673 : TransactionState s = CurrentTransactionState;
710 :
711 : /*
712 : * We shouldn't have a transaction resource owner already.
713 : */
714 : Assert(TopTransactionResourceOwner == NULL);
715 :
716 : /*
717 : * Create a toplevel resource owner for the transaction.
718 : */
719 13673 : s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
720 :
721 13673 : TopTransactionResourceOwner = s->curTransactionOwner;
722 13673 : CurTransactionResourceOwner = s->curTransactionOwner;
723 13673 : CurrentResourceOwner = s->curTransactionOwner;
724 13673 : }
725 :
726 : /* ----------------------------------------------------------------
727 : * StartSubTransaction stuff
728 : * ----------------------------------------------------------------
729 : */
730 :
731 : /*
732 : * AtSubStart_Memory
733 : */
734 : static void
735 : AtSubStart_Memory(void)
736 84 : {
737 84 : TransactionState s = CurrentTransactionState;
738 :
739 : Assert(CurTransactionContext != NULL);
740 :
741 : /*
742 : * Create a CurTransactionContext, which will be used to hold data that
743 : * survives subtransaction commit but disappears on subtransaction abort.
744 : * We make it a child of the immediate parent's CurTransactionContext.
745 : */
746 84 : CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
747 : "CurTransactionContext",
748 : ALLOCSET_DEFAULT_MINSIZE,
749 : ALLOCSET_DEFAULT_INITSIZE,
750 : ALLOCSET_DEFAULT_MAXSIZE);
751 84 : s->curTransactionContext = CurTransactionContext;
752 :
753 : /* Make the CurTransactionContext active. */
754 84 : MemoryContextSwitchTo(CurTransactionContext);
755 84 : }
756 :
757 : /*
758 : * AtSubStart_ResourceOwner
759 : */
760 : static void
761 : AtSubStart_ResourceOwner(void)
762 84 : {
763 84 : TransactionState s = CurrentTransactionState;
764 :
765 : Assert(s->parent != NULL);
766 :
767 : /*
768 : * Create a resource owner for the subtransaction. We make it a child of
769 : * the immediate parent's resource owner.
770 : */
771 84 : s->curTransactionOwner =
772 : ResourceOwnerCreate(s->parent->curTransactionOwner,
773 : "SubTransaction");
774 :
775 84 : CurTransactionResourceOwner = s->curTransactionOwner;
776 84 : CurrentResourceOwner = s->curTransactionOwner;
777 84 : }
778 :
779 : /* ----------------------------------------------------------------
780 : * CommitTransaction stuff
781 : * ----------------------------------------------------------------
782 : */
783 :
784 : /*
785 : * RecordTransactionCommit
786 : *
787 : * Returns latest XID among xact and its children, or InvalidTransactionId
788 : * if the xact has no XID. (We compute that here just because it's easier.)
789 : *
790 : * This is exported only to support an ugly hack in VACUUM FULL.
791 : */
792 : TransactionId
793 : RecordTransactionCommit(void)
794 12586 : {
795 12586 : TransactionId xid = GetTopTransactionIdIfAny();
796 12586 : bool markXidCommitted = TransactionIdIsValid(xid);
797 12586 : TransactionId latestXid = InvalidTransactionId;
798 : int nrels;
799 : RelFileNode *rels;
800 : bool haveNonTemp;
801 : int nchildren;
802 : TransactionId *children;
803 :
804 : /* Get data needed for commit record */
805 12586 : nrels = smgrGetPendingDeletes(true, &rels, &haveNonTemp);
806 12586 : nchildren = xactGetCommittedChildren(&children);
807 :
808 : /*
809 : * If we haven't been assigned an XID yet, we neither can, nor do we want
810 : * to write a COMMIT record.
811 : */
812 12586 : if (!markXidCommitted)
813 : {
814 : /*
815 : * We expect that every smgrscheduleunlink is followed by a catalog
816 : * update, and hence XID assignment, so we shouldn't get here with any
817 : * pending deletes. Use a real test not just an Assert to check this,
818 : * since it's a bit fragile.
819 : */
820 4120 : if (nrels != 0)
821 0 : elog(ERROR, "cannot commit a transaction that deleted files but has no xid");
822 :
823 : /* Can't have child XIDs either; AssignTransactionId enforces this */
824 : Assert(nchildren == 0);
825 :
826 : /*
827 : * If we didn't create XLOG entries, we're done here; otherwise we
828 : * should flush those entries the same as a commit record. (An
829 : * example of a possible record that wouldn't cause an XID to be
830 : * assigned is a sequence advance record due to nextval() --- we want
831 : * to flush that to disk before reporting commit.)
832 : */
833 4120 : if (XactLastRecEnd.xrecoff == 0)
834 3915 : goto cleanup;
835 : }
836 : else
837 : {
838 : /*
839 : * Begin commit critical section and insert the commit XLOG record.
840 : */
841 : XLogRecData rdata[3];
842 8466 : int lastrdata = 0;
843 : xl_xact_commit xlrec;
844 :
845 : /* Tell bufmgr and smgr to prepare for commit */
846 8466 : BufmgrCommit();
847 :
848 : /*
849 : * Mark ourselves as within our "commit critical section". This
850 : * forces any concurrent checkpoint to wait until we've updated
851 : * pg_clog. Without this, it is possible for the checkpoint to set
852 : * REDO after the XLOG record but fail to flush the pg_clog update to
853 : * disk, leading to loss of the transaction commit if the system
854 : * crashes a little later.
855 : *
856 : * Note: we could, but don't bother to, set this flag in
857 : * RecordTransactionAbort. That's because loss of a transaction abort
858 : * is noncritical; the presumption would be that it aborted, anyway.
859 : *
860 : * It's safe to change the inCommit flag of our own backend without
861 : * holding the ProcArrayLock, since we're the only one modifying it.
862 : * This makes checkpoint's determination of which xacts are inCommit a
863 : * bit fuzzy, but it doesn't matter.
864 : */
865 8466 : START_CRIT_SECTION();
866 8466 : MyProc->inCommit = true;
867 :
868 8466 : SetCurrentTransactionStopTimestamp();
869 8466 : xlrec.xact_time = xactStopTimestamp;
870 8466 : xlrec.nrels = nrels;
871 8466 : xlrec.nsubxacts = nchildren;
872 8466 : rdata[0].data = (char *) (&xlrec);
873 8466 : rdata[0].len = MinSizeOfXactCommit;
874 8466 : rdata[0].buffer = InvalidBuffer;
875 : /* dump rels to delete */
876 8466 : if (nrels > 0)
877 : {
878 339 : rdata[0].next = &(rdata[1]);
879 339 : rdata[1].data = (char *) rels;
880 339 : rdata[1].len = nrels * sizeof(RelFileNode);
881 339 : rdata[1].buffer = InvalidBuffer;
882 339 : lastrdata = 1;
883 : }
884 : /* dump committed child Xids */
885 8466 : if (nchildren > 0)
886 : {
887 8 : rdata[lastrdata].next = &(rdata[2]);
888 8 : rdata[2].data = (char *) children;
889 8 : rdata[2].len = nchildren * sizeof(TransactionId);
890 8 : rdata[2].buffer = InvalidBuffer;
891 8 : lastrdata = 2;
892 : }
893 8466 : rdata[lastrdata].next = NULL;
894 :
895 8466 : (void) XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
896 : }
897 :
898 : /*
899 : * Check if we want to commit asynchronously. If the user has set
900 : * synchronous_commit = off, and we're not doing cleanup of any non-temp
901 : * rels nor committing any command that wanted to force sync commit, then
902 : * we can defer flushing XLOG. (We must not allow asynchronous commit if
903 : * there are any non-temp tables to be deleted, because we might delete
904 : * the files before the COMMIT record is flushed to disk. We do allow
905 : * asynchronous commit if all to-be-deleted tables are temporary though,
906 : * since they are lost anyway if we crash.)
907 : */
908 8671 : if (XactSyncCommit || forceSyncCommit || haveNonTemp)
909 : {
910 : /*
911 : * Synchronous commit case.
912 : *
913 : * Sleep before flush! So we can flush more than one commit records
914 : * per single fsync. (The idea is some other backend may do the
915 : * XLogFlush while we're sleeping. This needs work still, because on
916 : * most Unixen, the minimum select() delay is 10msec or more, which is
917 : * way too long.)
918 : *
919 : * We do not sleep if enableFsync is not turned on, nor if there are
920 : * fewer than CommitSiblings other backends with active transactions.
921 : */
922 8671 : if (CommitDelay > 0 && enableFsync &&
923 : CountActiveBackends() >= CommitSiblings)
924 0 : pg_usleep(CommitDelay);
925 :
926 8671 : XLogFlush(XactLastRecEnd);
927 :
928 : /*
929 : * Now we may update the CLOG, if we wrote a COMMIT record above
930 : */
931 8671 : if (markXidCommitted)
932 : {
933 8466 : TransactionIdCommit(xid);
934 : /* to avoid race conditions, the parent must commit first */
935 8466 : TransactionIdCommitTree(nchildren, children);
936 : }
937 : }
938 : else
939 : {
940 : /*
941 : * Asynchronous commit case.
942 : *
943 : * Report the latest async commit LSN, so that the WAL writer knows to
944 : * flush this commit.
945 : */
946 0 : XLogSetAsyncCommitLSN(XactLastRecEnd);
947 :
948 : /*
949 : * We must not immediately update the CLOG, since we didn't flush the
950 : * XLOG. Instead, we store the LSN up to which the XLOG must be
951 : * flushed before the CLOG may be updated.
952 : */
953 0 : if (markXidCommitted)
954 : {
955 0 : TransactionIdAsyncCommit(xid, XactLastRecEnd);
956 : /* to avoid race conditions, the parent must commit first */
957 0 : TransactionIdAsyncCommitTree(nchildren, children, XactLastRecEnd);
958 : }
959 : }
960 :
961 : /*
962 : * If we entered a commit critical section, leave it now, and let
963 : * checkpoints proceed.
964 : */
965 8671 : if (markXidCommitted)
966 : {
967 8466 : MyProc->inCommit = false;
968 8466 : END_CRIT_SECTION();
969 : }
970 :
971 : /* Compute latestXid while we have the child XIDs handy */
972 8671 : latestXid = TransactionIdLatest(xid, nchildren, children);
973 :
974 : /* Reset XactLastRecEnd until the next transaction writes something */
975 8671 : XactLastRecEnd.xrecoff = 0;
976 :
977 12586 : cleanup:
978 : /* Clean up local data */
979 12586 : if (rels)
980 339 : pfree(rels);
981 12586 : if (children)
982 8 : pfree(children);
983 :
984 12586 : return latestXid;
985 : }
986 :
987 :
988 : /*
989 : * AtCommit_LocalCache
990 : */
991 : static void
992 : AtCommit_LocalCache(void)
993 10947 : {
994 : /*
995 : * Make catalog changes visible to me for the next command.
996 : */
997 10947 : CommandEndInvalidationMessages();
998 10947 : }
999 :
1000 : /*
1001 : * AtCommit_Memory
1002 : */
1003 : static void
1004 : AtCommit_Memory(void)
1005 12583 : {
1006 : /*
1007 : * Now that we're "out" of a transaction, have the system allocate things
1008 : * in the top memory context instead of per-transaction contexts.
1009 : */
1010 12583 : MemoryContextSwitchTo(TopMemoryContext);
1011 :
1012 : /*
1013 : * Release all transaction-local memory.
1014 : */
1015 : Assert(TopTransactionContext != NULL);
1016 12583 : MemoryContextDelete(TopTransactionContext);
1017 12583 : TopTransactionContext = NULL;
1018 12583 : CurTransactionContext = NULL;
1019 12583 : CurrentTransactionState->curTransactionContext = NULL;
1020 12583 : }
1021 :
1022 : /* ----------------------------------------------------------------
1023 : * CommitSubTransaction stuff
1024 : * ----------------------------------------------------------------
1025 : */
1026 :
1027 : /*
1028 : * AtSubCommit_Memory
1029 : */
1030 : static void
1031 : AtSubCommit_Memory(void)
1032 34 : {
1033 34 : TransactionState s = CurrentTransactionState;
1034 :
1035 : Assert(s->parent != NULL);
1036 :
1037 : /* Return to parent transaction level's memory context. */
1038 34 : CurTransactionContext = s->parent->curTransactionContext;
1039 34 : MemoryContextSwitchTo(CurTransactionContext);
1040 :
1041 : /*
1042 : * Ordinarily we cannot throw away the child's CurTransactionContext,
1043 : * since the data it contains will be needed at upper commit. However, if
1044 : * there isn't actually anything in it, we can throw it away. This avoids
1045 : * a small memory leak in the common case of "trivial" subxacts.
1046 : */
1047 34 : if (MemoryContextIsEmpty(s->curTransactionContext))
1048 : {
1049 29 : MemoryContextDelete(s->curTransactionContext);
1050 29 : s->curTransactionContext = NULL;
1051 : }
1052 34 : }
1053 :
1054 : /*
1055 : * AtSubCommit_childXids
1056 : *
1057 : * Pass my own XID and my child XIDs up to my parent as committed children.
1058 : */
1059 : static void
1060 : AtSubCommit_childXids(void)
1061 19 : {
1062 19 : TransactionState s = CurrentTransactionState;
1063 : MemoryContext old_cxt;
1064 :
1065 : Assert(s->parent != NULL);
1066 :
1067 : /*
1068 : * We keep the child-XID lists in TopTransactionContext; this avoids
1069 : * setting up child-transaction contexts for what might be just a few
1070 : * bytes of grandchild XIDs.
1071 : */
1072 38 : old_cxt = MemoryContextSwitchTo(TopTransactionContext);
1073 :
1074 19 : s->parent->childXids = lappend_xid(s->parent->childXids,
1075 : s->transactionId);
1076 :
1077 19 : if (s->childXids != NIL)
1078 : {
1079 5 : s->parent->childXids = list_concat(s->parent->childXids,
1080 : s->childXids);
1081 :
1082 : /*
1083 : * list_concat doesn't free the list header for the second list; do so
1084 : * here to avoid memory leakage (kluge)
1085 : */
1086 5 : pfree(s->childXids);
1087 5 : s->childXids = NIL;
1088 : }
1089 :
1090 : MemoryContextSwitchTo(old_cxt);
1091 19 : }
1092 :
1093 : /*
1094 : * RecordSubTransactionCommit
1095 : */
1096 : static void
1097 : RecordSubTransactionCommit(void)
1098 34 : {
1099 34 : TransactionId xid = GetCurrentTransactionIdIfAny();
1100 :
1101 : /*
1102 : * We do not log the subcommit in XLOG; it doesn't matter until the
1103 : * top-level transaction commits.
1104 : *
1105 : * We must mark the subtransaction subcommitted in the CLOG if it had a
1106 : * valid XID assigned. If it did not, nobody else will ever know about
1107 : * the existence of this subxact. We don't have to deal with deletions
1108 : * scheduled for on-commit here, since they'll be reassigned to our parent
1109 : * (who might still abort).
1110 : */
1111 34 : if (TransactionIdIsValid(xid))
1112 : {
1113 : /* XXX does this really need to be a critical section? */
1114 19 : START_CRIT_SECTION();
1115 :
1116 : /* Record subtransaction subcommit */
1117 19 : TransactionIdSubCommit(xid);
1118 :
1119 19 : END_CRIT_SECTION();
1120 : }
1121 34 : }
1122 :
1123 : /* ----------------------------------------------------------------
1124 : * AbortTransaction stuff
1125 : * ----------------------------------------------------------------
1126 : */
1127 :
1128 : /*
1129 : * RecordTransactionAbort
1130 : *
1131 : * Returns latest XID among xact and its children, or InvalidTransactionId
1132 : * if the xact has no XID. (We compute that here just because it's easier.)
1133 : */
1134 : static TransactionId
1135 : RecordTransactionAbort(bool isSubXact)
1136 1140 : {
1137 1140 : TransactionId xid = GetCurrentTransactionIdIfAny();
1138 : TransactionId latestXid;
1139 : int nrels;
1140 : RelFileNode *rels;
1141 : int nchildren;
1142 : TransactionId *children;
1143 : XLogRecData rdata[3];
1144 1140 : int lastrdata = 0;
1145 : xl_xact_abort xlrec;
1146 :
1147 : /*
1148 : * If we haven't been assigned an XID, nobody will care whether we aborted
1149 : * or not. Hence, we're done in that case. It does not matter if we have
1150 : * rels to delete (note that this routine is not responsible for actually
1151 : * deleting 'em). We cannot have any child XIDs, either.
1152 : */
1153 1140 : if (!TransactionIdIsValid(xid))
1154 : {
1155 : /* Reset XactLastRecEnd until the next transaction writes something */
1156 951 : if (!isSubXact)
1157 922 : XactLastRecEnd.xrecoff = 0;
1158 951 : return InvalidTransactionId;
1159 : }
1160 :
1161 : /*
1162 : * We have a valid XID, so we should write an ABORT record for it.
1163 : *
1164 : * We do not flush XLOG to disk here, since the default assumption after a
1165 : * crash would be that we aborted, anyway. For the same reason, we don't
1166 : * need to worry about interlocking against checkpoint start.
1167 : */
1168 :
1169 : /*
1170 : * Check that we haven't aborted halfway through RecordTransactionCommit.
1171 : */
1172 189 : if (TransactionIdDidCommit(xid))
1173 0 : elog(PANIC, "cannot abort transaction %u, it was already committed",
1174 : xid);
1175 :
1176 : /* Fetch the data we need for the abort record */
1177 189 : nrels = smgrGetPendingDeletes(false, &rels, NULL);
1178 189 : nchildren = xactGetCommittedChildren(&children);
1179 :
1180 : /* XXX do we really need a critical section here? */
1181 189 : START_CRIT_SECTION();
1182 :
1183 : /* Write the ABORT record */
1184 189 : if (isSubXact)
1185 21 : xlrec.xact_time = GetCurrentTimestamp();
1186 : else
1187 : {
1188 168 : SetCurrentTransactionStopTimestamp();
1189 168 : xlrec.xact_time = xactStopTimestamp;
1190 : }
1191 189 : xlrec.nrels = nrels;
1192 189 : xlrec.nsubxacts = nchildren;
1193 189 : rdata[0].data = (char *) (&xlrec);
1194 189 : rdata[0].len = MinSizeOfXactAbort;
1195 189 : rdata[0].buffer = InvalidBuffer;
1196 : /* dump rels to delete */
1197 189 : if (nrels > 0)
1198 : {
1199 38 : rdata[0].next = &(rdata[1]);
1200 38 : rdata[1].data = (char *) rels;
1201 38 : rdata[1].len = nrels * sizeof(RelFileNode);
1202 38 : rdata[1].buffer = InvalidBuffer;
1203 38 : lastrdata = 1;
1204 : }
1205 : /* dump committed child Xids */
1206 189 : if (nchildren > 0)
1207 : {
1208 5 : rdata[lastrdata].next = &(rdata[2]);
1209 5 : rdata[2].data = (char *) children;
1210 5 : rdata[2].len = nchildren * sizeof(TransactionId);
1211 5 : rdata[2].buffer = InvalidBuffer;
1212 5 : lastrdata = 2;
1213 : }
1214 189 : rdata[lastrdata].next = NULL;
1215 :
1216 189 : (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
1217 :
1218 : /*
1219 : * Mark the transaction aborted in clog. This is not absolutely necessary
1220 : * but we may as well do it while we are here; also, in the subxact case
1221 : * it is helpful because XactLockTableWait makes use of it to avoid
1222 : * waiting for already-aborted subtransactions. It is OK to do it without
1223 : * having flushed the ABORT record to disk, because in event of a crash
1224 : * we'd be assumed to have aborted anyway.
1225 : *
1226 : * The ordering here isn't critical but it seems best to mark the parent
1227 : * first. This assures an atomic transition of all the subtransactions to
1228 : * aborted state from the point of view of concurrent
1229 : * TransactionIdDidAbort calls.
1230 : */
1231 189 : TransactionIdAbort(xid);
1232 189 : TransactionIdAbortTree(nchildren, children);
1233 :
1234 189 : END_CRIT_SECTION();
1235 :
1236 : /* Compute latestXid while we have the child XIDs handy */
1237 189 : latestXid = TransactionIdLatest(xid, nchildren, children);
1238 :
1239 : /*
1240 : * If we're aborting a subtransaction, we can immediately remove failed
1241 : * XIDs from PGPROC's cache of running child XIDs. We do that here for
1242 : * subxacts, because we already have the child XID array at hand. For
1243 : * main xacts, the equivalent happens just after this function returns.
1244 : */
1245 189 : if (isSubXact)
1246 21 : XidCacheRemoveRunningXids(xid, nchildren, children, latestXid);
1247 :
1248 : /* Reset XactLastRecEnd until the next transaction writes something */
1249 189 : if (!isSubXact)
1250 168 : XactLastRecEnd.xrecoff = 0;
1251 :
1252 : /* And clean up local data */
1253 189 : if (rels)
1254 38 : pfree(rels);
1255 189 : if (children)
1256 5 : pfree(children);
1257 :
1258 189 : return latestXid;
1259 : }
1260 :
1261 : /*
1262 : * AtAbort_Memory
1263 : */
1264 : static void
1265 : AtAbort_Memory(void)
1266 1090 : {
1267 : /*
1268 : * Switch into TransactionAbortContext, which should have some free space
1269 : * even if nothing else does. We'll work in this context until we've
1270 : * finished cleaning up.
1271 : *
1272 : * It is barely possible to get here when we've not been able to create
1273 : * TransactionAbortContext yet; if so use TopMemoryContext.
1274 : */
1275 1090 : if (TransactionAbortContext != NULL)
1276 1090 : MemoryContextSwitchTo(TransactionAbortContext);
1277 : else
1278 0 : MemoryContextSwitchTo(TopMemoryContext);
1279 1090 : }
1280 :
1281 : /*
1282 : * AtSubAbort_Memory
1283 : */
1284 : static void
1285 : AtSubAbort_Memory(void)
1286 50 : {
1287 : Assert(TransactionAbortContext != NULL);
1288 :
1289 50 : MemoryContextSwitchTo(TransactionAbortContext);
1290 50 : }
1291 :
1292 :
1293 : /*
1294 : * AtAbort_ResourceOwner
1295 : */
1296 : static void
1297 : AtAbort_ResourceOwner(void)
1298 1090 : {
1299 : /*
1300 : * Make sure we have a valid ResourceOwner, if possible (else it will be
1301 : * NULL, which is OK)
1302 : */
1303 1090 : CurrentResourceOwner = TopTransactionResourceOwner;
1304 1090 : }
1305 :
1306 : /*
1307 : * AtSubAbort_ResourceOwner
1308 : */
1309 : static void
1310 : AtSubAbort_ResourceOwner(void)
1311 50 : {
1312 50 : TransactionState s = CurrentTransactionState;
1313 :
1314 : /* Make sure we have a valid ResourceOwner */
1315 50 : CurrentResourceOwner = s->curTransactionOwner;
1316 50 : }
1317 :
1318 :
1319 : /*
1320 : * AtSubAbort_childXids
1321 : */
1322 : static void
1323 : AtSubAbort_childXids(void)
1324 21 : {
1325 21 : TransactionState s = CurrentTransactionState;
1326 :
1327 : /*
1328 : * We keep the child-XID lists in TopTransactionContext (see
1329 : * AtSubCommit_childXids). This means we'd better free the list
1330 : * explicitly at abort to avoid leakage.
1331 : */
1332 21 : list_free(s->childXids);
1333 21 : s->childXids = NIL;
1334 21 : }
1335 :
1336 : /* ----------------------------------------------------------------
1337 : * CleanupTransaction stuff
1338 : * ----------------------------------------------------------------
1339 : */
1340 :
1341 : /*
1342 : * AtCleanup_Memory
1343 : */
1344 : static void
1345 : AtCleanup_Memory(void)
1346 1090 : {
1347 : Assert(CurrentTransactionState->parent == NULL);
1348 :
1349 : /*
1350 : * Now that we're "out" of a transaction, have the system allocate things
1351 : * in the top memory context instead of per-transaction contexts.
1352 : */
1353 1090 : MemoryContextSwitchTo(TopMemoryContext);
1354 :
1355 : /*
1356 : * Clear the special abort context for next time.
1357 : */
1358 1090 : if (TransactionAbortContext != NULL)
1359 1090 : MemoryContextResetAndDeleteChildren(TransactionAbortContext);
1360 :
1361 : /*
1362 : * Release all transaction-local memory.
1363 : */
1364 1090 : if (TopTransactionContext != NULL)
1365 1090 : MemoryContextDelete(TopTransactionContext);
1366 1090 : TopTransactionContext = NULL;
1367 1090 : CurTransactionContext = NULL;
1368 1090 : CurrentTransactionState->curTransactionContext = NULL;
1369 1090 : }
1370 :
1371 :
1372 : /* ----------------------------------------------------------------
1373 : * CleanupSubTransaction stuff
1374 : * ----------------------------------------------------------------
1375 : */
1376 :
1377 : /*
1378 : * AtSubCleanup_Memory
1379 : */
1380 : static void
1381 : AtSubCleanup_Memory(void)
1382 50 : {
1383 50 : TransactionState s = CurrentTransactionState;
1384 :
1385 : Assert(s->parent != NULL);
1386 :
1387 : /* Make sure we're not in an about-to-be-deleted context */
1388 50 : MemoryContextSwitchTo(s->parent->curTransactionContext);
1389 50 : CurTransactionContext = s->parent->curTransactionContext;
1390 :
1391 : /*
1392 : * Clear the special abort context for next time.
1393 : */
1394 50 : if (TransactionAbortContext != NULL)
1395 50 : MemoryContextResetAndDeleteChildren(TransactionAbortContext);
1396 :
1397 : /*
1398 : * Delete the subxact local memory contexts. Its CurTransactionContext can
1399 : * go too (note this also kills CurTransactionContexts from any children
1400 : * of the subxact).
1401 : */
1402 50 : if (s->curTransactionContext)
1403 50 : MemoryContextDelete(s->curTransactionContext);
1404 50 : s->curTransactionContext = NULL;
1405 50 : }
1406 :
1407 : /* ----------------------------------------------------------------
1408 : * interface routines
1409 : * ----------------------------------------------------------------
1410 : */
1411 :
1412 : /*
1413 : * StartTransaction
1414 : */
1415 : static void
1416 : StartTransaction(void)
1417 13673 : {
1418 : TransactionState s;
1419 : VirtualTransactionId vxid;
1420 :
1421 : /*
1422 : * Let's just make sure the state stack is empty
1423 : */
1424 13673 : s = &TopTransactionStateData;
1425 13673 : CurrentTransactionState = s;
1426 :
1427 : /*
1428 : * check the current transaction state
1429 : */
1430 13673 : if (s->state != TRANS_DEFAULT)
1431 0 : elog(WARNING, "StartTransaction while in %s state",
1432 : TransStateAsString(s->state));
1433 :
1434 : /*
1435 : * set the current transaction state information appropriately during
1436 : * start processing
1437 : */
1438 13673 : s->state = TRANS_START;
1439 13673 : s->transactionId = InvalidTransactionId; /* until assigned */
1440 :
1441 : /*
1442 : * Make sure we've freed any old snapshot, and reset xact state variables
1443 : */
1444 13673 : FreeXactSnapshot();
1445 13673 : XactIsoLevel = DefaultXactIsoLevel;
1446 13673 : XactReadOnly = DefaultXactReadOnly;
1447 13673 : forceSyncCommit = false;
1448 :
1449 : /*
1450 : * reinitialize within-transaction counters
1451 : */
1452 13673 : s->subTransactionId = TopSubTransactionId;
1453 13673 : currentSubTransactionId = TopSubTransactionId;
1454 13673 : currentCommandId = FirstCommandId;
1455 13673 : currentCommandIdUsed = false;
1456 :
1457 : /*
1458 : * must initialize resource-management stuff first
1459 : */
1460 13673 : AtStart_Memory();
1461 13673 : AtStart_ResourceOwner();
1462 :
1463 : /*
1464 : * Assign a new LocalTransactionId, and combine it with the backendId to
1465 : * form a virtual transaction id.
1466 : */
1467 13673 : vxid.backendId = MyBackendId;
1468 13673 : vxid.localTransactionId = GetNextLocalTransactionId();
1469 :
1470 : /*
1471 : * Lock the virtual transaction id before we announce it in the proc array
1472 : */
1473 13673 : VirtualXactLockTableInsert(vxid);
1474 :
1475 : /*
1476 : * Advertise it in the proc array. We assume assignment of
1477 : * LocalTransactionID is atomic, and the backendId should be set already.
1478 : */
1479 : Assert(MyProc->backendId == vxid.backendId);
1480 13673 : MyProc->lxid = vxid.localTransactionId;
1481 :
1482 : PG_TRACE1(transaction__start, vxid.localTransactionId);
1483 :
1484 : /*
1485 : * set transaction_timestamp() (a/k/a now()). We want this to be the same
1486 : * as the first command's statement_timestamp(), so don't do a fresh
1487 : * GetCurrentTimestamp() call (which'd be expensive anyway). Also, mark
1488 : * xactStopTimestamp as unset.
1489 : */
1490 13673 : xactStartTimestamp = stmtStartTimestamp;
1491 13673 : xactStopTimestamp = 0;
1492 13673 : pgstat_report_xact_timestamp(xactStartTimestamp);
1493 :
1494 : /*
1495 : * initialize current transaction state fields
1496 : *
1497 : * note: prevXactReadOnly is not used at the outermost level
1498 : */
1499 13673 : s->nestingLevel = 1;
1500 13673 : s->gucNestLevel = 1;
1501 13673 : s->childXids = NIL;
1502 13673 : GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt);
1503 : /* SecurityDefinerContext should never be set outside a transaction */
1504 : Assert(!s->prevSecDefCxt);
1505 :
1506 : /*
1507 : * initialize other subsystems for new transaction
1508 : */
1509 13673 : AtStart_GUC();
1510 13673 : AtStart_Inval();
1511 13673 : AtStart_Cache();
1512 13673 : AfterTriggerBeginXact();
1513 :
1514 : /*
1515 : * done with start processing, set current transaction state to "in
1516 : * progress"
1517 : */
1518 13673 : s->state = TRANS_INPROGRESS;
1519 :
1520 13673 : ShowTransactionState("StartTransaction");
1521 13673 : }
1522 :
1523 :
1524 : /*
1525 : * CommitTransaction
1526 : *
1527 : * NB: if you change this routine, better look at PrepareTransaction too!
1528 : */
1529 : static void
1530 : CommitTransaction(void)
1531 12585 : {
1532 12585 : TransactionState s = CurrentTransactionState;
1533 : TransactionId latestXid;
1534 :
1535 12585 : ShowTransactionState("CommitTransaction");
1536 :
1537 : /*
1538 : * check the current transaction state
1539 : */
1540 12585 : if (s->state != TRANS_INPROGRESS)
1541 0 : elog(WARNING, "CommitTransaction while in %s state",
1542 : TransStateAsString(s->state));
1543 : Assert(s->parent == NULL);
1544 :
1545 : /*
1546 : * Do pre-commit processing (most of this stuff requires database access,
1547 : * and in fact could still cause an error...)
1548 : *
1549 : * It is possible for CommitHoldablePortals to invoke functions that queue
1550 : * deferred triggers, and it's also possible that triggers create holdable
1551 : * cursors. So we have to loop until there's nothing left to do.
1552 : */
1553 : for (;;)
1554 : {
1555 : /*
1556 : * Fire all currently pending deferred triggers.
1557 : */
1558 12589 : AfterTriggerFireDeferred();
1559 :
1560 : /*
1561 : * Convert any open holdable cursors into static portals. If there
1562 : * weren't any, we are done ... otherwise loop back to check if they
1563 : * queued deferred triggers. Lather, rinse, repeat.
1564 : */
1565 12583 : if (!CommitHoldablePortals())
1566 12579 : break;
1567 : }
1568 :
1569 : /* Now we can shut down the deferred-trigger manager */
1570 12579 : AfterTriggerEndXact(true);
1571 :
1572 : /* Close any open regular cursors */
1573 12579 : AtCommit_Portals();
1574 :
1575 : /*
1576 : * Let ON COMMIT management do its thing (must happen after closing
1577 : * cursors, to avoid dangling-reference problems)
1578 : */
1579 12579 : PreCommit_on_commit_actions();
1580 :
1581 : /* close large objects before lower-level cleanup */
1582 12578 : AtEOXact_LargeObject(true);
1583 :
1584 : /* NOTIFY commit must come before lower-level cleanup */
1585 12578 : AtCommit_Notify();
1586 :
1587 : /*
1588 : * Update flat files if we changed pg_database, pg_authid or
1589 : * pg_auth_members. This should be the last step before commit.
1590 : */
1591 12578 : AtEOXact_UpdateFlatFiles(true);
1592 :
1593 : /* Prevent cancel/die interrupt while cleaning up */
1594 12578 : HOLD_INTERRUPTS();
1595 :
1596 : /*
1597 : * set the current transaction state information appropriately during
1598 : * commit processing
1599 : */
1600 12578 : s->state = TRANS_COMMIT;
1601 :
1602 : /*
1603 : * Here is where we really truly commit.
1604 : */
1605 12578 : latestXid = RecordTransactionCommit();
1606 :
1607 : PG_TRACE1(transaction__commit, MyProc->lxid);
1608 :
1609 : /*
1610 : * Let others know about no transaction in progress by me. Note that this
1611 : * must be done _before_ releasing locks we hold and _after_
1612 : * RecordTransactionCommit.
1613 : */
1614 12578 : ProcArrayEndTransaction(MyProc, latestXid);
1615 :
1616 : /*
1617 : * This is all post-commit cleanup. Note that if an error is raised here,
1618 : * it's too late to abort the transaction. This should be just
1619 : * noncritical resource releasing.
1620 : *
1621 : * The ordering of operations is not entirely random. The idea is:
1622 : * release resources visible to other backends (eg, files, buffer pins);
1623 : * then release locks; then release backend-local resources. We want to
1624 : * release locks at the point where any backend waiting for us will see
1625 : * our transaction as being fully cleaned up.
1626 : *
1627 : * Resources that can be associated with individual queries are handled by
1628 : * the ResourceOwner mechanism. The other calls here are for backend-wide
1629 : * state.
1630 : */
1631 :
1632 12578 : CallXactCallbacks(XACT_EVENT_COMMIT);
1633 :
1634 12578 : ResourceOwnerRelease(TopTransactionResourceOwner,
1635 : RESOURCE_RELEASE_BEFORE_LOCKS,
1636 : true, true);
1637 :
1638 : /* Check we've released all buffer pins */
1639 12578 : AtEOXact_Buffers(true);
1640 :
1641 : /* Clean up the relation cache */
1642 12578 : AtEOXact_RelationCache(true);
1643 :
1644 : /*
1645 : * Make catalog changes visible to all backends. This has to happen after
1646 : * relcache references are dropped (see comments for
1647 : * AtEOXact_RelationCache), but before locks are released (if anyone is
1648 : * waiting for lock on a relation we've modified, we want them to know
1649 : * about the catalog change before they start using the relation).
1650 : */
1651 12578 : AtEOXact_Inval(true);
1652 :
1653 : /*
1654 : * Likewise, dropping of files deleted during the transaction is best done
1655 : * after releasing relcache and buffer pins. (This is not strictly
1656 : * necessary during commit, since such pins should have been released
1657 : * already, but this ordering is definitely critical during abort.)
1658 : */
1659 12578 : smgrDoPendingDeletes(true);
1660 :
1661 12578 : AtEOXact_MultiXact();
1662 :
1663 12578 : ResourceOwnerRelease(TopTransactionResourceOwner,
1664 : RESOURCE_RELEASE_LOCKS,
1665 : true, true);
1666 12578 : ResourceOwnerRelease(TopTransactionResourceOwner,
1667 : RESOURCE_RELEASE_AFTER_LOCKS,
1668 : true, true);
1669 :
1670 : /* Check we've released all catcache entries */
1671 12578 : AtEOXact_CatCache(true);
1672 :
1673 12578 : AtEOXact_GUC(true, 1);
1674 12578 : AtEOXact_SPI(true);
1675 12578 : AtEOXact_xml();
1676 12578 : AtEOXact_on_commit_actions(true);
1677 12578 : AtEOXact_Namespace(true);
1678 : /* smgrcommit already done */
1679 12578 : AtEOXact_Files();
1680 12578 : AtEOXact_ComboCid();
1681 12578 : AtEOXact_HashTables(true);
1682 12578 : AtEOXact_PgStat(true);
1683 12578 : pgstat_report_xact_timestamp(0);
1684 :
1685 12578 : CurrentResourceOwner = NULL;
1686 12578 : ResourceOwnerDelete(TopTransactionResourceOwner);
1687 12578 : s->curTransactionOwner = NULL;
1688 12578 : CurTransactionResourceOwner = NULL;
1689 12578 : TopTransactionResourceOwner = NULL;
1690 :
1691 12578 : AtCommit_Memory();
1692 :
1693 12578 : s->transactionId = InvalidTransactionId;
1694 12578 : s->subTransactionId = InvalidSubTransactionId;
1695 12578 : s->nestingLevel = 0;
1696 12578 : s->gucNestLevel = 0;
1697 12578 : s->childXids = NIL;
1698 :
1699 : /*
1700 : * done with commit processing, set current transaction state back to
1701 : * default
1702 : */
1703 12578 : s->state = TRANS_DEFAULT;
1704 :
1705 12578 : RESUME_INTERRUPTS();
1706 12578 : }
1707 :
1708 :
1709 : /*
1710 : * PrepareTransaction
1711 : *
1712 : * NB: if you change this routine, better look at CommitTransaction too!
1713 : */
1714 : static void
1715 : PrepareTransaction(void)
1716 6 : {
1717 6 : TransactionState s = CurrentTransactionState;
1718 6 : TransactionId xid = GetCurrentTransactionId();
1719 : GlobalTransaction gxact;
1720 : TimestampTz prepared_at;
1721 :
1722 6 : ShowTransactionState("PrepareTransaction");
1723 :
1724 : /*
1725 : * check the current transaction state
1726 : */
1727 6 : if (s->state != TRANS_INPROGRESS)
1728 0 : elog(WARNING, "PrepareTransaction while in %s state",
1729 : TransStateAsString(s->state));
1730 : Assert(s->parent == NULL);
1731 :
1732 : /*
1733 : * Do pre-commit processing (most of this stuff requires database access,
1734 : * and in fact could still cause an error...)
1735 : *
1736 : * It is possible for PrepareHoldablePortals to invoke functions that
1737 : * queue deferred triggers, and it's also possible that triggers create
1738 : * holdable cursors. So we have to loop until there's nothing left to do.
1739 : */
1740 : for (;;)
1741 : {
1742 : /*
1743 : * Fire all currently pending deferred triggers.
1744 : */
1745 6 : AfterTriggerFireDeferred();
1746 :
1747 : /*
1748 : * Convert any open holdable cursors into static portals. If there
1749 : * weren't any, we are done ... otherwise loop back to check if they
1750 : * queued deferred triggers. Lather, rinse, repeat.
1751 : */
1752 6 : if (!PrepareHoldablePortals())
1753 6 : break;
1754 : }
1755 :
1756 : /* Now we can shut down the deferred-trigger manager */
1757 6 : AfterTriggerEndXact(true);
1758 :
1759 : /* Close any open regular cursors */
1760 6 : AtCommit_Portals();
1761 :
1762 : /*
1763 : * Let ON COMMIT management do its thing (must happen after closing
1764 : * cursors, to avoid dangling-reference problems)
1765 : */
1766 6 : PreCommit_on_commit_actions();
1767 :
1768 : /* close large objects before lower-level cleanup */
1769 6 : AtEOXact_LargeObject(true);
1770 :
1771 : /* NOTIFY and flatfiles will be handled below */
1772 :
1773 : /* Prevent cancel/die interrupt while cleaning up */
1774 6 : HOLD_INTERRUPTS();
1775 :
1776 : /*
1777 : * set the current transaction state information appropriately during
1778 : * prepare processing
1779 : */
1780 6 : s->state = TRANS_PREPARE;
1781 :
1782 6 : prepared_at = GetCurrentTimestamp();
1783 :
1784 : /* Tell bufmgr and smgr to prepare for commit */
1785 6 : BufmgrCommit();
1786 :
1787 : /*
1788 : * Reserve the GID for this transaction. This could fail if the requested
1789 : * GID is invalid or already in use.
1790 : */
1791 6 : gxact = MarkAsPreparing(xid, prepareGID, prepared_at,
1792 : GetUserId(), MyDatabaseId);
1793 5 : prepareGID = NULL;
1794 :
1795 : /*
1796 : * Collect data for the 2PC state file. Note that in general, no actual
1797 : * state change should happen in the called modules during this step,
1798 : * since it's still possible to fail before commit, and in that case we
1799 : * want transaction abort to be able to clean up. (In particular, the
1800 : * AtPrepare routines may error out if they find cases they cannot
1801 : * handle.) State cleanup should happen in the PostPrepare routines
1802 : * below. However, some modules can go ahead and clear state here because
1803 : * they wouldn't do anything with it during abort anyway.
1804 : *
1805 : * Note: because the 2PC state file records will be replayed in the same
1806 : * order they are made, the order of these calls has to match the order in
1807 : * which we want things to happen during COMMIT PREPARED or ROLLBACK
1808 : * PREPARED; in particular, pay attention to whether things should happen
1809 : * before or after releasing the transaction's locks.
1810 : */
1811 5 : StartPrepare(gxact);
1812 :
1813 5 : AtPrepare_Notify();
1814 5 : AtPrepare_UpdateFlatFiles();
1815 5 : AtPrepare_Inval();
1816 5 : AtPrepare_Locks();
1817 5 : AtPrepare_PgStat();
1818 :
1819 : /*
1820 : * Here is where we really truly prepare.
1821 : *
1822 : * We have to record transaction prepares even if we didn't make any
1823 : * updates, because the transaction manager might get confused if we lose
1824 : * a global transaction.
1825 : */
1826 5 : EndPrepare(gxact);
1827 :
1828 : /*
1829 : * Now we clean up backend-internal state and release internal resources.
1830 : */
1831 :
1832 : /* Reset XactLastRecEnd until the next transaction writes something */
1833 5 : XactLastRecEnd.xrecoff = 0;
1834 :
1835 : /*
1836 : * Let others know about no transaction in progress by me. This has to be
1837 : * done *after* the prepared transaction has been marked valid, else
1838 : * someone may think it is unlocked and recyclable.
1839 : */
1840 5 : ProcArrayClearTransaction(MyProc);
1841 :
1842 : /*
1843 : * This is all post-transaction cleanup. Note that if an error is raised
1844 : * here, it's too late to abort the transaction. This should be just
1845 : * noncritical resource releasing. See notes in CommitTransaction.
1846 : */
1847 :
1848 5 : CallXactCallbacks(XACT_EVENT_PREPARE);
1849 :
1850 5 : ResourceOwnerRelease(TopTransactionResourceOwner,
1851 : RESOURCE_RELEASE_BEFORE_LOCKS,
1852 : true, true);
1853 :
1854 : /* Check we've released all buffer pins */
1855 5 : AtEOXact_Buffers(true);
1856 :
1857 : /* Clean up the relation cache */
1858 5 : AtEOXact_RelationCache(true);
1859 :
1860 : /* notify and flatfiles don't need a postprepare call */
1861 :
1862 5 : PostPrepare_PgStat();
1863 :
1864 5 : PostPrepare_Inval();
1865 :
1866 5 : PostPrepare_smgr();
1867 :
1868 5 : AtEOXact_MultiXact();
1869 :
1870 5 : PostPrepare_Locks(xid);
1871 :
1872 5 : ResourceOwnerRelease(TopTransactionResourceOwner,
1873 : RESOURCE_RELEASE_LOCKS,
1874 : true, true);
1875 5 : ResourceOwnerRelease(TopTransactionResourceOwner,
1876 : RESOURCE_RELEASE_AFTER_LOCKS,
1877 : true, true);
1878 :
1879 : /* Check we've released all catcache entries */
1880 5 : AtEOXact_CatCache(true);
1881 :
1882 : /* PREPARE acts the same as COMMIT as far as GUC is concerned */
1883 5 : AtEOXact_GUC(true, 1);
1884 5 : AtEOXact_SPI(true);
1885 5 : AtEOXact_xml();
1886 5 : AtEOXact_on_commit_actions(true);
1887 5 : AtEOXact_Namespace(true);
1888 : /* smgrcommit already done */
1889 5 : AtEOXact_Files();
1890 5 : AtEOXact_ComboCid();
1891 5 : AtEOXact_HashTables(true);
1892 : /* don't call AtEOXact_PgStat here */
1893 :
1894 5 : CurrentResourceOwner = NULL;
1895 5 : ResourceOwnerDelete(TopTransactionResourceOwner);
1896 5 : s->curTransactionOwner = NULL;
1897 5 : CurTransactionResourceOwner = NULL;
1898 5 : TopTransactionResourceOwner = NULL;
1899 :
1900 5 : AtCommit_Memory();
1901 :
1902 5 : s->transactionId = InvalidTransactionId;
1903 5 : s->subTransactionId = InvalidSubTransactionId;
1904 5 : s->nestingLevel = 0;
1905 5 : s->gucNestLevel = 0;
1906 5 : s->childXids = NIL;
1907 :
1908 : /*
1909 : * done with 1st phase commit processing, set current transaction state
1910 : * back to default
1911 : */
1912 5 : s->state = TRANS_DEFAULT;
1913 :
1914 5 : RESUME_INTERRUPTS();
1915 5 : }
1916 :
1917 :
1918 : /*
1919 : * AbortTransaction
1920 : */
1921 : static void
1922 : AbortTransaction(void)
1923 1090 : {
1924 1090 : TransactionState s = CurrentTransactionState;
1925 : TransactionId latestXid;
1926 :
1927 : /* Prevent cancel/die interrupt while cleaning up */
1928 1090 : HOLD_INTERRUPTS();
1929 :
1930 : /* Make sure we have a valid memory context and resource owner */
1931 1090 : AtAbort_Memory();
1932 1090 : AtAbort_ResourceOwner();
1933 :
1934 : /*
1935 : * Release any LW locks we might be holding as quickly as possible.
1936 : * (Regular locks, however, must be held till we finish aborting.)
1937 : * Releasing LW locks is critical since we might try to grab them again
1938 : * while cleaning up!
1939 : */
1940 1090 : LWLockReleaseAll();
1941 :
1942 : /* Clean up buffer I/O and buffer context locks, too */
1943 1090 : AbortBufferIO();
1944 1090 : UnlockBuffers();
1945 :
1946 : /*
1947 : * Also clean up any open wait for lock, since the lock manager will choke
1948 : * if we try to wait for another lock before doing this.
1949 : */
1950 1090 : LockWaitCancel();
1951 :
1952 : /*
1953 : * check the current transaction state
1954 : */
1955 1090 : if (s->state != TRANS_INPROGRESS && s->state != TRANS_PREPARE)
1956 0 : elog(WARNING, "AbortTransaction while in %s state",
1957 : TransStateAsString(s->state));
1958 : Assert(s->parent == NULL);
1959 :
1960 : /*
1961 : * set the current transaction state information appropriately during the
1962 : * abort processing
1963 : */
1964 1090 : s->state = TRANS_ABORT;
1965 :
1966 : /*
1967 : * Reset user ID which might have been changed transiently. We need this
1968 : * to clean up in case control escaped out of a SECURITY DEFINER function
1969 : * or other local change of CurrentUserId; therefore, the prior value
1970 : * of SecurityDefinerContext also needs to be restored.
1971 : *
1972 : * (Note: it is not necessary to restore session authorization or role
1973 : * settings here because those can only be changed via GUC, and GUC will
1974 : * take care of rolling them back if need be.)
1975 : */
1976 1090 : SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
1977 :
1978 : /*
1979 : * do abort processing
1980 : */
1981 1090 : AfterTriggerEndXact(false);
1982 1090 : AtAbort_Portals();
1983 1090 : AtEOXact_LargeObject(false); /* 'false' means it's abort */
1984 1090 : AtAbort_Notify();
1985 1090 : AtEOXact_UpdateFlatFiles(false);
1986 :
1987 : /*
1988 : * Advertise the fact that we aborted in pg_clog (assuming that we got as
1989 : * far as assigning an XID to advertise).
1990 : */
1991 1090 : latestXid = RecordTransactionAbort(false);
1992 :
1993 : PG_TRACE1(transaction__abort, MyProc->lxid);
1994 :
1995 : /*
1996 : * Let others know about no transaction in progress by me. Note that this
1997 : * must be done _before_ releasing locks we hold and _after_
1998 : * RecordTransactionAbort.
1999 : */
2000 1090 : ProcArrayEndTransaction(MyProc, latestXid);
2001 :
2002 : /*
2003 : * Post-abort cleanup. See notes in CommitTransaction() concerning
2004 : * ordering.
2005 : */
2006 :
2007 1090 : CallXactCallbacks(XACT_EVENT_ABORT);
2008 :
2009 1090 : ResourceOwnerRelease(TopTransactionResourceOwner,
2010 : RESOURCE_RELEASE_BEFORE_LOCKS,
2011 : false, true);
2012 1090 : AtEOXact_Buffers(false);
2013 1090 : AtEOXact_RelationCache(false);
2014 1090 : AtEOXact_Inval(false);
2015 1090 : smgrDoPendingDeletes(false);
2016 1090 : AtEOXact_MultiXact();
2017 1090 : ResourceOwnerRelease(TopTransactionResourceOwner,
2018 : RESOURCE_RELEASE_LOCKS,
2019 : false, true);
2020 1090 : ResourceOwnerRelease(TopTransactionResourceOwner,
2021 : RESOURCE_RELEASE_AFTER_LOCKS,
2022 : false, true);
2023 1090 : AtEOXact_CatCache(false);
2024 :
2025 1090 : AtEOXact_GUC(false, 1);
2026 1090 : AtEOXact_SPI(false);
2027 1090 : AtEOXact_xml();
2028 1090 : AtEOXact_on_commit_actions(false);
2029 1090 : AtEOXact_Namespace(false);
2030 1090 : smgrabort();
2031 1090 : AtEOXact_Files();
2032 1090 : AtEOXact_ComboCid();
2033 1090 : AtEOXact_HashTables(false);
2034 1090 : AtEOXact_PgStat(false);
2035 1090 : pgstat_report_xact_timestamp(0);
2036 :
2037 : /*
2038 : * State remains TRANS_ABORT until CleanupTransaction().
2039 : */
2040 1090 : RESUME_INTERRUPTS();
2041 1090 : }
2042 :
2043 : /*
2044 : * CleanupTransaction
2045 : */
2046 : static void
2047 : CleanupTransaction(void)
2048 1090 : {
2049 1090 : TransactionState s = CurrentTransactionState;
2050 :
2051 : /*
2052 : * State should still be TRANS_ABORT from AbortTransaction().
2053 : */
2054 1090 : if (s->state != TRANS_ABORT)
2055 0 : elog(FATAL, "CleanupTransaction: unexpected state %s",
2056 : TransStateAsString(s->state));
2057 :
2058 : /*
2059 : * do abort cleanup processing
2060 : */
2061 1090 : AtCleanup_Portals(); /* now safe to release portal memory */
2062 :
2063 1090 : CurrentResourceOwner = NULL; /* and resource owner */
2064 1090 : if (TopTransactionResourceOwner)
2065 1090 : ResourceOwnerDelete(TopTransactionResourceOwner);
2066 1090 : s->curTransactionOwner = NULL;
2067 1090 : CurTransactionResourceOwner = NULL;
2068 1090 : TopTransactionResourceOwner = NULL;
2069 :
2070 1090 : AtCleanup_Memory(); /* and transaction memory */
2071 :
2072 1090 : s->transactionId = InvalidTransactionId;
2073 1090 : s->subTransactionId = InvalidSubTransactionId;
2074 1090 : s->nestingLevel = 0;
2075 1090 : s->gucNestLevel = 0;
2076 1090 : s->childXids = NIL;
2077 :
2078 : /*
2079 : * done with abort processing, set current transaction state back to
2080 : * default
2081 : */
2082 1090 : s->state = TRANS_DEFAULT;
2083 1090 : }
2084 :
2085 : /*
2086 : * StartTransactionCommand
2087 : */
2088 : void
2089 : StartTransactionCommand(void)
2090 15013 : {
2091 15013 : TransactionState s = CurrentTransactionState;
2092 :
2093 15013 : switch (s->blockState)
2094 : {
2095 : /*
2096 : * if we aren't in a transaction block, we just do our usual start
2097 : * transaction.
2098 : */
2099 : case TBLOCK_DEFAULT:
2100 13673 : StartTransaction();
2101 13673 : s->blockState = TBLOCK_STARTED;
2102 13673 : break;
2103 :
2104 : /*
2105 : * We are somewhere in a transaction block or subtransaction and
2106 : * about to start a new command. For now we do nothing, but
2107 : * someday we may do command-local resource initialization. (Note
2108 : * that any needed CommandCounterIncrement was done by the
2109 : * previous CommitTransactionCommand.)
2110 : */
2111 : case TBLOCK_INPROGRESS:
2112 : case TBLOCK_SUBINPROGRESS:
2113 : break;
2114 :
2115 : /*
2116 : * Here we are in a failed transaction block (one of the commands
2117 : * caused an abort) so we do nothing but remain in the abort
2118 : * state. Eventually we will get a ROLLBACK command which will
2119 : * get us out of this state. (It is up to other code to ensure
2120 : * that no commands other than ROLLBACK will be processed in these
2121 : * states.)
2122 : */
2123 : case TBLOCK_ABORT:
2124 : case TBLOCK_SUBABORT:
2125 : break;
2126 :
2127 : /* These cases are invalid. */
2128 : case TBLOCK_STARTED:
2129 : case TBLOCK_BEGIN:
2130 : case TBLOCK_SUBBEGIN:
2131 : case TBLOCK_END:
2132 : case TBLOCK_SUBEND:
2133 : case TBLOCK_ABORT_END:
2134 : case TBLOCK_SUBABORT_END:
2135 : case TBLOCK_ABORT_PENDING:
2136 : case TBLOCK_SUBABORT_PENDING:
2137 : case TBLOCK_SUBRESTART:
2138 : case TBLOCK_SUBABORT_RESTART:
2139 : case TBLOCK_PREPARE:
2140 0 : elog(ERROR, "StartTransactionCommand: unexpected state %s",
2141 : BlockStateAsString(s->blockState));
2142 : break;
2143 : }
2144 :
2145 : /*
2146 : * We must switch to CurTransactionContext before returning. This is
2147 : * already done if we called StartTransaction, otherwise not.
2148 : */
2149 : Assert(CurTransactionContext != NULL);
2150 15013 : MemoryContextSwitchTo(CurTransactionContext);
2151 15013 : }
2152 :
2153 : /*
2154 : * CommitTransactionCommand
2155 : */
2156 : void
2157 : CommitTransactionCommand(void)
2158 13952 : {
2159 13952 : TransactionState s = CurrentTransactionState;
2160 :
2161 13952 : switch (s->blockState)
2162 : {
2163 : /*
2164 : * This shouldn't happen, because it means the previous
2165 : * StartTransactionCommand didn't set the STARTED state
2166 : * appropriately.
2167 : */
2168 : case TBLOCK_DEFAULT:
2169 0 : elog(FATAL, "CommitTransactionCommand: unexpected state %s",
2170 : BlockStateAsString(s->blockState));
2171 0 : break;
2172 :
2173 : /*
2174 : * If we aren't in a transaction block, just do our usual
2175 : * transaction commit, and return to the idle state.
2176 : */
2177 : case TBLOCK_STARTED:
2178 12528 : CommitTransaction();
2179 12528 : s->blockState = TBLOCK_DEFAULT;
2180 12528 : break;
2181 :
2182 : /*
2183 : * We are completing a "BEGIN TRANSACTION" command, so we change
2184 : * to the "transaction block in progress" state and return. (We
2185 : * assume the BEGIN did nothing to the database, so we need no
2186 : * CommandCounterIncrement.)
2187 : */
2188 : case TBLOCK_BEGIN:
2189 99 : s->blockState = TBLOCK_INPROGRESS;
2190 99 : break;
2191 :
2192 : /*
2193 : * This is the case when we have finished executing a command
2194 : * someplace within a transaction block. We increment the command
2195 : * counter and return.
2196 : */
2197 : case TBLOCK_INPROGRESS:
2198 : case TBLOCK_SUBINPROGRESS:
2199 1116 : CommandCounterIncrement();
2200 1116 : break;
2201 :
2202 : /*
2203 : * We are completing a "COMMIT" command. Do it and return to the
2204 : * idle state.
2205 : */
2206 : case TBLOCK_END:
2207 47 : CommitTransaction();
2208 43 : s->blockState = TBLOCK_DEFAULT;
2209 43 : break;
2210 :
2211 : /*
2212 : * Here we are in the middle of a transaction block but one of the
2213 : * commands caused an abort so we do nothing but remain in the
2214 : * abort state. Eventually we will get a ROLLBACK comand.
2215 : */
2216 : case TBLOCK_ABORT:
2217 : case TBLOCK_SUBABORT:
2218 : break;
2219 :
2220 : /*
2221 : * Here we were in an aborted transaction block and we just got
2222 : * the ROLLBACK command from the user, so clean up the
2223 : * already-aborted transaction and return to the idle state.
2224 : */
2225 : case TBLOCK_ABORT_END:
2226 15 : CleanupTransaction();
2227 15 : s->blockState = TBLOCK_DEFAULT;
2228 15 : break;
2229 :
2230 : /*
2231 : * Here we were in a perfectly good transaction block but the user
2232 : * told us to ROLLBACK anyway. We have to abort the transaction
2233 : * and then clean up.
2234 : */
2235 : case TBLOCK_ABORT_PENDING:
2236 22 : AbortTransaction();
2237 22 : CleanupTransaction();
2238 22 : s->blockState = TBLOCK_DEFAULT;
2239 22 : break;
2240 :
2241 : /*
2242 : * We are completing a "PREPARE TRANSACTION" command. Do it and
2243 : * return to the idle state.
2244 : */
2245 : case TBLOCK_PREPARE:
2246 5 : PrepareTransaction();
2247 4 : s->blockState = TBLOCK_DEFAULT;
2248 4 : break;
2249 :
2250 : /*
2251 : * We were just issued a SAVEPOINT inside a transaction block.
2252 : * Start a subtransaction. (DefineSavepoint already did
2253 : * PushTransaction, so as to have someplace to put the SUBBEGIN
2254 : * state.)
2255 : */
2256 : case TBLOCK_SUBBEGIN:
2257 59 : StartSubTransaction();
2258 59 : s->blockState = TBLOCK_SUBINPROGRESS;
2259 59 : break;
2260 :
2261 : /*
2262 : * We were issued a COMMIT or RELEASE command, so we end the
2263 : * current subtransaction and return to the parent transaction.
2264 : * The parent might be ended too, so repeat till we are all the
2265 : * way out or find an INPROGRESS transaction.
2266 : */
2267 : case TBLOCK_SUBEND:
2268 : do
2269 : {
2270 30 : CommitSubTransaction();
2271 30 : s = CurrentTransactionState; /* changed by pop */
2272 30 : } while (s->blockState == TBLOCK_SUBEND);
2273 : /* If we had a COMMIT command, finish off the main xact too */
2274 24 : if (s->blockState == TBLOCK_END)
2275 : {
2276 : Assert(s->parent == NULL);
2277 10 : CommitTransaction();
2278 7 : s->blockState = TBLOCK_DEFAULT;
2279 : }
2280 14 : else if (s->blockState == TBLOCK_PREPARE)
2281 : {
2282 : Assert(s->parent == NULL);
2283 1 : PrepareTransaction();
2284 1 : s->blockState = TBLOCK_DEFAULT;
2285 : }
2286 : else
2287 : {
2288 : Assert(s->blockState == TBLOCK_INPROGRESS ||
2289 : s->blockState == TBLOCK_SUBINPROGRESS);
2290 : }
2291 : break;
2292 :
2293 : /*
2294 : * The current already-failed subtransaction is ending due to a
2295 : * ROLLBACK or ROLLBACK TO command, so pop it and recursively
2296 : * examine the parent (which could be in any of several states).
2297 : */
2298 : case TBLOCK_SUBABORT_END:
2299 3 : CleanupSubTransaction();
2300 3 : CommitTransactionCommand();
2301 3 : break;
2302 :
2303 : /*
2304 : * As above, but it's not dead yet, so abort first.
2305 : */
2306 : case TBLOCK_SUBABORT_PENDING:
2307 9 : AbortSubTransaction();
2308 9 : CleanupSubTransaction();
2309 9 : CommitTransactionCommand();
2310 9 : break;
2311 :
2312 : /*
2313 : * The current subtransaction is the target of a ROLLBACK TO
2314 : * command. Abort and pop it, then start a new subtransaction
2315 : * with the same name.
2316 : */
2317 : case TBLOCK_SUBRESTART:
2318 : {
2319 : char *name;
2320 : int savepointLevel;
2321 :
2322 : /* save name and keep Cleanup from freeing it */
2323 18 : name = s->name;
2324 18 : s->name = NULL;
2325 18 : savepointLevel = s->savepointLevel;
2326 :
2327 18 : AbortSubTransaction();
2328 18 : CleanupSubTransaction();
2329 :
2330 18 : DefineSavepoint(NULL);
2331 18 : s = CurrentTransactionState; /* changed by push */
2332 18 : s->name = name;
2333 18 : s->savepointLevel = savepointLevel;
2334 :
2335 : /* This is the same as TBLOCK_SUBBEGIN case */
2336 : AssertState(s->blockState == TBLOCK_SUBBEGIN);
2337 18 : StartSubTransaction();
2338 18 : s->blockState = TBLOCK_SUBINPROGRESS;
2339 : }
2340 18 : break;
2341 :
2342 : /*
2343 : * Same as above, but the subtransaction had already failed, so we
2344 : * don't need AbortSubTransaction.
2345 : */
2346 : case TBLOCK_SUBABORT_RESTART:
2347 : {
2348 : char *name;
2349 : int savepointLevel;
2350 :
2351 : /* save name and keep Cleanup from freeing it */
2352 7 : name = s->name;
2353 7 : s->name = NULL;
2354 7 : savepointLevel = s->savepointLevel;
2355 :
2356 7 : CleanupSubTransaction();
2357 :
2358 7 : DefineSavepoint(NULL);
2359 7 : s = CurrentTransactionState; /* changed by push */
2360 7 : s->name = name;
2361 7 : s->savepointLevel = savepointLevel;
2362 :
2363 : /* This is the same as TBLOCK_SUBBEGIN case */
2364 : AssertState(s->blockState == TBLOCK_SUBBEGIN);
2365 7 : StartSubTransaction();
2366 7 : s->blockState = TBLOCK_SUBINPROGRESS;
2367 : }
2368 : break;
2369 : }
2370 13944 : }
2371 :
2372 : /*
2373 : * AbortCurrentTransaction
2374 : */
2375 : void
2376 : AbortCurrentTransaction(void)
2377 1081 : {
2378 1081 : TransactionState s = CurrentTransactionState;
2379 :
2380 1081 : switch (s->blockState)
2381 : {
2382 : case TBLOCK_DEFAULT:
2383 0 : if (s->state == TRANS_DEFAULT)
2384 : {
2385 : /* we are idle, so nothing to do */
2386 : }
2387 : else
2388 : {
2389 : /*
2390 : * We can get here after an error during transaction start
2391 : * (state will be TRANS_START). Need to clean up the
2392 : * incompletely started transaction. First, adjust the
2393 : * low-level state to suppress warning message from
2394 : * AbortTransaction.
2395 : */
2396 0 : if (s->state == TRANS_START)
2397 0 : s->state = TRANS_INPROGRESS;
2398 0 : AbortTransaction();
2399 0 : CleanupTransaction();
2400 : }
2401 : break;
2402 :
2403 : /*
2404 : * if we aren't in a transaction block, we just do the basic abort
2405 : * & cleanup transaction.
2406 : */
2407 : case TBLOCK_STARTED:
2408 1045 : AbortTransaction();
2409 1045 : CleanupTransaction();
2410 1045 : s->blockState = TBLOCK_DEFAULT;
2411 1045 : break;
2412 :
2413 : /*
2414 : * If we are in TBLOCK_BEGIN it means something screwed up right
2415 : * after reading "BEGIN TRANSACTION". We assume that the user
2416 : * will interpret the error as meaning the BEGIN failed to get him
2417 : * into a transaction block, so we should abort and return to idle
2418 : * state.
2419 : */
2420 : case TBLOCK_BEGIN:
2421 0 : AbortTransaction();
2422 0 : CleanupTransaction();
2423 0 : s->blockState = TBLOCK_DEFAULT;
2424 0 : break;
2425 :
2426 : /*
2427 : * We are somewhere in a transaction block and we've gotten a
2428 : * failure, so we abort the transaction and set up the persistent
2429 : * ABORT state. We will stay in ABORT until we get a ROLLBACK.
2430 : */
2431 : case TBLOCK_INPROGRESS:
2432 15 : AbortTransaction();
2433 15 : s->blockState = TBLOCK_ABORT;
2434 : /* CleanupTransaction happens when we exit TBLOCK_ABORT_END */
2435 15 : break;
2436 :
2437 : /*
2438 : * Here, we failed while trying to COMMIT. Clean up the
2439 : * transaction and return to idle state (we do not want to stay in
2440 : * the transaction).
2441 : */
2442 : case TBLOCK_END:
2443 7 : AbortTransaction();
2444 7 : CleanupTransaction();
2445 7 : s->blockState = TBLOCK_DEFAULT;
2446 7 : break;
2447 :
2448 : /*
2449 : * Here, we are already in an aborted transaction state and are
2450 : * waiting for a ROLLBACK, but for some reason we failed again! So
2451 : * we just remain in the abort state.
2452 : */
2453 : case TBLOCK_ABORT:
2454 : case TBLOCK_SUBABORT:
2455 : break;
2456 :
2457 : /*
2458 : * We are in a failed transaction and we got the ROLLBACK command.
2459 : * We have already aborted, we just need to cleanup and go to idle
2460 : * state.
2461 : */
2462 : case TBLOCK_ABORT_END:
2463 0 : CleanupTransaction();
2464 0 : s->blockState = TBLOCK_DEFAULT;
2465 0 : break;
2466 :
2467 : /*
2468 : * We are in a live transaction and we got a ROLLBACK command.
2469 : * Abort, cleanup, go to idle state.
2470 : */
2471 : case TBLOCK_ABORT_PENDING:
2472 0 : AbortTransaction();
2473 0 : CleanupTransaction();
2474 0 : s->blockState = TBLOCK_DEFAULT;
2475 0 : break;
2476 :
2477 : /*
2478 : * Here, we failed while trying to PREPARE. Clean up the
2479 : * transaction and return to idle state (we do not want to stay in
2480 : * the transaction).
2481 : */
2482 : case TBLOCK_PREPARE:
2483 1 : AbortTransaction();
2484 1 : CleanupTransaction();
2485 1 : s->blockState = TBLOCK_DEFAULT;
2486 1 : break;
2487 :
2488 : /*
2489 : * We got an error inside a subtransaction. Abort just the
2490 : * subtransaction, and go to the persistent SUBABORT state until
2491 : * we get ROLLBACK.
2492 : */
2493 : case TBLOCK_SUBINPROGRESS:
2494 10 : AbortSubTransaction();
2495 10 : s->blockState = TBLOCK_SUBABORT;
2496 10 : break;
2497 :
2498 : /*
2499 : * If we failed while trying to create a subtransaction, clean up
2500 : * the broken subtransaction and abort the parent. The same
2501 : * applies if we get a failure while ending a subtransaction.
2502 : */
2503 : case TBLOCK_SUBBEGIN:
2504 : case TBLOCK_SUBEND:
2505 : case TBLOCK_SUBABORT_PENDING:
2506 : case TBLOCK_SUBRESTART:
2507 0 : AbortSubTransaction();
2508 0 : CleanupSubTransaction();
2509 0 : AbortCurrentTransaction();
2510 0 : break;
2511 :
2512 : /*
2513 : * Same as above, except the Abort() was already done.
2514 : */
2515 : case TBLOCK_SUBABORT_END:
2516 : case TBLOCK_SUBABORT_RESTART:
2517 0 : CleanupSubTransaction();
2518 0 : AbortCurrentTransaction();
2519 : break;
2520 : }
2521 1081 : }
2522 :
2523 : /*
2524 : * PreventTransactionChain
2525 : *
2526 : * This routine is to be called by statements that must not run inside
2527 : * a transaction block, typically because they have non-rollback-able
2528 : * side effects or do internal commits.
2529 : *
2530 : * If we have already started a transaction block, issue an error; also issue
2531 : * an error if we appear to be running inside a user-defined function (which
2532 : * could issue more commands and possibly cause a failure after the statement
2533 : * completes). Subtransactions are verboten too.
2534 : *
2535 : * isTopLevel: passed down from ProcessUtility to determine whether we are
2536 : * inside a function or multi-query querystring. (We will always fail if
2537 : * this is false, but it's convenient to centralize the check here instead of
2538 : * making callers do it.)
2539 : * stmtType: statement type name, for error messages.
2540 : */
2541 : void
2542 : PreventTransactionChain(bool isTopLevel, const char *stmtType)
2543 41 : {
2544 : /*
2545 : * xact block already started?
2546 : */
2547 41 : if (IsTransactionBlock())
2548 1 : ereport(ERROR,
2549 : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2550 : /* translator: %s represents an SQL statement name */
2551 : errmsg("%s cannot run inside a transaction block",
2552 : stmtType)));
2553 :
2554 : /*
2555 : * subtransaction?
2556 : */
2557 40 : if (IsSubTransaction())
2558 0 : ereport(ERROR,
2559 : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2560 : /* translator: %s represents an SQL statement name */
2561 : errmsg("%s cannot run inside a subtransaction",
2562 : stmtType)));
2563 :
2564 : /*
2565 : * inside a function call?
2566 : */
2567 40 : if (!isTopLevel)
2568 0 : ereport(ERROR,
2569 : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2570 : /* translator: %s represents an SQL statement name */
2571 : errmsg("%s cannot be executed from a function or multi-command string",
2572 : stmtType)));
2573 :
2574 : /* If we got past IsTransactionBlock test, should be in default state */
2575 40 : if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2576 : CurrentTransactionState->blockState != TBLOCK_STARTED)
2577 0 : elog(FATAL, "cannot prevent transaction chain");
2578 : /* all okay */
2579 40 : }
2580 :
2581 : /*
2582 : * RequireTransactionChain
2583 : *
2584 : * This routine is to be called by statements that must run inside
2585 : * a transaction block, because they have no effects that persist past
2586 : * transaction end (and so calling them outside a transaction block
2587 : * is presumably an error). DECLARE CURSOR is an example.
2588 : *
2589 : * If we appear to be running inside a user-defined function, we do not
2590 : * issue an error, since the function could issue more commands that make
2591 : * use of the current statement's results. Likewise subtransactions.
2592 : * Thus this is an inverse for PreventTransactionChain.
2593 : *
2594 : * isTopLevel: passed down from ProcessUtility to determine whether we are
2595 : * inside a function.
2596 : * stmtType: statement type name, for error messages.
2597 : */
2598 : void
2599 : RequireTransactionChain(bool isTopLevel, const char *stmtType)
2600 140 : {
2601 : /*
2602 : * xact block already started?
2603 : */
2604 140 : if (IsTransactionBlock())
2605 137 : return;
2606 :
2607 : /*
2608 : * subtransaction?
2609 : */
2610 3 : if (IsSubTransaction())
2611 0 : return;
2612 :
2613 : /*
2614 : * inside a function call?
2615 : */
2616 3 : if (!isTopLevel)
2617 0 : return;
2618 :
2619 3 : ereport(ERROR,
2620 : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2621 : /* translator: %s represents an SQL statement name */
2622 : errmsg("%s can only be used in transaction blocks",
2623 : stmtType)));
2624 : }
2625 :
2626 : /*
2627 : * IsInTransactionChain
2628 : *
2629 : * This routine is for statements that need to behave differently inside
2630 : * a transaction block than when running as single commands. ANALYZE is
2631 : * currently the only example.
2632 : *
2633 : * isTopLevel: passed down from ProcessUtility to determine whether we are
2634 : * inside a function.
2635 : */
2636 : bool
2637 : IsInTransactionChain(bool isTopLevel)
2638 7 : {
2639 : /*
2640 : * Return true on same conditions that would make PreventTransactionChain
2641 : * error out
2642 : */
2643 7 : if (IsTransactionBlock())
2644 0 : return true;
2645 :
2646 7 : if (IsSubTransaction())
2647 0 : return true;
2648 :
2649 7 : if (!isTopLevel)
2650 0 : return true;
2651 :
2652 7 : if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
2653 : CurrentTransactionState->blockState != TBLOCK_STARTED)
2654 0 : return true;
2655 :
2656 7 : return false;
2657 : }
2658 :
2659 :
2660 : /*
2661 : * Register or deregister callback functions for start- and end-of-xact
2662 : * operations.
2663 : *
2664 : * These functions are intended for use by dynamically loaded modules.
2665 : * For built-in modules we generally just hardwire the appropriate calls
2666 : * (mainly because it's easier to control the order that way, where needed).
2667 : *
2668 : * At transaction end, the callback occurs post-commit or post-abort, so the
2669 : * callback functions can only do noncritical cleanup.
2670 : */
2671 : void
2672 : RegisterXactCallback(XactCallback callback, void *arg)
2673 12 : {
2674 : XactCallbackItem *item;
2675 :
2676 12 : item = (XactCallbackItem *)
2677 : MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
2678 12 : item->callback = callback;
2679 12 : item->arg = arg;
2680 12 : item->next = Xact_callbacks;
2681 12 : Xact_callbacks = item;
2682 12 : }
2683 :
2684 : void
2685 : UnregisterXactCallback(XactCallback callback, void *arg)
2686 0 : {
2687 : XactCallbackItem *item;
2688 : XactCallbackItem *prev;
2689 :
2690 0 : prev = NULL;
2691 0 : for (item = Xact_callbacks; item; prev = item, item = item->next)
2692 : {
2693 0 : if (item->callback == callback && item->arg == arg)
2694 : {
2695 0 : if (prev)
2696 0 : prev->next = item->next;
2697 : else
2698 0 : Xact_callbacks = item->next;
2699 0 : pfree(item);
2700 0 : break;
2701 : }
2702 : }
2703 0 : }
2704 :
2705 : static void
2706 : CallXactCallbacks(XactEvent event)
2707 13673 : {
2708 : XactCallbackItem *item;
2709 :
2710 14494 : for (item = Xact_callbacks; item; item = item->next)
2711 821 : (*item->callback) (event, item->arg);
2712 13673 : }
2713 :
2714 :
2715 : /*
2716 : * Register or deregister callback functions for start- and end-of-subxact
2717 : * operations.
2718 : *
2719 : * Pretty much same as above, but for subtransaction events.
2720 : *
2721 : * At subtransaction end, the callback occurs post-subcommit or post-subabort,
2722 : * so the callback functions can only do noncritical cleanup. At
2723 : * subtransaction start, the callback is called when the subtransaction has
2724 : * finished initializing.
2725 : */
2726 : void
2727 : RegisterSubXactCallback(SubXactCallback callback, void *arg)
2728 12 : {
2729 : SubXactCallbackItem *item;
2730 :
2731 12 : item = (SubXactCallbackItem *)
2732 : MemoryContextAlloc(TopMemoryContext, sizeof(SubXactCallbackItem));
2733 12 : item->callback = callback;
2734 12 : item->arg = arg;
2735 12 : item->next = SubXact_callbacks;
2736 12 : SubXact_callbacks = item;
2737 12 : }
2738 :
2739 : void
2740 : UnregisterSubXactCallback(SubXactCallback callback, void *arg)
2741 0 : {
2742 : SubXactCallbackItem *item;
2743 : SubXactCallbackItem *prev;
2744 :
2745 0 : prev = NULL;
2746 0 : for (item = SubXact_callbacks; item; prev = item, item = item->next)
2747 : {
2748 0 : if (item->callback == callback && item->arg == arg)
2749 : {
2750 0 : if (prev)
2751 0 : prev->next = item->next;
2752 : else
2753 0 : SubXact_callbacks = item->next;
2754 0 : pfree(item);
2755 0 : break;
2756 : }
2757 : }
2758 0 : }
2759 :
2760 : static void
2761 : CallSubXactCallbacks(SubXactEvent event,
2762 : SubTransactionId mySubid,
2763 : SubTransactionId parentSubid)
2764 168 : {
2765 : SubXactCallbackItem *item;
2766 :
2767 218 : for (item = SubXact_callbacks; item; item = item->next)
2768 50 : (*item->callback) (event, mySubid, parentSubid, item->arg);
2769 168 : }
2770 :
2771 :
2772 : /* ----------------------------------------------------------------
2773 : * transaction block support
2774 : * ----------------------------------------------------------------
2775 : */
2776 :
2777 : /*
2778 : * BeginTransactionBlock
2779 : * This executes a BEGIN command.
2780 : */
2781 : void
2782 : BeginTransactionBlock(void)
2783 99 : {
2784 99 : TransactionState s = CurrentTransactionState;
2785 :
2786 99 : switch (s->blockState)
2787 : {
2788 : /*
2789 : * We are not inside a transaction block, so allow one to begin.
2790 : */
2791 : case TBLOCK_STARTED:
2792 99 : s->blockState = TBLOCK_BEGIN;
2793 99 : break;
2794 :
2795 : /*
2796 : * Already a transaction block in progress.
2797 : */
2798 : case TBLOCK_INPROGRESS:
2799 : case TBLOCK_SUBINPROGRESS:
2800 : case TBLOCK_ABORT:
2801 : case TBLOCK_SUBABORT:
2802 0 : ereport(WARNING,
2803 : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
2804 : errmsg("there is already a transaction in progress")));
2805 : break;
2806 :
2807 : /* These cases are invalid. */
2808 : case TBLOCK_DEFAULT:
2809 : case TBLOCK_BEGIN:
2810 : case TBLOCK_SUBBEGIN:
2811 : case TBLOCK_END:
2812 : case TBLOCK_SUBEND:
2813 : case TBLOCK_ABORT_END:
2814 : case TBLOCK_SUBABORT_END:
2815 : case TBLOCK_ABORT_PENDING:
2816 : case TBLOCK_SUBABORT_PENDING:
2817 : case TBLOCK_SUBRESTART:
2818 : case TBLOCK_SUBABORT_RESTART:
2819 : case TBLOCK_PREPARE:
2820 0 : elog(FATAL, "BeginTransactionBlock: unexpected state %s",
2821 : BlockStateAsString(s->blockState));
2822 : break;
2823 : }
2824 99 : }
2825 :
2826 : /*
2827 : * PrepareTransactionBlock
2828 : * This executes a PREPARE command.
2829 : *
2830 : * Since PREPARE may actually do a ROLLBACK, the result indicates what
2831 : * happened: TRUE for PREPARE, FALSE for ROLLBACK.
2832 : *
2833 : * Note that we don't actually do anything here except change blockState.
2834 : * The real work will be done in the upcoming PrepareTransaction().
2835 : * We do it this way because it's not convenient to change memory context,
2836 : * resource owner, etc while executing inside a Portal.
2837 : */
2838 : bool
2839 : PrepareTransactionBlock(char *gid)
2840 6 : {
2841 : TransactionState s;
2842 : bool result;
2843 :
2844 : /* Set up to commit the current transaction */
2845 6 : result = EndTransactionBlock();
2846 :
2847 : /* If successful, change outer tblock state to PREPARE */
2848 6 : if (result)
2849 : {
2850 6 : s = CurrentTransactionState;
2851 :
2852 14 : while (s->parent != NULL)
2853 2 : s = s->parent;
2854 :
2855 6 : if (s->blockState == TBLOCK_END)
2856 : {
2857 : /* Save GID where PrepareTransaction can find it again */
2858 6 : prepareGID = MemoryContextStrdup(TopTransactionContext, gid);
2859 :
2860 6 : s->blockState = TBLOCK_PREPARE;
2861 : }
2862 : else
2863 : {
2864 : /*
2865 : * ignore case where we are not in a transaction;
2866 : * EndTransactionBlock already issued a warning.
2867 : */
2868 : Assert(s->blockState == TBLOCK_STARTED);
2869 : /* Don't send back a PREPARE result tag... */
2870 0 : result = false;
2871 : }
2872 : }
2873 :
2874 6 : return result;
2875 : }
2876 :
2877 : /*
2878 : * EndTransactionBlock
2879 : * This executes a COMMIT command.
2880 : *
2881 : * Since COMMIT may actually do a ROLLBACK, the result indicates what
2882 : * happened: TRUE for COMMIT, FALSE for ROLLBACK.
2883 : *
2884 : * Note that we don't actually do anything here except change blockState.
2885 : * The real work will be done in the upcoming CommitTransactionCommand().
2886 : * We do it this way because it's not convenient to change memory context,
2887 : * resource owner, etc while executing inside a Portal.
2888 : */
2889 : bool
2890 : EndTransactionBlock(void)
2891 73 : {
2892 73 : TransactionState s = CurrentTransactionState;
2893 73 : bool result = false;
2894 :
2895 73 : switch (s->blockState)
2896 : {
2897 : /*
2898 : * We are in a transaction block, so tell CommitTransactionCommand
2899 : * to COMMIT.
2900 : */
2901 : case TBLOCK_INPROGRESS:
2902 52 : s->blockState = TBLOCK_END;
2903 52 : result = true;
2904 52 : break;
2905 :
2906 : /*
2907 : * We are in a failed transaction block. Tell
2908 : * CommitTransactionCommand it's time to exit the block.
2909 : */
2910 : case TBLOCK_ABORT:
2911 5 : s->blockState = TBLOCK_ABORT_END;
2912 5 : break;
2913 :
2914 : /*
2915 : * We are in a live subtransaction block. Set up to subcommit all
2916 : * open subtransactions and then commit the main transaction.
2917 : */
2918 : case TBLOCK_SUBINPROGRESS:
2919 28 : while (s->parent != NULL)
2920 : {
2921 17 : if (s->blockState == TBLOCK_SUBINPROGRESS)
2922 17 : s->blockState = TBLOCK_SUBEND;
2923 : else
2924 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
2925 : BlockStateAsString(s->blockState));
2926 17 : s = s->parent;
2927 : }
2928 11 : if (s->blockState == TBLOCK_INPROGRESS)
2929 11 : s->blockState = TBLOCK_END;
2930 : else
2931 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
2932 : BlockStateAsString(s->blockState));
2933 11 : result = true;
2934 11 : break;
2935 :
2936 : /*
2937 : * Here we are inside an aborted subtransaction. Treat the COMMIT
2938 : * as ROLLBACK: set up to abort everything and exit the main
2939 : * transaction.
2940 : */
2941 : case TBLOCK_SUBABORT:
2942 4 : while (s->parent != NULL)
2943 : {
2944 2 : if (s->blockState == TBLOCK_SUBINPROGRESS)
2945 0 : s->blockState = TBLOCK_SUBABORT_PENDING;
2946 2 : else if (s->blockState == TBLOCK_SUBABORT)
2947 2 : s->blockState = TBLOCK_SUBABORT_END;
2948 : else
2949 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
2950 : BlockStateAsString(s->blockState));
2951 2 : s = s->parent;
2952 : }
2953 2 : if (s->blockState == TBLOCK_INPROGRESS)
2954 2 : s->blockState = TBLOCK_ABORT_PENDING;
2955 0 : else if (s->blockState == TBLOCK_ABORT)
2956 0 : s->blockState = TBLOCK_ABORT_END;
2957 : else
2958 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
2959 : BlockStateAsString(s->blockState));
2960 : break;
2961 :
2962 : /*
2963 : * The user issued COMMIT when not inside a transaction. Issue a
2964 : * WARNING, staying in TBLOCK_STARTED state. The upcoming call to
2965 : * CommitTransactionCommand() will then close the transaction and
2966 : * put us back into the default state.
2967 : */
2968 : case TBLOCK_STARTED:
2969 3 : ereport(WARNING,
2970 : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
2971 : errmsg("there is no transaction in progress")));
2972 3 : result = true;
2973 3 : break;
2974 :
2975 : /* These cases are invalid. */
2976 : case TBLOCK_DEFAULT:
2977 : case TBLOCK_BEGIN:
2978 : case TBLOCK_SUBBEGIN:
2979 : case TBLOCK_END:
2980 : case TBLOCK_SUBEND:
2981 : case TBLOCK_ABORT_END:
2982 : case TBLOCK_SUBABORT_END:
2983 : case TBLOCK_ABORT_PENDING:
2984 : case TBLOCK_SUBABORT_PENDING:
2985 : case TBLOCK_SUBRESTART:
2986 : case TBLOCK_SUBABORT_RESTART:
2987 : case TBLOCK_PREPARE:
2988 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
2989 : BlockStateAsString(s->blockState));
2990 : break;
2991 : }
2992 :
2993 73 : return result;
2994 : }
2995 :
2996 : /*
2997 : * UserAbortTransactionBlock
2998 : * This executes a ROLLBACK command.
2999 : *
3000 : * As above, we don't actually do anything here except change blockState.
3001 : */
3002 : void
3003 : UserAbortTransactionBlock(void)
3004 30 : {
3005 30 : TransactionState s = CurrentTransactionState;
3006 :
3007 30 : switch (s->blockState)
3008 : {
3009 : /*
3010 : * We are inside a transaction block and we got a ROLLBACK command
3011 : * from the user, so tell CommitTransactionCommand to abort and
3012 : * exit the transaction block.
3013 : */
3014 : case TBLOCK_INPROGRESS:
3015 14 : s->blockState = TBLOCK_ABORT_PENDING;
3016 14 : break;
3017 :
3018 : /*
3019 : * We are inside a failed transaction block and we got a ROLLBACK
3020 : * command from the user. Abort processing is already done, so
3021 : * CommitTransactionCommand just has to cleanup and go back to
3022 : * idle state.
3023 : */
3024 : case TBLOCK_ABORT:
3025 10 : s->blockState = TBLOCK_ABORT_END;
3026 10 : break;
3027 :
3028 : /*
3029 : * We are inside a subtransaction. Mark everything up to top
3030 : * level as exitable.
3031 : */
3032 : case TBLOCK_SUBINPROGRESS:
3033 : case TBLOCK_SUBABORT:
3034 12 : while (s->parent != NULL)
3035 : {
3036 7 : if (s->blockState == TBLOCK_SUBINPROGRESS)
3037 6 : s->blockState = TBLOCK_SUBABORT_PENDING;
3038 1 : else if (s->blockState == TBLOCK_SUBABORT)
3039 1 : s->blockState = TBLOCK_SUBABORT_END;
3040 : else
3041 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
3042 : BlockStateAsString(s->blockState));
3043 7 : s = s->parent;
3044 : }
3045 5 : if (s->blockState == TBLOCK_INPROGRESS)
3046 5 : s->blockState = TBLOCK_ABORT_PENDING;
3047 0 : else if (s->blockState == TBLOCK_ABORT)
3048 0 : s->blockState = TBLOCK_ABORT_END;
3049 : else
3050 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
3051 : BlockStateAsString(s->blockState));
3052 : break;
3053 :
3054 : /*
3055 : * The user issued ABORT when not inside a transaction. Issue a
3056 : * WARNING and go to abort state. The upcoming call to
3057 : * CommitTransactionCommand() will then put us back into the
3058 : * default state.
3059 : */
3060 : case TBLOCK_STARTED:
3061 1 : ereport(NOTICE,
3062 : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
3063 : errmsg("there is no transaction in progress")));
3064 1 : s->blockState = TBLOCK_ABORT_PENDING;
3065 1 : break;
3066 :
3067 : /* These cases are invalid. */
3068 : case TBLOCK_DEFAULT:
3069 : case TBLOCK_BEGIN:
3070 : case TBLOCK_SUBBEGIN:
3071 : case TBLOCK_END:
3072 : case TBLOCK_SUBEND:
3073 : case TBLOCK_ABORT_END:
3074 : case TBLOCK_SUBABORT_END:
3075 : case TBLOCK_ABORT_PENDING:
3076 : case TBLOCK_SUBABORT_PENDING:
3077 : case TBLOCK_SUBRESTART:
3078 : case TBLOCK_SUBABORT_RESTART:
3079 : case TBLOCK_PREPARE:
3080 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
3081 : BlockStateAsString(s->blockState));
3082 : break;
3083 : }
3084 30 : }
3085 :
3086 : /*
3087 : * DefineSavepoint
3088 : * This executes a SAVEPOINT command.
3089 : */
3090 : void
3091 : DefineSavepoint(char *name)
3092 67 : {
3093 67 : TransactionState s = CurrentTransactionState;
3094 :
3095 67 : switch (s->blockState)
3096 : {
3097 : case TBLOCK_INPROGRESS:
3098 : case TBLOCK_SUBINPROGRESS:
3099 : /* Normal subtransaction start */
3100 67 : PushTransaction();
3101 67 : s = CurrentTransactionState; /* changed by push */
3102 :
3103 : /*
3104 : * Savepoint names, like the TransactionState block itself, live
3105 : * in TopTransactionContext.
3106 : */
3107 67 : if (name)
3108 42 : s->name = MemoryContextStrdup(TopTransactionContext, name);
3109 : break;
3110 :
3111 : /* These cases are invalid. */
3112 : case TBLOCK_DEFAULT:
3113 : case TBLOCK_STARTED:
3114 : case TBLOCK_BEGIN:
3115 : case TBLOCK_SUBBEGIN:
3116 : case TBLOCK_END:
3117 : case TBLOCK_SUBEND:
3118 : case TBLOCK_ABORT:
3119 : case TBLOCK_SUBABORT:
3120 : case TBLOCK_ABORT_END:
3121 : case TBLOCK_SUBABORT_END:
3122 : case TBLOCK_ABORT_PENDING:
3123 : case TBLOCK_SUBABORT_PENDING:
3124 : case TBLOCK_SUBRESTART:
3125 : case TBLOCK_SUBABORT_RESTART:
3126 : case TBLOCK_PREPARE:
3127 0 : elog(FATAL, "DefineSavepoint: unexpected state %s",
3128 : BlockStateAsString(s->blockState));
3129 : break;
3130 : }
3131 67 : }
3132 :
3133 : /*
3134 : * ReleaseSavepoint
3135 : * This executes a RELEASE command.
3136 : *
3137 : * As above, we don't actually do anything here except change blockState.
3138 : */
3139 : void
3140 : ReleaseSavepoint(List *options)
3141 13 : {
3142 13 : TransactionState s = CurrentTransactionState;
3143 : TransactionState target,
3144 : xact;
3145 : ListCell *cell;
3146 13 : char *name = NULL;
3147 :
3148 13 : switch (s->blockState)
3149 : {
3150 : /*
3151 : * We can't rollback to a savepoint if there is no savepoint
3152 : * defined.
3153 : */
3154 : case TBLOCK_INPROGRESS:
3155 0 : ereport(ERROR,
3156 : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
3157 : errmsg("no such savepoint")));
3158 : break;
3159 :
3160 : /*
3161 : * We are in a non-aborted subtransaction. This is the only valid
3162 : * case.
3163 : */
3164 : case TBLOCK_SUBINPROGRESS:
3165 : break;
3166 :
3167 : /* These cases are invalid. */
3168 : case TBLOCK_DEFAULT:
3169 : case TBLOCK_STARTED:
3170 : case TBLOCK_BEGIN:
3171 : case TBLOCK_SUBBEGIN:
3172 : case TBLOCK_END:
3173 : case TBLOCK_SUBEND:
3174 : case TBLOCK_ABORT:
3175 : case TBLOCK_SUBABORT:
3176 : case TBLOCK_ABORT_END:
3177 : case TBLOCK_SUBABORT_END:
3178 : case TBLOCK_ABORT_PENDING:
3179 : case TBLOCK_SUBABORT_PENDING:
3180 : case TBLOCK_SUBRESTART:
3181 : case TBLOCK_SUBABORT_RESTART:
3182 : case TBLOCK_PREPARE:
3183 0 : elog(FATAL, "ReleaseSavepoint: unexpected state %s",
3184 : BlockStateAsString(s->blockState));
3185 : break;
3186 : }
3187 :
3188 26 : foreach(cell, options)
3189 : {
3190 13 : DefElem *elem = lfirst(cell);
3191 :
3192 13 : if (strcmp(elem->defname, "savepoint_name") == 0)
3193 13 : name = strVal(elem->arg);
3194 : }
3195 :
3196 : Assert(PointerIsValid(name));
3197 :
3198 13 : for (target = s; PointerIsValid(target); target = target->parent)
3199 : {
3200 13 : if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
3201 13 : break;
3202 : }
3203 :
3204 13 : if (!PointerIsValid(target))
3205 0 : ereport(ERROR,
3206 : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
3207 : errmsg("no such savepoint")));
3208 :
3209 : /* disallow crossing savepoint level boundaries */
3210 13 : if (target->savepointLevel != s->savepointLevel)
3211 0 : ereport(ERROR,
3212 : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
3213 : errmsg("no such savepoint")));
3214 :
3215 : /*
3216 : * Mark "commit pending" all subtransactions up to the target
3217 : * subtransaction. The actual commits will happen when control gets to
3218 : * CommitTransactionCommand.
3219 : */
3220 13 : xact = CurrentTransactionState;
3221 : for (;;)
3222 : {
3223 : Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
3224 13 : xact->blockState = TBLOCK_SUBEND;
3225 13 : if (xact == target)
3226 13 : break;
3227 0 : xact = xact->parent;
3228 : Assert(PointerIsValid(xact));
3229 0 : }
3230 13 : }
3231 :
3232 : /*
3233 : * RollbackToSavepoint
3234 : * This executes a ROLLBACK TO <savepoint> command.
3235 : *
3236 : * As above, we don't actually do anything here except change blockState.
3237 : */
3238 : void
3239 : RollbackToSavepoint(List *options)
3240 25 : {
3241 25 : TransactionState s = CurrentTransactionState;
3242 : TransactionState target,
3243 : xact;
3244 : ListCell *cell;
3245 25 : char *name = NULL;
3246 :
3247 25 : switch (s->blockState)
3248 : {
3249 : /*
3250 : * We can't rollback to a savepoint if there is no savepoint
3251 : * defined.
3252 : */
3253 : case TBLOCK_INPROGRESS:
3254 : case TBLOCK_ABORT:
3255 0 : ereport(ERROR,
3256 : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
3257 : errmsg("no such savepoint")));
3258 : break;
3259 :
3260 : /*
3261 : * There is at least one savepoint, so proceed.
3262 : */
3263 : case TBLOCK_SUBINPROGRESS:
3264 : case TBLOCK_SUBABORT:
3265 : break;
3266 :
3267 : /* These cases are invalid. */
3268 : case TBLOCK_DEFAULT:
3269 : case TBLOCK_STARTED:
3270 : case TBLOCK_BEGIN:
3271 : case TBLOCK_SUBBEGIN:
3272 : case TBLOCK_END:
3273 : case TBLOCK_SUBEND:
3274 : case TBLOCK_ABORT_END:
3275 : case TBLOCK_SUBABORT_END:
3276 : case TBLOCK_ABORT_PENDING:
3277 : case TBLOCK_SUBABORT_PENDING:
3278 : case TBLOCK_SUBRESTART:
3279 : case TBLOCK_SUBABORT_RESTART:
3280 : case TBLOCK_PREPARE:
3281 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
3282 : BlockStateAsString(s->blockState));
3283 : break;
3284 : }
3285 :
3286 50 : foreach(cell, options)
3287 : {
3288 25 : DefElem *elem = lfirst(cell);
3289 :
3290 25 : if (strcmp(elem->defname, "savepoint_name") == 0)
3291 25 : name = strVal(elem->arg);
3292 : }
3293 :
3294 : Assert(PointerIsValid(name));
3295 :
3296 28 : for (target = s; PointerIsValid(target); target = target->parent)
3297 : {
3298 28 : if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
3299 25 : break;
3300 : }
3301 :
3302 25 : if (!PointerIsValid(target))
3303 0 : ereport(ERROR,
3304 : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
3305 : errmsg("no such savepoint")));
3306 :
3307 : /* disallow crossing savepoint level boundaries */
3308 25 : if (target->savepointLevel != s->savepointLevel)
3309 0 : ereport(ERROR,
3310 : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
3311 : errmsg("no such savepoint")));
3312 :
3313 : /*
3314 : * Mark "abort pending" all subtransactions up to the target
3315 : * subtransaction. The actual aborts will happen when control gets to
3316 : * CommitTransactionCommand.
3317 : */
3318 25 : xact = CurrentTransactionState;
3319 : for (;;)
3320 : {
3321 28 : if (xact == target)
3322 25 : break;
3323 3 : if (xact->blockState == TBLOCK_SUBINPROGRESS)
3324 3 : xact->blockState = TBLOCK_SUBABORT_PENDING;
3325 0 : else if (xact->blockState == TBLOCK_SUBABORT)
3326 0 : xact->blockState = TBLOCK_SUBABORT_END;
3327 : else
3328 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
3329 : BlockStateAsString(xact->blockState));
3330 3 : xact = xact->parent;
3331 : Assert(PointerIsValid(xact));
3332 3 : }
3333 :
3334 : /* And mark the target as "restart pending" */
3335 25 : if (xact->blockState == TBLOCK_SUBINPROGRESS)
3336 18 : xact->blockState = TBLOCK_SUBRESTART;
3337 7 : else if (xact->blockState == TBLOCK_SUBABORT)
3338 7 : xact->blockState = TBLOCK_SUBABORT_RESTART;
3339 : else
3340 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
3341 : BlockStateAsString(xact->blockState));
3342 25 : }
3343 :
3344 : /*
3345 : * BeginInternalSubTransaction
3346 : * This is the same as DefineSavepoint except it allows TBLOCK_STARTED,
3347 : * TBLOCK_END, and TBLOCK_PREPARE states, and therefore it can safely be
3348 : * used in functions that might be called when not inside a BEGIN block
3349 : * or when running deferred triggers at COMMIT/PREPARE time. Also, it
3350 : * automatically does CommitTransactionCommand/StartTransactionCommand
3351 : * instead of expecting the caller to do it.
3352 : */
3353 : void
3354 : BeginInternalSubTransaction(char *name)
3355 17 : {
3356 17 : TransactionState s = CurrentTransactionState;
3357 :
3358 17 : switch (s->blockState)
3359 : {
3360 : case TBLOCK_STARTED:
3361 : case TBLOCK_INPROGRESS:
3362 : case TBLOCK_END:
3363 : case TBLOCK_PREPARE:
3364 : case TBLOCK_SUBINPROGRESS:
3365 : /* Normal subtransaction start */
3366 17 : PushTransaction();
3367 17 : s = CurrentTransactionState; /* changed by push */
3368 :
3369 : /*
3370 : * Savepoint names, like the TransactionState block itself, live
3371 : * in TopTransactionContext.
3372 : */
3373 17 : if (name)
3374 0 : s->name = MemoryContextStrdup(TopTransactionContext, name);
3375 : break;
3376 :
3377 : /* These cases are invalid. */
3378 : case TBLOCK_DEFAULT:
3379 : case TBLOCK_BEGIN:
3380 : case TBLOCK_SUBBEGIN:
3381 : case TBLOCK_SUBEND:
3382 : case TBLOCK_ABORT:
3383 : case TBLOCK_SUBABORT:
3384 : case TBLOCK_ABORT_END:
3385 : case TBLOCK_SUBABORT_END:
3386 : case TBLOCK_ABORT_PENDING:
3387 : case TBLOCK_SUBABORT_PENDING:
3388 : case TBLOCK_SUBRESTART:
3389 : case TBLOCK_SUBABORT_RESTART:
3390 0 : elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
3391 : BlockStateAsString(s->blockState));
3392 : break;
3393 : }
3394 :
3395 17 : CommitTransactionCommand();
3396 17 : StartTransactionCommand();
3397 17 : }
3398 :
3399 : /*
3400 : * ReleaseCurrentSubTransaction
3401 : *
3402 : * RELEASE (ie, commit) the innermost subtransaction, regardless of its
3403 : * savepoint name (if any).
3404 : * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
3405 : */
3406 : void
3407 : ReleaseCurrentSubTransaction(void)
3408 4 : {
3409 4 : TransactionState s = CurrentTransactionState;
3410 :
3411 4 : if (s->blockState != TBLOCK_SUBINPROGRESS)
3412 0 : elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
3413 : BlockStateAsString(s->blockState));
3414 : Assert(s->state == TRANS_INPROGRESS);
3415 4 : MemoryContextSwitchTo(CurTransactionContext);
3416 4 : CommitSubTransaction();
3417 4 : s = CurrentTransactionState; /* changed by pop */
3418 : Assert(s->state == TRANS_INPROGRESS);
3419 4 : }
3420 :
3421 : /*
3422 : * RollbackAndReleaseCurrentSubTransaction
3423 : *
3424 : * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
3425 : * of its savepoint name (if any).
3426 : * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
3427 : */
3428 : void
3429 : RollbackAndReleaseCurrentSubTransaction(void)
3430 13 : {
3431 13 : TransactionState s = CurrentTransactionState;
3432 :
3433 13 : switch (s->blockState)
3434 : {
3435 : /* Must be in a subtransaction */
3436 : case TBLOCK_SUBINPROGRESS:
3437 : case TBLOCK_SUBABORT:
3438 : break;
3439 :
3440 : /* These cases are invalid. */
3441 : case TBLOCK_DEFAULT:
3442 : case TBLOCK_STARTED:
3443 : case TBLOCK_BEGIN:
3444 : case TBLOCK_SUBBEGIN:
3445 : case TBLOCK_INPROGRESS:
3446 : case TBLOCK_END:
3447 : case TBLOCK_SUBEND:
3448 : case TBLOCK_ABORT:
3449 : case TBLOCK_ABORT_END:
3450 : case TBLOCK_SUBABORT_END:
3451 : case TBLOCK_ABORT_PENDING:
3452 : case TBLOCK_SUBABORT_PENDING:
3453 : case TBLOCK_SUBRESTART:
3454 : case TBLOCK_SUBABORT_RESTART:
3455 : case TBLOCK_PREPARE:
3456 0 : elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
3457 : BlockStateAsString(s->blockState));
3458 : break;
3459 : }
3460 :
3461 : /*
3462 : * Abort the current subtransaction, if needed.
3463 : */
3464 13 : if (s->blockState == TBLOCK_SUBINPROGRESS)
3465 13 : AbortSubTransaction();
3466 :
3467 : /* And clean it up, too */
3468 13 : CleanupSubTransaction();
3469 :
3470 13 : s = CurrentTransactionState; /* changed by pop */
3471 : AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
3472 : s->blockState == TBLOCK_INPROGRESS ||
3473 : s->blockState == TBLOCK_STARTED);
3474 13 : }
3475 :
3476 : /*
3477 : * AbortOutOfAnyTransaction
3478 : *
3479 : * This routine is provided for error recovery purposes. It aborts any
3480 : * active transaction or transaction block, leaving the system in a known
3481 : * idle state.
3482 : */
3483 : void
3484 : AbortOutOfAnyTransaction(void)
3485 173 : {
3486 173 : TransactionState s = CurrentTransactionState;
3487 :
3488 : /*
3489 : * Get out of any transaction or nested transaction
3490 : */
3491 : do
3492 : {
3493 173 : switch (s->blockState)
3494 : {
3495 : case TBLOCK_DEFAULT:
3496 : /* Not in a transaction, do nothing */
3497 : break;
3498 : case TBLOCK_STARTED:
3499 : case TBLOCK_BEGIN:
3500 : case TBLOCK_INPROGRESS:
3501 : case TBLOCK_END:
3502 : case TBLOCK_ABORT_PENDING:
3503 : case TBLOCK_PREPARE:
3504 : /* In a transaction, so clean up */
3505 0 : AbortTransaction();
3506 0 : CleanupTransaction();
3507 0 : s->blockState = TBLOCK_DEFAULT;
3508 0 : break;
3509 : case TBLOCK_ABORT:
3510 : case TBLOCK_ABORT_END:
3511 : /* AbortTransaction already done, still need Cleanup */
3512 0 : CleanupTransaction();
3513 0 : s->blockState = TBLOCK_DEFAULT;
3514 0 : break;
3515 :
3516 : /*
3517 : * In a subtransaction, so clean it up and abort parent too
3518 : */
3519 : case TBLOCK_SUBBEGIN:
3520 : case TBLOCK_SUBINPROGRESS:
3521 : case TBLOCK_SUBEND:
3522 : case TBLOCK_SUBABORT_PENDING:
3523 : case TBLOCK_SUBRESTART:
3524 0 : AbortSubTransaction();
3525 0 : CleanupSubTransaction();
3526 0 : s = CurrentTransactionState; /* changed by pop */
3527 0 : break;
3528 :
3529 : case TBLOCK_SUBABORT:
3530 : case TBLOCK_SUBABORT_END:
3531 : case TBLOCK_SUBABORT_RESTART:
3532 : /* As above, but AbortSubTransaction already done */
3533 0 : CleanupSubTransaction();
3534 0 : s = CurrentTransactionState; /* changed by pop */
3535 : break;
3536 : }
3537 173 : } while (s->blockState != TBLOCK_DEFAULT);
3538 :
3539 : /* Should be out of all subxacts now */
3540 : Assert(s->parent == NULL);
3541 173 : }
3542 :
3543 : /*
3544 : * IsTransactionBlock --- are we within a transaction block?
3545 : */
3546 : bool
3547 : IsTransactionBlock(void)
3548 188 : {
3549 188 : TransactionState s = CurrentTransactionState;
3550 :
3551 188 : if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
3552 50 : return false;
3553 :
3554 138 : return true;
3555 : }
3556 :
3557 : /*
3558 : * IsTransactionOrTransactionBlock --- are we within either a transaction
3559 : * or a transaction block? (The backend is only really "idle" when this
3560 : * returns false.)
3561 : *
3562 : * This should match up with IsTransactionBlock and IsTransactionState.
3563 : */
3564 : bool
3565 : IsTransactionOrTransactionBlock(void)
3566 175877 : {
3567 175877 : TransactionState s = CurrentTransactionState;
3568 :
3569 175877 : if (s->blockState == TBLOCK_DEFAULT)
3570 173147 : return false;
3571 :
3572 2730 : return true;
3573 : }
3574 :
3575 : /*
3576 : * TransactionBlockStatusCode - return status code to send in ReadyForQuery
3577 : */
3578 : char
3579 : TransactionBlockStatusCode(void)
3580 9702 : {
3581 9702 : TransactionState s = CurrentTransactionState;
3582 :
3583 9702 : switch (s->blockState)
3584 : {
3585 : case TBLOCK_DEFAULT:
3586 : case TBLOCK_STARTED:
3587 8379 : return 'I'; /* idle --- not in transaction */
3588 : case TBLOCK_BEGIN:
3589 : case TBLOCK_SUBBEGIN:
3590 : case TBLOCK_INPROGRESS:
3591 : case TBLOCK_SUBINPROGRESS:
3592 : case TBLOCK_END:
3593 : case TBLOCK_SUBEND:
3594 : case TBLOCK_PREPARE:
3595 1295 : return 'T'; /* in transaction */
3596 : case TBLOCK_ABORT:
3597 : case TBLOCK_SUBABORT:
3598 : case TBLOCK_ABORT_END:
3599 : case TBLOCK_SUBABORT_END:
3600 : case TBLOCK_ABORT_PENDING:
3601 : case TBLOCK_SUBABORT_PENDING:
3602 : case TBLOCK_SUBRESTART:
3603 : case TBLOCK_SUBABORT_RESTART:
3604 28 : return 'E'; /* in failed transaction */
3605 : }
3606 :
3607 : /* should never get here */
3608 0 : elog(FATAL, "invalid transaction block state: %s",
3609 : BlockStateAsString(s->blockState));
3610 0 : return 0; /* keep compiler quiet */
3611 : }
3612 :
3613 : /*
3614 : * IsSubTransaction
3615 : */
3616 : bool
3617 : IsSubTransaction(void)
3618 72 : {
3619 72 : TransactionState s = CurrentTransactionState;
3620 :
3621 72 : if (s->nestingLevel >= 2)
3622 2 : return true;
3623 :
3624 70 : return false;
3625 : }
3626 :
3627 : /*
3628 : * StartSubTransaction
3629 : *
3630 : * If you're wondering why this is separate from PushTransaction: it's because
3631 : * we can't conveniently do this stuff right inside DefineSavepoint. The
3632 : * SAVEPOINT utility command will be executed inside a Portal, and if we
3633 : * muck with CurrentMemoryContext or CurrentResourceOwner then exit from
3634 : * the Portal will undo those settings. So we make DefineSavepoint just
3635 : * push a dummy transaction block, and when control returns to the main
3636 : * idle loop, CommitTransactionCommand will be called, and we'll come here
3637 : * to finish starting the subtransaction.
3638 : */
3639 : static void
3640 : StartSubTransaction(void)
3641 84 : {
3642 84 : TransactionState s = CurrentTransactionState;
3643 :
3644 84 : if (s->state != TRANS_DEFAULT)
3645 0 : elog(WARNING, "StartSubTransaction while in %s state",
3646 : TransStateAsString(s->state));
3647 :
3648 84 : s->state = TRANS_START;
3649 :
3650 : /*
3651 : * Initialize subsystems for new subtransaction
3652 : *
3653 : * must initialize resource-management stuff first
3654 : */
3655 84 : AtSubStart_Memory();
3656 84 : AtSubStart_ResourceOwner();
3657 84 : AtSubStart_Inval();
3658 84 : AtSubStart_Notify();
3659 84 : AfterTriggerBeginSubXact();
3660 :
3661 84 : s->state = TRANS_INPROGRESS;
3662 :
3663 : /*
3664 : * Call start-of-subxact callbacks
3665 : */
3666 84 : CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
3667 : s->parent->subTransactionId);
3668 :
3669 84 : ShowTransactionState("StartSubTransaction");
3670 84 : }
3671 :
3672 : /*
3673 : * CommitSubTransaction
3674 : *
3675 : * The caller has to make sure to always reassign CurrentTransactionState
3676 : * if it has a local pointer to it after calling this function.
3677 : */
3678 : static void
3679 : CommitSubTransaction(void)
3680 34 : {
3681 34 : TransactionState s = CurrentTransactionState;
3682 :
3683 34 : ShowTransactionState("CommitSubTransaction");
3684 :
3685 34 : if (s->state != TRANS_INPROGRESS)
3686 0 : elog(WARNING, "CommitSubTransaction while in %s state",
3687 : TransStateAsString(s->state));
3688 :
3689 : /* Pre-commit processing goes here -- nothing to do at the moment */
3690 :
3691 34 : s->state = TRANS_COMMIT;
3692 :
3693 : /* Must CCI to ensure commands of subtransaction are seen as done */
3694 34 : CommandCounterIncrement();
3695 :
3696 : /* Mark subtransaction as subcommitted */
3697 34 : RecordSubTransactionCommit();
3698 :
3699 : /* Post-commit cleanup */
3700 34 : if (TransactionIdIsValid(s->transactionId))
3701 19 : AtSubCommit_childXids();
3702 34 : AfterTriggerEndSubXact(true);
3703 34 : AtSubCommit_Portals(s->subTransactionId,
3704 : s->parent->subTransactionId,
3705 : s->parent->curTransactionOwner);
3706 34 : AtEOSubXact_LargeObject(true, s->subTransactionId,
3707 : s->parent->subTransactionId);
3708 34 : AtSubCommit_Notify();
3709 34 : AtEOSubXact_UpdateFlatFiles(true, s->subTransactionId,
3710 : s->parent->subTransactionId);
3711 :
3712 34 : CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
3713 : s->parent->subTransactionId);
3714 :
3715 34 : ResourceOwnerRelease(s->curTransactionOwner,
3716 : RESOURCE_RELEASE_BEFORE_LOCKS,
3717 : true, false);
3718 34 : AtEOSubXact_RelationCache(true, s->subTransactionId,
3719 : s->parent->subTransactionId);
3720 34 : AtEOSubXact_Inval(true);
3721 34 : AtSubCommit_smgr();
3722 :
3723 : /*
3724 : * The only lock we actually release here is the subtransaction XID lock.
3725 : * The rest just get transferred to the parent resource owner.
3726 : */
3727 34 : CurrentResourceOwner = s->curTransactionOwner;
3728 34 : if (TransactionIdIsValid(s->transactionId))
3729 19 : XactLockTableDelete(s->transactionId);
3730 :
3731 34 : ResourceOwnerRelease(s->curTransactionOwner,
3732 : RESOURCE_RELEASE_LOCKS,
3733 : true, false);
3734 34 : ResourceOwnerRelease(s->curTransactionOwner,
3735 : RESOURCE_RELEASE_AFTER_LOCKS,
3736 : true, false);
3737 :
3738 34 : AtEOXact_GUC(true, s->gucNestLevel);
3739 34 : AtEOSubXact_SPI(true, s->subTransactionId);
3740 34 : AtEOSubXact_on_commit_actions(true, s->subTransactionId,
3741 : s->parent->subTransactionId);
3742 34 : AtEOSubXact_Namespace(true, s->subTransactionId,
3743 : s->parent->subTransactionId);
3744 34 : AtEOSubXact_Files(true, s->subTransactionId,
3745 : s->parent->subTransactionId);
3746 34 : AtEOSubXact_HashTables(true, s->nestingLevel);
3747 34 : AtEOSubXact_PgStat(true, s->nestingLevel);
3748 :
3749 : /*
3750 : * We need to restore the upper transaction's read-only state, in case the
3751 : * upper is read-write while the child is read-only; GUC will incorrectly
3752 : * think it should leave the child state in place.
3753 : */
3754 34 : XactReadOnly = s->prevXactReadOnly;
3755 :
3756 34 : CurrentResourceOwner = s->parent->curTransactionOwner;
3757 34 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
3758 34 : ResourceOwnerDelete(s->curTransactionOwner);
3759 34 : s->curTransactionOwner = NULL;
3760 :
3761 34 : AtSubCommit_Memory();
3762 :
3763 34 : s->state = TRANS_DEFAULT;
3764 :
3765 34 : PopTransaction();
3766 34 : }
3767 :
3768 : /*
3769 : * AbortSubTransaction
3770 : */
3771 : static void
3772 : AbortSubTransaction(void)
3773 50 : {
3774 50 : TransactionState s = CurrentTransactionState;
3775 :
3776 : /* Prevent cancel/die interrupt while cleaning up */
3777 50 : HOLD_INTERRUPTS();
3778 :
3779 : /* Make sure we have a valid memory context and resource owner */
3780 50 : AtSubAbort_Memory();
3781 50 : AtSubAbort_ResourceOwner();
3782 :
3783 : /*
3784 : * Release any LW locks we might be holding as quickly as possible.
3785 : * (Regular locks, however, must be held till we finish aborting.)
3786 : * Releasing LW locks is critical since we might try to grab them again
3787 : * while cleaning up!
3788 : *
3789 : * FIXME This may be incorrect --- Are there some locks we should keep?
3790 : * Buffer locks, for example? I don't think so but I'm not sure.
3791 : */
3792 50 : LWLockReleaseAll();
3793 :
3794 50 : AbortBufferIO();
3795 50 : UnlockBuffers();
3796 :
3797 50 : LockWaitCancel();
3798 :
3799 : /*
3800 : * check the current transaction state
3801 : */
3802 50 : ShowTransactionState("AbortSubTransaction");
3803 :
3804 50 : if (s->state != TRANS_INPROGRESS)
3805 0 : elog(WARNING, "AbortSubTransaction while in %s state",
3806 : TransStateAsString(s->state));
3807 :
3808 50 : s->state = TRANS_ABORT;
3809 :
3810 : /*
3811 : * Reset user ID which might have been changed transiently. (See notes
3812 : * in AbortTransaction.)
3813 : */
3814 50 : SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
3815 :
3816 : /*
3817 : * We can skip all this stuff if the subxact failed before creating a
3818 : * ResourceOwner...
3819 : */
3820 50 : if (s->curTransactionOwner)
3821 : {
3822 50 : AfterTriggerEndSubXact(false);
3823 50 : AtSubAbort_Portals(s->subTransactionId,
3824 : s->parent->subTransactionId,
3825 : s->parent->curTransactionOwner);
3826 50 : AtEOSubXact_LargeObject(false, s->subTransactionId,
3827 : s->parent->subTransactionId);
3828 50 : AtSubAbort_Notify();
3829 50 : AtEOSubXact_UpdateFlatFiles(false, s->subTransactionId,
3830 : s->parent->subTransactionId);
3831 :
3832 : /* Advertise the fact that we aborted in pg_clog. */
3833 50 : (void) RecordTransactionAbort(true);
3834 :
3835 : /* Post-abort cleanup */
3836 50 : if (TransactionIdIsValid(s->transactionId))
3837 21 : AtSubAbort_childXids();
3838 :
3839 50 : CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
3840 : s->parent->subTransactionId);
3841 :
3842 50 : ResourceOwnerRelease(s->curTransactionOwner,
3843 : RESOURCE_RELEASE_BEFORE_LOCKS,
3844 : false, false);
3845 50 : AtEOSubXact_RelationCache(false, s->subTransactionId,
3846 : s->parent->subTransactionId);
3847 50 : AtEOSubXact_Inval(false);
3848 50 : AtSubAbort_smgr();
3849 50 : ResourceOwnerRelease(s->curTransactionOwner,
3850 : RESOURCE_RELEASE_LOCKS,
3851 : false, false);
3852 50 : ResourceOwnerRelease(s->curTransactionOwner,
3853 : RESOURCE_RELEASE_AFTER_LOCKS,
3854 : false, false);
3855 :
3856 50 : AtEOXact_GUC(false, s->gucNestLevel);
3857 50 : AtEOSubXact_SPI(false, s->subTransactionId);
3858 50 : AtEOXact_xml();
3859 50 : AtEOSubXact_on_commit_actions(false, s->subTransactionId,
3860 : s->parent->subTransactionId);
3861 50 : AtEOSubXact_Namespace(false, s->subTransactionId,
3862 : s->parent->subTransactionId);
3863 50 : AtEOSubXact_Files(false, s->subTransactionId,
3864 : s->parent->subTransactionId);
3865 50 : AtEOSubXact_HashTables(false, s->nestingLevel);
3866 50 : AtEOSubXact_PgStat(false, s->nestingLevel);
3867 : }
3868 :
3869 : /*
3870 : * Restore the upper transaction's read-only state, too. This should be
3871 : * redundant with GUC's cleanup but we may as well do it for consistency
3872 : * with the commit case.
3873 : */
3874 50 : XactReadOnly = s->prevXactReadOnly;
3875 :
3876 50 : RESUME_INTERRUPTS();
3877 50 : }
3878 :
3879 : /*
3880 : * CleanupSubTransaction
3881 : *
3882 : * The caller has to make sure to always reassign CurrentTransactionState
3883 : * if it has a local pointer to it after calling this function.
3884 : */
3885 : static void
3886 : CleanupSubTransaction(void)
3887 50 : {
3888 50 : TransactionState s = CurrentTransactionState;
3889 :
3890 50 : ShowTransactionState("CleanupSubTransaction");
3891 :
3892 50 : if (s->state != TRANS_ABORT)
3893 0 : elog(WARNING, "CleanupSubTransaction while in %s state",
3894 : TransStateAsString(s->state));
3895 :
3896 50 : AtSubCleanup_Portals(s->subTransactionId);
3897 :
3898 50 : CurrentResourceOwner = s->parent->curTransactionOwner;
3899 50 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
3900 50 : if (s->curTransactionOwner)
3901 50 : ResourceOwnerDelete(s->curTransactionOwner);
3902 50 : s->curTransactionOwner = NULL;
3903 :
3904 50 : AtSubCleanup_Memory();
3905 :
3906 50 : s->state = TRANS_DEFAULT;
3907 :
3908 50 : PopTransaction();
3909 50 : }
3910 :
3911 : /*
3912 : * PushTransaction
3913 : * Create transaction state stack entry for a subtransaction
3914 : *
3915 : * The caller has to make sure to always reassign CurrentTransactionState
3916 : * if it has a local pointer to it after calling this function.
3917 : */
3918 : static void
3919 : PushTransaction(void)
3920 84 : {
3921 84 : TransactionState p = CurrentTransactionState;
3922 : TransactionState s;
3923 :
3924 : /*
3925 : * We keep subtransaction state nodes in TopTransactionContext.
3926 : */
3927 84 : s = (TransactionState)
3928 : MemoryContextAllocZero(TopTransactionContext,
3929 : sizeof(TransactionStateData));
3930 :
3931 : /*
3932 : * Assign a subtransaction ID, watching out for counter wraparound.
3933 : */
3934 84 : currentSubTransactionId += 1;
3935 84 : if (currentSubTransactionId == InvalidSubTransactionId)
3936 : {
3937 0 : currentSubTransactionId -= 1;
3938 0 : pfree(s);
3939 0 : ereport(ERROR,
3940 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3941 : errmsg("cannot have more than 2^32-1 subtransactions in a transaction")));
3942 : }
3943 :
3944 : /*
3945 : * We can now stack a minimally valid subtransaction without fear of
3946 : * failure.
3947 : */
3948 84 : s->transactionId = InvalidTransactionId; /* until assigned */
3949 84 : s->subTransactionId = currentSubTransactionId;
3950 84 : s->parent = p;
3951 84 : s->nestingLevel = p->nestingLevel + 1;
3952 84 : s->gucNestLevel = NewGUCNestLevel();
3953 84 : s->savepointLevel = p->savepointLevel;
3954 84 : s->state = TRANS_DEFAULT;
3955 84 : s->blockState = TBLOCK_SUBBEGIN;
3956 84 : GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt);
3957 84 : s->prevXactReadOnly = XactReadOnly;
3958 :
3959 84 : CurrentTransactionState = s;
3960 :
3961 : /*
3962 : * AbortSubTransaction and CleanupSubTransaction have to be able to cope
3963 : * with the subtransaction from here on out; in particular they should not
3964 : * assume that it necessarily has a transaction context, resource owner,
3965 : * or XID.
3966 : */
3967 84 : }
3968 :
3969 : /*
3970 : * PopTransaction
3971 : * Pop back to parent transaction state
3972 : *
3973 : * The caller has to make sure to always reassign CurrentTransactionState
3974 : * if it has a local pointer to it after calling this function.
3975 : */
3976 : static void
3977 : PopTransaction(void)
3978 84 : {
3979 84 : TransactionState s = CurrentTransactionState;
3980 :
3981 84 : if (s->state != TRANS_DEFAULT)
3982 0 : elog(WARNING, "PopTransaction while in %s state",
3983 : TransStateAsString(s->state));
3984 :
3985 84 : if (s->parent == NULL)
3986 0 : elog(FATAL, "PopTransaction with no parent");
3987 :
3988 84 : CurrentTransactionState = s->parent;
3989 :
3990 : /* Let's just make sure CurTransactionContext is good */
3991 84 : CurTransactionContext = s->parent->curTransactionContext;
3992 84 : MemoryContextSwitchTo(CurTransactionContext);
3993 :
3994 : /* Ditto for ResourceOwner links */
3995 84 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
3996 84 : CurrentResourceOwner = s->parent->curTransactionOwner;
3997 :
3998 : /* Free the old child structure */
3999 84 : if (s->name)
4000 42 : pfree(s->name);
4001 84 : pfree(s);
4002 84 : }
4003 :
4004 : /*
4005 : * ShowTransactionState
4006 : * Debug support
4007 : */
4008 : static void
4009 : ShowTransactionState(const char *str)
4010 26482 : {
4011 : /* skip work if message will definitely not be printed */
4012 26482 : if (log_min_messages <= DEBUG3 || client_min_messages <= DEBUG3)
4013 : {
4014 0 : elog(DEBUG3, "%s", str);
4015 0 : ShowTransactionStateRec(CurrentTransactionState);
4016 : }
4017 26482 : }
4018 :
4019 : /*
4020 : * ShowTransactionStateRec
4021 : * Recursive subroutine for ShowTransactionState
4022 : */
4023 : static void
4024 : ShowTransactionStateRec(TransactionState s)
4025 0 : {
4026 0 : if (s->parent)
4027 0 : ShowTransactionStateRec(s->parent);
4028 :
4029 : /* use ereport to suppress computation if msg will not be printed */
4030 0 : ereport(DEBUG3,
4031 : (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u%s, nestlvl: %d, children: %s",
4032 : PointerIsValid(s->name) ? s->name : "unnamed",
4033 : BlockStateAsString(s->blockState),
4034 : TransStateAsString(s->state),
4035 : (unsigned int) s->transactionId,
4036 : (unsigned int) s->subTransactionId,
4037 : (unsigned int) currentCommandId,
4038 : currentCommandIdUsed ? " (used)" : "",
4039 : s->nestingLevel,
4040 : nodeToString(s->childXids))));
4041 0 : }
4042 :
4043 : /*
4044 : * BlockStateAsString
4045 : * Debug support
4046 : */
4047 : static const char *
4048 : BlockStateAsString(TBlockState blockState)
4049 0 : {
4050 0 : switch (blockState)
4051 : {
4052 : case TBLOCK_DEFAULT:
4053 0 : return "DEFAULT";
4054 : case TBLOCK_STARTED:
4055 0 : return "STARTED";
4056 : case TBLOCK_BEGIN:
4057 0 : return "BEGIN";
4058 : case TBLOCK_INPROGRESS:
4059 0 : return "INPROGRESS";
4060 : case TBLOCK_END:
4061 0 : return "END";
4062 : case TBLOCK_ABORT:
4063 0 : return "ABORT";
4064 : case TBLOCK_ABORT_END:
4065 0 : return "ABORT END";
4066 : case TBLOCK_ABORT_PENDING:
4067 0 : return "ABORT PEND";
4068 : case TBLOCK_PREPARE:
4069 0 : return "PREPARE";
4070 : case TBLOCK_SUBBEGIN:
4071 0 : return "SUB BEGIN";
4072 : case TBLOCK_SUBINPROGRESS:
4073 0 : return "SUB INPROGRS";
4074 : case TBLOCK_SUBEND:
4075 0 : return "SUB END";
4076 : case TBLOCK_SUBABORT:
4077 0 : return "SUB ABORT";
4078 : case TBLOCK_SUBABORT_END:
4079 0 : return "SUB ABORT END";
4080 : case TBLOCK_SUBABORT_PENDING:
4081 0 : return "SUB ABRT PEND";
4082 : case TBLOCK_SUBRESTART:
4083 0 : return "SUB RESTART";
4084 : case TBLOCK_SUBABORT_RESTART:
4085 0 : return "SUB AB RESTRT";
4086 : }
4087 0 : return "UNRECOGNIZED";
4088 : }
4089 :
4090 : /*
4091 : * TransStateAsString
4092 : * Debug support
4093 : */
4094 : static const char *
4095 : TransStateAsString(TransState state)
4096 0 : {
4097 0 : switch (state)
4098 : {
4099 : case TRANS_DEFAULT:
4100 0 : return "DEFAULT";
4101 : case TRANS_START:
4102 0 : return "START";
4103 : case TRANS_INPROGRESS:
4104 0 : return "INPROGR";
4105 : case TRANS_COMMIT:
4106 0 : return "COMMIT";
4107 : case TRANS_ABORT:
4108 0 : return "ABORT";
4109 : case TRANS_PREPARE:
4110 0 : return "PREPARE";
4111 : }
4112 0 : return "UNRECOGNIZED";
4113 : }
4114 :
4115 : /*
4116 : * xactGetCommittedChildren
4117 : *
4118 : * Gets the list of committed children of the current transaction. The return
4119 : * value is the number of child transactions. *children is set to point to a
4120 : * palloc'd array of TransactionIds. If there are no subxacts, *children is
4121 : * set to NULL.
4122 : */
4123 : int
4124 : xactGetCommittedChildren(TransactionId **ptr)
4125 12780 : {
4126 12780 : TransactionState s = CurrentTransactionState;
4127 : int nchildren;
4128 : TransactionId *children;
4129 : ListCell *p;
4130 :
4131 25560 : nchildren = list_length(s->childXids);
4132 12780 : if (nchildren == 0)
4133 : {
4134 12766 : *ptr = NULL;
4135 12766 : return 0;
4136 : }
4137 :
4138 14 : children = (TransactionId *) palloc(nchildren * sizeof(TransactionId));
4139 14 : *ptr = children;
4140 :
4141 47 : foreach(p, s->childXids)
4142 : {
4143 19 : TransactionId child = lfirst_xid(p);
4144 :
4145 19 : *children++ = child;
4146 : }
4147 :
4148 14 : return nchildren;
4149 : }
4150 :
4151 : /*
4152 : * XLOG support routines
4153 : */
4154 :
4155 : static void
4156 : xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid)
4157 0 : {
4158 : TransactionId *sub_xids;
4159 : TransactionId max_xid;
4160 : int i;
4161 :
4162 0 : TransactionIdCommit(xid);
4163 :
4164 : /* Mark committed subtransactions as committed */
4165 0 : sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
4166 0 : TransactionIdCommitTree(xlrec->nsubxacts, sub_xids);
4167 :
4168 : /* Make sure nextXid is beyond any XID mentioned in the record */
4169 0 : max_xid = xid;
4170 0 : for (i = 0; i < xlrec->nsubxacts; i++)
4171 : {
4172 0 : if (TransactionIdPrecedes(max_xid, sub_xids[i]))
4173 0 : max_xid = sub_xids[i];
4174 : }
4175 0 : if (TransactionIdFollowsOrEquals(max_xid,
4176 : ShmemVariableCache->nextXid))
4177 : {
4178 0 : ShmemVariableCache->nextXid = max_xid;
4179 0 : TransactionIdAdvance(ShmemVariableCache->nextXid);
4180 : }
4181 :
4182 : /* Make sure files supposed to be dropped are dropped */
4183 0 : for (i = 0; i < xlrec->nrels; i++)
4184 : {
4185 0 : XLogDropRelation(xlrec->xnodes[i]);
4186 0 : smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
4187 : }
4188 0 : }
4189 :
4190 : static void
4191 : xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
4192 0 : {
4193 : TransactionId *sub_xids;
4194 : TransactionId max_xid;
4195 : int i;
4196 :
4197 0 : TransactionIdAbort(xid);
4198 :
4199 : /* Mark subtransactions as aborted */
4200 0 : sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
4201 0 : TransactionIdAbortTree(xlrec->nsubxacts, sub_xids);
4202 :
4203 : /* Make sure nextXid is beyond any XID mentioned in the record */
4204 0 : max_xid = xid;
4205 0 : for (i = 0; i < xlrec->nsubxacts; i++)
4206 : {
4207 0 : if (TransactionIdPrecedes(max_xid, sub_xids[i]))
4208 0 : max_xid = sub_xids[i];
4209 : }
4210 0 : if (TransactionIdFollowsOrEquals(max_xid,
4211 : ShmemVariableCache->nextXid))
4212 : {
4213 0 : ShmemVariableCache->nextXid = max_xid;
4214 0 : TransactionIdAdvance(ShmemVariableCache->nextXid);
4215 : }
4216 :
4217 : /* Make sure files supposed to be dropped are dropped */
4218 0 : for (i = 0; i < xlrec->nrels; i++)
4219 : {
4220 0 : XLogDropRelation(xlrec->xnodes[i]);
4221 0 : smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
4222 : }
4223 0 : }
4224 :
4225 : void
4226 : xact_redo(XLogRecPtr lsn, XLogRecord *record)
4227 0 : {
4228 0 : uint8 info = record->xl_info & ~XLR_INFO_MASK;
4229 :
4230 0 : if (info == XLOG_XACT_COMMIT)
4231 : {
4232 0 : xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
4233 :
4234 0 : xact_redo_commit(xlrec, record->xl_xid);
4235 : }
4236 0 : else if (info == XLOG_XACT_ABORT)
4237 : {
4238 0 : xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
4239 :
4240 0 : xact_redo_abort(xlrec, record->xl_xid);
4241 : }
4242 0 : else if (info == XLOG_XACT_PREPARE)
4243 : {
4244 : /* the record contents are exactly the 2PC file */
4245 0 : RecreateTwoPhaseFile(record->xl_xid,
4246 : XLogRecGetData(record), record->xl_len);
4247 : }
4248 0 : else if (info == XLOG_XACT_COMMIT_PREPARED)
4249 : {
4250 0 : xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) XLogRecGetData(record);
4251 :
4252 0 : xact_redo_commit(&xlrec->crec, xlrec->xid);
4253 0 : RemoveTwoPhaseFile(xlrec->xid, false);
4254 : }
4255 0 : else if (info == XLOG_XACT_ABORT_PREPARED)
4256 : {
4257 0 : xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) XLogRecGetData(record);
4258 :
4259 0 : xact_redo_abort(&xlrec->arec, xlrec->xid);
4260 0 : RemoveTwoPhaseFile(xlrec->xid, false);
4261 : }
4262 : else
4263 0 : elog(PANIC, "xact_redo: unknown op code %u", info);
4264 0 : }
4265 :
4266 : static void
4267 : xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
4268 0 : {
4269 : int i;
4270 :
4271 0 : appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
4272 0 : if (xlrec->nrels > 0)
4273 : {
4274 0 : appendStringInfo(buf, "; rels:");
4275 0 : for (i = 0; i < xlrec->nrels; i++)
4276 : {
4277 0 : RelFileNode rnode = xlrec->xnodes[i];
4278 :
4279 0 : appendStringInfo(buf, " %u/%u/%u",
4280 : rnode.spcNode, rnode.dbNode, rnode.relNode);
4281 : }
4282 : }
4283 0 : if (xlrec->nsubxacts > 0)
4284 : {
4285 : TransactionId *xacts = (TransactionId *)
4286 0 : &xlrec->xnodes[xlrec->nrels];
4287 :
4288 0 : appendStringInfo(buf, "; subxacts:");
4289 0 : for (i = 0; i < xlrec->nsubxacts; i++)
4290 0 : appendStringInfo(buf, " %u", xacts[i]);
4291 : }
4292 0 : }
4293 :
4294 : static void
4295 : xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
4296 0 : {
4297 : int i;
4298 :
4299 0 : appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
4300 0 : if (xlrec->nrels > 0)
4301 : {
4302 0 : appendStringInfo(buf, "; rels:");
4303 0 : for (i = 0; i < xlrec->nrels; i++)
4304 : {
4305 0 : RelFileNode rnode = xlrec->xnodes[i];
4306 :
4307 0 : appendStringInfo(buf, " %u/%u/%u",
4308 : rnode.spcNode, rnode.dbNode, rnode.relNode);
4309 : }
4310 : }
4311 0 : if (xlrec->nsubxacts > 0)
4312 : {
4313 : TransactionId *xacts = (TransactionId *)
4314 0 : &xlrec->xnodes[xlrec->nrels];
4315 :
4316 0 : appendStringInfo(buf, "; subxacts:");
4317 0 : for (i = 0; i < xlrec->nsubxacts; i++)
4318 0 : appendStringInfo(buf, " %u", xacts[i]);
4319 : }
4320 0 : }
4321 :
4322 : void
4323 : xact_desc(StringInfo buf, uint8 xl_info, char *rec)
4324 0 : {
4325 0 : uint8 info = xl_info & ~XLR_INFO_MASK;
4326 :
4327 0 : if (info == XLOG_XACT_COMMIT)
4328 : {
4329 0 : xl_xact_commit *xlrec = (xl_xact_commit *) rec;
4330 :
4331 0 : appendStringInfo(buf, "commit: ");
4332 0 : xact_desc_commit(buf, xlrec);
4333 : }
4334 0 : else if (info == XLOG_XACT_ABORT)
4335 : {
4336 0 : xl_xact_abort *xlrec = (xl_xact_abort *) rec;
4337 :
4338 0 : appendStringInfo(buf, "abort: ");
4339 0 : xact_desc_abort(buf, xlrec);
4340 : }
4341 0 : else if (info == XLOG_XACT_PREPARE)
4342 : {
4343 0 : appendStringInfo(buf, "prepare");
4344 : }
4345 0 : else if (info == XLOG_XACT_COMMIT_PREPARED)
4346 : {
4347 0 : xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
4348 :
4349 0 : appendStringInfo(buf, "commit %u: ", xlrec->xid);
4350 0 : xact_desc_commit(buf, &xlrec->crec);
4351 : }
4352 0 : else if (info == XLOG_XACT_ABORT_PREPARED)
4353 : {
4354 0 : xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
4355 :
4356 0 : appendStringInfo(buf, "abort %u: ", xlrec->xid);
4357 0 : xact_desc_abort(buf, &xlrec->arec);
4358 : }
4359 : else
4360 0 : appendStringInfo(buf, "UNKNOWN");
4361 0 : }
|