xact.c 38.6 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * xact.c
4
 *	  top level transaction system support routines
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * 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.67 2000/06/18 22:43:51 tgl Exp $
12
 *
13
 * NOTES
14
 *		Transaction aborts can now occur two ways:
15
 *
16 17
 *		1)	system dies from some internal cause  (Assert, etc..)
 *		2)	user types abort
18
 *
19 20 21
 *		These two cases used to be treated identically, but now
 *		we need to distinguish them.  Why?	consider the following
 *		two situatuons:
22
 *
23 24 25 26 27 28
 *				case 1							case 2
 *				------							------
 *		1) user types BEGIN				1) user types BEGIN
 *		2) user does something			2) user does something
 *		3) user does not like what		3) system aborts for some reason
 *		   she shes and types ABORT
29
 *
30 31 32 33 34
 *		In case 1, we want to abort the transaction and return to the
 *		default state.	In case 2, there may be more commands coming
 *		our way which are part of the same transaction block and we have
 *		to ignore these commands until we see an END transaction.
 *		(or an ABORT! --djm)
35
 *
36 37 38 39
 *		Internal aborts are now handled by AbortTransactionBlock(), just as
 *		they always have been, and user aborts are now handled by
 *		UserAbortTransactionBlock().  Both of them rely on AbortTransaction()
 *		to do all the real work.  The only difference is what state we
B
Bruce Momjian 已提交
40
 *		enter after AbortTransaction() does its work:
41
 *
42 43
 *		* AbortTransactionBlock() leaves us in TBLOCK_ABORT and
 *		* UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
44
 *
45 46 47 48 49 50 51 52
 *	 NOTES
 *		This file is an attempt at a redesign of the upper layer
 *		of the V1 transaction system which was too poorly thought
 *		out to describe.  This new system hopes to be both simpler
 *		in design, simpler to extend and needs to contain added
 *		functionality to solve problems beyond the scope of the V1
 *		system.  (In particuler, communication of transaction
 *		information between parallel backends has to be supported)
53
 *
54
 *		The essential aspects of the transaction system are:
55
 *
56 57 58 59 60
 *				o  transaction id generation
 *				o  transaction log updating
 *				o  memory cleanup
 *				o  cache invalidation
 *				o  lock cleanup
61
 *
62 63 64 65 66
 *		Hence, the functional division of the transaction code is
 *		based on what of the above things need to be done during
 *		a start/commit/abort transaction.  For instance, the
 *		routine AtCommit_Memory() takes care of all the memory
 *		cleanup stuff done at commit time.
67
 *
68
 *		The code is layered as follows:
69
 *
70 71 72 73
 *				StartTransaction
 *				CommitTransaction
 *				AbortTransaction
 *				UserAbortTransaction
74
 *
75 76 77
 *		are provided to do the lower level work like recording
 *		the transaction status in the log and doing memory cleanup.
 *		above these routines are another set of functions:
78
 *
79 80 81
 *				StartTransactionCommand
 *				CommitTransactionCommand
 *				AbortCurrentTransaction
82
 *
83 84 85 86 87 88 89 90 91
 *		These are the routines used in the postgres main processing
 *		loop.  They are sensitive to the current transaction block state
 *		and make calls to the lower level routines appropriately.
 *
 *		Support for transaction blocks is provided via the functions:
 *
 *				StartTransactionBlock
 *				CommitTransactionBlock
 *				AbortTransactionBlock
92
 *
93 94 95 96
 *		These are invoked only in responce to a user "BEGIN", "END",
 *		or "ABORT" command.  The tricky part about these functions
 *		is that they are called within the postgres main loop, in between
 *		the StartTransactionCommand() and CommitTransactionCommand().
97
 *
98
 *		For example, consider the following sequence of user commands:
99
 *
100 101 102 103
 *		1)		begin
 *		2)		retrieve (foo.all)
 *		3)		append foo (bar = baz)
 *		4)		end
104
 *
105 106
 *		in the main processing loop, this results in the following
 *		transaction sequence:
107
 *
108 109 110 111
 *			/	StartTransactionCommand();
 *		1) /	ProcessUtility();				<< begin
 *		   \		StartTransactionBlock();
 *			\	CommitTransactionCommand();
112
 *
113 114 115
 *			/	StartTransactionCommand();
 *		2) <	ProcessQuery();					<< retrieve (foo.all)
 *			\	CommitTransactionCommand();
116
 *
117 118 119
 *			/	StartTransactionCommand();
 *		3) <	ProcessQuery();					<< append foo (bar = baz)
 *			\	CommitTransactionCommand();
120
 *
121 122 123 124
 *			/	StartTransactionCommand();
 *		4) /	ProcessUtility();				<< end
 *		   \		CommitTransactionBlock();
 *			\	CommitTransactionCommand();
125
 *
126 127 128 129 130 131
 *		The point of this example is to demonstrate the need for
 *		StartTransactionCommand() and CommitTransactionCommand() to
 *		be state smart -- they should do nothing in between the calls
 *		to StartTransactionBlock() and EndTransactionBlock() and
 *		outside these calls they need to do normal start/commit
 *		processing.
132
 *
133 134 135 136
 *		Furthermore, suppose the "retrieve (foo.all)" caused an abort
 *		condition.	We would then want to abort the transaction and
 *		ignore all subsequent commands up to the "end".
 *		-cim 3/23/90
137 138 139
 *
 *-------------------------------------------------------------------------
 */
M
-Wall'd  
Marc G. Fournier 已提交
140

141 142 143 144 145
/*
 * Large object clean up added in CommitTransaction() to prevent buffer leaks.
 * [PA, 7/17/98]
 * [PA] is Pascal André <andre@via.ecp.fr>
 */
