Идентификация операции внутри триггера
Идентификация операции внутри триггера
Описание проблемы : Есть в наличии 2 таблицы Т1 (master) и Т2 (detail), связанные друг с другом ограничением внешнего ключа. Для внешнего ключа настроены каскадные изменения. На таблице Т2 висит триггер after delete.
Вопрос : Как внутри вышеупомянутого триггера узнать чем было спровоцировано удаление записи? Это результат срабатывания системного триггера, обслуживающего каскадные изменения при удалении записи из таблицы Т1, или же это обычное удаление записи из таблицы Т2 посредством выполнения оператора delete? Можно ли вообще внутри триггера как-то отличить друг от друга эти 2 удаления?
System Info : FireBird 1.5.2 CS
Вопрос : Как внутри вышеупомянутого триггера узнать чем было спровоцировано удаление записи? Это результат срабатывания системного триггера, обслуживающего каскадные изменения при удалении записи из таблицы Т1, или же это обычное удаление записи из таблицы Т2 посредством выполнения оператора delete? Можно ли вообще внутри триггера как-то отличить друг от друга эти 2 удаления?
System Info : FireBird 1.5.2 CS
никак. вопрос - зачем? что такого внутри триггера t2.after_delete, что он должен отличать удаление напрямую от удаления через каскад?Можно ли вообще внутри триггера как-то отличить друг от друга эти 2 удаления
а если это удаление будет не каскадным, а триггером на таблице master - это что, третий случай? А если из триггера вообще другой таблицы - четвертый?
Ничего особенного.kdv писал(а):что такого внутри триггера t2.after_delete, что он должен отличать удаление напрямую от удаления через каскад?

А по поводу допустимого множества случаев, то здесь также все просто. Различать нужно только 2 из них: непосредственное удаление и все остальные.

-
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
Re: Идентификация операции внутри триггера
Проблемы в этом разделе не нашёл.Naidenov писал(а):Описание проблемы :
Выполнять удаление разными пользователями.Naidenov писал(а):Как внутри вышеупомянутого триггера узнать чем было спровоцировано удаление записи?
Всё зависит от того, для чего именно нужен этот протокол.Naidenov писал(а):Ничего особенного.kdv писал(а):что такого внутри триггера t2.after_delete, что он должен отличать удаление напрямую от удаления через каскад?Совершенно тривиальное протоколирование изменений таблицы Т2.
А по поводу допустимого множества случаев, то здесь также все просто. Различать нужно только 2 из них: непосредственное удаление и все остальные.
У нас была похожая задача, когда нужно было вести и отображать историю изменений объекта, а объект раскладывался на несколько таблиц.
Т.к. для одного логического изменения использовалась одна, явно стартуемая, транзакция, то решение очевидно - добавить в протокол ID транзакции и группировать по нему.
Возможно я чего-то недопонимаю, но мне кажется, что сгруппировав записи по id_transaction, нельзя ответить на вопрос: как отличить непосредственное удаление от всех прочих? Вряд ли мне поможет знание того, что в рамках транзакции TR1 было выполнено удаление DEL1, а в рамках транзакции TR2 было выполнено удаление DEL2. А какое из них "какого сорта"?Tonal писал(а):решение очевидно - добавить в протокол ID транзакции и группировать по нему.
P.S. Еще раз прошу прощение, может быть я туго воспринимаю и недогоняю...

Всё же неясно, нафига. Ну да ладно. Проктологи рекомендуют.
Код: Выделить всё
CREATE TRIGGER CHILD_AD FOR CHILD ACTIVE AFTER DELETE POSITION 0
as
declare variable FK_Cnt integer;
begin
select count(*) from parent where id=old.parentid into :FK_Cnt;
if (FK_Cnt = 0) then
-- Это каскадное удаление
else
-- Удаление вручную
end
собственно, проктологические варианты решения должны навевать на мысль, что что-то здесь не так. В триггере обычно нет никакой возможности определить, откуда идет удаление - из процедуры, другого триггера, fk, и так далее.
В репликаторах такая задача решается определением специального имени пользователя, которое и анализируется в триггере для того чтобы отличить операторский и "репликаторский" ввод.
В репликаторах такая задача решается определением специального имени пользователя, которое и анализируется в триггере для того чтобы отличить операторский и "репликаторский" ввод.
В случае именно каскадного удаления FK - можно, из-за особенностей удаления (мастер-деталь).kdv писал(а):В триггере обычно нет никакой возможности определить, откуда идет удаление - из процедуры, другого триггера, fk, и так далее.
Я вперёд сказалkdv писал(а):...такая задача решается определением специального имени пользователя

В нашем случае велось протоколирование и мастера и деталя.Naidenov писал(а):Возможно я чего-то недопонимаю, но мне кажется, что сгруппировав записи по id_transaction, нельзя ответить на вопрос: как отличить непосредственное удаление от всех прочих?Tonal писал(а):решение очевидно - добавить в протокол ID транзакции и группировать по нему.
Соответственно, если в потоколе для одной транзакции присутствовали записи удаления и мастера и подчинённых детей, стал быть было каскадное удаление.
Если мастер отсутствовал - значит было непосредственное удаление.
Ты бы всё же рассказал, для чего ты этот протокол использовать хочешь - глядишь и решений бы адекватных накидали.
А то, в твоей постановке очень уж практологические решения получаются...
P.S. Да, похоже можно с помощью контекстных переменных извратиться:
1) В триггере мастера before_delete устанавливаем контекстную переменную для контекста транзакции.
2) В триггере мастера after_delete сбрасываем
3) В триггере деталя проверяем - установлена - стал быть удаление по FK.
Ну и эту же переменную можно заиспользовать для индикации что удаляем из ХП или другого триггера.

Это поведение где-нибудь описано?WildSery писал(а):Так не получится - After Delete мастера наступит раньше, чем начнут удаляться детали.Tonal писал(а):похоже можно с помощью контекстных переменных извратиться:
Тогда, after delet мастера можно убрать, а и заложиться на то, что в одной транзакции удаления никогда не будет одновременно удаления обоих видов.

Хотя тут тоже есть завязка на то, что триггер before delete будет выполнятся до удаления детей...
Короче, самое правильное решение - триггеры с проверкой и процедура удаления.
В триггерах (на мастере и деталях) проверяем переменную транзакции - если null - кидаем исключение.
В процедуре устанавливаем переменную и запускаем удаление.