Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Greenhorn
Member

Откуда:
Сообщений: 311
Добрый день.

+ select @@version
Microsoft SQL Server 2012 - 11.0.5058.0 (X64)
May 14 2014 18:34:29
Copyright (c) Microsoft Corporation
Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)


Есть исполнительная система в которой присутствует следующий код
--------- RUN QUERY
BEGIN TRY 
  EXEC( @stmt ); 
  SET @RowCnt = @@ROWCOUNT;
END TRY
BEGIN CATCH
  if XACT_STATE() != 0
    ROLLBACK TRAN

  SELECT @Err = ERROR_NUMBER(), @ErrDescr = cast(ERROR_MESSAGE() as nvarchar(512))
END CATCH  
---------

Где в @stmt динамически сформированный запрос вида
create table dbo.someTable(somevalue varchar(1024))
insert into dbo.someTable
exec dbo.SomeSP


Так вот, в dbo.SomeSP генерится Exception, который гасится блоком TRY CATCH.
НО, по условию задачи, ERROR_NUMBER(), ERROR_MESSAGE() выдаются в виде выборки, которая успешно вставляется в dbo.someTable.

При этом исполнительная система, оказывается не в курсе о возникших затруднениях и, как следствие, в логи, которые она ведет, ничего не попадает.

Вопрос. Каким бы способом уведомить исполнительную систему о возникших проблемах сохранив "insert into dbo.someTable",
если она не в курсе о содержимом динамического запроса, и о структуре dbo.someTable ?
12 дек 14, 11:39    [16987554]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Glory
Member

Откуда:
Сообщений: 104751
Greenhorn
Вопрос. Каким бы способом уведомить исполнительную систему о возникших проблемах сохранив "insert into dbo.someTable",
если она не в курсе о содержимом динамического запроса, и о структуре dbo.someTable ?

Ваш вопрос о том, как передать клиенту сообщение, ничего ему не передавая ?
12 дек 14, 11:44    [16987610]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Greenhorn
Member

Откуда:
Сообщений: 311
Glory
Greenhorn
Вопрос. Каким бы способом уведомить исполнительную систему о возникших проблемах сохранив "insert into dbo.someTable",
если она не в курсе о содержимом динамического запроса, и о структуре dbo.someTable ?

Ваш вопрос о том, как передать клиенту сообщение, ничего ему не передавая ?

Клиентом является "исполнительная система" - хранимая процедура.

В том то и вопрос - КАК передать хотя бы ERROR_MESSAGE() не взводя EXCEPTION ?
12 дек 14, 11:51    [16987681]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Glory
Member

Откуда:
Сообщений: 104751
Greenhorn
В том то и вопрос - КАК передать хотя бы ERROR_MESSAGE() не взводя EXCEPTION ?

У процедуры есть выходные параметры и возвращаемое значение.
Но для их получения придется их читать.
12 дек 14, 11:53    [16987693]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Greenhorn
Member

Откуда:
Сообщений: 311
Glory
Greenhorn
В том то и вопрос - КАК передать хотя бы ERROR_MESSAGE() не взводя EXCEPTION ?

У процедуры есть выходные параметры и возвращаемое значение.
Но для их получения придется их читать.

Я уже писал, что о запросе (т.е. о процедуре) и о структуре таблицы в которую идет вставка, "исполнительной системе" ничего не известно.

Одно из решений:
-- Исполнительная система --
declare @stmt nvarchar(max)
      , @RowCnt int
      , @Err int
      , @ErrDescr nvarchar(1024)