146
#include "postgres.h"
M
-Wall'd  
Marc G. Fournier 已提交
147

148
#include "access/nbtree.h"
149
#include "catalog/heap.h"
H
Hiroshi Inoue 已提交
150
#include "catalog/index.h"
151 152
#include "commands/async.h"
#include "commands/sequence.h"
153
#include "commands/trigger.h"
154
#include "libpq/be-fsstubs.h"
B
Bruce Momjian 已提交
155
#include "storage/proc.h"
156
#include "storage/sinval.h"
157
#include "utils/temprel.h"
B
Bruce Momjian 已提交
158 159 160
#include "utils/inval.h"
#include "utils/portal.h"
#include "utils/relcache.h"
161

162
extern bool SharedBufferChanged;
163

164 165 166 167 168
static void AbortTransaction(void);
static void AtAbort_Cache(void);
static void AtAbort_Locks(void);
static void AtAbort_Memory(void);
static void AtCommit_Cache(void);
H
 
Hiroshi Inoue 已提交
169
static void AtCommit_LocalCache(void);
170 171 172 173 174 175 176 177 178
static void AtCommit_Locks(void);
static void AtCommit_Memory(void);
static void AtStart_Cache(void);
static void AtStart_Locks(void);
static void AtStart_Memory(void);
static void CommitTransaction(void);
static void RecordTransactionAbort(void);
static void RecordTransactionCommit(void);
static void StartTransaction(void);
179

180
/* ----------------
181
 *		global variables holding the current transaction state.
182
 *
183 184 185 186
 *		Note: when we are running several slave processes, the
 *			  current transaction state data is copied into shared memory
 *			  and the CurrentTransactionState pointer changed to
 *			  point to the shared copy.  All this occurrs in slaves.c
187 188 189
 * ----------------
 */
TransactionStateData CurrentTransactionStateData = {
190 191
	0,							/* transaction id */
	FirstCommandId,				/* command id */
192
	0,							/* scan command id */
193 194 195 196
	0x0,						/* start time */
	TRANS_DEFAULT,				/* transaction state */
	TBLOCK_DEFAULT				/* transaction block state */
};
197

198
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
199

B
Bruce Momjian 已提交
200 201
int			DefaultXactIsoLevel = XACT_READ_COMMITTED;
int			XactIsoLevel;
V
Vadim B. Mikheev 已提交
202

203
/* ----------------
204
 *		info returned when the system is disabled
205 206 207 208
 *
 * Apparently a lot of this code is inherited from other prototype systems.
 * For DisabledStartTime, use a symbolic value to make the relationships clearer.
 * The old value of 1073741823 corresponds to a date in y2004, which is coming closer
209 210 211
 *	every day. It appears that if we return a value guaranteed larger than
 *	any real time associated with a transaction then comparisons in other
 *	modules will still be correct. Let's use BIG_ABSTIME for this. tgl 2/14/97
212
 *
213 214 215 216
 *		Note:  I have no idea what the significance of the
 *			   1073741823 in DisabledStartTime.. I just carried
 *			   this over when converting things from the old
 *			   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 233 234
 *		catalog creation transaction bootstrapping flag.
 *		This should be eliminated and added to the transaction
 *		state stuff.  -cim 3/19/90
235 236
 * ----------------
 */
237
bool		AMI_OVERRIDE = false;
238

239
/* ----------------------------------------------------------------
240
 *					 transaction state accessors
241 242
 * ----------------------------------------------------------------
 */
243

244
/* --------------------------------
245 246
 *		TranactionFlushEnabled()
 *		SetTranactionFlushEnabled()
247
 *
248 249 250 251 252 253
 *		These are used to test and set the "TransactionFlushState"
 *		varable.  If this variable is true (the default), then
 *		the system will flush all dirty buffers to disk at the end
 *		of each transaction.   If false then we are assuming the
 *		buffer pool resides in stable main memory, in which case we
 *		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 266
void
SetTransactionFlushEnabled(bool state)
267 268
{
	TransactionFlushState = (state == true);
269
}
270

271 272

/* --------------------------------
273
 *		IsTransactionState
274
 *
275 276
 *		This returns true if we are currently running a query
 *		within an executing transaction.
277 278 279
 * --------------------------------
 */
bool
280
IsTransactionState(void)
281
{
282 283 284 285
	TransactionState s = CurrentTransactionState;

	switch (s->state)
	{
286 287 288 289 290 291 292 293 294 295 296 297
		case TRANS_DEFAULT:
			return false;
		case TRANS_START:
			return true;
		case TRANS_INPROGRESS:
			return true;
		case TRANS_COMMIT:
			return true;
		case TRANS_ABORT:
			return true;
		case TRANS_DISABLED:
			return false;
298 299 300 301 302
	}

	/*
	 * Shouldn't get here, but lint is not happy with this...
	 */
303
	return false;
304
}
B
Bruce Momjian 已提交
305

306
#endif
307 308

/* --------------------------------
309
 *		IsAbortedTransactionBlockState
310
 *
311 312
 *		This returns true if we are currently running a query
 *		within an aborted transaction block.
313 314 315 316 317
 * --------------------------------
 */
bool
IsAbortedTransactionBlockState()
{
318 319 320 321 322 323
	TransactionState s = CurrentTransactionState;

	if (s->blockState == TBLOCK_ABORT)
		return true;

	return false;
324 325 326
}

/* --------------------------------
327
 *		OverrideTransactionSystem
328
 *
329 330 331 332
 *		This is used to temporarily disable the transaction
 *		processing system in order to do initialization of
 *		the transaction system data structures and relations
 *		themselves.
333 334
 * --------------------------------
 */
