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