Выбрать главу

Триггеры

Триггер является подпрограммой, связанной с таблицей или просмотром, которая автоматически выполняет некоторые действия, когда строка таблицы или просмотра добавляется, изменяется или удаляется.

Триггер никогда не вызывается напрямую. Когда приложение или пользователь пытается выполнить INSERT, UPDATE или DELETE для строки таблицы, триггеры, связанные с этой таблицей, вызываются автоматически. Триггеры могут использовать исключения и события. Они также могут вызывать хранимые процедуры.

Триггеры являются мощным инструментом в различных вариантах использования. Перечислим способы использования триггеров.

* Для выполнения коррелированных изменений при выполнении оператора DML с таблицей. Например, триггер может добавлять записи во внутренний или внешний протокол изменений. Триггер AFTER DELETE (после удаления) может добавить строку в таблицу истории.

* Для проверки исходных данных.

* Для преобразования данных, например, для автоматического конвертирования входного текста в буквы верхнего регистра или для получения значения автоинкрементного ключа из генератора.

* Для информирования приложений об изменениях базы данных с использованием средств сообщения о событиях (event alerter).

* Для выполнения пользовательских каскадных изменений целостности данных.

* Чтобы сделать просмотр только для чтения изменяемым. Подробности см. в разд. "Преобразование просмотров только для чтения в изменяемые"главы 24.

Триггеры хранятся как объекты базы данных так же, как хранимые процедуры и исключения. Объявленные как ACTIVE, они остаются активными, пока не будут деактивированы оператором ALTER TRIGGER или удалены из базы данных с помощью DROP TRIGGER.

Триггер никогда не вызывается явно - активный триггер выполняется автоматически, когда заданная операция DML выполняется для его таблицы.

Преимущества использования триггеров

Перечислим преимущества использования триггеров.

* Автоматическое применение ограничения данных, чтобы убедиться, что пользователи вводят только допустимые значения в столбцы.

* Сокращение объема поддержки приложений, поскольку изменения триггеров автоматически отражаются на всех приложениях, которые используют связанные таблицы, без необходимости их повторной компиляции и сборки.

* Автоматическое протоколирование изменений таблиц. Приложение может использовать протоколирование изменений с помощью триггера, который вызывается при модификации таблицы.

* Автоматическое информирование об изменениях базы данных с помощью средств сообщения о событиях.

Триггеры в качестве автоинкрементного механизма

Триггеры могут быть использованы в комбинации с генераторами для реализации автоинкрементных ключей. Подробные инструкции вы можете найти в главе 31.

Триггеры и транзакции

Триггеры всегда выполняются в контексте конкретной операции DML, как часть этой операции и внутри той транзакции, которая осуществляет запрос оператора DML. Нет смысла отделять их от транзакции или от операции, которая привела к выполнению триггера. Если транзакция будет отменена, то и все действия, выполненные триггером, также будут отменены.

Расширения языка PSQL

Расширения языка PSQL включают следующие языковые элементы:

* операторы BEGIN и END для выделения блоков кода, которые могут быть вложенными;

* операторы DECLARE VARIABLE для объявления локальных переменных;

* конструкция FOR SELECT <спецификация-выбора> INTO <список-переменных? DO инкапсулирует курсор SQL для выполнения цикла просмотра наборов. Циклы могут быть вложенными;

* циклы WHILE;

* оператор SUSPEND для пересылки строки в кэш строк;

* конструкция IF ... THEN и ELSE для ветвления в программе;

* оператор EXCEPTION <объявленное-имя-исключения> для вызова пользовательских исключений;

* необязательные блоки WHEN <условие-исключения> DO для перехвата и обработки исключений;

* POST_EVENT <строка> для передачи сообщений клиентам.

Firebird версии 1.5 и более поздние также поддерживает:

* оператор EXECUTE STATEMENT для выполнения специальных операторов DML и DDL в модуле;

* логические контекстные переменные UPDATING, INSERTING и DELETING;