335
int			SavedTransactionState;
336 337 338 339

void
OverrideTransactionSystem(bool flag)
{
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	TransactionState s = CurrentTransactionState;

	if (flag == true)
	{
		if (s->state == TRANS_DISABLED)
			return;

		SavedTransactionState = s->state;
		s->state = TRANS_DISABLED;
	}
	else
	{
		if (s->state != TRANS_DISABLED)
			return;

		s->state = SavedTransactionState;
	}
357 358 359
}

/* --------------------------------
360
 *		GetCurrentTransactionId
361
 *
362 363
 *		This returns the id of the current transaction, or
 *		the id of the "disabled" transaction.
364 365 366 367 368
 * --------------------------------
 */
TransactionId
GetCurrentTransactionId()
{
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
	TransactionState s = CurrentTransactionState;

	/* ----------------
	 *	if the transaction system is disabled, we return
	 *	the special "disabled" transaction id.
	 * ----------------
	 */
	if (s->state == TRANS_DISABLED)
		return (TransactionId) DisabledTransactionId;

	/* ----------------
	 *	otherwise return the current transaction id.
	 * ----------------
	 */
	return (TransactionId) s->transactionIdData;
384 385 386 387
}


/* --------------------------------
388
 *		GetCurrentCommandId
389 390 391 392 393
 * --------------------------------
 */
CommandId
GetCurrentCommandId()
{
394 395 396 397 398 399 400 401 402 403 404
	TransactionState s = CurrentTransactionState;

	/* ----------------
	 *	if the transaction system is disabled, we return
	 *	the special "disabled" command id.
	 * ----------------
	 */
	if (s->state == TRANS_DISABLED)
		return (CommandId) DisabledCommandId;

	return s->commandId;
405 406
}

407 408 409
CommandId
GetScanCommandId()
{
410 411 412 413 414 415 416 417 418 419 420
	TransactionState s = CurrentTransactionState;

	/* ----------------
	 *	if the transaction system is disabled, we return
	 *	the special "disabled" command id.
	 * ----------------
	 */
	if (s->state == TRANS_DISABLED)
		return (CommandId) DisabledCommandId;

	return s->scanCommandId;
421 422
}

423 424

/* --------------------------------
425
 *		GetCurrentTransactionStartTime
426 427 428 429 430
 * --------------------------------
 */
AbsoluteTime
GetCurrentTransactionStartTime()
{
431 432 433 434 435 436 437 438 439 440 441
	TransactionState s = CurrentTransactionState;

	/* ----------------
	 *	if the transaction system is disabled, we return
	 *	the special "disabled" starting time.
	 * ----------------
	 */
	if (s->state == TRANS_DISABLED)
		return (AbsoluteTime) DisabledStartTime;

	return s->startTime;
442 443 444 445
}


/* --------------------------------
446
 *		TransactionIdIsCurrentTransactionId
447 448 449 450 451
 * --------------------------------
 */
bool
TransactionIdIsCurrentTransactionId(TransactionId xid)
{
452 453 454 455 456 457 458
	TransactionState s = CurrentTransactionState;

	if (AMI_OVERRIDE)
		return false;

	return (bool)
		TransactionIdEquals(xid, s->transactionIdData);
459 460 461 462
}


/* --------------------------------
463
 *		CommandIdIsCurrentCommandId
464 465 466 467 468
 * --------------------------------
 */
bool
CommandIdIsCurrentCommandId(CommandId cid)
{
469 470 471 472 473
	TransactionState s = CurrentTransactionState;

	if (AMI_OVERRIDE)
		return false;

474
	return (cid == s->commandId) ? true : false;
475 476
}

477 478 479
bool
CommandIdGEScanCommandId(CommandId cid)
{
480 481 482 483 484
	TransactionState s = CurrentTransactionState;

	if (AMI_OVERRIDE)
		return false;

485
	return (cid >= s->scanCommandId) ? true : false;
486 487
}

488 489

/* --------------------------------
490
 *		ClearCommandIdCounterOverflowFlag
491 492
 * --------------------------------
 */
493
#ifdef NOT_USED
494 495 496
void
ClearCommandIdCounterOverflowFlag()
{
497
	CommandIdCounterOverflowFlag = false;
498
}
499

500
#endif
501 502

/* --------------------------------
503
 *		CommandCounterIncrement
504 505 506 507 508
 * --------------------------------
 */
void
CommandCounterIncrement()
{
509 510 511 512
	CurrentTransactionStateData.commandId += 1;
	if (CurrentTransactionStateData.commandId == FirstCommandId)
	{
		CommandIdCounterOverflowFlag = true;
513
		elog(ERROR, "You may only have 2^32-1 commands per transaction");
514 515
	}

516
	CurrentTransactionStateData.scanCommandId = CurrentTransactionStateData.commandId;
517

H
 
Hiroshi Inoue 已提交
518
	/*
519 520
	 * make cache changes visible to me.  AtCommit_LocalCache() instead of
	 * AtCommit_Cache() is called here.
H
 
Hiroshi Inoue 已提交
521 522
	 */
	AtCommit_LocalCache();
523
	AtStart_Cache();
V
Vadim B. Mikheev 已提交
524

525 526
}

527 528
void
SetScanCommandId(CommandId savedId)
529 530
{

531 532
	CurrentTransactionStateData.scanCommandId = savedId;

533 534
}

535
/* ----------------------------------------------------------------
536
 *						initialization stuff
537 538 539 540 541
 * ----------------------------------------------------------------
 */
