Can CLR execution continue after 'THROW' is encountered in T-SQL?

It appears that this behavior is specific to connections using "Context Connection = true;". I have tried to get around this by writing out the try-catch-finally structure instead of using the using macro, but that had no effect.

A Microsoft Connect bug was filed almost 3 months ago regarding this behavior. In that Connect bug it was speculated that THROW raises a ThreadAbortException that cannot be reset via the Thread.ResetAbort method. I tried explicitly catching this exception, and even calling Thread.ResetAbort when catching the generic Exception, but to no avail. So I am not sure if a ThreadAbortException is really being called, but regardless, the current process ends immediately. And, it even displays the error as a T-SQL error and not a .NET Framework error, which is odd.

The reporter of that Connect bug tested on SQL Server 2014, and I tested on SQL Server 2012. I cannot say for certain if this behavior still exists in SQL Server 2016, but I strongly suspect that it does given that there doesn't seem to be much effort (if any) put into fixing and/or improving SQL Server's CLR Integration (i.e. SQLCLR). So for now, and likely the foreseeable future, there are three possible work-arounds that have worked for me:

  1. Replace THROW with RAISERROR(); RETURN; for procs that might be called by SQLCLR objects. The only downsides I can think of are:
    • Can't set a custom ERROR_NUMBER on-the-fly
    • Can't re-throw to send the original, system-defined ERROR_NUMBER to the caller
  2. Wrap your query in a T-SQL TRY / CATCH that uses RAISERROR:

      String _Query = @"
    BEGIN TRY
      EXEC dbo.TestThrowSql @CauseError;
    END TRY
    BEGIN CATCH
      DECLARE @ErrorMessage NVARCHAR(4000);
      SET @ErrorMessage = ERROR_MESSAGE();
      RAISERROR(@ErrorMessage, 16, 1);
    END CATCH;
    ";
    

    The benefit here is that you can continue to use THROW and it will work as expected when called by non-SQLCLR app code, by SQLCLR app code that is not using the Context Connection, by other Stored Procedures, in SQL Agent jobs, etc. That and you don't have to go back and edit any existing Stored Procedures :-).

  3. Switch to using a regular / external connection string. The downsides here are:
    • The Context Connection is much faster.
    • The Context Connection can be done in a SAFE Assembly.
    • The Context Connection has access to session-based items (i.e. CONTEXT_INFO, local temporary tables, etc.)