@@ -265,6 +265,8 @@ static void CallSubXactCallbacks(SubXactEvent event,
265265 SubTransactionId mySubid ,
266266 SubTransactionId parentSubid );
267267static void CleanupTransaction (void );
268+ static void CheckTransactionChain (bool isTopLevel , bool throwError ,
269+ const char * stmtType );
268270static void CommitTransaction (void );
269271static TransactionId RecordTransactionAbort (bool isSubXact );
270272static void StartTransaction (void );
@@ -2948,6 +2950,26 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType)
29482950 /* all okay */
29492951}
29502952
2953+ /*
2954+ * These two functions allow for warnings or errors if a command is
2955+ * executed outside of a transaction block.
2956+ *
2957+ * While top-level transaction control commands (BEGIN/COMMIT/ABORT) and
2958+ * SET that have no effect issue warnings, all other no-effect commands
2959+ * generate errors.
2960+ */
2961+ void
2962+ WarnNoTransactionChain (bool isTopLevel , const char * stmtType )
2963+ {
2964+ CheckTransactionChain (isTopLevel , false, stmtType );
2965+ }
2966+
2967+ void
2968+ RequireTransactionChain (bool isTopLevel , const char * stmtType )
2969+ {
2970+ CheckTransactionChain (isTopLevel , true, stmtType );
2971+ }
2972+
29512973/*
29522974 * RequireTransactionChain
29532975 *
@@ -2957,16 +2979,16 @@ PreventTransactionChain(bool isTopLevel, const char *stmtType)
29572979 * is presumably an error). DECLARE CURSOR is an example.
29582980 *
29592981 * If we appear to be running inside a user-defined function, we do not
2960- * issue an error , since the function could issue more commands that make
2982+ * issue anything , since the function could issue more commands that make
29612983 * use of the current statement's results. Likewise subtransactions.
29622984 * Thus this is an inverse for PreventTransactionChain.
29632985 *
29642986 * isTopLevel: passed down from ProcessUtility to determine whether we are
29652987 * inside a function.
2966- * stmtType: statement type name, for error messages.
2988+ * stmtType: statement type name, for warning or error messages.
29672989 */
2968- void
2969- RequireTransactionChain (bool isTopLevel , const char * stmtType )
2990+ static void
2991+ CheckTransactionChain (bool isTopLevel , bool throwError , const char * stmtType )
29702992{
29712993 /*
29722994 * xact block already started?
@@ -2986,11 +3008,12 @@ RequireTransactionChain(bool isTopLevel, const char *stmtType)
29863008 if (!isTopLevel )
29873009 return ;
29883010
2989- ereport (ERROR ,
3011+ ereport (throwError ? ERROR : WARNING ,
29903012 (errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
29913013 /* translator: %s represents an SQL statement name */
29923014 errmsg ("%s can only be used in transaction blocks" ,
29933015 stmtType )));
3016+ return ;
29943017}
29953018
29963019/*
@@ -3425,12 +3448,12 @@ UserAbortTransactionBlock(void)
34253448
34263449 /*
34273450 * The user issued ABORT when not inside a transaction. Issue a
3428- * NOTICE and go to abort state. The upcoming call to
3451+ * WARNING and go to abort state. The upcoming call to
34293452 * CommitTransactionCommand() will then put us back into the
34303453 * default state.
34313454 */
34323455 case TBLOCK_STARTED :
3433- ereport (NOTICE ,
3456+ ereport (WARNING ,
34343457 (errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
34353458 errmsg ("there is no transaction in progress" )));
34363459 s -> blockState = TBLOCK_ABORT_PENDING ;
0 commit comments