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

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

Вот исключение:

CREATE EXCEPTION E_REFUSE_ORDER 'Operation refused. ' ^

/* Операция отвергнута */

А вот триггер:

CREATE TRIGGER BA_SALES0 FOR SALES

ACTIVE BEFORE INSERT OR UPDATE POSITION 0 AS

DECLARE VARIABLE ORDER_STATE SMALLINT = 0;

BEGIN

IF (UPDATING AND OLD.ORDER_STATUS = 'shipped') THEN

ORDER_STATE = 1;

IF (

(EXISTS (SELECT ON_HOLD FROM CUSTOMER

WHERE CUST_NO = NEW.CUST_NO

AND ON_HOLD IS NOT NULL)

AND (INSERTING OR ORDER_STATE = 0)) THEN

ORDER_STATE = 2;

IF (ORDER_STATE = 1) THEN

EXCEPTION E_REFUSE_ORDER 'Order ' || NEW.PO_NUMBER || ' already shipped.';

/* EXCEPTION E_REFUSE_ORDER 'Заказ ' || NEW.PO_NUMBER || ' уже отправлен' */

ELSE

IF (ORDER_STATE = 2) THEN

EXCEPTION E_REFUSE_ORDER

'Order '|| NEW.PO_NUMBER ||'. Customer ' || NEW.CUST_NO || ' is on hold.';

/* 'Заказ '|| NEW.PO_NUMBER ||'. Покупатель ' || NEW.CUST_NO || ' заблокирован'; */

END ^

В массиве состояния ошибки клиент получит имя исключения вместе с сообщением времени выполнения.

Список кодов ошибок

Приложение 10 содержит списки внутренне определенных исключений, включая коды SQLCODE, GDSCODE, символы для GDSCODE и сообщения на английском языке, соответствующие текущему состоянию релиза Firebird 1.5.0.

При создании двоичного кода Firebird сообщения на английском языке выбираются из внутренней базы данных. Коды SQLCODE сохраняются, но GDSCODE вычисляются на лету. Файл firebird.msg в вашем корневом каталоге Firebird создан в виде двоичного дерева, к которому обращаются клиент и сервер при работе сервера.

Написание вашего собственного списка кодов ошибок

Ради любопытства вы можете легко получить версию gbak для базы данных (с именем gbak.msg) из репозитория CVS проекта Firebird. Войдите на http:// sourceforge.net/projects/firebird и идите по ссылке CVS Browser, пока не доберетесь до ветви с именем ,/firebird/firebird2/src/msgs/. В нижней части дисплея щелкните по стрелке выпадающего списка для поиска интересующей вас ветви. Оттуда вы сможете получить файл.

Следующая хранимая процедура сгенерировала список для приложения 10. Она выводит список во внешнюю таблицу, но вы можете модифицировать эту процедуру подходящим для вас образом.

SET TERM ^;

/* Выходной файл */

CREATE TABLE ERRORCODES

EXTERNAL FILE

'С:\Program Files\Firebird\Firebird_1_5\MyData\27 94app10.txt'

(Listltem CHAR(169))^

COMMIT^

/* При необходимости уберите комментарии в следующей секции и объявите функцию ASCII_CHAR() для получения символов возврата каретки и перевода строки */

/* DECLARE EXTERNAL FUNCTION ascii_char

INTEGER

RETURNS CSTRING(1) FREE_IT

ENTRY_POINT 'IB_UDF_ascii_char' MODULE_NAME 'ib_udf'^

COMMIT^

/* Под конец сама хранимая процедура, создающая текстовый файл, эквивалентный приложению 10 данной книги*/

CREATE PROCEDURE OUTPUT ERRCODES

AS

DECLARE VARIABLE SQC SMALLINT;

DECLARE VARIABLE NUM SMALLINT;

DECLARE VARIABLE FAC SMALLINT;

DECLARE VARIABLE SYM VARCHAR(32);

DECLARE VARIABLE TXTVARCHAR(118) ;

DECLARE VARIABLE GDC CHAR(9) CHARACTER SET OCTETS

DECLARE VARIABLE BASEO INTEGER = 335544320;

DECLARE VARIABLE CALCNUM INTEGER;

DECLARE VARIABLE EOL CHAR(2) ;

BEGIN

EOL = ASCII_CHAR(13) || ASCII_CHAR(10);

/* последовательность конца строки */

FOR SELECT

S.SQL_CODE,

S.NUMBER,

S.FAC_CODE,

S. GDS_SYMBOL,

M.TEXT

FROM SYSTEM_ERRORS S

JOIN MESSAGES M

ON

M.FAC_CODE = S.FAC_CODE

AND M.NUMBER = S.NUMBER

AND M.SYMBOL = S.GDS_SYMBOL

/* Устранение некоторых нежелательных/ненужных кодов */

WHERE M.TEXTNOT CONTAINING 'journal'

AND M.TEXTNOT CONTAINING 'dump'

AND s.GDS_SYMBOL NOT CONTAINING 'license'

AND S.GDS_SYMBOL NOT CONTAINING 'wal_'

AND S. GDS_SYMBOLIS NOT NOLL

AND S.SQL_CODE < 102

ORDER BY1 DESC, 2

INTO :SQC, :NUM, :FAC, :SYM, :TXT

DO

BEGIN

/* Тексты сообщений в нижнем регистре, следовательно, мы выполним небольшой трюк для перевода в верхний регистр первой буквы */

IF (TXT IS NULL) THEN

TXT = '(Message unknown)';

ELSE

TXT = UPPER(SUBSTRING(TXT FROM 1 FOR 1)) ||

SUBSTRING(TXT FROM 2);

/* Разработанные значения кодов (FAC_CODE) и чисел NUMBER используются для генерации чисел GDSCODE. Очень просто получить их из последних таблиц SYSTEM_ERRORS и MESSAGES */

IF (FAC IS NOT NULL AND NUM IS NOT NULL) THEN

/* Нам не нужны наполовину приготовленные коды ошибок! */

BEGIN

CALCNUM = BASE0 + (FAC * 65535);

CALCNUM = CALCNUM + NUM + FAC;

GDC = CAST(CALCNUM AS CHAR(9));

INSERT INTO ERRORCODES

VALUES(

/* все переменные поступают в одной строке */

:SQC || ' | ' || :GDC | | ' | ' || :SYM | | ' |' | | :TXT || :EOL) ;

END

END

END ^

COMMIT^

EXECUTE PROCEDURE OUTPUT_ERRCODES ^

COMMIT ^

SET TERM ; ^

/* Текстовый файл теперь готов к обработке текстовым процессором для небольшой корректировки, чтобы избавиться от лишних пробелов, созданных в правой части выходной строки. Быстрый поиск и замена заменят все разделители '|' на ASCII 9 (tab), потому что это было требованием к табуляции для печати. */

События

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

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

Когда транзакция подтверждается, сообщения обо всех произошедших событиях передаются всем ожидающим их клиентским приложениям. После этого клиентское приложение может отреагировать на это событие любым образом.

Использование сообщений о событиях

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

Эти возможности безграничны в терминах масштаба и приложения. Некоторыми примерами являются:

* сервисы фоновой репликации данных запрашивают новый элемент;

* приложение продажи билетов использует эту схему в качестве сигнала для обновления открытых наборов данных в других офисах, когда происходит изменение выделенных мест или расписания;

* приложение инвентаризации выдает отделу закупок сообщение "запас на исходе", когда количество элементов инвентаризации находится ниже минимально допустимого уровня запасов;