@@ -265,6 +265,8 @@ static void CallSubXactCallbacks(SubXactEvent event,
265265SubTransactionId mySubid ,
266266SubTransactionId 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- *issuean error , since the function could issue more commands that make
2982+ *issueanything , 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, forwarning 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)
29863008if (!isTopLevel )
29873009return ;
29883010
2989- ereport (ERROR ,
3011+ ereport (throwError ? ERROR : WARNING ,
29903012(errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
29913013/* translator: %s represents an SQL statement name */
29923014errmsg ("%s can only be used in transaction blocks" ,
29933015stmtType )));
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 */
34323455case TBLOCK_STARTED :
3433- ereport (NOTICE ,
3456+ ereport (WARNING ,
34343457(errcode (ERRCODE_NO_ACTIVE_SQL_TRANSACTION ),
34353458errmsg ("there is no transaction in progress" )));
34363459s -> blockState = TBLOCK_ABORT_PENDING ;