aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xact.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2004-07-31 07:39:21 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2004-07-31 07:39:21 +0000
commitbeda4814c12d8dc8dc455cb96f0b1055fb149ecb (patch)
tree968f682e5a52be375ff0684bac85c87a968c0544 /src/backend/access/transam/xact.c
parentb5d2821929e69ef1c8a690d886e12b1ef8498a3b (diff)
downloadpostgresql-beda4814c12d8dc8dc455cb96f0b1055fb149ecb.tar.gz
postgresql-beda4814c12d8dc8dc455cb96f0b1055fb149ecb.zip
plpgsql does exceptions.
There are still some things that need refinement; in particular I fear that the recognized set of error condition names probably has little in common with what Oracle recognizes. But it's a start.
Diffstat (limited to 'src/backend/access/transam/xact.c')
-rw-r--r--src/backend/access/transam/xact.c137
1 files changed, 123 insertions, 14 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index f938cdcc5ba..b6758a14b22 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.173 2004/07/28 14:23:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.174 2004/07/31 07:39:18 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@@ -1589,7 +1589,8 @@ CleanupTransaction(void)
* State should still be TRANS_ABORT from AbortTransaction().
*/
if (s->state != TRANS_ABORT)
- elog(FATAL, "CleanupTransaction and not in abort state");
+ elog(FATAL, "CleanupTransaction: unexpected state %s",
+ TransStateAsString(s->state));
/*
* do abort cleanup processing
@@ -1773,7 +1774,7 @@ CommitTransactionCommand(void)
/*
* We were just issued a SAVEPOINT inside a transaction block.
- * Start a subtransaction. (BeginTransactionBlock already
+ * Start a subtransaction. (DefineSavepoint already
* did PushTransaction, so as to have someplace to put the
* SUBBEGIN state.)
*/
@@ -1853,6 +1854,7 @@ CleanupAbortedSubTransactions(bool returnName)
AssertState(PointerIsValid(s->parent));
Assert(s->parent->blockState == TBLOCK_SUBINPROGRESS ||
s->parent->blockState == TBLOCK_INPROGRESS ||
+ s->parent->blockState == TBLOCK_STARTED ||
s->parent->blockState == TBLOCK_SUBABORT_PENDING);
/*
@@ -1878,7 +1880,8 @@ CleanupAbortedSubTransactions(bool returnName)
}
AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
- s->blockState == TBLOCK_INPROGRESS);
+ s->blockState == TBLOCK_INPROGRESS ||
+ s->blockState == TBLOCK_STARTED);
return name;
}
@@ -2468,7 +2471,7 @@ DefineSavepoint(char *name)
case TBLOCK_SUBABORT_PENDING:
case TBLOCK_SUBENDABORT_RELEASE:
case TBLOCK_SUBEND:
- elog(FATAL, "BeginTransactionBlock: unexpected state %s",
+ elog(FATAL, "DefineSavepoint: unexpected state %s",
BlockStateAsString(s->blockState));
break;
}
@@ -2657,20 +2660,126 @@ RollbackToSavepoint(List *options)
}
/*
- * RollbackAndReleaseSavepoint
+ * BeginInternalSubTransaction
+ * This is the same as DefineSavepoint except it allows TBLOCK_STARTED
+ * state, and therefore it can safely be used in a function that might
+ * be called when not inside a BEGIN block. Also, we automatically
+ * cycle through CommitTransactionCommand/StartTransactionCommand
+ * instead of expecting the caller to do it.
+ *
+ * Optionally, name can be NULL to create an unnamed savepoint.
+ */
+void
+BeginInternalSubTransaction(char *name)
+{
+ TransactionState s = CurrentTransactionState;
+
+ switch (s->blockState)
+ {
+ case TBLOCK_STARTED:
+ case TBLOCK_INPROGRESS:
+ case TBLOCK_SUBINPROGRESS:
+ /* Normal subtransaction start */
+ PushTransaction();
+ s = CurrentTransactionState; /* changed by push */
+ /*
+ * Note that we are allocating the savepoint name in the
+ * parent transaction's CurTransactionContext, since we
+ * don't yet have a transaction context for the new guy.
+ */
+ if (name)
+ s->name = MemoryContextStrdup(CurTransactionContext, name);
+ s->blockState = TBLOCK_SUBBEGIN;
+ break;
+
+ /* These cases are invalid. Reject them altogether. */
+ case TBLOCK_DEFAULT:
+ case TBLOCK_BEGIN:
+ case TBLOCK_SUBBEGIN:
+ case TBLOCK_ABORT:
+ case TBLOCK_SUBABORT:
+ case TBLOCK_ENDABORT:
+ case TBLOCK_END:
+ case TBLOCK_SUBENDABORT_ALL:
+ case TBLOCK_SUBENDABORT:
+ case TBLOCK_SUBABORT_PENDING:
+ case TBLOCK_SUBENDABORT_RELEASE:
+ case TBLOCK_SUBEND:
+ elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
+ BlockStateAsString(s->blockState));
+ break;
+ }
+
+ CommitTransactionCommand();
+ StartTransactionCommand();
+}
+
+/*
+ * ReleaseCurrentSubTransaction
+ *
+ * RELEASE (ie, commit) the innermost subtransaction, regardless of its
+ * savepoint name (if any).
+ * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
+ */
+void
+ReleaseCurrentSubTransaction(void)
+{
+ TransactionState s = CurrentTransactionState;
+
+ if (s->blockState != TBLOCK_SUBINPROGRESS)
+ elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
+ BlockStateAsString(s->blockState));
+ MemoryContextSwitchTo(CurTransactionContext);
+ CommitTransactionToLevel(GetCurrentTransactionNestLevel());
+}
+
+/*
+ * RollbackAndReleaseCurrentSubTransaction
*
- * Executes a ROLLBACK TO command, immediately followed by a RELEASE
- * of the same savepoint.
+ * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
+ * of its savepoint name (if any).
+ * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
*/
void
-RollbackAndReleaseSavepoint(List *options)
+RollbackAndReleaseCurrentSubTransaction(void)
{
- TransactionState s;
+ TransactionState s = CurrentTransactionState;
- RollbackToSavepoint(options);
- s = CurrentTransactionState;
- Assert(s->blockState == TBLOCK_SUBENDABORT);
+ switch (s->blockState)
+ {
+ /* Must be in a subtransaction */
+ case TBLOCK_SUBABORT:
+ case TBLOCK_SUBINPROGRESS:
+ break;
+
+ /* these cases are invalid. */
+ case TBLOCK_DEFAULT:
+ case TBLOCK_STARTED:
+ case TBLOCK_ABORT:
+ case TBLOCK_INPROGRESS:
+ case TBLOCK_BEGIN:
+ case TBLOCK_END:
+ case TBLOCK_ENDABORT:
+ case TBLOCK_SUBEND:
+ case TBLOCK_SUBENDABORT_ALL:
+ case TBLOCK_SUBENDABORT:
+ case TBLOCK_SUBABORT_PENDING:
+ case TBLOCK_SUBENDABORT_RELEASE:
+ case TBLOCK_SUBBEGIN:
+ elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
+ BlockStateAsString(s->blockState));
+ break;
+ }
+
+ /*
+ * Abort the current subtransaction, if needed.
+ */
+ if (s->blockState == TBLOCK_SUBINPROGRESS)
+ AbortSubTransaction();
s->blockState = TBLOCK_SUBENDABORT_RELEASE;
+
+ /* And clean it up, too */
+ CleanupAbortedSubTransactions(false);
}
/*
@@ -2748,7 +2857,7 @@ AbortOutOfAnyTransaction(void)
* Commit everything from the current transaction level
* up to the specified level (inclusive).
*/
-void
+static void
CommitTransactionToLevel(int level)
{
TransactionState s = CurrentTransactionState;