Является ли pg_trigger_depth () плохим для предотвращения каскадирования триггеров (рекурсии)?


8

Почему pg_trigger_depth() = 0плохо использовать (для чего-либо кроме отладки) при предотвращении каскадирования триггера (рекурсии)?

Может ли кто-нибудь предоставить код, чтобы продемонстрировать, почему это плохо?

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

Я думал, что это будет хорошим решением этого (моего) вопроса здесь, но мне говорят иначе:

Подумал, что это хороший вопрос.

Это предлагается здесь как решение:

Документация Postgres 9.3:

https://www.postgresql.org/docs/9.3/static/functions-info.html

Ответы:


1

Да, всегда плохо делать поведение зависимым от pg_trigger_depth()

Может быть, я немного менее склонен к общим заявлениям, но что хорошего это может сделать? Я не вижу аргумента, почему вы хотели бы такую ​​функцию. Основной целью базы данных является обеспечение целостности данных. И, насколько я понимаю, и я могу ошибаться, такое использование всегда является потенциальным нарушением целостности данных. В ответе @ Эрвина он говорит «если забудешь» . Смысл обеспечения целостности заключается в том, чтобы устранить эту возможность. Если агент может запомнить все и понять последствия и код, связанный с ними, вы можете получить целостность данных из всего .

Давайте введем несколько терминов, в программировании мы имеем

  • «состояние», которое включает в себя все, к чему имеет доступ программист.
  • «контекст исполнения», который включает среду для исполнения.

Кроме того, у нас есть термин для функции, которая не имеет состояния, которое мы называем чистой функцией ,

Функция всегда оценивает одно и то же значение результата, учитывая одно и то же значение аргумента. Значение результата функции не может зависеть от какой-либо скрытой информации или состояния, которые могут изменяться во время выполнения программы или между различными выполнениями программы, а также не может зависеть от какого-либо внешнего ввода от устройств ввода-вывода (обычно - см. Ниже).

Различие чистоты является полезным , поскольку она исключает нагрузку на память что - либо от имени компьютера или программиста: f(x) = yэто всегда верно. Здесь вы нарушаете чистоту в худшем месте - базе данных. И вы делаете это сложным и подверженным ошибкам способом - делая внутренний контекст выполнения ощутимой вещью в состоянии вашего приложения БД.

Я бы не хотел этого. Просто подумайте о сложностях, которые вы должны мысленно буферизовать.

  • Table A«S Trigger Aпожаров
    • Trigger Aвсегда выдает DML Table B, стреляя Trigger B.
      • Trigger Bусловно выдает ДМЛ на Table Aстрельбу Trigger A.
      • Trigger Bвсегда выдает DML Table A, стреляя Trigger A.
    • Trigger Aусловно выдает ДМЛ на Table Bстрельбу Trigger B.
      • Trigger Bусловно выдает ДМЛ на Table Aстрельбу Trigger A.
      • Trigger Bвсегда выдает DML Table A, стреляя Trigger A.

Если это выглядит сложным, имейте в виду, что «условно» можно далее расширить до «это произошло, но это может случиться не всегда» и «это не произошло, но это может произойти в другом месте».

Чтобы pg_trigger_depth()даже быть полезным, вы должны иметь ряд событий, которые также сложны. И теперь, вы хотите, чтобы выполнение зависело от содержимого выполнения в этой цепочке?

Я бы избежал этого. Если ваша система триггеров такая сложная, вы сами играете в «горячий картофель» с ручной гранатой в шкафу, и это вряд ли закончится хорошо.


10

Это не плохо использовать как таковое (ИМХО). Вам просто нужно знать о последствиях.

Я бы предпочел сделать это pg_trigger_depth() < 1вместо pg_trigger_depth() = 0принципала, но здесь это не важно. Мы говорим о триггерах, таких как:

CREATE TRIGGER my_trigger
AFTER INSERT ON my_tbl
FOR EACH ROW
WHEN (pg_trigger_depth() < 1)
EXECUTE PROCEDURE my_trigger_func();

Если позже вы добавите триггеры, которые, в свою очередь, сработают, то ничего не произойдет. Ваш триггер реагирует только на не триггерные события. В зависимости от вашей настройки это может быть именно то, что вам нужно - или что-то вроде ловушки, если вы забудете об этом и позже добавите больше триггеров, которые в свою очередь (также) будут запускать этот триггер. Вы меняете поведение по умолчанию. Обязательно документируйте это четко.

Имейте в виду, что pg_trigger_depth()учитывает любой триггер , а не только один и тот же триггер, чтобы предотвратить рекурсию, поэтому условие предотвращает срабатывание триггера, если он также вызывается из любого другого триггера.
Руководство:

текущий уровень вложенности триггеров PostgreSQL (0, если не вызывается, прямо или косвенно, из триггера)

Связанные с:

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.