void
InitializeTransactionSystem()
{
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 570 571 572 573

	/*
	 * at present, it is unknown to me what belongs here -cim 3/18/90
	 *
	 * There isn't anything to do at the start of a xact for locks. -mer
	 * 5/24/92
	 */
574 575 576
}

/* --------------------------------
577
 *		AtStart_Memory
578 579
 * --------------------------------
 */
580
static void
581
AtStart_Memory()
582
{
583 584
	Portal		portal;
	MemoryContext portalContext;
585 586 587 588 589 590 591 592 593 594 595 596 597 598

	/* ----------------
	 *	get the blank portal and its memory context
	 * ----------------
	 */
	portal = GetPortalByName(NULL);
	portalContext = (MemoryContext) PortalGetHeapMemory(portal);

	/* ----------------
	 *	tell system to allocate in the blank portal context
	 * ----------------
	 */
	MemoryContextSwitchTo(portalContext);
	StartPortalAllocMode(DefaultAllocMode, 0);
599 600 601 602
}


/* ----------------------------------------------------------------
603
 *						CommitTransaction stuff
604 605 606 607
 * ----------------------------------------------------------------
 */

/* --------------------------------
608
 *		RecordTransactionCommit
609
 *
610 611 612 613 614
 *		Note: the two calls to BufferManagerFlush() exist to ensure
 *			  that data pages are written before log pages.  These
 *			  explicit calls should be replaced by a more efficient
 *			  ordered page write scheme in the buffer manager
 *			  -cim 3/18/90
615 616
 * --------------------------------
 */
617
static void
618
RecordTransactionCommit()
619
{
620 621
	TransactionId xid;
	int			leak;
622 623 624 625 626 627 628

	/* ----------------
	 *	get the current transaction id
	 * ----------------
	 */
	xid = GetCurrentTransactionId();

629 630 631
	/*
	 * flush the buffer manager pages.	Note: if we have stable main
	 * memory, dirty shared buffers are not flushed plai 8/7/90
632 633 634
	 */
	leak = BufferPoolCheckLeak();

635
	/*
636 637
	 * If no one shared buffer was changed by this transaction then we
	 * don't flush shared buffers and don't record commit status.
638
	 */
639 640
	if (SharedBufferChanged)
	{
V
Vadim B. Mikheev 已提交
641
		FlushBufferPool();
642
		if (leak)
643
			ResetBufferPool(true);
644 645

		/*
646 647
		 * have the transaction access methods record the status of this
		 * transaction id in the pg_log relation.
648 649 650 651
		 */
		TransactionIdCommit(xid);

		/*
652
		 * Now write the log info to the disk too.
653 654
		 */
		leak = BufferPoolCheckLeak();
V
Vadim B. Mikheev 已提交
655
		FlushBufferPool();
656
	}
657 658

	if (leak)
659
		ResetBufferPool(true);
660 661 662 663
}


/* --------------------------------
664
 *		AtCommit_Cache
665 666
 * --------------------------------
 */
667
static void
668 669
AtCommit_Cache()
{
670
	/* ----------------
H
 
Hiroshi Inoue 已提交
671
	 * Make catalog changes visible to all backend.
672 673 674
	 * ----------------
	 */
	RegisterInvalid(true);
675 676
}

H
 
Hiroshi Inoue 已提交
677 678 679 680 681 682 683 684 685 686 687 688 689 690
/* --------------------------------
 *		AtCommit_LocalCache
 * --------------------------------
 */
static void
AtCommit_LocalCache()
{
	/* ----------------
	 * Make catalog changes visible to me for the next command.
	 * ----------------
	 */
	ImmediateLocalInvalidation(true);
}

691
/* --------------------------------
692
 *		AtCommit_Locks
693 694
 * --------------------------------
 */
695
static void
696
AtCommit_Locks()
697
{
698 699 700 701 702 703 704
	/* ----------------
	 *	XXX What if ProcReleaseLocks fails?  (race condition?)
	 *
	 *	Then you're up a creek! -mer 5/24/92
	 * ----------------
	 */
	ProcReleaseLocks();
705 706 707
}

/* --------------------------------
708
 *		AtCommit_Memory
709 710
 * --------------------------------
 */
711
static void
712
AtCommit_Memory()
713
{
714 715
	Portal		portal;

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 726 727 728 729
	 *	system allocate things in the top memory context instead
	 *	of the blank portal memory context.
	 * ----------------
	 */
	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 748 749 750 751

	/* ----------------
	 *	get the current transaction id
	 * ----------------
	 */
	xid = GetCurrentTransactionId();

752 753 754 755
	/*
	 * Have the transaction access methods record the status of this
	 * transaction id in the pg_log relation. We skip it if no one shared
	 * buffer was changed by this transaction.
756
	 */
757
	if (SharedBufferChanged && !TransactionIdDidCommit(xid))
758
		TransactionIdAbort(xid);
759

760 761 762 763
	/*
	 * Tell bufmgr and smgr to release resources.
	 */
	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 786 787 788 789 790
	/* ----------------
	 *	XXX What if ProcReleaseLocks() fails?  (race condition?)
	 *
	 *	Then you're up a creek without a paddle! -mer
	 * ----------------
	 */
	ProcReleaseLocks();
791 792 793 794
}


/* --------------------------------
795
 *		AtAbort_Memory
796 797
 * --------------------------------
 */
