Повторное удаление ошибки T-SQL

#sql-server-2008 #tsql

#sql-server-2008 #tsql

Вопрос:

В следующей процедуре, которую я нашел здесь:

 ALTER PROCEDURE [dbo].[usp_RethrowError]
AS -- Return if there is no error information to retrieve.
    IF ERROR_NUMBER() IS NULL
        RETURN;

    DECLARE @ErrorMessage           NVARCHAR(4000),
            @OriginalErrorNumber    INT,
            @RethrownErrorNumber    INT,
            @ErrorSeverity          INT,
            @ErrorState             INT,
            @ErrorLine              INT,
            @ErrorProcedure         NVARCHAR(200);

    -- Assign variables to error-handling functions that 
    -- capture information for RAISERROR.
    SELECT
         @OriginalErrorNumber    = ERROR_NUMBER()
        ,@ErrorSeverity          = ERROR_SEVERITY()
        ,@ErrorSeverity          = ERROR_SEVERITY()
        ,@ErrorState             = ERROR_STATE()
        ,@ErrorLine              = ERROR_LINE()
        ,@ErrorProcedure         = ISNULL(ERROR_PROCEDURE(),'-');

    --Severity levels from 0 through 18 can be specified by any user. 
    --Severity levels from 19 through 25 can only be specified by members of the sysadmin fixed server role or users with ALTER TRACE permissions
    IF @OriginalErrorNumber < 19 
        SET @RethrownErrorNumber = @OriginalErrorNumber
    ELSE
        SET @RethrownErrorNumber = 18

    -- Building the message string that will contain original
    -- error information.
    SELECT
        @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, '   'Message: '   ERROR_MESSAGE();


    -- Raise an error: msg_str parameter of RAISERROR will contain
    -- the original error information.
    RAISERROR (@ErrorMessage,
               @ErrorSeverity,
               @ErrorState,
               @RethrownErrorNumber,        -- parameter: original error number or 18, if the original was >=19.
               @ErrorSeverity,              -- parameter: original error severity.
               @ErrorState,                 -- parameter: original error state.
               @ErrorProcedure,             -- parameter: original error procedure name.
               @ErrorLine                   -- parameter: original error line number.
              );
  

Кто-нибудь может объяснить следующую строку:

  SELECT
        @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, '   'Message: '   ERROR_MESSAGE();
  

Я понимаю, что вхождения % являются заполнителями для целых чисел со знаком (%d) и strinf (%s), но я не понимаю, какие переменные сопоставлены этим заполнителям. Похоже, они не соответствуют параметрам, указанным в вызове RAISERROR:

 RAISERROR (@ErrorMessage,
           @ErrorSeverity,
           @ErrorState,
           @RethrownErrorNumber,        -- parameter: original error number or 18, if the original was >=19.
           @ErrorSeverity,              -- parameter: original error severity.

       @ErrorState,                 -- parameter: original error state.
       @ErrorProcedure,             -- parameter: original error procedure name.
       @ErrorLine                   -- parameter: original error line number.
          );
  

Я внес два небольших изменения в подпрограмму, одно для снижения серьезности, если> 19, а другое для использования исходного состояния вместо того, чтобы всегда передавать 1.

Если вы, ребята, не слишком сильно испортите эту процедуру моими незначительными изменениями, я добавлю информацию об ошибке протоколирования в пользовательскую таблицу непосредственно перед повторным переносом.

Для вызова:

 DECLARE @Zero INT
SET @Zero = 0

BEGIN TRY
 SELECT 5 / @Zero
END TRY
BEGIN CATCH
 PRINT 'We have an error...'
 EXEC usp_RethrowError
END CATCH
  

Последующие вопросы:

1) В ссылке выше упоминается, что эта процедура не будет работать при взаимоблокировках. Есть причина, почему?

2) Я добавил часть «ЕСЛИ @OriginalErrorNumber < 19». Я не слишком обеспокоен тем, что при возникновении ошибки > 18 повторное удаление ошибки будет иметь степень серьезности 18. В любом случае я нажимаю на прерывание, и первоначальная серьезность будет зарегистрирована. Есть ли что-нибудь еще в этой процедуре, о чем мне нужно беспокоиться?

Комментарии:

1. Примечание сбоку: возможно, что в нем ERROR_MESSAGE() будут некоторые printf() строки подстановки в стиле, такие как %s . Я бы рекомендовал передать, ERROR_MESSAGE() используя 'Message: %s' и включив ERROR_MESSAGE() в конце списка аргументов вашего нового RAISERROR() вызова, потому что в противном случае любые символы подстановки в printf() стиле в ERROR_MESSAGE() будут заменены TSQL на строку (null) , когда символы подстановки должны передаваться без подстановки.

Ответ №1:

Надеюсь, это поможет!

Вы на правильном пути, ErrorMessage — это строка шаблона, которая используется RAISERROR. Рассмотрение грамматической структуры RAISERROR устранит путаницу:

 RAISERROR ( { msg_id | msg_str | @local_variable }
    { ,severity ,state }
    [ ,argument [ ,...n ] ] )
    [ WITH option [ ,...n ] ]
  

Первыми тремя обязательными аргументами являются строка шаблона сообщения (msg_str), серьезность и состояние. За ними следуют необязательные аргументы, которые заменят параметры подстановки в msg_str.

Таким образом, код позволяет:

msg_str быть сообщением об ошибке

серьезность — это серьезность ошибки

состояние будет ErrorState

в качестве аргументов могут использоваться RethrownErrorNumber, ErrorSeverity, ErrorState, ErrorProcedure, ErrorLine

Ссылка http://msdn.microsoft.com/en-us/library/ms178592.aspx

Комментарии:

1. Я думаю, что заполнители % соответствуют указанным вами аргументам , начиная с 4-го параметра@RethrownErrorNumber, который я передаю в процедуру RAISERROR. Первые 3 параметра должны служить только для повторного удаления ошибки. Заполнители относятся соответственно к параметрам аргумента (4-й параметр и далее).) Спасибо!