On Sun, Mar 28, 2004 at 06:16:59PM -0400, Alvaro Herrera wrote:
> After all this, I still think the TRANS state is unnecesary. I will add
> checks in the low level routines so they see what TBLOCK state they are
> called in, which should be enough to keep the current functionality
> and robustness.
Please review this one.
--
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"La persona que no quer�a pecar / estaba obligada a sentarse
en duras y empinadas sillas / desprovistas, por cierto
de blandos atenuantes" (Patricio Vogel)
Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql-server/src/backend/access/transam/xact.c,v
retrieving revision 1.164
diff -c -r1.164 xact.c
*** src/backend/access/transam/xact.c 11 Feb 2004 22:55:24 -0000 1.164
--- src/backend/access/transam/xact.c 28 Mar 2004 22:55:45 -0000
***************
*** 197,203 ****
FirstCommandId, /* command id */
0, /* scan command id */
0x0, /* start time */
- TRANS_DEFAULT, /* transaction state */
TBLOCK_DEFAULT /* transaction block state from the
client
* perspective */
};
--- 197,202 ----
***************
*** 239,305 ****
* ----------------------------------------------------------------
*/
- #ifdef NOT_USED
-
- /* --------------------------------
- * TransactionFlushEnabled()
- * SetTransactionFlushEnabled()
- *
- * These are used to test and set the "TransactionFlushState"
- * variable. 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.
- * --------------------------------
- */
- static int TransactionFlushState = 1;
-
- int
- TransactionFlushEnabled(void)
- {
- return TransactionFlushState;
- }
-
- void
- SetTransactionFlushEnabled(bool state)
- {
- TransactionFlushState = (state == true);
- }
- #endif
-
-
- /*
- * IsTransactionState
- *
- * This returns true if we are currently running a query
- * within an executing transaction.
- */
- bool
- IsTransactionState(void)
- {
- TransactionState s = CurrentTransactionState;
-
- switch (s->state)
- {
- 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;
- }
-
- /*
- * Shouldn't get here, but lint is not happy with this...
- */
- return false;
- }
-
/*
* IsAbortedTransactionBlockState
*
--- 238,243 ----
***************
*** 852,866 ****
/*
* check the current transaction state
*/
! if (s->state != TRANS_DEFAULT)
! elog(WARNING, "StartTransaction and not in default state");
!
! /*
! * set the current transaction state information appropriately during
! * start processing
! */
! s->state = TRANS_START;
!
/*
* Make sure we've freed any old snapshot, and reset xact state variables
*/
--- 790,798 ----
/*
* check the current transaction state
*/
! if (s->blockState != TBLOCK_DEFAULT)
! elog(WARNING, "StartTransaction and not in DEFAULT state");
!
/*
* Make sure we've freed any old snapshot, and reset xact state variables
*/
***************
*** 893,904 ****
*/
DeferredTriggerBeginXact();
- /*
- * done with start processing, set current transaction state to "in
- * progress"
- */
- s->state = TRANS_INPROGRESS;
-
}
/*
--- 825,830 ----
***************
*** 909,919 ****
{
TransactionState s = CurrentTransactionState;
! /*
! * check the current transaction state
! */
! if (s->state != TRANS_INPROGRESS)
! elog(WARNING, "CommitTransaction and not in in-progress state");
/*
* Tell the trigger manager that this transaction is about to be
--- 835,842 ----
{
TransactionState s = CurrentTransactionState;
! if (s->blockState != TBLOCK_INPROGRESS)
! elog(WARNING, "CommitTransaction and not in INPROGRESS state");
/*
* Tell the trigger manager that this transaction is about to be
***************
*** 932,943 ****
HOLD_INTERRUPTS();
/*
- * set the current transaction state information appropriately during
- * the abort processing
- */
- s->state = TRANS_COMMIT;
-
- /*
* Do pre-commit processing (most of this stuff requires database
* access, and in fact could still cause an error...)
*/
--- 855,860 ----
***************
*** 1012,1023 ****
pgstat_count_xact_commit();
AtCommit_Memory();
- /*
- * done with commit processing, set current transaction state back to
- * default
- */
- s->state = TRANS_DEFAULT;
-
RESUME_INTERRUPTS();
}
--- 929,934 ----
***************
*** 1053,1066 ****
/*
* check the current transaction state
*/
! if (s->state != TRANS_INPROGRESS)
! elog(WARNING, "AbortTransaction and not in in-progress state");
!
! /*
! * set the current transaction state information appropriately during
! * the abort processing
! */
! s->state = TRANS_ABORT;
/* Make sure we are in a valid memory context */
AtAbort_Memory();
--- 964,971 ----
/*
* check the current transaction state
*/
! if (s->blockState == TBLOCK_DEFAULT)
! elog(WARNING, "AbortTransaction and in DEFAULT state");
/* Make sure we are in a valid memory context */
AtAbort_Memory();
***************
*** 1122,1130 ****
SetReindexProcessing(InvalidOid, InvalidOid);
pgstat_count_xact_rollback();
- /*
- * State remains TRANS_ABORT until CleanupTransaction().
- */
RESUME_INTERRUPTS();
}
--- 1027,1032 ----
***************
*** 1137,1145 ****
TransactionState s = CurrentTransactionState;
/*
! * State should still be TRANS_ABORT from AbortTransaction().
*/
! if (s->state != TRANS_ABORT)
elog(FATAL, "CleanupTransaction and not in abort state");
/*
--- 1039,1047 ----
TransactionState s = CurrentTransactionState;
/*
! * State should still be TBLOCK_ABORT after AbortTransaction().
*/
! if (s->blockState != TBLOCK_ABORT && s->blockState != TBLOCK_ENDABORT)
elog(FATAL, "CleanupTransaction and not in abort state");
/*
***************
*** 1148,1158 ****
AtCleanup_Portals(); /* now safe to release portal memory */
AtCleanup_Memory(); /* and transaction memory */
- /*
- * done with abort processing, set current transaction state back to
- * default
- */
- s->state = TRANS_DEFAULT;
}
/*
--- 1050,1055 ----
***************
*** 1171,1176 ****
--- 1068,1082 ----
*/
case TBLOCK_DEFAULT:
StartTransaction();
+ s->blockState = TBLOCK_STARTED;
+ break;
+
+ /*
+ * We should never experience this -- it means the STARTED
state
+ * was not changed in the previous CommitTransactionCommand.
+ */
+ case TBLOCK_STARTED:
+ elog(WARNING, "StartTransactionCommand: unexpected
TBLOCK_STARTED");
break;
/*
***************
*** 1202,1210 ****
*/
case TBLOCK_END:
elog(WARNING, "StartTransactionCommand: unexpected
TBLOCK_END");
- s->blockState = TBLOCK_DEFAULT;
CommitTransaction();
StartTransaction();
break;
/*
--- 1108,1116 ----
*/
case TBLOCK_END:
elog(WARNING, "StartTransactionCommand: unexpected
TBLOCK_END");
CommitTransaction();
StartTransaction();
+ s->blockState = TBLOCK_DEFAULT;
break;
/*
***************
*** 1247,1257 ****
switch (s->blockState)
{
/*
* If we aren't in a transaction block, just do our usual
* transaction commit.
*/
! case TBLOCK_DEFAULT:
CommitTransaction();
break;
/*
--- 1153,1173 ----
switch (s->blockState)
{
/*
+ * This shouldn't happen, because it means the previous
+ * StartTransactionCommand didn't set the STARTED state
+ * appropiately.
+ */
+ case TBLOCK_DEFAULT:
+ elog(WARNING, "CommitTransactionCommand: unexpected
TBLOCK_DEFAULT");
+ break;
+
+ /*
* If we aren't in a transaction block, just do our usual
* transaction commit.
*/
! case TBLOCK_STARTED:
CommitTransaction();
+ s->blockState = TBLOCK_DEFAULT;
break;
/*
***************
*** 1314,1326 ****
switch (s->blockState)
{
/*
* if we aren't in a transaction block, we just do the basic
* abort & cleanup transaction.
*/
! case TBLOCK_DEFAULT:
AbortTransaction();
CleanupTransaction();
break;
/*
--- 1230,1250 ----
switch (s->blockState)
{
+ /*
+ * we aren't in a transaction, so we do nothing.
+ */
+ case TBLOCK_DEFAULT:
+ break;
+
/*
* if we aren't in a transaction block, we just do the basic
* abort & cleanup transaction.
*/
! case TBLOCK_STARTED:
AbortTransaction();
+ s->blockState = TBLOCK_ABORT;
CleanupTransaction();
+ s->blockState = TBLOCK_DEFAULT;
break;
/*
***************
*** 1330,1338 ****
* things.
*/
case TBLOCK_BEGIN:
- s->blockState = TBLOCK_ABORT;
AbortTransaction();
! /* CleanupTransaction happens when we exit TBLOCK_ABORT */
break;
/*
--- 1254,1262 ----
* things.
*/
case TBLOCK_BEGIN:
AbortTransaction();
! s->blockState = TBLOCK_ABORT;
! /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
break;
/*
***************
*** 1342,1350 ****
* restore us to a normal state.
*/
case TBLOCK_INPROGRESS:
- s->blockState = TBLOCK_ABORT;
AbortTransaction();
! /* CleanupTransaction happens when we exit TBLOCK_ABORT */
break;
/*
--- 1266,1274 ----
* restore us to a normal state.
*/
case TBLOCK_INPROGRESS:
AbortTransaction();
! s->blockState = TBLOCK_ABORT;
! /* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
break;
/*
***************
*** 1353,1361 ****
* and put us back into the default state.
*/
case TBLOCK_END:
- s->blockState = TBLOCK_DEFAULT;
AbortTransaction();
CleanupTransaction();
break;
/*
--- 1277,1286 ----
* and put us back into the default state.
*/
case TBLOCK_END:
AbortTransaction();
+ s->blockState = TBLOCK_ABORT;
CleanupTransaction();
+ s->blockState = TBLOCK_DEFAULT;
break;
/*
***************
*** 1420,1426 ****
/* translator: %s represents an SQL statement name */
errmsg("%s cannot be executed from a function", stmtType)));
/* If we got past IsTransactionBlock test, should be in default state */
! if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
elog(ERROR, "cannot prevent transaction chain");
/* all okay */
}
--- 1345,1352 ----
/* translator: %s represents an SQL statement name */
errmsg("%s cannot be executed from a function", stmtType)));
/* If we got past IsTransactionBlock test, should be in default state */
! if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
! CurrentTransactionState->blockState != TBLOCK_STARTED)
elog(ERROR, "cannot prevent transaction chain");
/* all okay */
}
***************
*** 1534,1561 ****
{
TransactionState s = CurrentTransactionState;
! /*
! * check the current transaction state
! */
! if (s->blockState != TBLOCK_DEFAULT)
! ereport(WARNING,
! (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
! errmsg("there is already a transaction in
progress")));
! /*
! * set the current transaction block state information appropriately
! * during begin processing
! */
! s->blockState = TBLOCK_BEGIN;
! /*
! * do begin processing here. Nothing to do at present.
! */
! /*
! * done with begin processing, set block state to inprogress
! */
! s->blockState = TBLOCK_INPROGRESS;
}
/*
--- 1460,1495 ----
{
TransactionState s = CurrentTransactionState;
! switch (s->blockState) {
! /*
! * We are inside a transaction, so allow a transaction block
! * to begin.
! */
! case TBLOCK_STARTED:
! s->blockState = TBLOCK_BEGIN;
! break;
! /* Already a transaction block in progress. */
! case TBLOCK_INPROGRESS:
! ereport(WARNING,
! (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
! errmsg("there is already a transaction in
progress")));
! /*
! * This shouldn't happen, because a transaction in aborted
state
! * will not be allowed to call BeginTransactionBlock.
! */
! case TBLOCK_ABORT:
! elog(WARNING, "BeginTransactionBlock: unexpected
TBLOCK_ABORT");
! break;
! case TBLOCK_DEFAULT:
! case TBLOCK_BEGIN:
! case TBLOCK_ENDABORT:
! case TBLOCK_END:
! elog(FATAL, "BeginTransactionBlock: not in a user-allowed
state!");
! break;
! }
}
/*
***************
*** 1566,1650 ****
{
TransactionState s = CurrentTransactionState;
! /*
! * check the current transaction state
! */
! 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;
! }
! /*
! * here, the user issued COMMIT when not inside a transaction. Issue a
! * WARNING and go to abort state. The upcoming call to
! * CommitTransactionCommand() will then put us back into the default
! * state.
! */
! ereport(WARNING,
! (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
! errmsg("there is no transaction in progress")));
! AbortTransaction();
! s->blockState = TBLOCK_ENDABORT;
! }
! /*
! * AbortTransactionBlock
! */
! #ifdef NOT_USED
! static void
! AbortTransactionBlock(void)
! {
! TransactionState s = CurrentTransactionState;
! /*
! * check the current transaction state
! */
! 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 an END TRANSACTION command.
! */
! s->blockState = TBLOCK_ABORT;
! AbortTransaction();
! return;
}
-
- /*
- * here, the user issued ABORT when not inside a transaction. Issue a
- * WARNING and go to abort state. The upcoming call to
- * CommitTransactionCommand() will then put us back into the default
- * state.
- */
- ereport(WARNING,
- (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
- errmsg("there is no transaction in progress")));
- AbortTransaction();
- s->blockState = TBLOCK_ENDABORT;
}
- #endif
/*
* UserAbortTransactionBlock
--- 1500,1549 ----
{
TransactionState s = CurrentTransactionState;
! switch (s->blockState) {
/*
* 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
*/
! case TBLOCK_INPROGRESS:
! s->blockState = TBLOCK_END;
! break;
! /*
! * 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.
! */
! case TBLOCK_ABORT:
! s->blockState = TBLOCK_ENDABORT;
! break;
! case TBLOCK_STARTED:
! /*
! * here, the user issued COMMIT when not inside a transaction.
Issue a
! * WARNING and go to abort state. The upcoming call to
! * CommitTransactionCommand() will then put us back into the
default
! * state.
! */
! ereport(WARNING,
! (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
! errmsg("there is no transaction in
progress")));
! AbortTransaction();
! s->blockState = TBLOCK_ENDABORT;
! break;
! case TBLOCK_DEFAULT:
! case TBLOCK_BEGIN:
! case TBLOCK_ENDABORT:
! case TBLOCK_END:
! elog(FATAL, "EndTransactionBlock and not in a user-allowed
state");
! break;
}
}
/*
* UserAbortTransactionBlock
***************
*** 1669,1680 ****
{
/*
* 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;
AbortTransaction();
s->blockState = TBLOCK_ENDABORT;
return;
--- 1568,1577 ----
{
/*
* here we were inside a transaction block and we got an abort
! * command from the user, so we move to the ENDABORT state and
! * do abort processing so we will end up in the default state
! * after the upcoming CommitTransactionCommand().
*/
AbortTransaction();
s->blockState = TBLOCK_ENDABORT;
return;
***************
*** 1706,1733 ****
TransactionState s = CurrentTransactionState;
/*
! * Get out of any low-level transaction
*/
! switch (s->state)
{
! case TRANS_START:
! case TRANS_INPROGRESS:
! case TRANS_COMMIT:
/* In a transaction, so clean up */
AbortTransaction();
CleanupTransaction();
break;
! case TRANS_ABORT:
/* AbortTransaction already done, still need Cleanup */
CleanupTransaction();
break;
- case TRANS_DEFAULT:
- /* Not in a transaction, do nothing */
- break;
}
/*
! * Now reset the high-level state
*/
s->blockState = TBLOCK_DEFAULT;
}
--- 1603,1633 ----
TransactionState s = CurrentTransactionState;
/*
! * Get out of any transaction
*/
! switch (s->blockState)
{
! case TBLOCK_DEFAULT:
! /* Not in a transaction, do nothing */
! break;
! case TBLOCK_STARTED:
! case TBLOCK_BEGIN:
! case TBLOCK_INPROGRESS:
! case TBLOCK_END:
/* In a transaction, so clean up */
AbortTransaction();
+ s->blockState = TBLOCK_ABORT;
CleanupTransaction();
break;
! case TBLOCK_ABORT:
! case TBLOCK_ENDABORT:
/* AbortTransaction already done, still need Cleanup */
CleanupTransaction();
break;
}
/*
! * Now reset the transaction state
*/
s->blockState = TBLOCK_DEFAULT;
}
***************
*** 1740,1746 ****
{
TransactionState s = CurrentTransactionState;
! if (s->blockState == TBLOCK_DEFAULT)
return false;
return true;
--- 1640,1646 ----
{
TransactionState s = CurrentTransactionState;
! if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
return false;
return true;
***************
*** 1758,1764 ****
{
TransactionState s = CurrentTransactionState;
! if (s->blockState == TBLOCK_DEFAULT && s->state == TRANS_DEFAULT)
return false;
return true;
--- 1658,1664 ----
{
TransactionState s = CurrentTransactionState;
! if (s->blockState == TBLOCK_DEFAULT)
return false;
return true;
***************
*** 1775,1780 ****
--- 1675,1681 ----
switch (s->blockState)
{
case TBLOCK_DEFAULT:
+ case TBLOCK_STARTED:
return 'I'; /* idle --- not in transaction
*/
case TBLOCK_BEGIN:
case TBLOCK_INPROGRESS:
Index: src/backend/catalog/namespace.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql-server/src/backend/catalog/namespace.c,v
retrieving revision 1.63
diff -c -r1.63 namespace.c
*** src/backend/catalog/namespace.c 13 Feb 2004 01:08:20 -0000 1.63
--- src/backend/catalog/namespace.c 26 Mar 2004 22:52:42 -0000
***************
*** 1801,1807 ****
* If we aren't inside a transaction, we cannot do database access so
* cannot verify the individual names. Must accept the list on faith.
*/
! if (source >= PGC_S_INTERACTIVE && IsTransactionState())
{
/*
* Verify that all the names are either valid namespace names or
--- 1801,1807 ----
* If we aren't inside a transaction, we cannot do database access so
* cannot verify the individual names. Must accept the list on faith.
*/
! if (source >= PGC_S_INTERACTIVE && IsTransactionOrTransactionBlock())
{
/*
* Verify that all the names are either valid namespace names or
Index: src/backend/commands/variable.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql-server/src/backend/commands/variable.c,v
retrieving revision 1.93
diff -c -r1.93 variable.c
*** src/backend/commands/variable.c 19 Jan 2004 19:04:40 -0000 1.93
--- src/backend/commands/variable.c 26 Mar 2004 22:53:02 -0000
***************
*** 776,782 ****
/* not a saved ID, so look it up */
HeapTuple userTup;
! if (!IsTransactionState())
{
/*
* Can't do catalog lookups, so fail. The upshot of this is
--- 776,782 ----
/* not a saved ID, so look it up */
HeapTuple userTup;
! if (!IsTransactionOrTransactionBlock())
{
/*
* Can't do catalog lookups, so fail. The upshot of this is
Index: src/backend/utils/mb/mbutils.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql-server/src/backend/utils/mb/mbutils.c,v
retrieving revision 1.46
diff -c -r1.46 mbutils.c
*** src/backend/utils/mb/mbutils.c 15 Mar 2004 10:41:25 -0000 1.46
--- src/backend/utils/mb/mbutils.c 26 Mar 2004 22:53:33 -0000
***************
*** 114,120 ****
* postgresql.conf. Which would probably be a stupid thing to do
* anyway.
*/
! if (!IsTransactionState())
return -1;
/*
--- 114,120 ----
* postgresql.conf. Which would probably be a stupid thing to do
* anyway.
*/
! if (!IsTransactionOrTransactionBlock())
return -1;
/*
***************
*** 232,238 ****
unsigned char *result;
Oid proc;
! if (!IsTransactionState())
return src;
if (src_encoding == dest_encoding)
--- 232,238 ----
unsigned char *result;
Oid proc;
! if (!IsTransactionOrTransactionBlock())
return src;
if (src_encoding == dest_encoding)
Index: src/include/access/xact.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql-server/src/include/access/xact.h,v
retrieving revision 1.61
diff -c -r1.61 xact.h
*** src/include/access/xact.h 11 Feb 2004 22:55:25 -0000 1.61
--- src/include/access/xact.h 27 Mar 2004 02:52:30 -0000
***************
*** 41,63 ****
extern bool XactReadOnly;
/*
- * transaction states - transaction state from server perspective
- */
- typedef enum TransState
- {
- TRANS_DEFAULT,
- TRANS_START,
- TRANS_INPROGRESS,
- TRANS_COMMIT,
- TRANS_ABORT
- } TransState;
-
- /*
* transaction block states - transaction state of client queries
*/
typedef enum TBlockState
{
TBLOCK_DEFAULT,
TBLOCK_BEGIN,
TBLOCK_INPROGRESS,
TBLOCK_END,
--- 41,52 ----
extern bool XactReadOnly;
/*
* transaction block states - transaction state of client queries
*/
typedef enum TBlockState
{
TBLOCK_DEFAULT,
+ TBLOCK_STARTED,
TBLOCK_BEGIN,
TBLOCK_INPROGRESS,
TBLOCK_END,
***************
*** 79,85 ****
CommandId commandId;
AbsoluteTime startTime;
int startTimeUsec;
- TransState state;
TBlockState blockState;
} TransactionStateData;
--- 68,73 ----
***************
*** 123,129 ****
* extern definitions
* ----------------
*/
- extern bool IsTransactionState(void);
extern bool IsAbortedTransactionBlockState(void);
extern TransactionId GetCurrentTransactionId(void);
extern CommandId GetCurrentCommandId(void);
--- 111,116 ----
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?
http://archives.postgresql.org