798
static void
799
AtAbort_Memory()
800
{
801 802 803
	Portal		portal;

	/* ----------------
804
	 *	Release all heap memory in the blank portal.
805 806 807
	 * ----------------
	 */
	portal = GetPortalByName(NULL);
808
	PortalResetHeapMemory(portal);
809

810
	/* ----------------
811 812 813
	 *	Now that we're "out" of a transaction, have the
	 *	system allocate things in the top memory context instead
	 *	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 831
StartTransaction()
{
832 833
	TransactionState s = CurrentTransactionState;

V
Vadim B. Mikheev 已提交
834
	FreeXactSnapshot();
835
	XactIsoLevel = DefaultXactIsoLevel;
V
Vadim B. Mikheev 已提交
836

837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
	/* ----------------
	 *	Check the current transaction state.  If the transaction system
	 *	is switched off, or if we're already in a transaction, do nothing.
	 *	We're already in a transaction when the monitor sends a null
	 *	command to the backend to flush the comm channel.  This is a
	 *	hacky fix to a communications problem, and we keep having to
	 *	deal with it here.	We should fix the comm channel code.  mao 080891
	 * ----------------
	 */
	if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
		return;

	/* ----------------
	 *	set the current transaction state information
	 *	appropriately during start processing
	 * ----------------
	 */
	s->state = TRANS_START;

H
Hiroshi Inoue 已提交
856
	SetReindexProcessing(false);
857 858 859 860 861 862
	/* ----------------
	 *	generate a new transaction id
	 * ----------------
	 */
	GetNewTransactionId(&(s->transactionIdData));

V
Vadim B. Mikheev 已提交
863 864
	XactLockTableInsert(s->transactionIdData);

865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
	/* ----------------
	 *	initialize current transaction state fields
	 * ----------------
	 */
	s->commandId = FirstCommandId;
	s->scanCommandId = FirstCommandId;
	s->startTime = GetCurrentAbsoluteTime();

	/* ----------------
	 *	initialize the various transaction subsystems
	 * ----------------
	 */
	AtStart_Cache();
	AtStart_Locks();
	AtStart_Memory();

881 882 883 884 885 886
	/* ----------------
	 *	Tell the trigger manager to we're starting a transaction
	 * ----------------
	 */
	DeferredTriggerBeginXact();

887 888 889 890 891 892 893
	/* ----------------
	 *	done with start processing, set current transaction
	 *	state to "in progress"
	 * ----------------
	 */
	s->state = TRANS_INPROGRESS;

894 895
}

896
#ifdef NOT_USED
897 898 899 900 901 902 903
/* ---------------
 * Tell me if we are currently in progress
 * ---------------
 */
bool
CurrentXactInProgress()
{
904
	return CurrentTransactionState->state == TRANS_INPROGRESS;
905
}
906
#endif
907 908

/* --------------------------------
909
 *		CommitTransaction
910 911 912
 *
 * --------------------------------
 */
913
static void
914 915
CommitTransaction()
{
916
	TransactionState s = CurrentTransactionState;
917 918

	/* ----------------
919
	 *	check the current transaction state
920 921
	 * ----------------
	 */
922 923 924 925 926 927
	if (s->state == TRANS_DISABLED)
		return;

	if (s->state != TRANS_INPROGRESS)
		elog(NOTICE, "CommitTransaction and not in in-progress state ");

928 929 930
	/* ----------------
	 *	Tell the trigger manager that this transaction is about to be
	 *	committed. He'll invoke all trigger deferred until XACT before
931
	 *	we really start on committing the transaction.
932 933 934 935
	 * ----------------
	 */
	DeferredTriggerEndXact();

936
	/* ----------------
937 938
	 *	set the current transaction state information
	 *	appropriately during the abort processing
939 940
	 * ----------------
	 */
941 942
	s->state = TRANS_COMMIT;

943
	/* ----------------
944
	 *	do commit processing
945 946
	 * ----------------
	 */
947

948
	/* handle commit for large objects [ PA, 7/17/98 ] */
949
	lo_commit(true);
950

951 952 953
	/* NOTIFY commit must also come before lower-level cleanup */
	AtCommit_Notify();

954 955 956
	CloseSequences();
	AtEOXact_portals();
	RecordTransactionCommit();
957 958

	/*
959 960 961 962 963 964 965
	 * Let others know about no transaction in progress by me. Note that
	 * this must be done _before_ releasing locks we hold and
	 * SpinAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked
	 * by xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot -
	 * if xid 2' GetSnapshotData sees xid 1 as running then it must see
	 * xid 0 as running as well or it will see two tuple versions - one
	 * deleted by xid 1 and one inserted by xid 0.
966 967 968
	 */
	if (MyProc != (PROC *) NULL)
	{
969 970
		/* Lock SInvalLock because that's what GetSnapshotData uses. */
		SpinAcquire(SInvalLock);
971 972
		MyProc->xid = InvalidTransactionId;
		MyProc->xmin = InvalidTransactionId;
973
		SpinRelease(SInvalLock);
974 975
	}

976
	RelationPurgeLocalRelation(true);
977
	AtEOXact_nbtree();
978 979 980
	AtCommit_Cache();
	AtCommit_Locks();
	AtCommit_Memory();
981
	AtEOXact_Files();
982

983
	/* ----------------
984 985
	 *	done with commit processing, set current transaction
	 *	state back to default
986 987
	 * ----------------
	 */
988
	s->state = TRANS_DEFAULT;
989
	SharedBufferChanged = false;/* safest place to do it */
990

991
}
992

993
/* --------------------------------
994 995
 *		AbortTransaction
 *
996 997
 * --------------------------------
 */
