~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/access/transam/xact.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

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