Определение оператора создания триггера.
::=
::=
::=
::=
::=
::=
::=
<Имя таблицы>
должно задавать объект (базовую таблицу или представление), для которого создается триггер.
<Имя схемы>
задает имя схемы, владельцем которой является текущий
пользователь. Создавать триггеры в «чужих» схемах запрещено.
Опция OR REPLACE
заставляет удалять существующий в БД триггер и создавать его под тем же именем, но с указанными параметрами.
Опция IF NOT EXISTS
отменяет выполнение оператора, если указанный триггер уже существует в БД.
Одновременное использование опций IF NOT EXISTS
и OR REPLACE
запрещено.
<Операция>
задает операцию по обработке данных таблицы, при выполнении которой должен срабатывать триггер:
INSERT
– при добавлении данных;
DELETE
– при удалении данных;
UPDATE
– при корректировке данных.
Если указана операция UPDATE
без конструкции OF
, триггер будет срабатывать при корректировке любого поля записи таблицы.
<Имя столбца>
должно ссылаться на столбец в <имени таблицы>
.
Если указана операция UPDATE OF <столбец>[, …]
, триггер будет срабатывать при корректировке только перечисленных столбцов записи таблицы.
Опции BEFORE
, AFTER
, INSTEAD OF
определяют момент срабатывания триггера при выполнении операций обработки данных:
BEFORE
– перед выполнением <операции>
;
AFTER
– после выполнения <операции>
;
INSTEAD OF
– взамен выполнения <операции>
.
Конструкция INSTEAD OF
применима только для базовых таблиц (не представлений).
Конструкция INSTEAD OF
не применима для таблиц, работающих в циклическом режиме, поскольку такие триггеры препятствуют удалению записей (см. оператор ALTER TABLE … SET RECORDS LIMIT
пункта «Модификация таблицы»).
Конструкция INSTEAD OF
допустима как для режима FOR EACH ROW
, так и для FOR STATEMENT
. Она позволяет выполнить проверку достоверности значений, которые должны быть добавлены, обновлены или удалены, и, в случае их достоверности, выполняет соответствующую операцию. Например, при обработке заказа на некоторый товар триггер INSTEAD OF UPDATE
может проверить, есть ли в таблице заказов строка с требуемым товаром. Если да, сумма заказа будет увеличена (операция UPDATE
), если нет – запись будет добавлена (операция INSERT
).
Если на операцию создано несколько триггеров одного времени действия, они будут выполняться в порядке их системных номеров, который обычно, но не всегда, совпадает с порядком создания триггеров.
Конструкция FOR EACH…
определяет сферу действия триггера:
ROW
– для каждой записи. Триггер будет срабатывать во время выполнения <операции>
при обработке каждой записи таблицы. Возврат триггером значения TRUE
разрешает, а FALSE
– запрещает выполнение операции только для текущей записи (имеет смысл применительно к BEFORE
);
STATEMENT
– для каждого оператора. Триггер будет срабатывать один раз при выполнении оператора, соответствующего заданной <операции>
. Возврат триггером BEFORE ... FOR EACH STATEMENT
значения FALSE
отменяет действие всей операции.
Если конструкция FOR EACH…
не задана, по умолчанию используется FOR EACH STATEMENT
.
Если один из BEFORE-триггеров запретил операцию, то последующие AFTER-триггеры выполняться не будут.
Например, в операторе UPDATE AUTO SET MAKE ='BMW' where PERSONID IN (SELECT PERSONID FROM PERSON WHERE SALARY BETWEEN 2000 AND 50000)
; триггер на UPDATE
при указании FOR EACH ROW
выполнится столько раз, сколько записей выбирается по условию WHERE
; при указании FOR EACH STATEMENT
– только один раз (в случае выполнения условия WHERE
).
<Псевдоним для старой записи>
задает префикс, используемый для обращения к старым значениям столбца. Если не задан, по умолчанию используется OLD
.
<Псевдоним для новой записи>
задает префикс, используемый для обращения к новым значениям столбца. Если не задан, по умолчанию используется NEW
.
update auto set old.color=new.color where personid=256; update auto set "Старое".color="Новое".color where personid=256;
Понятия «старое» и «новое» значение столбца применимы только для операции UPDATE
, независимо от времени действия триггера.
Для операции INSERT
имеет смысл только «новое» значение столбца.
Для операции DELETE
имеет смысл только «старое» значение столбца.
Запрещено создавать триггер на таблицу другого пользователя.
Имя триггера должно быть уникально в пределах <имя схемы>
.
Опции <триггер на системные события>
:
AFTER LOGON
– активизирует триггер после успешного открытия канала с СУБД (после установления соединения с СУБД). Если триггер возвращает ошибку, то для
всех пользователей, за исключением LINTER_SYSTEM_USER
, выполняется очистка канала;
BEFORE LOGOFF
– активизирует триггер перед закрытием канала (перед закрытием соединения по инициативе пользователя или при выполнении команд KILL
, CKIL
интерфейса нижнего уровня). Для курсорных запросов эти триггеры выполнять не следует;
DATABASE
– активизирует триггер при открытии/закрытии любого канала;
<имя пользователя>
– активизирует триггер при открытии/закрытии канала для указанного пользователя.
Триггеры AFTER LOGON
/BEFORE LOGOFF
может создавать/модифицировать/удалять только создатель БД.
Тело триггера (конструкция EXECUTE <тело триггера>
) должно быть написано на процедурном языке СУБД ЛИНТЕР (см. документ «СУБД ЛИНТЕР. Процедурный язык»).
Опция FOR DEBUG
позволяет выполнять отладку триггера с помощью отладчика триггеров и хранимых процедур СУБД ЛИНТЕР.
На каждую операцию можно создавать не более 255 триггеров.
Для хранения тела оттранслированной процедуры, возвращающей тип данных «курсор», в БД должна существовать системная таблица $$$PRCD
.
Порядок вызова триггеров с разными значениями <время действия>
следующий:
BEFORE EACH STATEMENT
;
BEFORE EACH ROW
;
AFTER EACH ROW
;
AFTER EACH STATEMENT
.
Триггер BEFORE EACH ROW
может изменить значение поля записи, помещаемое в БД, для операторов INSERT
и UPDATE
.
Возврат триггером BEFORE ... FOR EACH ROW
значения FALSE
означает отмену действия операции только для текущей записи.
В режиме FOR STATEMENT
перед обработкой триггеров на условие BEFORE STATEMENT
происходит выполнение всех триггеров на условие INSTEAD OF
. Если был выполнен хотя бы один триггер INSTEAD OF
(даже если он вернул ошибку), дальнейшая обработка запроса и всех его триггеров прекращается.
В режиме FOR EACH ROW
перед обработкой триггеров на условие BEFORE
происходит выполнение всех триггеров на условие INSTEAD OF
. Если был выполнен хотя бы один триггер INSTEAD OF
(даже если он вернул ошибку), обработка записи и триггеров FOR EACH ROW
прекращается, происходит переход к обработке следующей записи. При этом триггеры на условие FOR STATEMENT
(BEFORE
и AFTER
) выполняются в обычном режиме.
В момент активизации <триггера на системные события>
канал получает статус «занят», что дает возможность триггеру выполняться без помех.
В триггере на системные события все операторы выполняются от имени пользователя, который устанавливает/разрывает соединение, в триггере на обработку данных все операторы выполняются от имени пользователя, который выполняет операцию.
При наличии нескольких <триггеров на системные события>
сначала выполняются триггеры для всей БД, затем – для указанного пользователя.
create or replace table test (i int, ch char( 40 )); create or replace trigger test1 after logon on SYSTEM execute code execute direct "insert into test values (1,'After logon for user 1');"; return TRUE; end; create or replace trigger test2 after logon on DATABASE execute code execute direct "insert into test values (1,'After logon for database 1');"; return TRUE; end; create or replace trigger test3 after logon on SYSTEM execute code execute direct "insert into test values (1,'After logon for user 2');"; return TRUE; end; create or replace trigger test4 after logon on DATABASE execute code execute direct "insert into test values (1,'After logon for database 2');"; return TRUE; end; username SYSTEM/MANAGER select * from test; I CH - -- | 1|After logon for database 1 | | 1|After logon for database 2 | | 1|After logon for user 1 | | 1|After logon for user 2 |
Если один из триггеров вернул ошибку, остальные триггеры не выполняются.
create or replace table test (i int, ch char( 40 )); create or replace trigger test1 after logon on SYSTEM execute code execute direct "insert into test values (1,'After logon for user 1');"; return FALSE; end; create or replace trigger test2 after logon on DATABASE execute code execute direct "insert into test values (1,'After logon for database 1');";return FALSE; end; create or replace trigger test3 after logon on SYSTEM execute code execute direct "insert into test values (1,'After logon for user 2');"; return FALSE; end; create or replace trigger test4 after logon on DATABASE execute code execute direct "insert into test values (1,'After logon for database 2');"; return FALSE; end; username SYSTEM/MANAGER // триггер test1 вернул FALSE, поэтому триггеры test2, test3, test4 // выполняться не будут, канал для пользователя SYSTEM открыт (т.к. это // создатель БД – создателю БД нельзя случайно запретить подсоединение к БД // созданием LOGON-триггера, возвращающего значение FALSE) create or replace user TTT identified by 'TTT'; username TTT/TTT // ошибка – нет привилегий 1022 (возвращается в случае возврата // LOGON-триггером значения FALSE для любого пользователя, кроме создателя БД) // триггер test1 вернул FALSE, поэтому триггеры test1, test2, test3, test4 выполняться не будут username SYSTEM/MANAGER select * from test; I CH - -- | 1|After logon for database 1 | | 1|After logon for database 1 |
По окончании работы триггеров статус канала восстанавливается.
В случае занятости транслятора процедурного языка ядро СУБД ЛИНТЕР будет ожидать его освобождения.
CREATE TRIGGER UPDPERSON AFTER UPDATE ON PERSON FOR EACH ROW EXECUTE CODE if old.personid = new.personid then execute direct "insert into journal values('PERSON','UPDATE'," + itoa(old.personid) + ",sysdate, 'personid not changed');"; // return true; // endif execute direct "insert into journal values('PERSON','UPDATE'," + itoa(old.personid) + ",sysdate, 'set personid ='+itoa(new.personid)+ ' – cause update for auto');"; // execute direct "update auto set personid=" + itoa(new.personid) + " where personid = " + itoa(old.personid) + ";"; // END;