998 999
static void
AbortTransaction()
1000
{
1001 1002 1003 1004 1005
	TransactionState s = CurrentTransactionState;

	/*
	 * Let others to know about no transaction in progress - vadim
	 * 11/26/96
1006
	 */
1007
	if (MyProc != (PROC *) NULL)
1008
	{
1009
		MyProc->xid = InvalidTransactionId;
1010 1011
		MyProc->xmin = InvalidTransactionId;
	}
1012

1013
	/* ----------------
1014
	 *	check the current transaction state
1015 1016
	 * ----------------
	 */
1017 1018 1019 1020 1021 1022
	if (s->state == TRANS_DISABLED)
		return;

	if (s->state != TRANS_INPROGRESS)
		elog(NOTICE, "AbortTransaction and not in in-progress state ");

1023 1024
	/* ----------------
	 *	Tell the trigger manager that this transaction is about to be
1025
	 *	aborted.
1026 1027 1028 1029
	 * ----------------
	 */
	DeferredTriggerAbortXact();

1030
	/* ----------------
1031 1032
	 *	set the current transaction state information
	 *	appropriately during the abort processing
1033 1034
	 * ----------------
	 */
1035 1036
	s->state = TRANS_ABORT;

1037
	/* ----------------
1038
	 *	do abort processing
1039 1040
	 * ----------------
	 */
1041
	lo_commit(false);			/* 'false' means it's abort */
V
Vadim B. Mikheev 已提交
1042
	UnlockBuffers();
1043
	AtAbort_Notify();
1044 1045
	CloseSequences();
	AtEOXact_portals();
H
Hiroshi Inoue 已提交
1046 1047
	if (CommonSpecialPortalIsOpen())
		CommonSpecialPortalClose();
1048 1049
	RecordTransactionAbort();
	RelationPurgeLocalRelation(false);
1050
	invalidate_temp_relations();
1051
	AtEOXact_nbtree();
1052 1053 1054
	AtAbort_Cache();
	AtAbort_Locks();
	AtAbort_Memory();
1055
	AtEOXact_Files();
1056

1057
	/* ----------------
1058 1059
	 *	done with abort processing, set current transaction
	 *	state back to default
1060 1061
	 * ----------------
	 */
1062
	s->state = TRANS_DEFAULT;
1063
	SharedBufferChanged = false;/* safest place to do it */
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
}

/* --------------------------------
 *		StartTransactionCommand
 * --------------------------------
 */
void
StartTransactionCommand()
{
	TransactionState s = CurrentTransactionState;

	switch (s->blockState)
	{
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
			/* ----------------
			 *		if we aren't in a transaction block, we
			 *		just do our usual start transaction.
			 * ----------------
			 */
		case TBLOCK_DEFAULT:
			StartTransaction();
			break;

			/* ----------------
			 *		We should never experience this -- if we do it
			 *		means the BEGIN state was not changed in the previous
			 *		CommitTransactionCommand().  If we get it, we print
			 *		a warning and change to the in-progress state.
			 * ----------------
			 */
		case TBLOCK_BEGIN:
			elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
			s->blockState = TBLOCK_INPROGRESS;
			break;

			/* ----------------
			 *		This is the case when are somewhere in a transaction
			 *		block and about to start a new command.  For now we
			 *		do nothing but someday we may do command-local resource
			 *		initialization.
			 * ----------------
			 */
		case TBLOCK_INPROGRESS:
			break;

			/* ----------------
B
Bruce Momjian 已提交
1109
			 *		As with BEGIN, we should never experience this
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
			 *		if we do it means the END state was not changed in the
			 *		previous CommitTransactionCommand().  If we get it, we
			 *		print a warning, commit the transaction, start a new
			 *		transaction and change to the default state.
			 * ----------------
			 */
		case TBLOCK_END:
			elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
			s->blockState = TBLOCK_DEFAULT;
			CommitTransaction();
			StartTransaction();
			break;

			/* ----------------
			 *		Here we are in the middle of a transaction block but
			 *		one of the commands caused an abort so we do nothing
			 *		but remain in the abort state.	Eventually we will get
			 *		to the "END TRANSACTION" which will set things straight.
			 * ----------------
			 */
		case TBLOCK_ABORT:
			break;

			/* ----------------
			 *		This means we somehow aborted and the last call to
			 *		CommitTransactionCommand() didn't clear the state so
			 *		we remain in the ENDABORT state and mabey next time
			 *		we get to CommitTransactionCommand() the state will
			 *		get reset to default.
			 * ----------------
			 */
		case TBLOCK_ENDABORT:
			elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
			break;
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
	}
}

/* --------------------------------
 *		CommitTransactionCommand
 * --------------------------------
 */
