Предотвращение рекурсивного запуска в PostgreSQL
Как предотвратить рекурсивное выполнение триггера? Предположим, что я хочу построить описание "tree-able" на графике учетной записи. Итак, что я делаю, когда новая запись вставлена /обновлена, я обновляю родительскую запись down_qty
, поэтому это приведет к рекурсивному запуску запуска обновления.
Прямо сейчас, мой код в порядке - я помещаю это в первую строку триггера UPDATE
:
-- prevents recursive trigger
if new.track_recursive_trigger <> old.track_recursive_trigger then
return new;
end if;
И это пример кода из моего триггера, когда мне нужно обновить родительскую запись qty:
update account_category set
track_recursive_trigger = track_recursive_trigger + 1, -- i put this line to prevent recursive trigger
down_qty = down_qty - (old.down_qty + 1)
where account_category_id = m_parent_account;
Я думаю, если есть способ в PostgreSQL обнаружить рекурсивный триггер без введения нового поля, что-то похожее на MSSQL trigger_nestlevel
.
[EDIT]
Я петлю внутри дерева, мне нужно поднять down_qty
каждого account_category
обратно в свой корень. Например, я вставляю новую категорию учетных записей, она должна увеличивать down_qty
своего родителя account_category
, аналогично, когда я изменяю родительский элемент категории account_category
, мне нужно уменьшить down_qty
of account_category
previous parent account_category
. Хотя я думаю, что это возможно, я не позволяю PostgreSQL делать рекурсивный триггер. Я использовал MSSQL до того момента, когда уровень рекурсивной глубины триггера ограничен только до уровней 16
.
Ответы
Ответ 1
В pg, вам нужно отслеживать рекурсию триггеров.
Если триггерная функция выполняет SQL команд, то эти команды могут снова срабатывает огонь. Это называется каскадные триггеры. Нет прямого ограничение количества каскадов уровни. Каскады можно вызывают рекурсивный вызов тот же триггер; например, INSERT триггер может выполнить команду, которая вставляет дополнительную строку в та же таблица, вызывающая триггер INSERT чтобы снова уволить. Это триггер обязанности программиста избегать бесконечная рекурсия в таких сценариях.
http://www.postgresql.org/docs/8.3/static/trigger-definition.html
Ответ 2
Это то, что я делаю в PostgreSQL 9.2, хотя я должен признать, что я не нашел этот подход документированным. Существует функция pg_trigger_depth()
описанная здесь, которую я использую, чтобы различать оригинальные и вложенные вызовы в триггере.
CREATE TRIGGER trg_taxonomic_positions
AFTER INSERT OR UPDATE OF taxonomic_position
ON taxon_concepts
FOR EACH ROW
WHEN (pg_trigger_depth() = 0)
EXECUTE PROCEDURE trg_taxonomic_positions()
Ответ 3
В начале определения триггера вы можете отключить триггеры в этой конкретной таблице и повторно использовать их в конце (и убедитесь, что исключение не прекращает выполнение до ожидаемого!). У этого есть много глубоких отверстий, но может работать для некоторых световых реализаций. Обратите внимание, что для этой реализации вам также потребуются привилегии для отключения триггеров.
Ответ 4
Чтобы избежать неограниченной рекурсии, см. мой ответ здесь. Как прокомментировали другие, если ваша структура данных является истинным деревом (у root (s) не будет родителя (ов)), и рекурсия будет всегда останавливаться в корне. Для узлов с единственным родительским указателем единственным способом для неограниченной рекурсии будет наличие циклов. (метод в моей ссылке будет чаще всего посещать node)