![]() |
Технология Клиент-Сервер 2000'3 |
||||||
|
В версии 8i разработчик сталкивается с целой серией новых видов триггеров. Шесть из них запускаются событиями, возникающими при выполнении операций на уровне схемы, и поэтому носят название “триггеры для событий уровня схемы БД” (schema-level event triggers). Что это за триггеры?
Вот перечень запускающих их событий:
Событие |
Описание триггера |
SERVERERROR |
Триггер срабатывает при возникновении серверной ошибки |
LOGON |
Триггер срабатывает при успешном подключении к системе клиентского приложения |
LOGOFF |
Триггер срабатывает перед отключением клиентского приложения |
CREATE |
Триггер срабатывает при добавлении к схеме нового объекта командой CREATE |
DROP |
Триггер срабатывает перед попыткой удалить из схемы объект командой DROP |
ALTER |
Триггер срабатывает при изменении объекта схемы командой ALTER |
Общий синтаксис описания триггеров схемы таков:
CREATE [ OR REPLACE ] TRIGGER имя_триггера { BEFORE | AFTER } { SERVERERROR | LOGON | LOGOFF | CREATE | DROP | ALTER } ON имя_схемы.SCHEMA BEGIN текст на PL/SQL END;
С каждым событием из таблицы выше связано несколько атрибутов. Фактически эти атрибуты – системные функции, возвращающие при обращении к ним из тела триггера некоторый результат. Ниже эти атрибуты перечисляются, причем первые шесть из них относятся к уровню базы данных (но могут использоваться в триггерах уровня схемы).
Имя |
Тип |
Описание |
SYSEVENT |
VARCHAR2(30) |
Имя события, активизировавшего триггер |
LOGIN_USER |
VARCHAR2(30) |
Имя пользователя, инициировавшего сеанс работы с Oracle |
INSTANCE_NUM |
NUMBER |
Имя экземпляра СУБД |
DATABASE_NAME |
VARCHAR2(50) |
Имя БД |
SERVER_ERROR |
NUMBER |
Функция, возвращающая номер ошибки на указанном месте магазина ошибок. 1 соответствует верхушке магазина. Пример: SERVER_ERROR(2) выдаст номер ошибки на втором от верха месте в магазине. |
IS_SERVERERROR |
BOOLEAN |
Функция, возвращающая TRUE при наличии указанной ошибке в текущем магазине ошибок; FALSE в противном случае. |
DICTIONARY_OBJ_OWNER |
VARCHAR2(30) |
Владелец объекта из словаря-справочника, действие с которым привело к активизации триггера. |
DICTIONARY_OBJ_NAME |
VARCHAR2(30) |
Имя объекта из словаря-справочника, действие с которым привело к активизации триггера |
DICTIONARY_OBJ_TYPE |
VARCHAR2(30) |
Тип объекта из словаря-справочника, действие с которым привело к активизации триггера |
DES_ENCRYPTED_PASSWORD |
VARCHAR2(30) |
Зашифрованный (DES) пароль создаваемого или изменяемого пользователя. |
Вот какие правила и атрибуты свойственны каждому событию:
Событие |
Правило |
Атрибуты |
LOGON |
Условие можно указать, воспользовавшись USERID( ) или USERNAME( ) |
SYSEVENT |
LOGOFF |
Условие можно указать, воспользовавшись USERID( ) или USERNAME( ) |
SYSEVENT |
BEFORE CREATE AFTER CREATE |
В пределах триггера удалять создаваемый объект нельзя. Триггер выполняется в рамках текущей транзакции. |
SYSEVENT |
BEFORE ALTER AFTER ALTER |
В пределах триггера удалять изменяемый объект нельзя. Триггер выполняется в рамках текущей транзакции. |
SYSEVENT |
BEFORE DROP AFTER DROP |
В пределах триггера изменять удаляемый объект нельзя. Триггер выполняется в рамках текущей транзакции. |
SYSEVENT |
В своей последней книге Стив Фойерштайн приводит пример использования триггера уровня схемы, который здесь помещается с небольшими изменениями.
Предположим, мы хотим разрешить пользователям входить в систему под именем SCOTT, но запретить им удалять все таблицы, начинающиеся с EMP. Предположим, что это очень важные таблицы. Триггер, запрещающий это делать, может выглядеть примерно так:
CREATE OR REPLACE TRIGGER no_drop_trg BEFORE DROP ON SCOTT.SCHEMA DECLARE v_msg VARCHAR2(1000) := 'No drop allowed on ' || DICTIONARY_OBJ_OWNER || '.' || DICTIONARY_OBJ_NAME || ' from ' || LOGIN_USER; BEGIN IF DICTIONARY_OBJ_OWNER = 'SCOTT' AND DICTIONARY_OBJ_NAME LIKE 'EMP%' AND DICTIONARY_OBJ_TYPE = 'TABLE' THEN RAISE_APPLICATION_ERROR ( -20905, v_msg); END IF; END; /
(Для того, чтобы триггер оттранслировался, нужно установить значение параметра COMPATIBLE в INIT.ORA не меньшее, чем 8.1.0.0.0).
Теперь в ответ на
DROP TABLE EMP;
вы получите результат
drop table emp * ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-20905: No drop allowed on SCOTT.EMP from SCOTT ORA-06512: at line 12
и таблица останется целой (удаление не сработает, поскольку мы инициировали ошибку).
Остается отметить, что мы защитили нашу таблицу на уровне DDL (и, тем самым, сохранили, по крайней мере, ее структуру), но не предохранились от несанкционированного удаления строк из таблицы (уровень DML). Для этого придется воспользоваться другими средствами Oracle: обычными триггерами таблицы и … средствами резервного копирования и восстановления. В промышленной же прикладной системе, передаваемой заказчику, и то, и другое, и третье, вероятно, должно играть роль “второго эшелона обороны”, вступающего в игру после отказов в “первом эшелоне” – процедурном доступе к таблицам или доступе, полностью контролируемом приложением.
С другой стороны, если наша цель – не просто защитить таблицу от удаления, а предпринять при попытке удаления какие-нибудь вспомогательные действия (журнализировать акт такой попытки, скопировать таблицу во временную область перед удалением и так далее), то приемлемой альтернативы триггеру типа приведенного выше нет.
Кроме триггеров для событий уровня схемы БД, в Oracle 8i существуют так называемые триггерах для событий уровня системы (database-level event triggers). Они запускаются при возникновении в системе (СУБД) следующих событий:
Событие |
Описание триггера |
SERVERERROR |
Триггер срабатывает при возникновении серверной ошибки |
LOGON |
Триггер срабатывает при успешном подключении к системе клиентского приложения |
LOGOFF |
Триггер срабатывает перед отключением клиентского приложения от СУБД |
STARTUP |
Триггер срабатывает немедленно после открытия БД |
SHUTDOWN |
Триггер срабатывает непосредственно перед попыткой закрыть СУБД “нормальным образом”, то есть всеми вариантами команды SHUTDOWN кроме варианта SHUTDOWN ABORT |
Общий синтаксис описания триггеров схемы таков:
CREATE [ OR REPLACE ] TRIGGER имя_триггера { BEFORE | AFTER } { SERVERERROR | LOGON | LOGOFF | STARTUP | SHUTDOWN } ON DATABASE BEGIN текст на PL/SQL END;
С каждым событием из предыдущей таблицы связано несколько атрибутов. Фактически эти атрибуты – системные функции, возвращающие некоторый результат при обращении к ним из тела триггера. Ниже эти атрибуты перечисляются. Первые шесть из них нам уже знакомы по триггерам событий уровня схемы.
Вот какие правила и атрибуты свойственны каждому событию:
Событие |
Правило |
Атрибуты |
SERVERERROR |
По умолчанию триггер будет срабатывать при всех событиях. Однако специальным указанием можно “сказать”, чтобы триггер срабатывал только при интересующих нас событиях. |
SYSEVENT |
LOGON |
Условие можно указать, воспользовавшись USERID( ) или USERNAME( ) |
SYSEVENT |
LOGOFF |
Условие можно указать, воспользовавшись USERID( ) или USERNAME( ) |
SYSEVENT |
STARTUP |
В теле триггера не допускается использование операций с БД – DML и запросов. Можно, однако, запускать программы (например, listener), закреплять в SGA пакеты и т. д. |
SYSEVENT |
SHUTDOWN |
В теле триггера не допускается использование операций с БД – DML и запросов. Можно, однако, останавливать или запускать программы (например, для сбора статистики работы СУБД и занесения ее в журнал) |
SYSEVENT |
При написании триггера нужно учитывать следующие обстоятельства:
Перед запуском триггера Oracle автоматически инициирует автономную транзакцию, а после окончания его выполнения фиксирует (commit) выполнение всех DML-операций безотносительно к логике транзакций пользователя.
В определении триггеров LOGON, STARTUP и SERVERERROR можно указывать только слово AFTER. Если указать BEFORE, при трансляции будет выдана ошибка.
Аналогично, в определении триггеров LOGOFF и SHUTDOWN можно указывать только BEFORE.
Обращения из процедур DBMS_OUTPUT не дадут на экране никакой выдачи в пределах текущего сеанса. Для того, чтобы как-то записать информацию, нужно будет воспользоваться записью в таблицы, в файл ОС или средством pipeline.
Триггер на SERVERERROR не срабатывает на следующие пять событий: ORA-01403, ORA-01422, ORA-04030, ORA-01034 и ORA-01007.
Триггеры событий в СУБД могут использоваться в разных целях: для прикрепления объектов к SGA при старте системы, для отслеживания входов в БД, для трассировки ошибок.
Так, прикрепление наиболее часто используемых пакетов в SGA при старте системы может (в случае интенсивной загрузки СУБД) ускорить среднее время обращения к процедурам этих пакетов (они не будут участвовать в страничном обмене) и уменьшить отрицательные последствия фрагментации SGA. Следующий пример Стивена Фойерстина показывает, как можно таким образом закрепить в SGA пакеты STANDARD и DBMS_STANDARD, встроенные в систему:
CREATE OR REPLACE TRIGGER pin_code_on_startup AFTER STARTUP ON DATABASE BEGIN DBMS_SHARED_POOL.KEEP (‘SYS.STANDARD’, ‘P’); DBMS_SHARED_POOL.KEEP (‘SYS.DBMS_STANDARD’, ‘P’); END; /
Для закрепления пользовательских пакетов, включающих требуемые процедуры или функции, можно самостоятельно составить более сложные схемы, базирующиеся в конце-концов на триггере AFTER STARTUP.
Oracle PL/SQL Programming. Steven Feuerstein. O’Reilly & Associates, October 1999.
Документация по Oracle
Copyright © 1994-2016 ООО "К-Пресс"