]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xact.c
Ye-old pgindent run. Same 4-space tabs.
[postgresql] / src / backend / access / transam / xact.c
1 /*-------------------------------------------------------------------------
2  *
3  * xact.c
4  *        top level transaction system support routines
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.64 2000/04/12 17:14:53 momjian Exp $
12  *
13  * NOTES
14  *              Transaction aborts can now occur two ways:
15  *
16  *              1)      system dies from some internal cause  (Assert, etc..)
17  *              2)      user types abort
18  *
19  *              These two cases used to be treated identically, but now
20  *              we need to distinguish them.  Why?      consider the following
21  *              two situatuons:
22  *
23  *                              case 1                                                  case 2
24  *                              ------                                                  ------
25  *              1) user types BEGIN                             1) user types BEGIN
26  *              2) user does something                  2) user does something
27  *              3) user does not like what              3) system aborts for some reason
28  *                 she shes and types ABORT
29  *
30  *              In case 1, we want to abort the transaction and return to the
31  *              default state.  In case 2, there may be more commands coming
32  *              our way which are part of the same transaction block and we have
33  *              to ignore these commands until we see an END transaction.
34  *              (or an ABORT! --djm)
35  *
36  *              Internal aborts are now handled by AbortTransactionBlock(), just as
37  *              they always have been, and user aborts are now handled by
38  *              UserAbortTransactionBlock().  Both of them rely on AbortTransaction()
39  *              to do all the real work.  The only difference is what state we
40  *              enter after AbortTransaction() does its work:
41  *
42  *              * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
43  *              * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
44  *
45  *       NOTES
46  *              This file is an attempt at a redesign of the upper layer
47  *              of the V1 transaction system which was too poorly thought
48  *              out to describe.  This new system hopes to be both simpler
49  *              in design, simpler to extend and needs to contain added
50  *              functionality to solve problems beyond the scope of the V1
51  *              system.  (In particuler, communication of transaction
52  *              information between parallel backends has to be supported)
53  *
54  *              The essential aspects of the transaction system are:
55  *
56  *                              o  transaction id generation
57  *                              o  transaction log updating
58  *                              o  memory cleanup
59  *                              o  cache invalidation
60  *                              o  lock cleanup
61  *
62  *              Hence, the functional division of the transaction code is
63  *              based on what of the above things need to be done during
64  *              a start/commit/abort transaction.  For instance, the
65  *              routine AtCommit_Memory() takes care of all the memory
66  *              cleanup stuff done at commit time.
67  *
68  *              The code is layered as follows:
69  *
70  *                              StartTransaction
71  *                              CommitTransaction
72  *                              AbortTransaction
73  *                              UserAbortTransaction
74  *
75  *              are provided to do the lower level work like recording
76  *              the transaction status in the log and doing memory cleanup.
77  *              above these routines are another set of functions:
78  *
79  *                              StartTransactionCommand
80  *                              CommitTransactionCommand
81  *                              AbortCurrentTransaction
82  *
83  *              These are the routines used in the postgres main processing
84  *              loop.  They are sensitive to the current transaction block state
85  *              and make calls to the lower level routines appropriately.
86  *
87  *              Support for transaction blocks is provided via the functions:
88  *
89  *                              StartTransactionBlock
90  *                              CommitTransactionBlock
91  *                              AbortTransactionBlock
92  *
93  *              These are invoked only in responce to a user "BEGIN", "END",
94  *              or "ABORT" command.  The tricky part about these functions
95  *              is that they are called within the postgres main loop, in between
96  *              the StartTransactionCommand() and CommitTransactionCommand().
97  *
98  *              For example, consider the following sequence of user commands:
99  *
100  *              1)              begin
101  *              2)              retrieve (foo.all)
102  *              3)              append foo (bar = baz)
103  *              4)              end
104  *
105  *              in the main processing loop, this results in the following
106  *              transaction sequence:
107  *
108  *                      /       StartTransactionCommand();
109  *              1) /    ProcessUtility();                               << begin
110  *                 \            StartTransactionBlock();
111  *                      \       CommitTransactionCommand();
112  *
113  *                      /       StartTransactionCommand();
114  *              2) <    ProcessQuery();                                 << retrieve (foo.all)
115  *                      \       CommitTransactionCommand();
116  *
117  *                      /       StartTransactionCommand();
118  *              3) <    ProcessQuery();                                 << append foo (bar = baz)
119  *                      \       CommitTransactionCommand();
120  *
121  *                      /       StartTransactionCommand();
122  *              4) /    ProcessUtility();                               << end
123  *                 \            CommitTransactionBlock();
124  *                      \       CommitTransactionCommand();
125  *
126  *              The point of this example is to demonstrate the need for
127  *              StartTransactionCommand() and CommitTransactionCommand() to
128  *              be state smart -- they should do nothing in between the calls
129  *              to StartTransactionBlock() and EndTransactionBlock() and
130  *              outside these calls they need to do normal start/commit
131  *              processing.
132  *
133  *              Furthermore, suppose the "retrieve (foo.all)" caused an abort
134  *              condition.      We would then want to abort the transaction and
135  *              ignore all subsequent commands up to the "end".
136  *              -cim 3/23/90
137  *
138  *-------------------------------------------------------------------------
139  */
140
141 /*
142  * Large object clean up added in CommitTransaction() to prevent buffer leaks.
143  * [PA, 7/17/98]
144  * [PA] is Pascal AndrĂ© <andre@via.ecp.fr>
145  */
146 #include "postgres.h"
147
148 #include "access/nbtree.h"
149 #include "catalog/heap.h"
150 #include "catalog/index.h"
151 #include "commands/async.h"
152 #include "commands/sequence.h"
153 #include "commands/vacuum.h"
154 #include "commands/trigger.h"
155 #include "libpq/be-fsstubs.h"
156 #include "storage/proc.h"
157 #include "storage/sinval.h"
158 #include "utils/temprel.h"
159 #include "utils/inval.h"
160 #include "utils/portal.h"
161 #include "utils/relcache.h"
162
163 extern bool SharedBufferChanged;
164
165 static void AbortTransaction(void);
166 static void AtAbort_Cache(void);
167 static void AtAbort_Locks(void);
168 static void AtAbort_Memory(void);
169 static void AtCommit_Cache(void);
170 static void AtCommit_LocalCache(void);
171 static void AtCommit_Locks(void);
172 static void AtCommit_Memory(void);
173 static void AtStart_Cache(void);
174 static void AtStart_Locks(void);
175 static void AtStart_Memory(void);
176 static void CommitTransaction(void);
177 static void RecordTransactionAbort(void);
178 static void RecordTransactionCommit(void);
179 static void StartTransaction(void);
180
181 /* ----------------
182  *              global variables holding the current transaction state.
183  *
184  *              Note: when we are running several slave processes, the
185  *                        current transaction state data is copied into shared memory
186  *                        and the CurrentTransactionState pointer changed to
187  *                        point to the shared copy.  All this occurrs in slaves.c
188  * ----------------
189  */
190 TransactionStateData CurrentTransactionStateData = {
191         0,                                                      /* transaction id */
192         FirstCommandId,                         /* command id */
193         0,                                                      /* scan command id */
194         0x0,                                            /* start time */
195         TRANS_DEFAULT,                          /* transaction state */
196         TBLOCK_DEFAULT                          /* transaction block state */
197 };
198
199 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
200
201 int                     DefaultXactIsoLevel = XACT_READ_COMMITTED;
202 int                     XactIsoLevel;
203
204 /* ----------------
205  *              info returned when the system is disabled
206  *
207  * Apparently a lot of this code is inherited from other prototype systems.
208  * For DisabledStartTime, use a symbolic value to make the relationships clearer.
209  * The old value of 1073741823 corresponds to a date in y2004, which is coming closer
210  *      every day. It appears that if we return a value guaranteed larger than
211  *      any real time associated with a transaction then comparisons in other
212  *      modules will still be correct. Let's use BIG_ABSTIME for this. tgl 2/14/97
213  *
214  *              Note:  I have no idea what the significance of the
215  *                         1073741823 in DisabledStartTime.. I just carried
216  *                         this over when converting things from the old
217  *                         V1 transaction system.  -cim 3/18/90
218  * ----------------
219  */
220 TransactionId DisabledTransactionId = (TransactionId) -1;
221
222 CommandId       DisabledCommandId = (CommandId) -1;
223
224 AbsoluteTime DisabledStartTime = (AbsoluteTime) BIG_ABSTIME;    /* 1073741823; */
225
226 /* ----------------
227  *              overflow flag
228  * ----------------
229  */
230 bool            CommandIdCounterOverflowFlag;
231
232 /* ----------------
233  *              catalog creation transaction bootstrapping flag.
234  *              This should be eliminated and added to the transaction
235  *              state stuff.  -cim 3/19/90
236  * ----------------
237  */
238 bool            AMI_OVERRIDE = false;
239
240 /* ----------------------------------------------------------------
241  *                                       transaction state accessors
242  * ----------------------------------------------------------------
243  */
244
245 /* --------------------------------
246  *              TranactionFlushEnabled()
247  *              SetTranactionFlushEnabled()
248  *
249  *              These are used to test and set the "TransactionFlushState"
250  *              varable.  If this variable is true (the default), then
251  *              the system will flush all dirty buffers to disk at the end
252  *              of each transaction.   If false then we are assuming the
253  *              buffer pool resides in stable main memory, in which case we
254  *              only do writes as necessary.
255  * --------------------------------
256  */
257 static int      TransactionFlushState = 1;
258
259 int
260 TransactionFlushEnabled(void)
261 {
262         return TransactionFlushState;
263 }
264
265 #ifdef NOT_USED
266 void
267 SetTransactionFlushEnabled(bool state)
268 {
269         TransactionFlushState = (state == true);
270 }
271
272
273 /* --------------------------------
274  *              IsTransactionState
275  *
276  *              This returns true if we are currently running a query
277  *              within an executing transaction.
278  * --------------------------------
279  */
280 bool
281 IsTransactionState(void)
282 {
283         TransactionState s = CurrentTransactionState;
284
285         switch (s->state)
286         {
287                 case TRANS_DEFAULT:
288                         return false;
289                 case TRANS_START:
290                         return true;
291                 case TRANS_INPROGRESS:
292                         return true;
293                 case TRANS_COMMIT:
294                         return true;
295                 case TRANS_ABORT:
296                         return true;
297                 case TRANS_DISABLED:
298                         return false;
299         }
300
301         /*
302          * Shouldn't get here, but lint is not happy with this...
303          */
304         return false;
305 }
306
307 #endif
308
309 /* --------------------------------
310  *              IsAbortedTransactionBlockState
311  *
312  *              This returns true if we are currently running a query
313  *              within an aborted transaction block.
314  * --------------------------------
315  */
316 bool
317 IsAbortedTransactionBlockState()
318 {
319         TransactionState s = CurrentTransactionState;
320
321         if (s->blockState == TBLOCK_ABORT)
322                 return true;
323
324         return false;
325 }
326
327 /* --------------------------------
328  *              OverrideTransactionSystem
329  *
330  *              This is used to temporarily disable the transaction
331  *              processing system in order to do initialization of
332  *              the transaction system data structures and relations
333  *              themselves.
334  * --------------------------------
335  */
336 int                     SavedTransactionState;
337
338 void
339 OverrideTransactionSystem(bool flag)
340 {
341         TransactionState s = CurrentTransactionState;
342
343         if (flag == true)
344         {
345                 if (s->state == TRANS_DISABLED)
346                         return;
347
348                 SavedTransactionState = s->state;
349                 s->state = TRANS_DISABLED;
350         }
351         else
352         {
353                 if (s->state != TRANS_DISABLED)
354                         return;
355
356                 s->state = SavedTransactionState;
357         }
358 }
359
360 /* --------------------------------
361  *              GetCurrentTransactionId
362  *
363  *              This returns the id of the current transaction, or
364  *              the id of the "disabled" transaction.
365  * --------------------------------
366  */
367 TransactionId
368 GetCurrentTransactionId()
369 {
370         TransactionState s = CurrentTransactionState;
371
372         /* ----------------
373          *      if the transaction system is disabled, we return
374          *      the special "disabled" transaction id.
375          * ----------------
376          */
377         if (s->state == TRANS_DISABLED)
378                 return (TransactionId) DisabledTransactionId;
379
380         /* ----------------
381          *      otherwise return the current transaction id.
382          * ----------------
383          */
384         return (TransactionId) s->transactionIdData;
385 }
386
387
388 /* --------------------------------
389  *              GetCurrentCommandId
390  * --------------------------------
391  */
392 CommandId
393 GetCurrentCommandId()
394 {
395         TransactionState s = CurrentTransactionState;
396
397         /* ----------------
398          *      if the transaction system is disabled, we return
399          *      the special "disabled" command id.
400          * ----------------
401          */
402         if (s->state == TRANS_DISABLED)
403                 return (CommandId) DisabledCommandId;
404
405         return s->commandId;
406 }
407
408 CommandId
409 GetScanCommandId()
410 {
411         TransactionState s = CurrentTransactionState;
412
413         /* ----------------
414          *      if the transaction system is disabled, we return
415          *      the special "disabled" command id.
416          * ----------------
417          */
418         if (s->state == TRANS_DISABLED)
419                 return (CommandId) DisabledCommandId;
420
421         return s->scanCommandId;
422 }
423
424
425 /* --------------------------------
426  *              GetCurrentTransactionStartTime
427  * --------------------------------
428  */
429 AbsoluteTime
430 GetCurrentTransactionStartTime()
431 {
432         TransactionState s = CurrentTransactionState;
433
434         /* ----------------
435          *      if the transaction system is disabled, we return
436          *      the special "disabled" starting time.
437          * ----------------
438          */
439         if (s->state == TRANS_DISABLED)
440                 return (AbsoluteTime) DisabledStartTime;
441
442         return s->startTime;
443 }
444
445
446 /* --------------------------------
447  *              TransactionIdIsCurrentTransactionId
448  * --------------------------------
449  */
450 bool
451 TransactionIdIsCurrentTransactionId(TransactionId xid)
452 {
453         TransactionState s = CurrentTransactionState;
454
455         if (AMI_OVERRIDE)
456                 return false;
457
458         return (bool)
459                 TransactionIdEquals(xid, s->transactionIdData);
460 }
461
462
463 /* --------------------------------
464  *              CommandIdIsCurrentCommandId
465  * --------------------------------
466  */
467 bool
468 CommandIdIsCurrentCommandId(CommandId cid)
469 {
470         TransactionState s = CurrentTransactionState;
471
472         if (AMI_OVERRIDE)
473                 return false;
474
475         return (cid == s->commandId) ? true : false;
476 }
477
478 bool
479 CommandIdGEScanCommandId(CommandId cid)
480 {
481         TransactionState s = CurrentTransactionState;
482
483         if (AMI_OVERRIDE)
484                 return false;
485
486         return (cid >= s->scanCommandId) ? true : false;
487 }
488
489
490 /* --------------------------------
491  *              ClearCommandIdCounterOverflowFlag
492  * --------------------------------
493  */
494 #ifdef NOT_USED
495 void
496 ClearCommandIdCounterOverflowFlag()
497 {
498         CommandIdCounterOverflowFlag = false;
499 }
500
501 #endif
502
503 /* --------------------------------
504  *              CommandCounterIncrement
505  * --------------------------------
506  */
507 void
508 CommandCounterIncrement()
509 {
510         CurrentTransactionStateData.commandId += 1;
511         if (CurrentTransactionStateData.commandId == FirstCommandId)
512         {
513                 CommandIdCounterOverflowFlag = true;
514                 elog(ERROR, "You may only have 2^32-1 commands per transaction");
515         }
516
517         CurrentTransactionStateData.scanCommandId = CurrentTransactionStateData.commandId;
518
519         /*
520          * make cache changes visible to me.  AtCommit_LocalCache() instead of
521          * AtCommit_Cache() is called here.
522          */
523         AtCommit_LocalCache();
524         AtStart_Cache();
525
526 }
527
528 void
529 SetScanCommandId(CommandId savedId)
530 {
531
532         CurrentTransactionStateData.scanCommandId = savedId;
533
534 }
535
536 /* ----------------------------------------------------------------
537  *                                              initialization stuff
538  * ----------------------------------------------------------------
539  */
540 void
541 InitializeTransactionSystem()
542 {
543         InitializeTransactionLog();
544 }
545
546 /* ----------------------------------------------------------------
547  *                                              StartTransaction stuff
548  * ----------------------------------------------------------------
549  */
550
551 /* --------------------------------
552  *              AtStart_Cache
553  * --------------------------------
554  */
555 static void
556 AtStart_Cache()
557 {
558         DiscardInvalid();
559 }
560
561 /* --------------------------------
562  *              AtStart_Locks
563  * --------------------------------
564  */
565 static void
566 AtStart_Locks()
567 {
568
569         /*
570          * at present, it is unknown to me what belongs here -cim 3/18/90
571          *
572          * There isn't anything to do at the start of a xact for locks. -mer
573          * 5/24/92
574          */
575 }
576
577 /* --------------------------------
578  *              AtStart_Memory
579  * --------------------------------
580  */
581 static void
582 AtStart_Memory()
583 {
584         Portal          portal;
585         MemoryContext portalContext;
586
587         /* ----------------
588          *      get the blank portal and its memory context
589          * ----------------
590          */
591         portal = GetPortalByName(NULL);
592         portalContext = (MemoryContext) PortalGetHeapMemory(portal);
593
594         /* ----------------
595          *      tell system to allocate in the blank portal context
596          * ----------------
597          */
598         MemoryContextSwitchTo(portalContext);
599         StartPortalAllocMode(DefaultAllocMode, 0);
600 }
601
602
603 /* ----------------------------------------------------------------
604  *                                              CommitTransaction stuff
605  * ----------------------------------------------------------------
606  */
607
608 /* --------------------------------
609  *              RecordTransactionCommit
610  *
611  *              Note: the two calls to BufferManagerFlush() exist to ensure
612  *                        that data pages are written before log pages.  These
613  *                        explicit calls should be replaced by a more efficient
614  *                        ordered page write scheme in the buffer manager
615  *                        -cim 3/18/90
616  * --------------------------------
617  */
618 static void
619 RecordTransactionCommit()
620 {
621         TransactionId xid;
622         int                     leak;
623
624         /* ----------------
625          *      get the current transaction id
626          * ----------------
627          */
628         xid = GetCurrentTransactionId();
629
630         /*
631          * flush the buffer manager pages.      Note: if we have stable main
632          * memory, dirty shared buffers are not flushed plai 8/7/90
633          */
634         leak = BufferPoolCheckLeak();
635
636         /*
637          * If no one shared buffer was changed by this transaction then we
638          * don't flush shared buffers and don't record commit status.
639          */
640         if (SharedBufferChanged)
641         {
642                 FlushBufferPool();
643                 if (leak)
644                         ResetBufferPool(true);
645
646                 /*
647                  * have the transaction access methods record the status of this
648                  * transaction id in the pg_log relation.
649                  */
650                 TransactionIdCommit(xid);
651
652                 /*
653                  * Now write the log info to the disk too.
654                  */
655                 leak = BufferPoolCheckLeak();
656                 FlushBufferPool();
657         }
658
659         if (leak)
660                 ResetBufferPool(true);
661 }
662
663
664 /* --------------------------------
665  *              AtCommit_Cache
666  * --------------------------------
667  */
668 static void
669 AtCommit_Cache()
670 {
671         /* ----------------
672          * Make catalog changes visible to all backend.
673          * ----------------
674          */
675         RegisterInvalid(true);
676 }
677
678 /* --------------------------------
679  *              AtCommit_LocalCache
680  * --------------------------------
681  */
682 static void
683 AtCommit_LocalCache()
684 {
685         /* ----------------
686          * Make catalog changes visible to me for the next command.
687          * ----------------
688          */
689         ImmediateLocalInvalidation(true);
690 }
691
692 /* --------------------------------
693  *              AtCommit_Locks
694  * --------------------------------
695  */
696 static void
697 AtCommit_Locks()
698 {
699         /* ----------------
700          *      XXX What if ProcReleaseLocks fails?  (race condition?)
701          *
702          *      Then you're up a creek! -mer 5/24/92
703          * ----------------
704          */
705         ProcReleaseLocks();
706 }
707
708 /* --------------------------------
709  *              AtCommit_Memory
710  * --------------------------------
711  */
712 static void
713 AtCommit_Memory()
714 {
715         Portal          portal;
716
717         /* ----------------
718          *      Release all heap memory in the blank portal.
719          * ----------------
720          */
721         portal = GetPortalByName(NULL);
722         PortalResetHeapMemory(portal);
723
724         /* ----------------
725          *      Now that we're "out" of a transaction, have the
726          *      system allocate things in the top memory context instead
727          *      of the blank portal memory context.
728          * ----------------
729          */
730         MemoryContextSwitchTo(TopMemoryContext);
731 }
732
733 /* ----------------------------------------------------------------
734  *                                              AbortTransaction stuff
735  * ----------------------------------------------------------------
736  */
737
738 /* --------------------------------
739  *              RecordTransactionAbort
740  * --------------------------------
741  */
742 static void
743 RecordTransactionAbort()
744 {
745         TransactionId xid;
746
747         /* ----------------
748          *      get the current transaction id
749          * ----------------
750          */
751         xid = GetCurrentTransactionId();
752
753         /*
754          * Have the transaction access methods record the status of this
755          * transaction id in the pg_log relation. We skip it if no one shared
756          * buffer was changed by this transaction.
757          */
758         if (SharedBufferChanged && !TransactionIdDidCommit(xid))
759                 TransactionIdAbort(xid);
760
761         /*
762          * Tell bufmgr and smgr to release resources.
763          */
764         ResetBufferPool(false);         /* false -> is abort */
765 }
766
767 /* --------------------------------
768  *              AtAbort_Cache
769  * --------------------------------
770  */
771 static void
772 AtAbort_Cache()
773 {
774         RelationCacheAbort();
775         RegisterInvalid(false);
776 }
777
778 /* --------------------------------
779  *              AtAbort_Locks
780  * --------------------------------
781  */
782 static void
783 AtAbort_Locks()
784 {
785         /* ----------------
786          *      XXX What if ProcReleaseLocks() fails?  (race condition?)
787          *
788          *      Then you're up a creek without a paddle! -mer
789          * ----------------
790          */
791         ProcReleaseLocks();
792 }
793
794
795 /* --------------------------------
796  *              AtAbort_Memory
797  * --------------------------------
798  */
799 static void
800 AtAbort_Memory()
801 {
802         Portal          portal;
803
804         /* ----------------
805          *      Release all heap memory in the blank portal.
806          * ----------------
807          */
808         portal = GetPortalByName(NULL);
809         PortalResetHeapMemory(portal);
810
811         /* ----------------
812          *      Now that we're "out" of a transaction, have the
813          *      system allocate things in the top memory context instead
814          *      of the blank portal memory context.
815          * ----------------
816          */
817         MemoryContextSwitchTo(TopMemoryContext);
818 }
819
820 /* ----------------------------------------------------------------
821  *                                              interface routines
822  * ----------------------------------------------------------------
823  */
824
825 /* --------------------------------
826  *              StartTransaction
827  *
828  * --------------------------------
829  */
830 static void
831 StartTransaction()
832 {
833         TransactionState s = CurrentTransactionState;
834
835         FreeXactSnapshot();
836         XactIsoLevel = DefaultXactIsoLevel;
837
838         /* ----------------
839          *      Check the current transaction state.  If the transaction system
840          *      is switched off, or if we're already in a transaction, do nothing.
841          *      We're already in a transaction when the monitor sends a null
842          *      command to the backend to flush the comm channel.  This is a
843          *      hacky fix to a communications problem, and we keep having to
844          *      deal with it here.      We should fix the comm channel code.  mao 080891
845          * ----------------
846          */
847         if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
848                 return;
849
850         /* ----------------
851          *      set the current transaction state information
852          *      appropriately during start processing
853          * ----------------
854          */
855         s->state = TRANS_START;
856
857         SetReindexProcessing(false);
858         /* ----------------
859          *      generate a new transaction id
860          * ----------------
861          */
862         GetNewTransactionId(&(s->transactionIdData));
863
864         XactLockTableInsert(s->transactionIdData);
865
866         /* ----------------
867          *      initialize current transaction state fields
868          * ----------------
869          */
870         s->commandId = FirstCommandId;
871         s->scanCommandId = FirstCommandId;
872         s->startTime = GetCurrentAbsoluteTime();
873
874         /* ----------------
875          *      initialize the various transaction subsystems
876          * ----------------
877          */
878         AtStart_Cache();
879         AtStart_Locks();
880         AtStart_Memory();
881
882         /* --------------
883            initialize temporary relations list
884            the tempRelList is a list of temporary relations that
885            are created in the course of the transactions
886            they need to be destroyed properly at the end of the transactions
887          */
888         InitNoNameRelList();
889
890         /* ----------------
891          *      Tell the trigger manager to we're starting a transaction
892          * ----------------
893          */
894         DeferredTriggerBeginXact();
895
896         /* ----------------
897          *      done with start processing, set current transaction
898          *      state to "in progress"
899          * ----------------
900          */
901         s->state = TRANS_INPROGRESS;
902
903 }
904
905 /* ---------------
906  * Tell me if we are currently in progress
907  * ---------------
908  */
909 bool
910 CurrentXactInProgress()
911 {
912         return CurrentTransactionState->state == TRANS_INPROGRESS;
913 }
914
915 /* --------------------------------
916  *              CommitTransaction
917  *
918  * --------------------------------
919  */
920 static void
921 CommitTransaction()
922 {
923         TransactionState s = CurrentTransactionState;
924
925         /* ----------------
926          *      check the current transaction state
927          * ----------------
928          */
929         if (s->state == TRANS_DISABLED)
930                 return;
931
932         if (s->state != TRANS_INPROGRESS)
933                 elog(NOTICE, "CommitTransaction and not in in-progress state ");
934
935         /* ----------------
936          *      Tell the trigger manager that this transaction is about to be
937          *      committed. He'll invoke all trigger deferred until XACT before
938          *      we really start on committing the transaction.
939          * ----------------
940          */
941         DeferredTriggerEndXact();
942
943         /* ----------------
944          *      set the current transaction state information
945          *      appropriately during the abort processing
946          * ----------------
947          */
948         s->state = TRANS_COMMIT;
949
950         /* ----------------
951          *      do commit processing
952          * ----------------
953          */
954
955         /* handle commit for large objects [ PA, 7/17/98 ] */
956         lo_commit(true);
957
958         /* NOTIFY commit must also come before lower-level cleanup */
959         AtCommit_Notify();
960
961         CloseSequences();
962         DropNoNameRels();
963         AtEOXact_portals();
964         RecordTransactionCommit();
965
966         /*
967          * Let others know about no transaction in progress by me. Note that
968          * this must be done _before_ releasing locks we hold and
969          * SpinAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked
970          * by xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot -
971          * if xid 2' GetSnapshotData sees xid 1 as running then it must see
972          * xid 0 as running as well or it will see two tuple versions - one
973          * deleted by xid 1 and one inserted by xid 0.
974          */
975         if (MyProc != (PROC *) NULL)
976         {
977                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
978                 SpinAcquire(SInvalLock);
979                 MyProc->xid = InvalidTransactionId;
980                 MyProc->xmin = InvalidTransactionId;
981                 SpinRelease(SInvalLock);
982         }
983
984         RelationPurgeLocalRelation(true);
985         AtEOXact_nbtree();
986         AtCommit_Cache();
987         AtCommit_Locks();
988         AtCommit_Memory();
989         AtEOXact_Files();
990
991         /* ----------------
992          *      done with commit processing, set current transaction
993          *      state back to default
994          * ----------------
995          */
996         s->state = TRANS_DEFAULT;
997         SharedBufferChanged = false;/* safest place to do it */
998
999 }
1000
1001 /* --------------------------------
1002  *              AbortTransaction
1003  *
1004  * --------------------------------
1005  */
1006 static void
1007 AbortTransaction()
1008 {
1009         TransactionState s = CurrentTransactionState;
1010
1011         /*
1012          * Let others to know about no transaction in progress - vadim
1013          * 11/26/96
1014          */
1015         if (MyProc != (PROC *) NULL)
1016         {
1017                 MyProc->xid = InvalidTransactionId;
1018                 MyProc->xmin = InvalidTransactionId;
1019         }
1020
1021         /* ----------------
1022          *      check the current transaction state
1023          * ----------------
1024          */
1025         if (s->state == TRANS_DISABLED)
1026                 return;
1027
1028         if (s->state != TRANS_INPROGRESS)
1029                 elog(NOTICE, "AbortTransaction and not in in-progress state ");
1030
1031         /* ----------------
1032          *      Tell the trigger manager that this transaction is about to be
1033          *      aborted.
1034          * ----------------
1035          */
1036         DeferredTriggerAbortXact();
1037
1038         /* ----------------
1039          *      set the current transaction state information
1040          *      appropriately during the abort processing
1041          * ----------------
1042          */
1043         s->state = TRANS_ABORT;
1044
1045         /* ----------------
1046          *      do abort processing
1047          * ----------------
1048          */
1049         lo_commit(false);                       /* 'false' means it's abort */
1050         UnlockBuffers();
1051         AtAbort_Notify();
1052         CloseSequences();
1053         AtEOXact_portals();
1054         if (CommonSpecialPortalIsOpen())
1055                 CommonSpecialPortalClose();
1056         RecordTransactionAbort();
1057         RelationPurgeLocalRelation(false);
1058         DropNoNameRels();
1059         invalidate_temp_relations();
1060         AtEOXact_nbtree();
1061         AtAbort_Cache();
1062         AtAbort_Locks();
1063         AtAbort_Memory();
1064         AtEOXact_Files();
1065
1066         /* ----------------
1067          *      done with abort processing, set current transaction
1068          *      state back to default
1069          * ----------------
1070          */
1071         s->state = TRANS_DEFAULT;
1072         SharedBufferChanged = false;/* safest place to do it */
1073 }
1074
1075 /* --------------------------------
1076  *              StartTransactionCommand
1077  * --------------------------------
1078  */
1079 void
1080 StartTransactionCommand()
1081 {
1082         TransactionState s = CurrentTransactionState;
1083
1084         switch (s->blockState)
1085         {
1086                         /* ----------------
1087                          *              if we aren't in a transaction block, we
1088                          *              just do our usual start transaction.
1089                          * ----------------
1090                          */
1091                 case TBLOCK_DEFAULT:
1092                         StartTransaction();
1093                         break;
1094
1095                         /* ----------------
1096                          *              We should never experience this -- if we do it
1097                          *              means the BEGIN state was not changed in the previous
1098                          *              CommitTransactionCommand().  If we get it, we print
1099                          *              a warning and change to the in-progress state.
1100                          * ----------------
1101                          */
1102                 case TBLOCK_BEGIN:
1103                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1104                         s->blockState = TBLOCK_INPROGRESS;
1105                         break;
1106
1107                         /* ----------------
1108                          *              This is the case when are somewhere in a transaction
1109                          *              block and about to start a new command.  For now we
1110                          *              do nothing but someday we may do command-local resource
1111                          *              initialization.
1112                          * ----------------
1113                          */
1114                 case TBLOCK_INPROGRESS:
1115                         break;
1116
1117                         /* ----------------
1118                          *              As with BEGIN, we should never experience this
1119                          *              if we do it means the END state was not changed in the
1120                          *              previous CommitTransactionCommand().  If we get it, we
1121                          *              print a warning, commit the transaction, start a new
1122                          *              transaction and change to the default state.
1123                          * ----------------
1124                          */
1125                 case TBLOCK_END:
1126                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
1127                         s->blockState = TBLOCK_DEFAULT;
1128                         CommitTransaction();
1129                         StartTransaction();
1130                         break;
1131
1132                         /* ----------------
1133                          *              Here we are in the middle of a transaction block but
1134                          *              one of the commands caused an abort so we do nothing
1135                          *              but remain in the abort state.  Eventually we will get
1136                          *              to the "END TRANSACTION" which will set things straight.
1137                          * ----------------
1138                          */
1139                 case TBLOCK_ABORT:
1140                         break;
1141
1142                         /* ----------------
1143                          *              This means we somehow aborted and the last call to
1144                          *              CommitTransactionCommand() didn't clear the state so
1145                          *              we remain in the ENDABORT state and mabey next time
1146                          *              we get to CommitTransactionCommand() the state will
1147                          *              get reset to default.
1148                          * ----------------
1149                          */
1150                 case TBLOCK_ENDABORT:
1151                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1152                         break;
1153         }
1154 }
1155
1156 /* --------------------------------
1157  *              CommitTransactionCommand
1158  * --------------------------------
1159  */
1160 void
1161 CommitTransactionCommand()
1162 {
1163         TransactionState s = CurrentTransactionState;
1164
1165         switch (s->blockState)
1166         {
1167                         /* ----------------
1168                          *              if we aren't in a transaction block, we
1169                          *              just do our usual transaction commit
1170                          * ----------------
1171                          */
1172                 case TBLOCK_DEFAULT:
1173                         CommitTransaction();
1174                         break;
1175
1176                         /* ----------------
1177                          *              This is the case right after we get a "BEGIN TRANSACTION"
1178                          *              command, but the user hasn't done anything else yet, so
1179                          *              we change to the "transaction block in progress" state
1180                          *              and return.
1181                          * ----------------
1182                          */
1183                 case TBLOCK_BEGIN:
1184                         s->blockState = TBLOCK_INPROGRESS;
1185                         break;
1186
1187                         /* ----------------
1188                          *              This is the case when we have finished executing a command
1189                          *              someplace within a transaction block.  We increment the
1190                          *              command counter and return.  Someday we may free resources
1191                          *              local to the command.
1192                          *
1193                          *              That someday is today, at least for memory allocated by
1194                          *              command in the BlankPortal' HeapMemory context.
1195                          *                              - vadim 03/25/97
1196                          * ----------------
1197                          */
1198                 case TBLOCK_INPROGRESS:
1199                         CommandCounterIncrement();
1200 #ifdef TBL_FREE_CMD_MEMORY
1201                         EndPortalAllocMode();
1202                         StartPortalAllocMode(DefaultAllocMode, 0);
1203 #endif
1204                         break;
1205
1206                         /* ----------------
1207                          *              This is the case when we just got the "END TRANSACTION"
1208                          *              statement, so we go back to the default state and
1209                          *              commit the transaction.
1210                          * ----------------
1211                          */
1212                 case TBLOCK_END:
1213                         s->blockState = TBLOCK_DEFAULT;
1214                         CommitTransaction();
1215                         break;
1216
1217                         /* ----------------
1218                          *              Here we are in the middle of a transaction block but
1219                          *              one of the commands caused an abort so we do nothing
1220                          *              but remain in the abort state.  Eventually we will get
1221                          *              to the "END TRANSACTION" which will set things straight.
1222                          * ----------------
1223                          */
1224                 case TBLOCK_ABORT:
1225                         break;
1226
1227                         /* ----------------
1228                          *              Here we were in an aborted transaction block which
1229                          *              just processed the "END TRANSACTION" command from the
1230                          *              user, so now we return the to default state.
1231                          * ----------------
1232                          */
1233                 case TBLOCK_ENDABORT:
1234                         s->blockState = TBLOCK_DEFAULT;
1235                         break;
1236         }
1237 }
1238
1239 /* --------------------------------
1240  *              AbortCurrentTransaction
1241  * --------------------------------
1242  */
1243 void
1244 AbortCurrentTransaction()
1245 {
1246         TransactionState s = CurrentTransactionState;
1247
1248         switch (s->blockState)
1249         {
1250                         /* ----------------
1251                          *              if we aren't in a transaction block, we
1252                          *              just do our usual abort transaction.
1253                          * ----------------
1254                          */
1255                 case TBLOCK_DEFAULT:
1256                         AbortTransaction();
1257                         break;
1258
1259                         /* ----------------
1260                          *              If we are in the TBLOCK_BEGIN it means something
1261                          *              screwed up right after reading "BEGIN TRANSACTION"
1262                          *              so we enter the abort state.  Eventually an "END
1263                          *              TRANSACTION" will fix things.
1264                          * ----------------
1265                          */
1266                 case TBLOCK_BEGIN:
1267                         s->blockState = TBLOCK_ABORT;
1268                         AbortTransaction();
1269                         break;
1270
1271                         /* ----------------
1272                          *              This is the case when are somewhere in a transaction
1273                          *              block which aborted so we abort the transaction and
1274                          *              set the ABORT state.  Eventually an "END TRANSACTION"
1275                          *              will fix things and restore us to a normal state.
1276                          * ----------------
1277                          */
1278                 case TBLOCK_INPROGRESS:
1279                         s->blockState = TBLOCK_ABORT;
1280                         AbortTransaction();
1281                         break;
1282
1283                         /* ----------------
1284                          *              Here, the system was fouled up just after the
1285                          *              user wanted to end the transaction block so we
1286                          *              abort the transaction and put us back into the
1287                          *              default state.
1288                          * ----------------
1289                          */
1290                 case TBLOCK_END:
1291                         s->blockState = TBLOCK_DEFAULT;
1292                         AbortTransaction();
1293                         break;
1294
1295                         /* ----------------
1296                          *              Here, we are already in an aborted transaction
1297                          *              state and are waiting for an "END TRANSACTION" to
1298                          *              come along and lo and behold, we abort again!
1299                          *              So we just remain in the abort state.
1300                          * ----------------
1301                          */
1302                 case TBLOCK_ABORT:
1303                         break;
1304
1305                         /* ----------------
1306                          *              Here we were in an aborted transaction block which
1307                          *              just processed the "END TRANSACTION" command but somehow
1308                          *              aborted again.. since we must have done the abort
1309                          *              processing, we return to the default state.
1310                          * ----------------
1311                          */
1312                 case TBLOCK_ENDABORT:
1313                         s->blockState = TBLOCK_DEFAULT;
1314                         break;
1315         }
1316 }
1317
1318 /* ----------------------------------------------------------------
1319  *                                         transaction block support
1320  * ----------------------------------------------------------------
1321  */
1322 /* --------------------------------
1323  *              BeginTransactionBlock
1324  * --------------------------------
1325  */
1326 void
1327 BeginTransactionBlock(void)
1328 {
1329         TransactionState s = CurrentTransactionState;
1330
1331         /* ----------------
1332          *      check the current transaction state
1333          * ----------------
1334          */
1335         if (s->state == TRANS_DISABLED)
1336                 return;
1337
1338         if (s->blockState != TBLOCK_DEFAULT)
1339                 elog(NOTICE, "BEGIN: already a transaction in progress");
1340
1341         /* ----------------
1342          *      set the current transaction block state information
1343          *      appropriately during begin processing
1344          * ----------------
1345          */
1346         s->blockState = TBLOCK_BEGIN;
1347
1348         /* ----------------
1349          *      do begin processing
1350          * ----------------
1351          */
1352
1353         /* ----------------
1354          *      done with begin processing, set block state to inprogress
1355          * ----------------
1356          */
1357         s->blockState = TBLOCK_INPROGRESS;
1358 }
1359
1360 /* --------------------------------
1361  *              EndTransactionBlock
1362  * --------------------------------
1363  */
1364 void
1365 EndTransactionBlock(void)
1366 {
1367         TransactionState s = CurrentTransactionState;
1368
1369         /* ----------------
1370          *      check the current transaction state
1371          * ----------------
1372          */
1373         if (s->state == TRANS_DISABLED)
1374                 return;
1375
1376         if (s->blockState == TBLOCK_INPROGRESS)
1377         {
1378                 /* ----------------
1379                  *      here we are in a transaction block which should commit
1380                  *      when we get to the upcoming CommitTransactionCommand()
1381                  *      so we set the state to "END".  CommitTransactionCommand()
1382                  *      will recognize this and commit the transaction and return
1383                  *      us to the default state
1384                  * ----------------
1385                  */
1386                 s->blockState = TBLOCK_END;
1387                 return;
1388         }
1389
1390         if (s->blockState == TBLOCK_ABORT)
1391         {
1392                 /* ----------------
1393                  *      here, we are in a transaction block which aborted
1394                  *      and since the AbortTransaction() was already done,
1395                  *      we do whatever is needed and change to the special
1396                  *      "END ABORT" state.      The upcoming CommitTransactionCommand()
1397                  *      will recognise this and then put us back in the default
1398                  *      state.
1399                  * ----------------
1400                  */
1401                 s->blockState = TBLOCK_ENDABORT;
1402                 return;
1403         }
1404
1405         /* ----------------
1406          *      We should not get here, but if we do, we go to the ENDABORT
1407          *      state after printing a warning.  The upcoming call to
1408          *      CommitTransactionCommand() will then put us back into the
1409          *      default state.
1410          * ----------------
1411          */
1412         elog(NOTICE, "COMMIT: no transaction in progress");
1413         s->blockState = TBLOCK_ENDABORT;
1414 }
1415
1416 /* --------------------------------
1417  *              AbortTransactionBlock
1418  * --------------------------------
1419  */
1420 #ifdef NOT_USED
1421 static void
1422 AbortTransactionBlock(void)
1423 {
1424         TransactionState s = CurrentTransactionState;
1425
1426         /* ----------------
1427          *      check the current transaction state
1428          * ----------------
1429          */
1430         if (s->state == TRANS_DISABLED)
1431                 return;
1432
1433         if (s->blockState == TBLOCK_INPROGRESS)
1434         {
1435                 /* ----------------
1436                  *      here we were inside a transaction block something
1437                  *      screwed up inside the system so we enter the abort state,
1438                  *      do the abort processing and then return.
1439                  *      We remain in the abort state until we see the upcoming
1440                  *      END TRANSACTION command.
1441                  * ----------------
1442                  */
1443                 s->blockState = TBLOCK_ABORT;
1444
1445                 /* ----------------
1446                  *      do abort processing and return
1447                  * ----------------
1448                  */
1449                 AbortTransaction();
1450                 return;
1451         }
1452
1453         /* ----------------
1454          *      this case should not be possible, because it would mean
1455          *      the user entered an "abort" from outside a transaction block.
1456          *      So we print an error message, abort the transaction and
1457          *      enter the "ENDABORT" state so we will end up in the default
1458          *      state after the upcoming CommitTransactionCommand().
1459          * ----------------
1460          */
1461         elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
1462         AbortTransaction();
1463         s->blockState = TBLOCK_ENDABORT;
1464 }
1465
1466 #endif
1467
1468 /* --------------------------------
1469  *              UserAbortTransactionBlock
1470  * --------------------------------
1471  */
1472 void
1473 UserAbortTransactionBlock()
1474 {
1475         TransactionState s = CurrentTransactionState;
1476
1477         /* ----------------
1478          *      check the current transaction state
1479          * ----------------
1480          */
1481         if (s->state == TRANS_DISABLED)
1482                 return;
1483
1484         /*
1485          * if the transaction has already been automatically aborted with an
1486          * error, and the user subsequently types 'abort', allow it.  (the
1487          * behavior is the same as if they had typed 'end'.)
1488          */
1489         if (s->blockState == TBLOCK_ABORT)
1490         {
1491                 s->blockState = TBLOCK_ENDABORT;
1492                 return;
1493         }
1494
1495         if (s->blockState == TBLOCK_INPROGRESS)
1496         {
1497                 /* ----------------
1498                  *      here we were inside a transaction block and we
1499                  *      got an abort command from the user, so we move to
1500                  *      the abort state, do the abort processing and
1501                  *      then change to the ENDABORT state so we will end up
1502                  *      in the default state after the upcoming
1503                  *      CommitTransactionCommand().
1504                  * ----------------
1505                  */
1506                 s->blockState = TBLOCK_ABORT;
1507
1508                 /* ----------------
1509                  *      do abort processing
1510                  * ----------------
1511                  */
1512                 AbortTransaction();
1513
1514                 /* ----------------
1515                  *      change to the end abort state and return
1516                  * ----------------
1517                  */
1518                 s->blockState = TBLOCK_ENDABORT;
1519                 return;
1520         }
1521
1522         /* ----------------
1523          *      this case should not be possible, because it would mean
1524          *      the user entered a "rollback" from outside a transaction block.
1525          *      So we print an error message, abort the transaction and
1526          *      enter the "ENDABORT" state so we will end up in the default
1527          *      state after the upcoming CommitTransactionCommand().
1528          * ----------------
1529          */
1530         elog(NOTICE, "ROLLBACK: no transaction in progress");
1531         AbortTransaction();
1532         s->blockState = TBLOCK_ENDABORT;
1533 }
1534
1535 /* --------------------------------
1536  *              AbortOutOfAnyTransaction
1537  *
1538  * This routine is provided for error recovery purposes.  It aborts any
1539  * active transaction or transaction block, leaving the system in a known
1540  * idle state.
1541  * --------------------------------
1542  */
1543 void
1544 AbortOutOfAnyTransaction()
1545 {
1546         TransactionState s = CurrentTransactionState;
1547
1548         /*
1549          * Get out of any low-level transaction
1550          */
1551         if (s->state != TRANS_DEFAULT)
1552                 AbortTransaction();
1553
1554         /*
1555          * Now reset the high-level state
1556          */
1557         s->blockState = TBLOCK_DEFAULT;
1558 }
1559
1560 bool
1561 IsTransactionBlock()
1562 {
1563         TransactionState s = CurrentTransactionState;
1564
1565         if (s->blockState == TBLOCK_INPROGRESS
1566                 || s->blockState == TBLOCK_ABORT
1567                 || s->blockState == TBLOCK_ENDABORT)
1568                 return true;
1569
1570         return false;
1571 }