void
CommitTransactionCommand()
{
	TransactionState s = CurrentTransactionState;

	switch (s->blockState)
	{
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
			/* ----------------
			 *		if we aren't in a transaction block, we
			 *		just do our usual transaction commit
			 * ----------------
			 */
		case TBLOCK_DEFAULT:
			CommitTransaction();
			break;

			/* ----------------
			 *		This is the case right after we get a "BEGIN TRANSACTION"
			 *		command, but the user hasn't done anything else yet, so
			 *		we change to the "transaction block in progress" state
			 *		and return.
			 * ----------------
			 */
		case TBLOCK_BEGIN:
			s->blockState = TBLOCK_INPROGRESS;
			break;

			/* ----------------
			 *		This is the case when we have finished executing a command
			 *		someplace within a transaction block.  We increment the
			 *		command counter and return.  Someday we may free resources
			 *		local to the command.
			 *
			 *		That someday is today, at least for memory allocated by
			 *		command in the BlankPortal' HeapMemory context.
			 *				- vadim 03/25/97
			 * ----------------
			 */
		case TBLOCK_INPROGRESS:
			CommandCounterIncrement();
1191
#ifdef TBL_FREE_CMD_MEMORY
1192 1193
			EndPortalAllocMode();
			StartPortalAllocMode(DefaultAllocMode, 0);
1194
#endif
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
			break;

			/* ----------------
			 *		This is the case when we just got the "END TRANSACTION"
			 *		statement, so we go back to the default state and
			 *		commit the transaction.
			 * ----------------
			 */
		case TBLOCK_END:
			s->blockState = TBLOCK_DEFAULT;
			CommitTransaction();
			break;

			/* ----------------
			 *		Here we are in the middle of a transaction block but
			 *		one of the commands caused an abort so we do nothing
			 *		but remain in the abort state.	Eventually we will get
			 *		to the "END TRANSACTION" which will set things straight.
			 * ----------------
			 */
		case TBLOCK_ABORT:
			break;

			/* ----------------
			 *		Here we were in an aborted transaction block which
			 *		just processed the "END TRANSACTION" command from the
			 *		user, so now we return the to default state.
			 * ----------------
			 */
		case TBLOCK_ENDABORT:
			s->blockState = TBLOCK_DEFAULT;
			break;
1227
	}
1228 1229 1230
}

/* --------------------------------
1231
 *		AbortCurrentTransaction
1232 1233 1234 1235 1236
 * --------------------------------
 */
void
AbortCurrentTransaction()
{
1237 1238 1239 1240
	TransactionState s = CurrentTransactionState;

	switch (s->blockState)
	{
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
			/* ----------------
			 *		if we aren't in a transaction block, we
			 *		just do our usual abort transaction.
			 * ----------------
			 */
		case TBLOCK_DEFAULT:
			AbortTransaction();
			break;

			/* ----------------
			 *		If we are in the TBLOCK_BEGIN it means something
			 *		screwed up right after reading "BEGIN TRANSACTION"
			 *		so we enter the abort state.  Eventually an "END
			 *		TRANSACTION" will fix things.
			 * ----------------
			 */
		case TBLOCK_BEGIN:
			s->blockState = TBLOCK_ABORT;
			AbortTransaction();
			break;

			/* ----------------
			 *		This is the case when are somewhere in a transaction
			 *		block which aborted so we abort the transaction and
			 *		set the ABORT state.  Eventually an "END TRANSACTION"
			 *		will fix things and restore us to a normal state.
			 * ----------------
			 */
		case TBLOCK_INPROGRESS:
			s->blockState = TBLOCK_ABORT;
			AbortTransaction();
			break;

			/* ----------------
			 *		Here, the system was fouled up just after the
			 *		user wanted to end the transaction block so we
			 *		abort the transaction and put us back into the
			 *		default state.
			 * ----------------
			 */
		case TBLOCK_END:
			s->blockState = TBLOCK_DEFAULT;
			AbortTransaction();
			break;

			/* ----------------
			 *		Here, we are already in an aborted transaction
			 *		state and are waiting for an "END TRANSACTION" to
			 *		come along and lo and behold, we abort again!
			 *		So we just remain in the abort state.
			 * ----------------
			 */
		case TBLOCK_ABORT:
			break;

			/* ----------------
			 *		Here we were in an aborted transaction block which
			 *		just processed the "END TRANSACTION" command but somehow
			 *		aborted again.. since we must have done the abort
			 *		processing, we return to the default state.
			 * ----------------
			 */
		case TBLOCK_ENDABORT:
			s->blockState = TBLOCK_DEFAULT;
			break;
1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
	}
}

/* ----------------------------------------------------------------
 *					   transaction block support
 * ----------------------------------------------------------------
 */
/* --------------------------------
 *		BeginTransactionBlock
 * --------------------------------
 */
void
BeginTransactionBlock(void)
{
	TransactionState s = CurrentTransactionState;

1322
	/* ----------------
1323
	 *	check the current transaction state
1324 1325
	 * ----------------
	 */
1326 1327 1328 1329
	if (s->state == TRANS_DISABLED)
		return;

	if (s->blockState != TBLOCK_DEFAULT)
P
Peter Eisentraut 已提交
1330
		elog(NOTICE, "BEGIN: already a transaction in progress");
1331

1332
	/* ----------------
1333 1334
	 *	set the current transaction block state information
	 *	appropriately during begin processing
1335 1336
	 * ----------------
	 */
1337 1338
	s->blockState = TBLOCK_BEGIN;

1339
	/* ----------------
1340
	 *	do begin processing
1341 1342
	 * ----------------
	 */
1343

1344
	/* ----------------
1345
	 *	done with begin processing, set block state to inprogress
1346 1347
	 * ----------------
	 */
1348
	s->blockState = TBLOCK_INPROGRESS;
1349 1350 1351
}

/* --------------------------------
1352
 *		EndTransactionBlock
1353 1354 1355
 * --------------------------------
 */
