xact.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,442 行 · 第 1/5 页
C
2,442 行
TransactionState s = CurrentTransactionState; /* * State should still be TRANS_ABORT from AbortTransaction(). */ if (s->state != TRANS_ABORT) elog(FATAL, "CleanupTransaction: unexpected state %s", TransStateAsString(s->state)); /* * do abort cleanup processing */ AtCleanup_Portals(); /* now safe to release portal memory */ CurrentResourceOwner = NULL; /* and resource owner */ if (TopTransactionResourceOwner) ResourceOwnerDelete(TopTransactionResourceOwner); s->curTransactionOwner = NULL; CurTransactionResourceOwner = NULL; TopTransactionResourceOwner = NULL; AtCleanup_Memory(); /* and transaction memory */ s->transactionId = InvalidTransactionId; s->subTransactionId = InvalidSubTransactionId; s->nestingLevel = 0; s->childXids = NIL; /* * done with abort processing, set current transaction state back to * default */ s->state = TRANS_DEFAULT;}/* * StartTransactionCommand */voidStartTransactionCommand(void){ TransactionState s = CurrentTransactionState; switch (s->blockState) { /* * if we aren't in a transaction block, we just do our usual start * transaction. */ case TBLOCK_DEFAULT: StartTransaction(); s->blockState = TBLOCK_STARTED; break; /* * We are somewhere in a transaction block or subtransaction and * about to start a new command. For now we do nothing, but * someday we may do command-local resource initialization. (Note * that any needed CommandCounterIncrement was done by the * previous CommitTransactionCommand.) */ case TBLOCK_INPROGRESS: case TBLOCK_SUBINPROGRESS: break; /* * Here we are in a failed transaction block (one of the commands * caused an abort) so we do nothing but remain in the abort * state. Eventually we will get a ROLLBACK command which will * get us out of this state. (It is up to other code to ensure * that no commands other than ROLLBACK will be processed in these * states.) */ case TBLOCK_ABORT: case TBLOCK_SUBABORT: break; /* These cases are invalid. */ case TBLOCK_STARTED: case TBLOCK_BEGIN: case TBLOCK_SUBBEGIN: case TBLOCK_END: case TBLOCK_SUBEND: case TBLOCK_ABORT_END: case TBLOCK_SUBABORT_END: case TBLOCK_ABORT_PENDING: case TBLOCK_SUBABORT_PENDING: case TBLOCK_SUBRESTART: case TBLOCK_SUBABORT_RESTART: case TBLOCK_PREPARE: elog(ERROR, "StartTransactionCommand: unexpected state %s", BlockStateAsString(s->blockState)); break; } /* * We must switch to CurTransactionContext before returning. This is * already done if we called StartTransaction, otherwise not. */ Assert(CurTransactionContext != NULL); MemoryContextSwitchTo(CurTransactionContext);}/* * CommitTransactionCommand */voidCommitTransactionCommand(void){ TransactionState s = CurrentTransactionState; switch (s->blockState) { /* * This shouldn't happen, because it means the previous * StartTransactionCommand didn't set the STARTED state * appropriately. */ case TBLOCK_DEFAULT: elog(FATAL, "CommitTransactionCommand: unexpected state %s", BlockStateAsString(s->blockState)); break; /* * If we aren't in a transaction block, just do our usual * transaction commit, and return to the idle state. */ case TBLOCK_STARTED: CommitTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * We are completing a "BEGIN TRANSACTION" command, so we change * to the "transaction block in progress" state and return. (We * assume the BEGIN did nothing to the database, so we need no * CommandCounterIncrement.) */ 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. */ case TBLOCK_INPROGRESS: case TBLOCK_SUBINPROGRESS: CommandCounterIncrement(); break; /* * We are completing a "COMMIT" command. Do it and return to the * idle state. */ case TBLOCK_END: CommitTransaction(); s->blockState = TBLOCK_DEFAULT; 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 a ROLLBACK comand. */ case TBLOCK_ABORT: case TBLOCK_SUBABORT: break; /* * Here we were in an aborted transaction block and we just got * the ROLLBACK command from the user, so clean up the * already-aborted transaction and return to the idle state. */ case TBLOCK_ABORT_END: CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * Here we were in a perfectly good transaction block but the user * told us to ROLLBACK anyway. We have to abort the transaction * and then clean up. */ case TBLOCK_ABORT_PENDING: AbortTransaction(); CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * We are completing a "PREPARE TRANSACTION" command. Do it and * return to the idle state. */ case TBLOCK_PREPARE: PrepareTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * We were just issued a SAVEPOINT inside a transaction block. * Start a subtransaction. (DefineSavepoint already did * PushTransaction, so as to have someplace to put the SUBBEGIN * state.) */ case TBLOCK_SUBBEGIN: StartSubTransaction(); s->blockState = TBLOCK_SUBINPROGRESS; break; /* * We were issued a COMMIT or RELEASE command, so we end the * current subtransaction and return to the parent transaction. * The parent might be ended too, so repeat till we are all the * way out or find an INPROGRESS transaction. */ case TBLOCK_SUBEND: do { CommitSubTransaction(); s = CurrentTransactionState; /* changed by pop */ } while (s->blockState == TBLOCK_SUBEND); /* If we had a COMMIT command, finish off the main xact too */ if (s->blockState == TBLOCK_END) { Assert(s->parent == NULL); CommitTransaction(); s->blockState = TBLOCK_DEFAULT; } else if (s->blockState == TBLOCK_PREPARE) { Assert(s->parent == NULL); PrepareTransaction(); s->blockState = TBLOCK_DEFAULT; } else { Assert(s->blockState == TBLOCK_INPROGRESS || s->blockState == TBLOCK_SUBINPROGRESS); } break; /* * The current already-failed subtransaction is ending due to a * ROLLBACK or ROLLBACK TO command, so pop it and recursively * examine the parent (which could be in any of several states). */ case TBLOCK_SUBABORT_END: CleanupSubTransaction(); CommitTransactionCommand(); break; /* * As above, but it's not dead yet, so abort first. */ case TBLOCK_SUBABORT_PENDING: AbortSubTransaction(); CleanupSubTransaction(); CommitTransactionCommand(); break; /* * The current subtransaction is the target of a ROLLBACK TO * command. Abort and pop it, then start a new subtransaction * with the same name. */ case TBLOCK_SUBRESTART: { char *name; int savepointLevel; /* save name and keep Cleanup from freeing it */ name = s->name; s->name = NULL; savepointLevel = s->savepointLevel; AbortSubTransaction(); CleanupSubTransaction(); DefineSavepoint(NULL); s = CurrentTransactionState; /* changed by push */ s->name = name; s->savepointLevel = savepointLevel; /* This is the same as TBLOCK_SUBBEGIN case */ AssertState(s->blockState == TBLOCK_SUBBEGIN); StartSubTransaction(); s->blockState = TBLOCK_SUBINPROGRESS; } break; /* * Same as above, but the subtransaction had already failed, so we * don't need AbortSubTransaction. */ case TBLOCK_SUBABORT_RESTART: { char *name; int savepointLevel; /* save name and keep Cleanup from freeing it */ name = s->name; s->name = NULL; savepointLevel = s->savepointLevel; CleanupSubTransaction(); DefineSavepoint(NULL); s = CurrentTransactionState; /* changed by push */ s->name = name; s->savepointLevel = savepointLevel; /* This is the same as TBLOCK_SUBBEGIN case */ AssertState(s->blockState == TBLOCK_SUBBEGIN); StartSubTransaction(); s->blockState = TBLOCK_SUBINPROGRESS; } break; }}/* * AbortCurrentTransaction */voidAbortCurrentTransaction(void){ TransactionState s = CurrentTransactionState; switch (s->blockState) { case TBLOCK_DEFAULT: if (s->state == TRANS_DEFAULT) { /* we are idle, so nothing to do */ } else { /* * We can get here after an error during transaction start * (state will be TRANS_START). Need to clean up the * incompletely started transaction. First, adjust the * low-level state to suppress warning message from * AbortTransaction. */ if (s->state == TRANS_START) s->state = TRANS_INPROGRESS; AbortTransaction(); CleanupTransaction(); } break; /* * if we aren't in a transaction block, we just do the basic abort * & cleanup transaction. */ case TBLOCK_STARTED: AbortTransaction(); CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * If we are in TBLOCK_BEGIN it means something screwed up right * after reading "BEGIN TRANSACTION". We assume that the user * will interpret the error as meaning the BEGIN failed to get him * into a transaction block, so we should abort and return to idle * state. */ case TBLOCK_BEGIN: AbortTransaction(); CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * We are somewhere in a transaction block and we've gotten a * failure, so we abort the transaction and set up the persistent * ABORT state. We will stay in ABORT until we get a ROLLBACK. */ case TBLOCK_INPROGRESS: AbortTransaction(); s->blockState = TBLOCK_ABORT; /* CleanupTransaction happens when we exit TBLOCK_ABORT_END */ break; /* * Here, we failed while trying to COMMIT. Clean up the * transaction and return to idle state (we do not want to stay in * the transaction). */ case TBLOCK_END: AbortTransaction(); CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * Here, we are already in an aborted transaction state and are * waiting for a ROLLBACK, but for some reason we failed again! So * we just remain in the abort state. */ case TBLOCK_ABORT: case TBLOCK_SUBABORT: break; /* * We are in a failed transaction and we got the ROLLBACK command. * We have already aborted, we just need to cleanup and go to idle * state. */ case TBLOCK_ABORT_END: CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * We are in a live transaction and we got a ROLLBACK command. * Abort, cleanup, go to idle state. */ case TBLOCK_ABORT_PENDING: AbortTransaction(); CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * Here, we failed while trying to PREPARE. Clean up the * transaction and return to idle state (we do not want to stay in * the transaction). */ case TBLOCK_PREPARE: AbortTransaction(); CleanupTransaction(); s->blockState = TBLOCK_DEFAULT; break; /* * We got an error inside a subtransaction. Abort just the * subtransaction, and go to the persistent SUBABORT state until * we get ROLLBACK. */ case TBLOCK_SUBINPROGRESS: AbortSubTransaction(); s->blockState = TBLOCK_SUBABORT; break; /* * If we failed while trying to create a subtransaction, clean up * the broken subtransaction and abort the parent. The same * applies if we get a failure while ending a subtransaction. */ case TBLOCK_SUBBEGIN: case TBLOCK_SUBEND: case TBLOCK_SUBABORT_PENDING: case TBLOCK_SUBRESTART: AbortSubTransaction(); CleanupSubTransaction(); AbortCurrentTransaction(); break; /* * Same as above, except the Abort() was already done. */ case TBLOCK_SUBABORT_END: case TBLOCK_SUBABORT_RESTART: CleanupSubTransaction(); AbortCurrentTransaction(); break; }}/* * PreventTransactionChain * * This routine is to be called by statements that must not run inside * a transaction block, typically because they have non-rollback-able * side effects or do internal commits. * * If we have already started a transaction block, issue an error; also issue * an error if we appear to be running inside a user-defined function (which * could issue more commands and possibly cause a failure after the statement * completes). Subtransactions are verboten too. * * stmtN
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?