* контекстная переменная ROW_COUNT для получения количества строк, полученных выполненным оператором DML в том же блоке;

* дополнительный синтаксис для EXCEPTION без аргументов - для повторного вызова исключений, а с необязательным текстовым аргументом - для передачи информации клиенту.

Ограничения PSQL

Существуют некоторые ограничения языка для кодов в модулях PSQL.

* Операторы, использующие подмножество языка определения данных (DDL) SQL Firebird, не разрешены в PSQL[111].

* Операторы управления транзакциями недопустимы в PSQL, потому что хранимые процедуры и триггеры всегда выполняются в контексте существующей клиентской транзакции, a Firebird не поддерживает вложенные транзакции.

* Некоторые другие типы операторов, зарезервированные для использования в других средах (например, в isql, скриптах или во встроенном SQL - см. следующий раздел). Допустимы все динамические операторы DML.

* Идентификаторы объектов метаданных, такие как имена таблиц, столбцов, просмотров или хранимых процедур, не могут передаваться хранимой процедуре или возвращаться хранимой процедурой в ее аргументах.

* Триггеры не могут получать или возвращать аргументы.

Типы операторов, не поддерживаемых в PSQL

Следующие типы операторов не поддерживаются в триггерах и хранимых процедурах:

* операторы языка определения данных (т. е. операторы, начинающиеся с ключевых слов CREATE, RECREATE, ALTER или DROP; SET GENERATOR; DECLARE EXTERNAL FUNCTION: DECLARE FILTER);

* операторы управления транзакциями: SET TRANSACTION, COMMIT, COMMIT RETAIN,

ROLLBACK, SAVEPOINT, RELEASE SAVEPOINT, ROLLBACK TO SAVEPOINT;

* операторы ESQL: PREPARE, DESCRIBE, EXECUTE;

* операторы CONNECT/DISCONNECT и отправки операторов SQL другим базам данных;

* GRANT/REVOKE;

* EVENT INIT/EVENT WAIT;

* BEGIN DECLARE SECTION/END DECLARE SECTION;

* BASED ON;

* WHENEVER;

* DECLARE CURSOR;

* OPEN;

* FETCH;

* любые операторы, начинающиеся с ключевых слов SET и SHOW.

Исключения

Обработчики исключений могут быть написаны, чтобы "съесть" ошибку, обрабатывая ее разными способами. Например, в итеративной подпрограмме входная строка, вызывающая исключение, необязательно должна приводить к остановке всего процесса. Обработка исключения внутри триггера или хранимой процедуры может позволить пропустить проблемную входную строку - например, поместив сообщение об ошибке в протокол в текстовый файл или в таблицу ошибок - и дав возможность продолжить дальнейшую обработку.

Код в модуле может обрабатывать ошибку в необязательном фрагменте кода, называемом блоком исключения, который является последовательностью операторов, заключенных в операторные скобки BEGIN и END, которым предшествует ключевое слово WHEN.

Необработанное исключение останавливает процесс, отменяет всю выполненную к этому моменту работу[112] и возвращает сообщение об ошибке приложению. Вы также можете написать код, вызывающий пользовательское исключение и останавливающий процесс. Вы можете обработать эту ошибку в вашем коде или остановить процесс и вернуть пользовательское сообщение клиентскому приложению. Если модуль является триггером, то операция DML, в которой появилась эта ошибка, также будет отменена. В базе данных вы можете создать столько пользовательских исключений, сколько вам нужно. Начиная с версии 1.5, вы можете использовать данные времени выполнения и конструировать тексты для ваших сообщений об исключениях "на лету".

вернуться

111

В версии 1.5 возможна передача оператора DDL в строке EXECUTE STATEMENT. Делайте это только в особых случаях.

вернуться

112

Только в отношении работы конкретного запроса SQL, выполненного из клиентского приложения, в "недрах" которого произошла ошибка. Работа, выполненная ранее другими запросами SQL в этой же транзакции, будет сохранена (если транзакция завершится по commit). - Прим. науч. ред.