void
1356
EndTransactionBlock(void)
1357
{
1358 1359
	TransactionState s = CurrentTransactionState;

1360
	/* ----------------
1361
	 *	check the current transaction state
1362 1363
	 * ----------------
	 */
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
	if (s->state == TRANS_DISABLED)
		return;

	if (s->blockState == TBLOCK_INPROGRESS)
	{
		/* ----------------
		 *	here we are in a transaction block which should commit
		 *	when we get to the upcoming CommitTransactionCommand()
		 *	so we set the state to "END".  CommitTransactionCommand()
		 *	will recognize this and commit the transaction and return
		 *	us to the default state
		 * ----------------
		 */
		s->blockState = TBLOCK_END;
		return;
	}

	if (s->blockState == TBLOCK_ABORT)
	{
		/* ----------------
		 *	here, we are in a transaction block which aborted
		 *	and since the AbortTransaction() was already done,
		 *	we do whatever is needed and change to the special
		 *	"END ABORT" state.	The upcoming CommitTransactionCommand()
		 *	will recognise this and then put us back in the default
		 *	state.
		 * ----------------
		 */
		s->blockState = TBLOCK_ENDABORT;
		return;
	}

1396
	/* ----------------
1397 1398 1399 1400
	 *	We should not get here, but if we do, we go to the ENDABORT
	 *	state after printing a warning.  The upcoming call to
	 *	CommitTransactionCommand() will then put us back into the
	 *	default state.
1401 1402
	 * ----------------
	 */
P
Peter Eisentraut 已提交
1403
	elog(NOTICE, "COMMIT: no transaction in progress");
1404 1405 1406 1407
	s->blockState = TBLOCK_ENDABORT;
}

/* --------------------------------
1408
 *		AbortTransactionBlock
1409 1410
 * --------------------------------
 */
1411 1412
#ifdef NOT_USED
static void
1413
AbortTransactionBlock(void)
1414
{
1415 1416
	TransactionState s = CurrentTransactionState;

1417
	/* ----------------
1418
	 *	check the current transaction state
1419 1420
	 * ----------------
	 */
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
	if (s->state == TRANS_DISABLED)
		return;

	if (s->blockState == TBLOCK_INPROGRESS)
	{
		/* ----------------
		 *	here we were inside a transaction block something
		 *	screwed up inside the system so we enter the abort state,
		 *	do the abort processing and then return.
		 *	We remain in the abort state until we see the upcoming
		 *	END TRANSACTION command.
		 * ----------------
		 */
		s->blockState = TBLOCK_ABORT;

		/* ----------------
		 *	do abort processing and return
		 * ----------------
		 */
		AbortTransaction();
		return;
	}

1444
	/* ----------------
1445 1446 1447 1448 1449
	 *	this case should not be possible, because it would mean
	 *	the user entered an "abort" from outside a transaction block.
	 *	So we print an error message, abort the transaction and
	 *	enter the "ENDABORT" state so we will end up in the default
	 *	state after the upcoming CommitTransactionCommand().
1450 1451
	 * ----------------
	 */
1452
	elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
1453
	AbortTransaction();
1454
	s->blockState = TBLOCK_ENDABORT;
1455
}
1456

1457
#endif
1458 1459

/* --------------------------------
1460
 *		UserAbortTransactionBlock
1461 1462 1463 1464 1465
 * --------------------------------
 */
void
UserAbortTransactionBlock()
{
1466 1467
	TransactionState s = CurrentTransactionState;

1468
	/* ----------------
1469
	 *	check the current transaction state
1470 1471
	 * ----------------
	 */
1472 1473 1474 1475 1476 1477 1478
	if (s->state == TRANS_DISABLED)
		return;

	/*
	 * if the transaction has already been automatically aborted with an
	 * error, and the user subsequently types 'abort', allow it.  (the
	 * behavior is the same as if they had typed 'end'.)
1479
	 */
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
	if (s->blockState == TBLOCK_ABORT)
	{
		s->blockState = TBLOCK_ENDABORT;
		return;
	}

	if (s->blockState == TBLOCK_INPROGRESS)
	{
		/* ----------------
		 *	here we were inside a transaction block and we
		 *	got an abort command from the user, so we move to
		 *	the abort state, do the abort processing and
		 *	then change to the ENDABORT state so we will end up
		 *	in the default state after the upcoming
		 *	CommitTransactionCommand().
		 * ----------------
		 */
		s->blockState = TBLOCK_ABORT;

		/* ----------------
		 *	do abort processing
		 * ----------------
		 */
		AbortTransaction();

		/* ----------------
		 *	change to the end abort state and return
		 * ----------------
		 */
		s->blockState = TBLOCK_ENDABORT;
		return;
	}

1513
	/* ----------------
1514
	 *	this case should not be possible, because it would mean
P
Peter Eisentraut 已提交
1515
	 *	the user entered a "rollback" from outside a transaction block.
1516 1517 1518
	 *	So we print an error message, abort the transaction and
	 *	enter the "ENDABORT" state so we will end up in the default
	 *	state after the upcoming CommitTransactionCommand().
1519 1520
	 * ----------------
	 */
P
Peter Eisentraut 已提交
1521
	elog(NOTICE, "ROLLBACK: no transaction in progress");
1522
	AbortTransaction();
1523 1524 1525
	s->blockState = TBLOCK_ENDABORT;
}

1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
/* --------------------------------
 *		AbortOutOfAnyTransaction
 *
 * This routine is provided for error recovery purposes.  It aborts any
 * active transaction or transaction block, leaving the system in a known
 * idle state.
 * --------------------------------
 */
void
AbortOutOfAnyTransaction()
{
	TransactionState s = CurrentTransactionState;

	/*
	 * Get out of any low-level transaction
	 */
	if (s->state != TRANS_DEFAULT)
		AbortTransaction();
B
Bruce Momjian 已提交
1544

1545 1546 1547 1548 1549 1550
	/*
	 * Now reset the high-level state
	 */
	s->blockState = TBLOCK_DEFAULT;
}

1551 1552 1553
bool
IsTransactionBlock()
{
1554 1555 1556
	TransactionState s = CurrentTransactionState;

	if (s->blockState == TBLOCK_INPROGRESS
1557
		|| s->blockState == TBLOCK_ABORT
1558
		|| s->blockState == TBLOCK_ENDABORT)
1559
		return true;
1560

1561
	return false;
1562
}