@@ -145,6 +145,7 @@ typedef enum TBlockState
145145/* transaction block states */
146146TBLOCK_BEGIN ,/* starting transaction block */
147147TBLOCK_INPROGRESS ,/* live transaction */
148+ TBLOCK_IMPLICIT_INPROGRESS ,/* live transaction after implicit BEGIN */
148149TBLOCK_PARALLEL_INPROGRESS ,/* live transaction inside parallel worker */
149150TBLOCK_END ,/* COMMIT received */
150151TBLOCK_ABORT ,/* failed xact, awaiting ROLLBACK */
@@ -2700,6 +2701,7 @@ StartTransactionCommand(void)
27002701 * previous CommitTransactionCommand.)
27012702 */
27022703case TBLOCK_INPROGRESS :
2704+ case TBLOCK_IMPLICIT_INPROGRESS :
27032705case TBLOCK_SUBINPROGRESS :
27042706break ;
27052707
@@ -2790,6 +2792,7 @@ CommitTransactionCommand(void)
27902792 * counter and return.
27912793 */
27922794case TBLOCK_INPROGRESS :
2795+ case TBLOCK_IMPLICIT_INPROGRESS :
27932796case TBLOCK_SUBINPROGRESS :
27942797CommandCounterIncrement ();
27952798break ;
@@ -3014,10 +3017,12 @@ AbortCurrentTransaction(void)
30143017break ;
30153018
30163019/*
3017- * if we aren't in a transaction block, we just do the basic abort
3018- * & cleanup transaction.
3020+ * If we aren't in a transaction block, we just do the basic abort
3021+ * & cleanup transaction. For this purpose, we treat an implicit
3022+ * transaction block as if it were a simple statement.
30193023 */
30203024case TBLOCK_STARTED :
3025+ case TBLOCK_IMPLICIT_INPROGRESS :
30213026AbortTransaction ();
30223027CleanupTransaction ();
30233028s -> blockState = TBLOCK_DEFAULT ;
@@ -3148,9 +3153,8 @@ AbortCurrentTransaction(void)
31483153 *completes). Subtransactions are verboten too.
31493154 *
31503155 *isTopLevel: passed down from ProcessUtility to determine whether we are
3151- *inside a function or multi-query querystring. (We will always fail if
3152- *this is false, but it's convenient to centralize the check here instead of
3153- *making callers do it.)
3156+ *inside a function. (We will always fail if this is false, but it's
3157+ *convenient to centralize the check here instead of making callers do it.)
31543158 *stmtType: statement type name, for error messages.
31553159 */
31563160void
@@ -3183,8 +3187,7 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType)
31833187ereport (ERROR ,
31843188(errcode (ERRCODE_ACTIVE_SQL_TRANSACTION ),
31853189/* translator: %s represents an SQL statement name */
3186- errmsg ("%s cannot be executed from a function or multi-command string" ,
3187- stmtType )));
3190+ errmsg ("%s cannot be executed from a function" ,stmtType )));
31883191
31893192/* If we got past IsTransactionBlock test, should be in default state */
31903193if (CurrentTransactionState -> blockState != TBLOCK_DEFAULT &&
@@ -3428,6 +3431,15 @@ BeginTransactionBlock(void)
34283431s -> blockState = TBLOCK_BEGIN ;
34293432break ;
34303433
3434+ /*
3435+ * BEGIN converts an implicit transaction block to a regular one.
3436+ * (Note that we allow this even if we've already done some
3437+ * commands, which is a bit odd but matches historical practice.)
3438+ */
3439+ case TBLOCK_IMPLICIT_INPROGRESS :
3440+ s -> blockState = TBLOCK_BEGIN ;
3441+ break ;
3442+
34313443/*
34323444 * Already a transaction block in progress.
34333445 */
@@ -3503,7 +3515,8 @@ PrepareTransactionBlock(char *gid)
35033515 * ignore case where we are not in a transaction;
35043516 * EndTransactionBlock already issued a warning.
35053517 */
3506- Assert (s -> blockState == TBLOCK_STARTED );
3518+ Assert (s -> blockState == TBLOCK_STARTED ||
3519+ s -> blockState == TBLOCK_IMPLICIT_INPROGRESS );
35073520/* Don't send back a PREPARE result tag... */
35083521result = false;
35093522}
@@ -3541,6 +3554,18 @@ EndTransactionBlock(void)
35413554result = true;
35423555break ;
35433556
3557+ /*
3558+ * In an implicit transaction block, commit, but issue a warning
3559+ * because there was no explicit BEGIN before this.
3560+ */
3561+ case TBLOCK_IMPLICIT_INPROGRESS :
3562+ ereport (WARNING ,
3563+ (errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
3564+ errmsg ("there is no transaction in progress" )));
3565+ s -> blockState = TBLOCK_END ;
3566+ result = true;
3567+ break ;
3568+
35443569/*
35453570 * We are in a failed transaction block. Tell
35463571 * CommitTransactionCommand it's time to exit the block.
@@ -3705,8 +3730,14 @@ UserAbortTransactionBlock(void)
37053730 * WARNING and go to abort state. The upcoming call to
37063731 * CommitTransactionCommand() will then put us back into the
37073732 * default state.
3733+ *
3734+ * We do the same thing with ABORT inside an implicit transaction,
3735+ * although in this case we might be rolling back actual database
3736+ * state changes. (It's debatable whether we should issue a
3737+ * WARNING in this case, but we have done so historically.)
37083738 */
37093739case TBLOCK_STARTED :
3740+ case TBLOCK_IMPLICIT_INPROGRESS :
37103741ereport (WARNING ,
37113742(errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
37123743errmsg ("there is no transaction in progress" )));
@@ -3743,6 +3774,58 @@ UserAbortTransactionBlock(void)
37433774}
37443775}
37453776
3777+ /*
3778+ * BeginImplicitTransactionBlock
3779+ *Start an implicit transaction block if we're not already in one.
3780+ *
3781+ * Unlike BeginTransactionBlock, this is called directly from the main loop
3782+ * in postgres.c, not within a Portal. So we can just change blockState
3783+ * without a lot of ceremony. We do not expect caller to do
3784+ * CommitTransactionCommand/StartTransactionCommand.
3785+ */
3786+ void
3787+ BeginImplicitTransactionBlock (void )
3788+ {
3789+ TransactionState s = CurrentTransactionState ;
3790+
3791+ /*
3792+ * If we are in STARTED state (that is, no transaction block is open),
3793+ * switch to IMPLICIT_INPROGRESS state, creating an implicit transaction
3794+ * block.
3795+ *
3796+ * For caller convenience, we consider all other transaction states as
3797+ * legal here; otherwise the caller would need its own state check, which
3798+ * seems rather pointless.
3799+ */
3800+ if (s -> blockState == TBLOCK_STARTED )
3801+ s -> blockState = TBLOCK_IMPLICIT_INPROGRESS ;
3802+ }
3803+
3804+ /*
3805+ * EndImplicitTransactionBlock
3806+ *End an implicit transaction block, if we're in one.
3807+ *
3808+ * Like EndTransactionBlock, we just make any needed blockState change here.
3809+ * The real work will be done in the upcoming CommitTransactionCommand().
3810+ */
3811+ void
3812+ EndImplicitTransactionBlock (void )
3813+ {
3814+ TransactionState s = CurrentTransactionState ;
3815+
3816+ /*
3817+ * If we are in IMPLICIT_INPROGRESS state, switch back to STARTED state,
3818+ * allowing CommitTransactionCommand to commit whatever happened during
3819+ * the implicit transaction block as though it were a single statement.
3820+ *
3821+ * For caller convenience, we consider all other transaction states as
3822+ * legal here; otherwise the caller would need its own state check, which
3823+ * seems rather pointless.
3824+ */
3825+ if (s -> blockState == TBLOCK_IMPLICIT_INPROGRESS )
3826+ s -> blockState = TBLOCK_STARTED ;
3827+ }
3828+
37463829/*
37473830 * DefineSavepoint
37483831 *This executes a SAVEPOINT command.
@@ -3780,6 +3863,28 @@ DefineSavepoint(char *name)
37803863s -> name = MemoryContextStrdup (TopTransactionContext ,name );
37813864break ;
37823865
3866+ /*
3867+ * We disallow savepoint commands in implicit transaction blocks.
3868+ * There would be no great difficulty in allowing them so far as
3869+ * this module is concerned, but a savepoint seems inconsistent
3870+ * with exec_simple_query's behavior of abandoning the whole query
3871+ * string upon error. Also, the point of an implicit transaction
3872+ * block (as opposed to a regular one) is to automatically close
3873+ * after an error, so it's hard to see how a savepoint would fit
3874+ * into that.
3875+ *
3876+ * The error messages for this are phrased as if there were no
3877+ * active transaction block at all, which is historical but
3878+ * perhaps could be improved.
3879+ */
3880+ case TBLOCK_IMPLICIT_INPROGRESS :
3881+ ereport (ERROR ,
3882+ (errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
3883+ /* translator: %s represents an SQL statement name */
3884+ errmsg ("%s can only be used in transaction blocks" ,
3885+ "SAVEPOINT" )));
3886+ break ;
3887+
37833888/* These cases are invalid. */
37843889case TBLOCK_DEFAULT :
37853890case TBLOCK_STARTED :
@@ -3834,15 +3939,23 @@ ReleaseSavepoint(List *options)
38343939switch (s -> blockState )
38353940{
38363941/*
3837- * We can't rollback to a savepoint if there is no savepoint
3838- * defined.
3942+ * We can't release a savepoint if there is no savepoint defined.
38393943 */
38403944case TBLOCK_INPROGRESS :
38413945ereport (ERROR ,
38423946(errcode (ERRCODE_S_E_INVALID_SPECIFICATION ),
38433947errmsg ("no such savepoint" )));
38443948break ;
38453949
3950+ case TBLOCK_IMPLICIT_INPROGRESS :
3951+ /* See comment about implicit transactions in DefineSavepoint */
3952+ ereport (ERROR ,
3953+ (errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
3954+ /* translator: %s represents an SQL statement name */
3955+ errmsg ("%s can only be used in transaction blocks" ,
3956+ "RELEASE SAVEPOINT" )));
3957+ break ;
3958+
38463959/*
38473960 * We are in a non-aborted subtransaction. This is the only valid
38483961 * case.
@@ -3957,6 +4070,15 @@ RollbackToSavepoint(List *options)
39574070errmsg ("no such savepoint" )));
39584071break ;
39594072
4073+ case TBLOCK_IMPLICIT_INPROGRESS :
4074+ /* See comment about implicit transactions in DefineSavepoint */
4075+ ereport (ERROR ,
4076+ (errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
4077+ /* translator: %s represents an SQL statement name */
4078+ errmsg ("%s can only be used in transaction blocks" ,
4079+ "ROLLBACK TO SAVEPOINT" )));
4080+ break ;
4081+
39604082/*
39614083 * There is at least one savepoint, so proceed.
39624084 */
@@ -4046,11 +4168,12 @@ RollbackToSavepoint(List *options)
40464168/*
40474169 * BeginInternalSubTransaction
40484170 *This is the same as DefineSavepoint except it allows TBLOCK_STARTED,
4049- *TBLOCK_END, and TBLOCK_PREPARE states, and therefore it can safely be
4050- *used in functions that might be called when not inside a BEGIN block
4051- *or when running deferred triggers at COMMIT/PREPARE time. Also, it
4052- *automatically does CommitTransactionCommand/StartTransactionCommand
4053- *instead of expecting the caller to do it.
4171+ *TBLOCK_IMPLICIT_INPROGRESS, TBLOCK_END, and TBLOCK_PREPARE states,
4172+ *and therefore it can safely be used in functions that might be called
4173+ *when not inside a BEGIN block or when running deferred triggers at
4174+ *COMMIT/PREPARE time. Also, it automatically does
4175+ *CommitTransactionCommand/StartTransactionCommand instead of expecting
4176+ *the caller to do it.
40544177 */
40554178void
40564179BeginInternalSubTransaction (char * name )
@@ -4076,6 +4199,7 @@ BeginInternalSubTransaction(char *name)
40764199{
40774200case TBLOCK_STARTED :
40784201case TBLOCK_INPROGRESS :
4202+ case TBLOCK_IMPLICIT_INPROGRESS :
40794203case TBLOCK_END :
40804204case TBLOCK_PREPARE :
40814205case TBLOCK_SUBINPROGRESS :
@@ -4180,6 +4304,7 @@ RollbackAndReleaseCurrentSubTransaction(void)
41804304case TBLOCK_DEFAULT :
41814305case TBLOCK_STARTED :
41824306case TBLOCK_BEGIN :
4307+ case TBLOCK_IMPLICIT_INPROGRESS :
41834308case TBLOCK_PARALLEL_INPROGRESS :
41844309case TBLOCK_SUBBEGIN :
41854310case TBLOCK_INPROGRESS :
@@ -4211,6 +4336,7 @@ RollbackAndReleaseCurrentSubTransaction(void)
42114336s = CurrentTransactionState ;/* changed by pop */
42124337AssertState (s -> blockState == TBLOCK_SUBINPROGRESS ||
42134338s -> blockState == TBLOCK_INPROGRESS ||
4339+ s -> blockState == TBLOCK_IMPLICIT_INPROGRESS ||
42144340s -> blockState == TBLOCK_STARTED );
42154341}
42164342
@@ -4259,6 +4385,7 @@ AbortOutOfAnyTransaction(void)
42594385case TBLOCK_STARTED :
42604386case TBLOCK_BEGIN :
42614387case TBLOCK_INPROGRESS :
4388+ case TBLOCK_IMPLICIT_INPROGRESS :
42624389case TBLOCK_PARALLEL_INPROGRESS :
42634390case TBLOCK_END :
42644391case TBLOCK_ABORT_PENDING :
@@ -4369,6 +4496,7 @@ TransactionBlockStatusCode(void)
43694496case TBLOCK_BEGIN :
43704497case TBLOCK_SUBBEGIN :
43714498case TBLOCK_INPROGRESS :
4499+ case TBLOCK_IMPLICIT_INPROGRESS :
43724500case TBLOCK_PARALLEL_INPROGRESS :
43734501case TBLOCK_SUBINPROGRESS :
43744502case TBLOCK_END :
@@ -5036,6 +5164,8 @@ BlockStateAsString(TBlockState blockState)
50365164return "BEGIN" ;
50375165case TBLOCK_INPROGRESS :
50385166return "INPROGRESS" ;
5167+ case TBLOCK_IMPLICIT_INPROGRESS :
5168+ return "IMPLICIT_INPROGRESS" ;
50395169case TBLOCK_PARALLEL_INPROGRESS :
50405170return "PARALLEL_INPROGRESS" ;
50415171case TBLOCK_END :