Использование OLD. контекстных переменных в INSERT триггерах

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
jake
Сообщения: 16
Зарегистрирован: 24 фев 2005, 09:03

Использование OLD. контекстных переменных в INSERT триггерах

Сообщение jake » 03 дек 2005, 11:48

Возникли вопросы по использованию OLD. контекстных переменных в INSERT триггерах.
Конечно в чистых триггерах на вставку OLD-переменные просто не нужны. Я говорю о универсальных триггерах
(on INSERT or UPDATE к примеру), вызываемых при вставке записи.


Пример:

Код: Выделить всё

CREATE TABLE TAB (
    ID  INTEGER
);

SET TERM ^ ;

CREATE TRIGGER TAB_BIU0 FOR TAB
ACTIVE BEFORE INSERT OR UPDATE POSITION 0
AS
begin
    if (old.ID=2) then new.ID=2;
end
^
Теперь встявляем в таблицу запись:

Код: Выделить всё

insert into Tab values(1);
Всё ОК, ошибок нет, т.е. вроде как можем использовать OLD-переменные в инсерт/апдейт триггерах напрямую, без ветвлений типа:

Код: Выделить всё

if (inserting) ....
if (updating)
теперь дабавим еще метаданных:

Код: Выделить всё

CREATE EXCEPTION ERR 'My Error!';

SET TERM ^ ;

CREATE PROCEDURE PROC 
AS
begin
    insert into Tab values(1);
    exception Err;
end^
и выполним процедуру:

Код: Выделить всё

execute procedure Proc;
в ответ ошибка:

Код: Выделить всё

Statement failed, SQLCODE = -508

no current record for fetch operation
-exception 1
-My Error!
далее отключаем ранее созданный триггер и пробуем еще раз выполнить процедуру:

Код: Выделить всё

Statement failed, SQLCODE = -836

exception 1
-My Error!
Т.е.ошибка -508 no current record for fetch operation вылазит из-за использования OLD.ID при выполнении инсерта.
Почему так?
Если просто вставляем запись, то всё ОК, а если после инсерта вызвать какое-то исключение,
то вылазит не это исключение, а ошибка, связанная с использованием OLD.ID.

Какая-то неоднозначность. Мне кажется, либо ошибка SQLCODE = -508 должна возникать всегда,
когда идет обращение к контексту OLD. в INSERT триггере, либо не должна возникать вообще,
что означало бы, что в INSERT триггере любая OLD.переменная is NULL.

Второй вариант кажется логичным, потому что позволяет использовать универсатьные триггеры действительно универсально,
без усложнения их логики. Сейчас вроде так и работает, но как-то не до конца...

Разьясните ситуацию.

Сервер: LI-V1.5.3.4854 Firebird 1.5
Последний раз редактировалось jake 03 дек 2005, 12:02, всего редактировалось 1 раз.

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 03 дек 2005, 14:00

no current record for fetch operation
Это предупреждение, а не ошибка. Если все ОК, то IBExpert его не показывает. Иначе приплюсовывает к тексту ошибки.

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Re: Использование OLD. контекстных переменных в INSERT тригг

Сообщение dimitr » 03 дек 2005, 14:07

jake писал(а):что означало бы, что в INSERT триггере любая OLD.переменная is NULL
Цитирую доку:

3. In multiple-action triggers both OLD and NEW contexts are available.
If the trigger invocation forbids one of them (e.g. OLD context for
INSERT operation), then all fields of that context will evaluate to NULL.
If you assign to unproper context, runtime exception will be thrown.

jake
Сообщения: 16
Зарегистрирован: 24 фев 2005, 09:03

Сообщение jake » 03 дек 2005, 17:08

dimitr писал(а):
no current record for fetch operation
Это предупреждение, а не ошибка. Если все ОК, то IBExpert его не показывает. Иначе приплюсовывает к тексту ошибки.
Не просто приплюсовывает текст. В результате этого предупреждения меняется SQLCODE. Код истиной ошибки, я так понимаю, теряется. (или можно где-то его достать?)
В описанном мной примере, я на клиенте ожидаю увидеть SQLCODE=-836 (чтоб обработать и отобразить только сам текст EXCEPTION-а), а получаю SQLCODE=-508...

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 05 дек 2005, 12:23

Ты прав. За кадром варнинг превращается в ошибку, портя этим ожидаемый SQLCODE. Буду исправлять.

Ответить