Триггеры
Триггером в СУБД ЛИНТЕР называется хранимая процедура, которая вызывается на выполнение ядром СУБД автоматически при наступлении в БД события, на которое настроен триггер.
События, на которое может быть настроен триггер, делятся на события обработки данных и системные события. В качестве события на обработку данных для триггера может выступать модификация (INSERT, DELETE или UPDATE) некоторой таблицы. В качестве системного события может быть событие регистрации пользователя. Триггер может вызываться один раз на весь SQL-оператор или на каждую операцию, выполняемую с записью таблицы. Триггеры различаются по времени срабатывания: до выполнения операции с записью (BEFORE), после выполнения операции (AFTER) и вместо выполнения операции (INSTEAD OF).
Тело триггера представляет собой исходный текст на процедурном языке, т.е. оно может включать декларации, исполняемые операторы и блок обработки исключений. В теле триггера разрешены любые операторы, в том числе, исполнение SQL-запросов, вызов хранимых процедур и т.д.
Триггеры типа INSTEAD OF применимы только к базовым таблицам и не применимы к представлениям.
В теле триггера, вызываемого на каждую строку (FOR EACH ROW) доступны специальные переменные с префиксом по умолчанию OLD и NEW, содержащие старое и новое значение строки. Обе эти переменные – структуры (т.е. с точки зрения языка хранимых процедур – курсорные переменные), включающие столбцы тех же имен и типов, что и обрабатываемая триггером таблица.
В зависимости от вида триггера эти переменные определяются следующим образом:
-
в триггере на INSERT доступна только переменная NEW; она содержит все значения, которые должны быть занесены в новую строку (если триггер BEFORE), или которые уже занесены (если триггер AFTER); при этом в триггере BEFORE допустимо присвоить полям переменной NEW новые значения, переопределив, таким образом, исходное поведение INSERT;
-
в триггере на UPDATE переменная NEW содержит значение, которое должно содержаться в строке после обновления (если триггер BEFORE), или которое уже там содержится (если триггер AFTER); при этом в триггере UPDATE допустимо присвоить полям переменной NEW новые значения, переопределив, таким образом, исходное поведение UPDATE; переменная OLD всегда содержит все значения, которые были в строке до обновления;
-
в триггере на DELETE доступна только переменная OLD; она содержит все значения удаляемой строки.
Кроме изменения значений переменной NEW, триггер BEFORE … FOR EACH ROW также может повлиять на ход выполнения SQL-запроса путем запрета операции. Для этого триггер должен вернуть логическое значение FALSE или завершиться с исключением. В такой ситуации конкретная строка, обработанная триггером, пропускается (не вставляется, не обновляется или не удаляется). Все остальные строки продолжают обрабатываться. Таким образом, в результате действия триггеров может оказаться, что часть строк, которые должны быть обработаны SQL-запросом, из этой обработки будут исключены. В этом случае количество реально обработанных строк можно получить с помощью соответствующих вызовов СУБД ЛИНТЕР.
СУБД ЛИНТЕР позволяет завершить и откатить весь SQL-оператор из триггера, вернув пользователю заданный код завершения.
С помощью триггеров можно снабдить СУБД такими возможностями, как альтернативный аудит, основанный на значениях данных, комплексный контроль безопасности и сложные правила целостности. Например, можно создать триггер, который будет позволять модифицировать некоторую таблицу лишь в заданный период времени.
Примечание
Хотя триггеры БД позволяют определять и вводить в действие правила целостности, они не эквивалентны этим правилам, а дополняют и/или расширяют их. Например, триггер, определенный для введения в действие правила целостности, не проверяет данные, уже загруженные в таблицу. Поэтому рекомендуется использовать триггеры вместо ограничений целостности только тогда, когда ограничение целостности не может быть реализовано подходящим правилом целостности.
Для поддержки триггеров должны существовать системные таблицы $$$TRIG
и $$$PROC
(создаются при выполнении SQL-скрипта systab.sql
).