]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xact.c
Implement reindex command
[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.61 2000/02/18 09:30:20 inoue 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         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()
520          * instead of 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
631          *      main memory, dirty shared buffers are not flushed
632          *      plai 8/7/90
633          */
634         leak = BufferPoolCheckLeak();
635
636         /*
637          * If no one shared buffer was changed by this transaction then
638          * we don't flush shared buffers and don't record commit status.
639          */
640         if (SharedBufferChanged)
641         {
642                 FlushBufferPool();
643                 if (leak)
644                         ResetBufferPool();
645
646                 /*
647                  *      have the transaction access methods record the status
648                  *      of this 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();
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
755          * this transaction id in the pg_log relation. We skip it
756          * if no one shared buffer was changed by this transaction.
757          */
758         if (SharedBufferChanged && !TransactionIdDidCommit(xid))
759                 TransactionIdAbort(xid);
760
761         ResetBufferPool();
762 }
763
764 /* --------------------------------
765  *              AtAbort_Cache
766  * --------------------------------
767  */
768 static void
769 AtAbort_Cache()
770 {
771         RelationCacheAbort();
772         RegisterInvalid(false);
773 }
774
775 /* --------------------------------
776  *              AtAbort_Locks
777  * --------------------------------
778  */
779 static void
780 AtAbort_Locks()
781 {
782         /* ----------------
783          *      XXX What if ProcReleaseLocks() fails?  (race condition?)
784          *
785          *      Then you're up a creek without a paddle! -mer
786          * ----------------
787          */
788         ProcReleaseLocks();
789 }
790
791
792 /* --------------------------------
793  *              AtAbort_Memory
794  * --------------------------------
795  */
796 static void
797 AtAbort_Memory()
798 {
799         Portal          portal;
800
801         /* ----------------
802          *      Release all heap memory in the blank portal.
803          * ----------------
804          */
805         portal = GetPortalByName(NULL);
806         PortalResetHeapMemory(portal);
807
808         /* ----------------
809          *      Now that we're "out" of a transaction, have the
810          *      system allocate things in the top memory context instead
811          *      of the blank portal memory context.
812          * ----------------
813          */
814         MemoryContextSwitchTo(TopMemoryContext);
815 }
816
817 /* ----------------------------------------------------------------
818  *                                              interface routines
819  * ----------------------------------------------------------------
820  */
821
822 /* --------------------------------
823  *              StartTransaction
824  *
825  * --------------------------------
826  */
827 static void
828 StartTransaction()
829 {
830         TransactionState s = CurrentTransactionState;
831
832         FreeXactSnapshot();
833         XactIsoLevel = DefaultXactIsoLevel;
834
835         /* ----------------
836          *      Check the current transaction state.  If the transaction system
837          *      is switched off, or if we're already in a transaction, do nothing.
838          *      We're already in a transaction when the monitor sends a null
839          *      command to the backend to flush the comm channel.  This is a
840          *      hacky fix to a communications problem, and we keep having to
841          *      deal with it here.      We should fix the comm channel code.  mao 080891
842          * ----------------
843          */
844         if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
845                 return;
846
847         /* ----------------
848          *      set the current transaction state information
849          *      appropriately during start processing
850          * ----------------
851          */
852         s->state = TRANS_START;
853
854         SetReindexProcessing(false);
855         /* ----------------
856          *      generate a new transaction id
857          * ----------------
858          */
859         GetNewTransactionId(&(s->transactionIdData));
860
861         XactLockTableInsert(s->transactionIdData);
862
863         /* ----------------
864          *      initialize current transaction state fields
865          * ----------------
866          */
867         s->commandId = FirstCommandId;
868         s->scanCommandId = FirstCommandId;
869         s->startTime = GetCurrentAbsoluteTime();
870
871         /* ----------------
872          *      initialize the various transaction subsystems
873          * ----------------
874          */
875         AtStart_Cache();
876         AtStart_Locks();
877         AtStart_Memory();
878
879         /* --------------
880            initialize temporary relations list
881            the tempRelList is a list of temporary relations that
882            are created in the course of the transactions
883            they need to be destroyed properly at the end of the transactions
884          */
885         InitNoNameRelList();
886
887         /* ----------------
888          *      Tell the trigger manager to we're starting a transaction
889          * ----------------
890          */
891         DeferredTriggerBeginXact();
892
893         /* ----------------
894          *      done with start processing, set current transaction
895          *      state to "in progress"
896          * ----------------
897          */
898         s->state = TRANS_INPROGRESS;
899
900 }
901
902 /* ---------------
903  * Tell me if we are currently in progress
904  * ---------------
905  */
906 bool
907 CurrentXactInProgress()
908 {
909         return CurrentTransactionState->state == TRANS_INPROGRESS;
910 }
911
912 /* --------------------------------
913  *              CommitTransaction
914  *
915  * --------------------------------
916  */
917 static void
918 CommitTransaction()
919 {
920         TransactionState s = CurrentTransactionState;
921
922         /* ----------------
923          *      check the current transaction state
924          * ----------------
925          */
926         if (s->state == TRANS_DISABLED)
927                 return;
928
929         if (s->state != TRANS_INPROGRESS)
930                 elog(NOTICE, "CommitTransaction and not in in-progress state ");
931
932         /* ----------------
933          *      Tell the trigger manager that this transaction is about to be
934          *      committed. He'll invoke all trigger deferred until XACT before
935          *      we really start on committing the transaction. 
936          * ----------------
937          */
938         DeferredTriggerEndXact();
939
940         /* ----------------
941          *      set the current transaction state information
942          *      appropriately during the abort processing
943          * ----------------
944          */
945         s->state = TRANS_COMMIT;
946
947         /* ----------------
948          *      do commit processing
949          * ----------------
950          */
951
952         /* handle commit for large objects [ PA, 7/17/98 ] */
953         lo_commit(true);
954
955         /* NOTIFY commit must also come before lower-level cleanup */
956         AtCommit_Notify();
957
958         CloseSequences();
959         DropNoNameRels();
960         AtEOXact_portals();
961         RecordTransactionCommit();
962
963         /*
964          * Let others know about no transaction in progress by me.
965          * Note that this must be done _before_ releasing locks we hold 
966          * and SpinAcquire(SInvalLock) is required: UPDATE with xid 0 is 
967          * blocked by xid 1' UPDATE, xid 1 is doing commit while xid 2 
968          * gets snapshot - if xid 2' GetSnapshotData sees xid 1 as running
969          * then it must see xid 0 as running as well or it will see two
970          * tuple versions - one deleted by xid 1 and one inserted by xid 0.
971          */
972         if (MyProc != (PROC *) NULL)
973         {
974                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
975                 SpinAcquire(SInvalLock);
976                 MyProc->xid = InvalidTransactionId;
977                 MyProc->xmin = InvalidTransactionId;
978                 SpinRelease(SInvalLock);
979         }
980
981         RelationPurgeLocalRelation(true);
982         AtEOXact_nbtree();
983         AtCommit_Cache();
984         AtCommit_Locks();
985         AtCommit_Memory();
986         AtEOXact_Files();
987
988         /* ----------------
989          *      done with commit processing, set current transaction
990          *      state back to default
991          * ----------------
992          */
993         s->state = TRANS_DEFAULT;
994         SharedBufferChanged = false;    /* safest place to do it */
995
996 }
997
998 /* --------------------------------
999  *              AbortTransaction
1000  *
1001  * --------------------------------
1002  */
1003 static void
1004 AbortTransaction()
1005 {
1006         TransactionState s = CurrentTransactionState;
1007
1008         /*
1009          * Let others to know about no transaction in progress - vadim
1010          * 11/26/96
1011          */
1012         if (MyProc != (PROC *) NULL)
1013         {
1014                 MyProc->xid = InvalidTransactionId;
1015                 MyProc->xmin = InvalidTransactionId;
1016         }
1017
1018         /* ----------------
1019          *      check the current transaction state
1020          * ----------------
1021          */
1022         if (s->state == TRANS_DISABLED)
1023                 return;
1024
1025         if (s->state != TRANS_INPROGRESS)
1026                 elog(NOTICE, "AbortTransaction and not in in-progress state ");
1027
1028         /* ----------------
1029          *      Tell the trigger manager that this transaction is about to be
1030          *      aborted. 
1031          * ----------------
1032          */
1033         DeferredTriggerAbortXact();
1034
1035         /* ----------------
1036          *      set the current transaction state information
1037          *      appropriately during the abort processing
1038          * ----------------
1039          */
1040         s->state = TRANS_ABORT;
1041
1042         /* ----------------
1043          *      do abort processing
1044          * ----------------
1045          */
1046         lo_commit(false);                       /* 'false' means it's abort */
1047         UnlockBuffers();
1048         AtAbort_Notify();
1049         CloseSequences();
1050         AtEOXact_portals();
1051         if (CommonSpecialPortalIsOpen())
1052                 CommonSpecialPortalClose();
1053         RecordTransactionAbort();
1054         RelationPurgeLocalRelation(false);
1055         DropNoNameRels();
1056         invalidate_temp_relations();
1057         AtEOXact_nbtree();
1058         AtAbort_Cache();
1059         AtAbort_Locks();
1060         AtAbort_Memory();
1061         AtEOXact_Files();
1062
1063         /* ----------------
1064          *      done with abort processing, set current transaction
1065          *      state back to default
1066          * ----------------
1067          */
1068         s->state = TRANS_DEFAULT;
1069         SharedBufferChanged = false;    /* safest place to do it */
1070 }
1071
1072 /* --------------------------------
1073  *              StartTransactionCommand
1074  * --------------------------------
1075  */
1076 void
1077 StartTransactionCommand()
1078 {
1079         TransactionState s = CurrentTransactionState;
1080
1081         switch (s->blockState)
1082         {
1083                         /* ----------------
1084                          *              if we aren't in a transaction block, we
1085                          *              just do our usual start transaction.
1086                          * ----------------
1087                          */
1088                 case TBLOCK_DEFAULT:
1089                         StartTransaction();
1090                         break;
1091
1092                         /* ----------------
1093                          *              We should never experience this -- if we do it
1094                          *              means the BEGIN state was not changed in the previous
1095                          *              CommitTransactionCommand().  If we get it, we print
1096                          *              a warning and change to the in-progress state.
1097                          * ----------------
1098                          */
1099                 case TBLOCK_BEGIN:
1100                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1101                         s->blockState = TBLOCK_INPROGRESS;
1102                         break;
1103
1104                         /* ----------------
1105                          *              This is the case when are somewhere in a transaction
1106                          *              block and about to start a new command.  For now we
1107                          *              do nothing but someday we may do command-local resource
1108                          *              initialization.
1109                          * ----------------
1110                          */
1111                 case TBLOCK_INPROGRESS:
1112                         break;
1113
1114                         /* ----------------
1115                          *              As with BEGIN, we should never experience this
1116                          *              if we do it means the END state was not changed in the
1117                          *              previous CommitTransactionCommand().  If we get it, we
1118                          *              print a warning, commit the transaction, start a new
1119                          *              transaction and change to the default state.
1120                          * ----------------
1121                          */
1122                 case TBLOCK_END:
1123                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
1124                         s->blockState = TBLOCK_DEFAULT;
1125                         CommitTransaction();
1126                         StartTransaction();
1127                         break;
1128
1129                         /* ----------------
1130                          *              Here we are in the middle of a transaction block but
1131                          *              one of the commands caused an abort so we do nothing
1132                          *              but remain in the abort state.  Eventually we will get
1133                          *              to the "END TRANSACTION" which will set things straight.
1134                          * ----------------
1135                          */
1136                 case TBLOCK_ABORT:
1137                         break;
1138
1139                         /* ----------------
1140                          *              This means we somehow aborted and the last call to
1141                          *              CommitTransactionCommand() didn't clear the state so
1142                          *              we remain in the ENDABORT state and mabey next time
1143                          *              we get to CommitTransactionCommand() the state will
1144                          *              get reset to default.
1145                          * ----------------
1146                          */
1147                 case TBLOCK_ENDABORT:
1148                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1149                         break;
1150         }
1151 }
1152
1153 /* --------------------------------
1154  *              CommitTransactionCommand
1155  * --------------------------------
1156  */
1157 void
1158 CommitTransactionCommand()
1159 {
1160         TransactionState s = CurrentTransactionState;
1161
1162         switch (s->blockState)
1163         {
1164                         /* ----------------
1165                          *              if we aren't in a transaction block, we
1166                          *              just do our usual transaction commit
1167                          * ----------------
1168                          */
1169                 case TBLOCK_DEFAULT:
1170                         CommitTransaction();
1171                         break;
1172
1173                         /* ----------------
1174                          *              This is the case right after we get a "BEGIN TRANSACTION"
1175                          *              command, but the user hasn't done anything else yet, so
1176                          *              we change to the "transaction block in progress" state
1177                          *              and return.
1178                          * ----------------
1179                          */
1180                 case TBLOCK_BEGIN:
1181                         s->blockState = TBLOCK_INPROGRESS;
1182                         break;
1183
1184                         /* ----------------
1185                          *              This is the case when we have finished executing a command
1186                          *              someplace within a transaction block.  We increment the
1187                          *              command counter and return.  Someday we may free resources
1188                          *              local to the command.
1189                          *
1190                          *              That someday is today, at least for memory allocated by
1191                          *              command in the BlankPortal' HeapMemory context.
1192                          *                              - vadim 03/25/97
1193                          * ----------------
1194                          */
1195                 case TBLOCK_INPROGRESS:
1196                         CommandCounterIncrement();
1197 #ifdef TBL_FREE_CMD_MEMORY
1198                         EndPortalAllocMode();
1199                         StartPortalAllocMode(DefaultAllocMode, 0);
1200 #endif
1201                         break;
1202
1203                         /* ----------------
1204                          *              This is the case when we just got the "END TRANSACTION"
1205                          *              statement, so we go back to the default state and
1206                          *              commit the transaction.
1207                          * ----------------
1208                          */
1209                 case TBLOCK_END:
1210                         s->blockState = TBLOCK_DEFAULT;
1211                         CommitTransaction();
1212                         break;
1213
1214                         /* ----------------
1215                          *              Here we are in the middle of a transaction block but
1216                          *              one of the commands caused an abort so we do nothing
1217                          *              but remain in the abort state.  Eventually we will get
1218                          *              to the "END TRANSACTION" which will set things straight.
1219                          * ----------------
1220                          */
1221                 case TBLOCK_ABORT:
1222                         break;
1223
1224                         /* ----------------
1225                          *              Here we were in an aborted transaction block which
1226                          *              just processed the "END TRANSACTION" command from the
1227                          *              user, so now we return the to default state.
1228                          * ----------------
1229                          */
1230                 case TBLOCK_ENDABORT:
1231                         s->blockState = TBLOCK_DEFAULT;
1232                         break;
1233         }
1234 }
1235
1236 /* --------------------------------
1237  *              AbortCurrentTransaction
1238  * --------------------------------
1239  */
1240 void
1241 AbortCurrentTransaction()
1242 {
1243         TransactionState s = CurrentTransactionState;
1244
1245         switch (s->blockState)
1246         {
1247                         /* ----------------
1248                          *              if we aren't in a transaction block, we
1249                          *              just do our usual abort transaction.
1250                          * ----------------
1251                          */
1252                 case TBLOCK_DEFAULT:
1253                         AbortTransaction();
1254                         break;
1255
1256                         /* ----------------
1257                          *              If we are in the TBLOCK_BEGIN it means something
1258                          *              screwed up right after reading "BEGIN TRANSACTION"
1259                          *              so we enter the abort state.  Eventually an "END
1260                          *              TRANSACTION" will fix things.
1261                          * ----------------
1262                          */
1263                 case TBLOCK_BEGIN:
1264                         s->blockState = TBLOCK_ABORT;
1265                         AbortTransaction();
1266                         break;
1267
1268                         /* ----------------
1269                          *              This is the case when are somewhere in a transaction
1270                          *              block which aborted so we abort the transaction and
1271                          *              set the ABORT state.  Eventually an "END TRANSACTION"
1272                          *              will fix things and restore us to a normal state.
1273                          * ----------------
1274                          */
1275                 case TBLOCK_INPROGRESS:
1276                         s->blockState = TBLOCK_ABORT;
1277                         AbortTransaction();
1278                         break;
1279
1280                         /* ----------------
1281                          *              Here, the system was fouled up just after the
1282                          *              user wanted to end the transaction block so we
1283                          *              abort the transaction and put us back into the
1284                          *              default state.
1285                          * ----------------
1286                          */
1287                 case TBLOCK_END:
1288                         s->blockState = TBLOCK_DEFAULT;
1289                         AbortTransaction();
1290                         break;
1291
1292                         /* ----------------
1293                          *              Here, we are already in an aborted transaction
1294                          *              state and are waiting for an "END TRANSACTION" to
1295                          *              come along and lo and behold, we abort again!
1296                          *              So we just remain in the abort state.
1297                          * ----------------
1298                          */
1299                 case TBLOCK_ABORT:
1300                         break;
1301
1302                         /* ----------------
1303                          *              Here we were in an aborted transaction block which
1304                          *              just processed the "END TRANSACTION" command but somehow
1305                          *              aborted again.. since we must have done the abort
1306                          *              processing, we return to the default state.
1307                          * ----------------
1308                          */
1309                 case TBLOCK_ENDABORT:
1310                         s->blockState = TBLOCK_DEFAULT;
1311                         break;
1312         }
1313 }
1314
1315 /* ----------------------------------------------------------------
1316  *                                         transaction block support
1317  * ----------------------------------------------------------------
1318  */
1319 /* --------------------------------
1320  *              BeginTransactionBlock
1321  * --------------------------------
1322  */
1323 void
1324 BeginTransactionBlock(void)
1325 {
1326         TransactionState s = CurrentTransactionState;
1327
1328         /* ----------------
1329          *      check the current transaction state
1330          * ----------------
1331          */
1332         if (s->state == TRANS_DISABLED)
1333                 return;
1334
1335         if (s->blockState != TBLOCK_DEFAULT)
1336                 elog(NOTICE, "BEGIN: already a transaction in progress");
1337
1338         /* ----------------
1339          *      set the current transaction block state information
1340          *      appropriately during begin processing
1341          * ----------------
1342          */
1343         s->blockState = TBLOCK_BEGIN;
1344
1345         /* ----------------
1346          *      do begin processing
1347          * ----------------
1348          */
1349
1350         /* ----------------
1351          *      done with begin processing, set block state to inprogress
1352          * ----------------
1353          */
1354         s->blockState = TBLOCK_INPROGRESS;
1355 }
1356
1357 /* --------------------------------
1358  *              EndTransactionBlock
1359  * --------------------------------
1360  */
1361 void
1362 EndTransactionBlock(void)
1363 {
1364         TransactionState s = CurrentTransactionState;
1365
1366         /* ----------------
1367          *      check the current transaction state
1368          * ----------------
1369          */
1370         if (s->state == TRANS_DISABLED)
1371                 return;
1372
1373         if (s->blockState == TBLOCK_INPROGRESS)
1374         {
1375                 /* ----------------
1376                  *      here we are in a transaction block which should commit
1377                  *      when we get to the upcoming CommitTransactionCommand()
1378                  *      so we set the state to "END".  CommitTransactionCommand()
1379                  *      will recognize this and commit the transaction and return
1380                  *      us to the default state
1381                  * ----------------
1382                  */
1383                 s->blockState = TBLOCK_END;
1384                 return;
1385         }
1386
1387         if (s->blockState == TBLOCK_ABORT)
1388         {
1389                 /* ----------------
1390                  *      here, we are in a transaction block which aborted
1391                  *      and since the AbortTransaction() was already done,
1392                  *      we do whatever is needed and change to the special
1393                  *      "END ABORT" state.      The upcoming CommitTransactionCommand()
1394                  *      will recognise this and then put us back in the default
1395                  *      state.
1396                  * ----------------
1397                  */
1398                 s->blockState = TBLOCK_ENDABORT;
1399                 return;
1400         }
1401
1402         /* ----------------
1403          *      We should not get here, but if we do, we go to the ENDABORT
1404          *      state after printing a warning.  The upcoming call to
1405          *      CommitTransactionCommand() will then put us back into the
1406          *      default state.
1407          * ----------------
1408          */
1409         elog(NOTICE, "COMMIT: no transaction in progress");
1410         s->blockState = TBLOCK_ENDABORT;
1411 }
1412
1413 /* --------------------------------
1414  *              AbortTransactionBlock
1415  * --------------------------------
1416  */
1417 #ifdef NOT_USED
1418 static void
1419 AbortTransactionBlock(void)
1420 {
1421         TransactionState s = CurrentTransactionState;
1422
1423         /* ----------------
1424          *      check the current transaction state
1425          * ----------------
1426          */
1427         if (s->state == TRANS_DISABLED)
1428                 return;
1429
1430         if (s->blockState == TBLOCK_INPROGRESS)
1431         {
1432                 /* ----------------
1433                  *      here we were inside a transaction block something
1434                  *      screwed up inside the system so we enter the abort state,
1435                  *      do the abort processing and then return.
1436                  *      We remain in the abort state until we see the upcoming
1437                  *      END TRANSACTION command.
1438                  * ----------------
1439                  */
1440                 s->blockState = TBLOCK_ABORT;
1441
1442                 /* ----------------
1443                  *      do abort processing and return
1444                  * ----------------
1445                  */
1446                 AbortTransaction();
1447                 return;
1448         }
1449
1450         /* ----------------
1451          *      this case should not be possible, because it would mean
1452          *      the user entered an "abort" from outside a transaction block.
1453          *      So we print an error message, abort the transaction and
1454          *      enter the "ENDABORT" state so we will end up in the default
1455          *      state after the upcoming CommitTransactionCommand().
1456          * ----------------
1457          */
1458         elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
1459         AbortTransaction();
1460         s->blockState = TBLOCK_ENDABORT;
1461 }
1462
1463 #endif
1464
1465 /* --------------------------------
1466  *              UserAbortTransactionBlock
1467  * --------------------------------
1468  */
1469 void
1470 UserAbortTransactionBlock()
1471 {
1472         TransactionState s = CurrentTransactionState;
1473
1474         /* ----------------
1475          *      check the current transaction state
1476          * ----------------
1477          */
1478         if (s->state == TRANS_DISABLED)
1479                 return;
1480
1481         /*
1482          * if the transaction has already been automatically aborted with an
1483          * error, and the user subsequently types 'abort', allow it.  (the
1484          * behavior is the same as if they had typed 'end'.)
1485          */
1486         if (s->blockState == TBLOCK_ABORT)
1487         {
1488                 s->blockState = TBLOCK_ENDABORT;
1489                 return;
1490         }
1491
1492         if (s->blockState == TBLOCK_INPROGRESS)
1493         {
1494                 /* ----------------
1495                  *      here we were inside a transaction block and we
1496                  *      got an abort command from the user, so we move to
1497                  *      the abort state, do the abort processing and
1498                  *      then change to the ENDABORT state so we will end up
1499                  *      in the default state after the upcoming
1500                  *      CommitTransactionCommand().
1501                  * ----------------
1502                  */
1503                 s->blockState = TBLOCK_ABORT;
1504
1505                 /* ----------------
1506                  *      do abort processing
1507                  * ----------------
1508                  */
1509                 AbortTransaction();
1510
1511                 /* ----------------
1512                  *      change to the end abort state and return
1513                  * ----------------
1514                  */
1515                 s->blockState = TBLOCK_ENDABORT;
1516                 return;
1517         }
1518
1519         /* ----------------
1520          *      this case should not be possible, because it would mean
1521          *      the user entered a "rollback" from outside a transaction block.
1522          *      So we print an error message, abort the transaction and
1523          *      enter the "ENDABORT" state so we will end up in the default
1524          *      state after the upcoming CommitTransactionCommand().
1525          * ----------------
1526          */
1527         elog(NOTICE, "ROLLBACK: no transaction in progress");
1528         AbortTransaction();
1529         s->blockState = TBLOCK_ENDABORT;
1530 }
1531
1532 /* --------------------------------
1533  *              AbortOutOfAnyTransaction
1534  *
1535  * This routine is provided for error recovery purposes.  It aborts any
1536  * active transaction or transaction block, leaving the system in a known
1537  * idle state.
1538  * --------------------------------
1539  */
1540 void
1541 AbortOutOfAnyTransaction()
1542 {
1543         TransactionState s = CurrentTransactionState;
1544
1545         /*
1546          * Get out of any low-level transaction
1547          */
1548         if (s->state != TRANS_DEFAULT)
1549                 AbortTransaction();
1550
1551         /*
1552          * Now reset the high-level state
1553          */
1554         s->blockState = TBLOCK_DEFAULT;
1555 }
1556
1557 bool
1558 IsTransactionBlock()
1559 {
1560         TransactionState s = CurrentTransactionState;
1561
1562         if (s->blockState == TBLOCK_INPROGRESS
1563                 || s->blockState == TBLOCK_ABORT
1564                 || s->blockState == TBLOCK_ENDABORT)
1565                 return true;
1566
1567         return false;
1568 }