--...
create table #StdError(Err int, ErrorDescr nvarchar(1024))
--...
set @stmt = -- Формируется динамически на основе запросов из FileTable, справочных таблиц и т.д. и т.п.
N'create table dbo.sometable(Res int)
insert into dbo.sometable(Res)
exec( -- запрос из FileTable или dbo.SomeSP @UnknownParam_1, @UnknownParam_2--...
''
  declare @Err int
  begin try
    select 1/0
    set @Err = 0
  end try
  begin catch
    set @Err = ERROR_NUMBER()
    if object_id(''''tempdb..#StdError'''') is not NULL
      insert into #StdError values(ERROR_NUMBER(), ERROR_MESSAGE() )
  end catch
    select @Err
'')'

--------- RUN QUERY
select @Err = null, @ErrDescr = null
BEGIN TRY 
  truncate table #StdError

  EXEC( @stmt ); 
  SET @RowCnt = @@ROWCOUNT;
  
  SELECT @Err = Err, @ErrDescr = ErrorDescr
  FROM #StdError
END TRY
BEGIN CATCH
  if XACT_STATE() != 0
    ROLLBACK TRAN

  SELECT @Err = ERROR_NUMBER(), @ErrDescr = cast(ERROR_MESSAGE() as nvarchar(512))
END CATCH  
---------

--...
SELECT @RowCnt, @Err , @ErrDescr
select * from dbo.sometable

drop table dbo.sometable
drop table #StdError


Вполне нормально, но терзают смутные сомнения ...

Еще идеи есть ?

Особенно если по проще как то можно ...
12 дек 14, 12:19    [16987926]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Glory
Member

Откуда:
Сообщений: 104751
Greenhorn
Я уже писал, что о запросе (т.е. о процедуре) и о структуре таблицы в которую идет вставка, "исполнительной системе" ничего не известно.

А причем тут ваши запрос и таблица ?
12 дек 14, 12:22    [16987948]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Greenhorn
Member

Откуда:
Сообщений: 311
Glory
Greenhorn
Я уже писал, что о запросе (т.е. о процедуре) и о структуре таблицы в которую идет вставка, "исполнительной системе" ничего не известно.

А причем тут ваши запрос и таблица ?

Гм...
"Мой запрос" - абстрактный пример формируемого динамически запроса в "исполнительной системе"
"таблица" - клиент ее знает какая это таблица.
Еще раз - "исполнительной системе" про эту таблицу ничего не известно.
В том числе и то, что она вообще существует или будет создана. Это клиенту известно, он заказывает "выполнение" ...
И клиенту не интересно, что во время выполнения произошли какие то там Exception_ы.
Это очень интересно системе логирования (часть "исполнительной системы").
12 дек 14, 12:32    [16988030]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Glory
Member

Откуда:
Сообщений: 104751
Greenhorn
Еще раз - "исполнительной системе" про эту таблицу ничего не известно.

Еще раз
Для того, чтобы родительский код узнал что-либо о статусе выполнения/завершения дочернего кода, дочерний код должен этот статуст выполнения/завершени возвращать.
12 дек 14, 12:34    [16988050]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Greenhorn
Member

Откуда:
Сообщений: 311
Glory
Greenhorn
Еще раз - "исполнительной системе" про эту таблицу ничего не известно.

Еще раз
Для того, чтобы родительский код узнал что-либо о статусе выполнения/завершения дочернего кода, дочерний код должен этот статуст выполнения/завершени возвращать.


Еще раз - КАК ???
Если "дочерний код" ничего не знает о "родительском коде" !!!

Вполне допустимо, что "дочерний код" догадывается о наличии таблицы #StdError в "родительском коде", и сообщает ему о своих проблемах через нее.
Но мне этот способ не очень нравится.

Может есть аналогичный способ ?
Особенно если можно обойтись без "догадок" ...
12 дек 14, 12:42    [16988132]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Glory
Member

Откуда:
Сообщений: 104751
Greenhorn
Еще раз - КАК ???
Если "дочерний код" ничего не знает о "родительском коде" !!!

Я фигею
Если ваш дочерний код написан так, что он не будет ничего сообщать о своем статусе, то никто и никогда и не сможет ничего узнать о статусе дочернего кода

Greenhorn
Вполне допустимо, что "дочерний код" догадывается о наличии таблицы #StdError в "родительском коде", и сообщает ему о своих проблемах через нее.
Но мне этот способ не очень нравится.

Фейспалм какой-то.
Черные ящики должны иметь входы и выходы. На первые падаются параметры, а со вторых читается состояние ящика. И ящику пофиг, что там снаружи. И пользователю пофиг, что там внутри ящика
12 дек 14, 12:46    [16988186]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 8815
автор
который гасится блоком TRY CATCH

А зачем гасится? Выбрасывайте ошибку наружу, исполнительная система её подхватит. Эскалация ошибки - лучшая практика.
12 дек 14, 13:21    [16988428]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
leov
Member

Откуда: С-Петербург
Сообщений: 616
Glory
Greenhorn
Еще раз - КАК ???
Если "дочерний код" ничего не знает о "родительском коде" !!!

Я фигею
Если ваш дочерний код написан так, что он не будет ничего сообщать о своем статусе, то никто и никогда и не сможет ничего узнать о статусе дочернего кода

Greenhorn
Вполне допустимо, что "дочерний код" догадывается о наличии таблицы #StdError в "родительском коде", и сообщает ему о своих проблемах через нее.
Но мне этот способ не очень нравится.

Фейспалм какой-то.
Черные ящики должны иметь входы и выходы. На первые падаются параметры, а со вторых читается состояние ящика. И ящику пофиг, что там снаружи. И пользователю пофиг, что там внутри ящика
"ничего не знает" и похоже ничего и не хочет знать, это по вашей постановке
на мой взгляд тут есть только два выхода
1. использовать какой-то стандартный ход - как-раз использование стандартно возвращаемого процедурой значения
2. слепить какую-то свою поделку которую вы примете в своей системе как стандарт и заставите всех ее использовать
это может быть вывод в лог sql или в постоянную или временную таблицу
или может по e-mail пошлете.....
12 дек 14, 13:33    [16988505]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
LexusR
Member

Откуда: Novosibirsk
Сообщений: 1887
create table #StdError(ErrorDescr nvarchar(1024))
DECLARE @OuutputMessage varchar(1000)
DECLARE @stmt nvarchar(max)
SET @stmt = N' 
  begin try
    select 1/0
    set @Err = 0
  end try
  begin catch
    set @OuutputMessage = ERROR_MESSAGE()
  end catch
'
EXECUTE sp_executesql @stmt, '@OuutputMessage varchar(1000) OUTPUT',
                      @OuutputMessage = @OuutputMessage OUTPUT;

insert into #StdError values(@OuutputMessage)
12 дек 14, 13:41    [16988553]     Ответить | Цитировать Сообщить модератору
 Re: Нужна идея - как прокинуть ошибку без raiserror, throw ?  [new]
LexusR
Member

Откуда: Novosibirsk
Сообщений: 1887
убрал неточности - рабочий макет

if OBJECT_ID('tempdb..#StdError') is not null drop table #StdError
create table #StdError(ErrorDescr nvarchar(1024))
DECLARE @OuutputMessage varchar(1000)
DECLARE @stmt nvarchar(max)
SET @stmt = N' 
  begin try
    select 1/0
    declare @Err int
    set @Err = 0
  end try
  begin catch
    set @OuutputMessage = ERROR_MESSAGE()
  end catch
'
EXECUTE sp_executesql @stmt, N'@OuutputMessage varchar(1000) OUTPUT',
                      @OuutputMessage = @OuutputMessage OUTPUT;

insert into #StdError values(@OuutputMessage)
select * from #StdError
12 дек 14, 13:45    [16988586]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить