Триггеры
Триггеры - это определяемые пользователем действия, которые выполняются, когда над таблице, к
которой прикреплен триггер, выполняются операции INSERT, UPDATE или DELETE. В SQLBase
действия триггера являются хранимыми процедурами. Иными словами, пользователь создает
хранимые процедуры, которые описывают действия, совершаемые триггерами.
В SQLBase триггеры используются для решения трех основных задач:
- Усиление ссылочной целостности - Триггеры могут быть использованы для
реализации ограничений ссылочной целостности, выходящие за пределы
стандартных ограничений SQLBase. Например, пользователь может захотеть
реализовать правило. каскадного изменения данных (update cascade rule). Он
может это сделать, создав триггер, который будет обновлять дочернюю
таблицу (таблицы) при каждом изменении колонки в родительской таблице.
- Проверка данных - Триггеры могут выполнять разнообразную проверку
данных. Значения колонок могут передаваться в триггерные процедуры в
качестве параметров, где над ними могут производиться самые разнообразные
операции. В текущей версии SQLBase реализован механизм, который
позволяет производить ввод данных в таблицы непосредственно из триггера,
без передачи информации извне. Например, пользователь может создать
триггер, который будет получать из приложения данные для ввода в строку
таблицы, создавать уникальный ключ для этой строки внутри своей процедуры
и передавать в базу данных полную строку с ключом. Помимо генерации
ключей, триггеры SQLBase могут выполнять и другие подобные операции.
- Регистрация изменения данных - Создатель таблицы или администратор
базы данных может пожелать иметь информацию о времени каждого
изменения данных в таблице, а также о том, какой пользователь эти изменения
производил. Для этого он создает триггер, в который поступает системное
время операции UPDATE и имя пользователя. Процедура триггера затем
вводит эту информацию в специальную таблицу регистрации изменений.
Использование триггеров подобного типа позволяет организовать системы
регистрации изменений не зависящие от действий пользователя и поэтому
наиболее надежные при попытках выполнения несанкционированных
операций.
Поскольку триггер запускается автоматически при изменении содержимого таблицы, любой
пользователь, обладающий привилегиями по отношению к этой таблице, может запустить триггер.
Следует отметить, что триггер всегда запускается с привилегиями автора, а не пользователя, т.е. на
время выполнения триггера пользователь получает привилегии автора процедуры, вызываемой
триггером.
Триггер может быть определен для выполнения либо перед операцией insert/update/delete (before
триггер), либо после нее (after триггер). Типичный пример использования before триггеров -
проверка данных. After триггеры полезны в тех случаях, когда хранимая процедура триггера
содержит код, анализирующий содержимое таблицы, на которой определен триггер, и этот код
должен включать результаты последней операции insert/update/delete.
Операции insert/update/delete, которые содержат предложения WHERE или суб-запросы (sub-
selects), модифицируют более одной строки таблицы. Триггеры SQLBase могут быть
сконфигурированы таким образом, чтобы запускаться только один раз за всю операцию или
каждый раз при изменении отдельной строки.
Update триггеры могут быть определены таким образом, чтобы запускаться только при изменении
отдельных колонок таблицы (селективные update триггеры) или реагировать на любое изменение
данных в таблице.
При передаче данных в процедуры триггеров можно использовать следующие типы данных в
качестве параметров процедур:
- Значения колонок таблицы - Поскольку триггер определяется на конкретной
таблице базы данных, он "знает" о ее строении: количестве, именах и типах
колонок и т.д. Поэтому значения колонок таблицы могут передаваться в
процедуру непосредственно по своим именам.
- Константы
- Псевдоконстанты - В процедуру можно передавать некоторые ключевые
слова SQLBase, такие как USER, SYSTIME и другие.
Если в процессе выполнения операции UPDATE содержимое колонки изменяется, имеется
возможность передать в процедуру триггера как старое, так и новое значение колонки. Для этого
служит предложение REFERENCING в определении триггера. Если предложение REFERENCING
не используется, по умолчанию значение колонки является старым для before update триггеров и
новым для after update триггеров. Поскольку для insert триггеров старых значений не существует,
значение колонки по умолчанию является новым. Аналогично, значение колонки для delete
триггера является старым.
Ограничения триггеров
- При использовании триггеров существует целый ряд ограничений:
- Все триггеры должны иметь уникальные имена.
- Нельзя иметь два идентичных триггера. Другими словами, не может быть
двух before insert триггеров на одной таблице.
- Если update триггер определен на конкретной колонке или группе колонок,
на данной таблице нельзя определить update триггер на всю таблицу.
- На таблице можно определить не более двух insert, двух delete и четырех
update триггеров одновременно.
- Допускается не более восьми уровней рекурсии триггеров. Рекурсия
триггеров возникает в тех случаях, когда операция insert/update/delete внутри
процедуры триггера запускает другой триггер.
- Предложение REFERENCING допускается только для update триггеров.
Кроме того, это предложение возможно только для триггеров, запускающихся
для каждой изменяемой строки отдельно, поскольку в противном случае
значения колонок становятся неопределенными.
- Хранимая процедура триггера должна быть статической.
Пример триггера
Ниже приведен пример триггера, который реагирует на обновление колонки в таблице.
Предположим, мы имеем таблицу T1, содержащую целочисленную колонку C1 и таблицу T2 с
колонками (OldC1 int, NewC1 int, Updater char(10)). В триггер передаются старое и новое значение
колонки C1 и имя пользователя. Триггер затем вводит эту информацию в таблицу T2. (Отметим
возможность определения хранимой процедуры триггера непосредственно в теле триггера с
помощью оператора INLINE.)
create trigger tg1 before update of c1 on t1
referencing old as o new as n
(execute inline (o.c1, n.c1, user)
procedure p1 static
parameters
number: old
number: new
string: updater
actions
call sqlimmediate( 'insert into t2 values (:old, :new, :updater)' )
for each row;