Index: src/backend/access/transam/xact.c =================================================================== RCS file: /home/alvherre/cvs/pgsql-server/src/backend/access/transam/xact.c,v retrieving revision 1.165 diff -c -r1.165 xact.c *** src/backend/access/transam/xact.c 5 Apr 2004 03:11:39 -0000 1.165 --- src/backend/access/transam/xact.c 14 Apr 2004 02:50:02 -0000 *************** *** 189,194 **** --- 189,219 ---- static void RecordTransactionAbort(void); static void StartTransaction(void); + #ifdef SUBTRANSACTIONS + static void StartSubTransaction(void); + static void CommitSubTransaction(void); + static void AbortSubTransaction(void); + static void CleanupSubTransaction(void); + static void PushCurrentTransaction(void); + static void PopTransaction(void); + static bool IsSubTransaction(void); + static void ShowTransactionState(void); + static void ShowTransactionStateRec(TransactionState, int); + #else /* SUBTRANSACTIONS */ + #define StartSubTransaction() + #define CommitSubTransaction() + #define AbortSubTransaction() + #define CleanupSubTransaction() + #define PushCurrentTransaction() + #define PopTransaction() + #define IsSubTransaction() (false) + #define ShowTransactionState() + #define ShowTransactionStateRec() + #endif /* SUBTRANSACTIONS */ + + static char *BlockStateAsString(TBlockState); + static char *TransStateAsString(TransState); + /* * global variables holding the current transaction state. */ *************** *** 200,205 **** --- 225,237 ---- TRANS_DEFAULT, /* transaction state */ TBLOCK_DEFAULT /* transaction block state from the client * perspective */ + #ifdef SUBTRANSACTIONS + , + 0, /* nesting level */ + NULL, /* top transaction memory context */ + NULL, /* commit memory context */ + NULL /* parent transaction */ + #endif }; static TransactionState CurrentTransactionState = &CurrentTransactionStateData; *************** *** 281,287 **** { TransactionState s = CurrentTransactionState; ! if (s->blockState == TBLOCK_ABORT) return true; return false; --- 313,320 ---- { TransactionState s = CurrentTransactionState; ! if (s->blockState == TBLOCK_ABORT || ! s->blockState == TBLOCK_SUBABORT) return true; return false; *************** *** 1145,1189 **** 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; - - /* - * 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(WARNING, "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; ! ! /* ! * As with BEGIN, we should never experience this 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(WARNING, "StartTransactionCommand: unexpected TBLOCK_END"); ! CommitTransaction(); ! StartTransaction(); ! s->blockState = TBLOCK_DEFAULT; break; /* --- 1178,1190 ---- 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: ! case TBLOCK_SUBINPROGRESS: break; /* *************** *** 1193,1209 **** * 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 maybe next time we get to ! * CommitTransactionCommand() the state will get reset to ! * default. ! */ case TBLOCK_ENDABORT: ! elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT"); break; } --- 1194,1214 ---- * TRANSACTION" which will set things straight. */ case TBLOCK_ABORT: + case TBLOCK_SUBABORT: break; ! /* These cases are invalid. */ ! case TBLOCK_STARTED: ! case TBLOCK_BEGIN: ! case TBLOCK_SUBBEGIN: ! case TBLOCK_SUBBEGINABORT: ! case TBLOCK_END: ! case TBLOCK_SUBEND: ! case TBLOCK_SUBENDABORT_OK: ! case TBLOCK_SUBENDABORT_ERROR: case TBLOCK_ENDABORT: ! elog(FATAL, "StartTransactionCommand: unexpected block state %s", ! BlockStateAsString(s->blockState)); break; } *************** *** 1231,1237 **** * appropiately. */ case TBLOCK_DEFAULT: ! elog(WARNING, "CommitTransactionCommand: unexpected TBLOCK_DEFAULT"); break; /* --- 1236,1242 ---- * appropiately. */ case TBLOCK_DEFAULT: ! elog(FATAL, "CommitTransactionCommand: unexpected TBLOCK_DEFAULT"); break; /* *************** *** 1290,1295 **** --- 1295,1362 ---- CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; + + /* + * We were just issued a BEGIN inside a transaction block. + * Start a subtransaction. + */ + case TBLOCK_SUBBEGIN: + PushCurrentTransaction(); + StartSubTransaction(); + s->blockState = TBLOCK_SUBINPROGRESS; + break; + + /* + * We were issued a BEGIN inside an aborted transaction block. + * Start a subtransaction, and put it in aborted state. + */ + case TBLOCK_SUBBEGINABORT: + PushCurrentTransaction(); + StartSubTransaction(); + AbortSubTransaction(); + s->blockState = TBLOCK_SUBABORT; + break; + + /* + * Inside a subtransaction, increment the command counter. + */ + case TBLOCK_SUBINPROGRESS: + CommandCounterIncrement(); + break; + + /* + * We where issued a COMMIT command, so we end the current + * subtransaction and return to the parent transaction. + */ + case TBLOCK_SUBEND: + CommitSubTransaction(); + PopTransaction(); + break; + + /* + * If we are in an aborted subtransaction, do nothing. + * Eventually we will receive a COMMIT or ROLLBACK. + */ + case TBLOCK_SUBABORT: + break; + + case TBLOCK_SUBENDABORT_OK: + CleanupSubTransaction(); + PopTransaction(); + break; + + /* + * FIXME -- I think I'm missing an Abort(Sub)?Transaction + * after changing the parent's state. + */ + case TBLOCK_SUBENDABORT_ERROR: + CleanupSubTransaction(); + PopTransaction(); + if (IsSubTransaction()) + s->blockState = TBLOCK_SUBABORT; + else + s->blockState = TBLOCK_ABORT; + break; } } *************** *** 1361,1366 **** --- 1428,1434 ---- * state. */ case TBLOCK_ABORT: + case TBLOCK_SUBABORT: break; /* *************** *** 1373,1378 **** --- 1441,1487 ---- CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; + + /* + * If we are just starting a subtransaction, put it + * in aborted state. + */ + case TBLOCK_SUBBEGIN: + case TBLOCK_SUBBEGINABORT: + PushCurrentTransaction(); + StartSubTransaction(); + AbortSubTransaction(); + s->blockState = TBLOCK_SUBABORT; + break; + + case TBLOCK_SUBINPROGRESS: + AbortSubTransaction(); + s->blockState = TBLOCK_SUBABORT; + break; + + /* + * If we are aborting an ending transaction, + * we have to abort the parent transaction too. + */ + case TBLOCK_SUBEND: + AbortSubTransaction(); + CleanupSubTransaction(); + PopTransaction(); + if (IsSubTransaction()) + AbortSubTransaction(); + else + AbortTransaction(); + break; + + case TBLOCK_SUBENDABORT_OK: + case TBLOCK_SUBENDABORT_ERROR: + CleanupSubTransaction(); + PopTransaction(); + if (IsSubTransaction()) + AbortSubTransaction(); + else + AbortTransaction(); + break; } } *************** *** 1418,1424 **** /* 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 */ } --- 1527,1533 ---- /* If we got past IsTransactionBlock test, should be in default state */ if (CurrentTransactionState->blockState != TBLOCK_DEFAULT && CurrentTransactionState->blockState != TBLOCK_STARTED) ! elog(FATAL, "cannot prevent transaction chain"); /* all okay */ } *************** *** 1540,1557 **** 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; /* These cases are invalid. Reject them altogether. */ --- 1649,1677 ---- s->blockState = TBLOCK_BEGIN; break; ! /* ! * Already a transaction block in progress. ! * Start a subtransaction, or squeak if we don't ! * have subtransactions compiled in. ! */ case TBLOCK_INPROGRESS: + #ifndef SUBTRANSACTIONS ereport(WARNING, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), errmsg("there is already a transaction in progress"))); + break; + #endif + case TBLOCK_SUBINPROGRESS: + s->blockState = TBLOCK_SUBBEGIN; + break; /* ! * An aborted transaction block should be allowed to start ! * a subtransaction, but it must put it in aborted state. */ case TBLOCK_ABORT: ! case TBLOCK_SUBABORT: ! s->blockState = TBLOCK_SUBBEGINABORT; break; /* These cases are invalid. Reject them altogether. */ *************** *** 1559,1565 **** case TBLOCK_BEGIN: case TBLOCK_ENDABORT: case TBLOCK_END: ! elog(FATAL, "BeginTransactionBlock: not in a user-allowed state!"); break; } } --- 1679,1691 ---- case TBLOCK_BEGIN: case TBLOCK_ENDABORT: case TBLOCK_END: ! case TBLOCK_SUBBEGIN: ! case TBLOCK_SUBBEGINABORT: ! case TBLOCK_SUBENDABORT_OK: ! case TBLOCK_SUBENDABORT_ERROR: ! case TBLOCK_SUBEND: ! elog(FATAL, "BeginTransactionBlock: unexpected %s", ! BlockStateAsString(s->blockState)); break; } } *************** *** 1584,1589 **** --- 1710,1724 ---- break; /* + * here we are in a subtransaction block. Signal + * CommitTransactionCommand() to end it and return to the + * parent transaction. + */ + case TBLOCK_SUBINPROGRESS: + s->blockState = TBLOCK_SUBEND; + 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 *************** *** 1594,1599 **** --- 1729,1743 ---- s->blockState = TBLOCK_ENDABORT; break; + /* + * here we are in an aborted subtransaction. Signal + * CommitTransactionCommand() to clean up and return to the + * parent transaction. + */ + case TBLOCK_SUBABORT: + s->blockState = TBLOCK_SUBENDABORT_ERROR; + break; + case TBLOCK_STARTED: /* * here, the user issued COMMIT when not inside a transaction. Issue a *************** *** 1613,1619 **** case TBLOCK_BEGIN: case TBLOCK_ENDABORT: case TBLOCK_END: ! elog(FATAL, "EndTransactionBlock and not in a user-allowed state"); break; } } --- 1757,1769 ---- case TBLOCK_BEGIN: case TBLOCK_ENDABORT: case TBLOCK_END: ! case TBLOCK_SUBBEGIN: ! case TBLOCK_SUBBEGINABORT: ! case TBLOCK_SUBEND: ! case TBLOCK_SUBENDABORT_OK: ! case TBLOCK_SUBENDABORT_ERROR: ! elog(FATAL, "EndTransactionBlock: unexpected %s", ! BlockStateAsString(s->blockState)); break; } } *************** *** 1626,1667 **** { TransactionState s = CurrentTransactionState; ! /* ! * 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'.) ! */ ! 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 ENDABORT state and * do abort processing so we will end up in the default state * after the upcoming CommitTransactionCommand(). */ ! s->blockState = TBLOCK_ABORT; ! AbortTransaction(); ! s->blockState = TBLOCK_ENDABORT; ! 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; } /* --- 1776,1844 ---- { TransactionState s = CurrentTransactionState; ! switch (s->blockState) { /* * 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(). */ ! case TBLOCK_ABORT: ! s->blockState = TBLOCK_ENDABORT; ! break; ! ! /* Ditto, for a subtransaction. */ ! case TBLOCK_SUBABORT: ! AbortSubTransaction(); ! s->blockState = TBLOCK_SUBENDABORT_OK; ! break; ! ! /* ! * 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(). ! */ ! case TBLOCK_INPROGRESS: ! AbortTransaction(); ! s->blockState = TBLOCK_ENDABORT; ! break; ! ! /* Ditto, for a subtransaction. */ ! case TBLOCK_SUBINPROGRESS: ! AbortSubTransaction(); ! s->blockState = TBLOCK_SUBENDABORT_OK; ! break; ! ! /* ! * 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. ! */ ! case TBLOCK_STARTED: ! ereport(WARNING, ! (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), ! errmsg("there is no transaction in progress"))); ! AbortTransaction(); ! s->blockState = TBLOCK_ENDABORT; ! break; ! ! /* these cases are invalid. */ ! case TBLOCK_DEFAULT: ! case TBLOCK_BEGIN: ! case TBLOCK_END: ! case TBLOCK_ENDABORT: ! case TBLOCK_SUBEND: ! case TBLOCK_SUBENDABORT_OK: ! case TBLOCK_SUBENDABORT_ERROR: ! case TBLOCK_SUBBEGIN: ! case TBLOCK_SUBBEGINABORT: ! elog(FATAL, "UserAbortTransactionBlock: unexpected %s", ! BlockStateAsString(s->blockState)); ! break; } } /* *************** *** 1697,1702 **** --- 1874,1903 ---- /* AbortTransaction already done, still need Cleanup */ CleanupTransaction(); break; + case TBLOCK_SUBBEGIN: + case TBLOCK_SUBBEGINABORT: + /* + * Just starting a new transaction -- return to parent. + * FIXME -- Is this correct? + */ + PopTransaction(); + AbortOutOfAnyTransaction(); + break; + case TBLOCK_SUBINPROGRESS: + case TBLOCK_SUBEND: + /* In a subtransaction, so clean it up and abort parent too */ + AbortSubTransaction(); + CleanupSubTransaction(); + PopTransaction(); + AbortOutOfAnyTransaction(); + break; + case TBLOCK_SUBABORT: + case TBLOCK_SUBENDABORT_OK: + case TBLOCK_SUBENDABORT_ERROR: + CleanupSubTransaction(); + PopTransaction(); + AbortOutOfAnyTransaction(); + break; } /* *************** *** 1753,1770 **** case TBLOCK_BEGIN: case TBLOCK_INPROGRESS: case TBLOCK_END: return 'T'; /* in transaction */ case TBLOCK_ABORT: case TBLOCK_ENDABORT: return 'E'; /* in failed transaction */ } /* should never get here */ ! elog(ERROR, "invalid transaction block state: %d", ! (int) s->blockState); return 0; /* keep compiler quiet */ } /* * XLOG support routines --- 1954,2220 ---- case TBLOCK_BEGIN: case TBLOCK_INPROGRESS: case TBLOCK_END: + case TBLOCK_SUBINPROGRESS: + case TBLOCK_SUBBEGIN: + case TBLOCK_SUBEND: return 'T'; /* in transaction */ case TBLOCK_ABORT: case TBLOCK_ENDABORT: + case TBLOCK_SUBABORT: + case TBLOCK_SUBENDABORT_OK: + case TBLOCK_SUBENDABORT_ERROR: + case TBLOCK_SUBBEGINABORT: return 'E'; /* in failed transaction */ } /* should never get here */ ! elog(FATAL, "invalid transaction block state: %s", ! BlockStateAsString(s->blockState)); return 0; /* keep compiler quiet */ } + #ifdef SUBTRANSACTIONS + /* + * IsSubTransaction + */ + bool + IsSubTransaction(void) + { + TransactionState s = CurrentTransactionState; + + switch (s->blockState) { + case TBLOCK_DEFAULT: + case TBLOCK_STARTED: + case TBLOCK_BEGIN: + case TBLOCK_INPROGRESS: + case TBLOCK_END: + case TBLOCK_ABORT: + case TBLOCK_ENDABORT: + return false; + case TBLOCK_SUBBEGIN: + case TBLOCK_SUBBEGINABORT: + case TBLOCK_SUBINPROGRESS: + case TBLOCK_SUBABORT: + case TBLOCK_SUBEND: + case TBLOCK_SUBENDABORT_OK: + case TBLOCK_SUBENDABORT_ERROR: + return true; + } + + /* Should not get here */ + Assert(false); + + /* Keep compiler quiet */ + return false; + } + + /* + * StartSubTransaction + */ + void + StartSubTransaction(void) + { + elog(DEBUG1, "StartSubTransaction"); + ShowTransactionState(); + } + + /* + * CommitSubTransaction + */ + void + CommitSubTransaction(void) + { + elog(DEBUG1, "CommitSubTransaction"); + ShowTransactionState(); + } + + /* + * AbortSubTransaction + */ + void + AbortSubTransaction(void) + { + elog(DEBUG1, "AbortSubTransaction"); + ShowTransactionState(); + } + + /* + * CleanupSubTransaction + */ + void + CleanupSubTransaction(void) + { + elog(DEBUG1, "CleanupSubTransaction"); + ShowTransactionState(); + } + + /* + * PushCurrentTransaction + */ + void + PushCurrentTransaction(void) + { + TransactionState parent; + TransactionState s = CurrentTransactionState; + MemoryContext old_cxt; + + /* + * Make sure the transaction state node is in a long-lived context + */ + old_cxt = MemoryContextSwitchTo(TopMemoryContext); + parent = (TransactionState) palloc(sizeof(TransactionStateData)); + MemoryContextSwitchTo(old_cxt); + + memcpy(parent, s, sizeof(TransactionStateData)); + + parent->topTransactionContext = TopTransactionContext; + s->parent = parent; + s->nestingLevel = s->parent->nestingLevel+1; + } + + /* + * PopTransaction + */ + void + PopTransaction(void) + { + TransactionState s = CurrentTransactionState; + TransactionState p; + + Assert(s->parent != NULL); + + p = s->parent; + + memcpy(s, p, sizeof(TransactionStateData)); + + /* Free the old parent structure */ + pfree(p); + } + + /* + * ShowTransactionState + */ + void + ShowTransactionState(void) + { + ShowTransactionStateRec(CurrentTransactionState, 0); + } + + /* + * ShowTransactionStateRec + */ + void + ShowTransactionStateRec(TransactionState s, int indent) + { + char *i; + char *blockState = BlockStateAsString(s->blockState); + char *state = TransStateAsString(s->state); + + i = (char *)malloc(sizeof(char) * indent + 1); + memset(i, ' ', indent); + memset(i + indent, '\0', 1); + + elog(DEBUG1, "%sblockState: %s; state: %s, tid/cid: %u/%u, nestlvl: %d", + i, + blockState, + state, + (unsigned int)s->transactionIdData, + (unsigned int)s->commandId , + s->nestingLevel); + free(i); + pfree(blockState); + pfree(state); + if (s->parent) + ShowTransactionStateRec(s->parent, indent + 1); + } + + #endif /* SUBTRANSACTIONS */ + + /* + * BlockStateAsString + * + * Returns the block state as a palloc'ed string + */ + char * + BlockStateAsString(TBlockState blockState) + { + char *tmp; + switch (blockState) { + case TBLOCK_DEFAULT: + tmp = "DEFAULT"; + break; + case TBLOCK_BEGIN: + tmp = "BEGIN"; + break; + case TBLOCK_INPROGRESS: + tmp = "INPROGRESS"; + break; + case TBLOCK_END: + tmp = "END"; + break; + case TBLOCK_ENDABORT: + tmp = "ENDABORT"; + break; + case TBLOCK_SUBBEGIN: + tmp = "SUB BEGIN"; + break; + case TBLOCK_SUBBEGINABORT: + tmp = "SUB BEGIN ABORT"; + break; + case TBLOCK_SUBEND: + tmp = "SUB END"; + break; + case TBLOCK_SUBABORT: + tmp = "SUB ABORT"; + break; + case TBLOCK_SUBENDABORT_OK: + tmp = "SUB ENDABORT OK"; + break; + case TBLOCK_SUBENDABORT_ERROR: + tmp = "SUB ENDABORT ERROR"; + break; + case TBLOCK_ABORT: + tmp = "ABORT"; + break; + default: + tmp = "UNKNOWN"; + break; + } + return pstrdup(tmp); + } + + /* + * TransStateAsString + * + * Returns the transaction internal state as a palloc'ed string + */ + char * + TransStateAsString(TransState state) + { + char *tmp; + + switch (state) { + case TRANS_DEFAULT: + tmp = "DEFAULT"; + break; + case TRANS_START: + tmp = "START"; + break; + case TRANS_COMMIT: + tmp = "COMMIT"; + break; + case TRANS_ABORT: + tmp = "ABORT"; + break; + case TRANS_INPROGRESS: + tmp = "INPROGRESS"; + break; + default: + tmp = "UNKNOWN"; + break; + } + return pstrdup(tmp); + } /* * XLOG support routines Index: src/backend/tcop/postgres.c =================================================================== RCS file: /home/alvherre/cvs/pgsql-server/src/backend/tcop/postgres.c,v retrieving revision 1.399 diff -c -r1.399 postgres.c *** src/backend/tcop/postgres.c 11 Apr 2004 00:54:44 -0000 1.399 --- src/backend/tcop/postgres.c 14 Apr 2004 02:43:43 -0000 *************** *** 846,851 **** --- 846,854 ---- TransactionStmt *stmt = (TransactionStmt *) parsetree; if (stmt->kind == TRANS_STMT_COMMIT || + #ifdef SUBTRANSACTIONS + stmt->kind == TRANS_STMT_BEGIN || + #endif stmt->kind == TRANS_STMT_ROLLBACK) allowit = true; } Index: src/include/pg_config_manual.h =================================================================== RCS file: /home/alvherre/cvs/pgsql-server/src/include/pg_config_manual.h,v retrieving revision 1.12 diff -c -r1.12 pg_config_manual.h *** src/include/pg_config_manual.h 24 Mar 2004 22:40:29 -0000 1.12 --- src/include/pg_config_manual.h 13 Apr 2004 22:21:56 -0000 *************** *** 235,237 **** --- 235,240 ---- /* #define ACLDEBUG */ /* #define RTDEBUG */ /* #define GISTDEBUG */ + + /* #define SUBTRANSACTIONS */ + Index: src/include/access/xact.h =================================================================== RCS file: /home/alvherre/cvs/pgsql-server/src/include/access/xact.h,v retrieving revision 1.62 diff -c -r1.62 xact.h *** src/include/access/xact.h 5 Apr 2004 03:11:39 -0000 1.62 --- src/include/access/xact.h 14 Apr 2004 02:43:46 -0000 *************** *** 63,69 **** TBLOCK_INPROGRESS, TBLOCK_END, TBLOCK_ABORT, ! TBLOCK_ENDABORT } TBlockState; /* --- 63,78 ---- TBLOCK_INPROGRESS, TBLOCK_END, TBLOCK_ABORT, ! TBLOCK_ENDABORT, ! ! TBLOCK_SUBBEGIN, ! TBLOCK_SUBBEGINABORT, ! TBLOCK_SUBINPROGRESS, ! TBLOCK_SUBEND, ! TBLOCK_SUBABORT, ! TBLOCK_SUBENDABORT_OK, ! TBLOCK_SUBENDABORT_ERROR ! } TBlockState; /* *************** *** 74,79 **** --- 83,89 ---- /* * transaction state structure */ + typedef struct TransactionStateData { TransactionId transactionIdData; *************** *** 82,87 **** --- 92,103 ---- int startTimeUsec; TransState state; TBlockState blockState; + #ifdef SUBTRANSACTIONS + int nestingLevel; + MemoryContext topTransactionContext; + MemoryContext commitContext; + struct TransactionStateData *parent; + #endif } TransactionStateData; typedef TransactionStateData *TransactionState;