Введение в дисциплину «Безопасность систем баз данных». Теоретические основы построения реляционных баз данных. Верификация баз данных и проведение аудита в СБД. Распределенные базы данных, страница 44

·  количество триггеров в связке будет равно мощности множества tables’ – создается по одному триггеру для каждой таблицы;

·  на основе анализа множества operations’ определяются наборы триггерных событий.

Проиллюстрируем вышесказанное следующим примером. Пусть имеются две взаимосвязанные таблицы: coaches (вагоны пассажирского поезда) и seats (посадочные места). Вагон характеризуется типом coach_type (купейный, плацкартный и т. п.), посадочное место – номером seat_number. Имеется требование: номер места в купейном вагоне не может быть больше 36. Формальный описатель этого требования следующий:

                (5.8)

Множество tables включает два элемента: seats и coaches.

Данное требование является требованием к состоянию, поэтому множество операций у него следующее:

operations = {ins(seats), upd(seats), del(seats), ins(coaches), upd(coaches), del(coaches)}.

В результате выполнения некоторых операций из множества operations требование (5.8) может нарушиться:

·  при добавлении и обновлении записей таблицы seats может появиться номер места больше 36, само же место – отнесено к купейному вагону;

·  при обновлении таблицы coaches тип вагона может быть изменен на купейный в тот момент, когда в вагоне уже зарегистрированы места с номерами более 36.

Операции del(seats), ins(coaches) и del(coaches) не вызовут нарушений.

Таким образом:

operations’ = {ins(seats), upd(seats), upd(coaches)},

tables’ = {seats, coaches}.

Поскольку множество tables’ содержит два элемента, для реализации требования (5.8) необходимо создать триггерную связку из двух триггеров, по одному для каждой таблицы:

·  триггер tr_seat_num будет реагировать на выполнение операций ins(seats) и upd(seats);

·  триггер tr_coach_seat_num будет реагировать на выполнение операции upd(coach).

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

Описатель (5.8) может быть переписан следующим образом:

   (5.9)

Понимать это следует так: невозможно, чтобы результат выборки  не был пустым.

Выражение  легко «переводится» на Transact-SQL, ему соответствует запрос:

select * from coaches, seats

                             where coach_type = 'Купе'

                             and seat_number > 36

                             and coaches.id_coach = seats.id_coach

Операция проверки на неравенство пустому множеству реализуется в Transact-SQL с помощью квантора существования exists. Самое сложное здесь – это правильно «перевести» операцию логического отрицания. Для этого важно понять смысл ее использования в выражении (5.9). Смысл таков: если результат выборки  стал непустым, триггер должен уничтожить некорректные изменения в связанной таблице. Самый простой способ сделать это – вернуть данные в исходное состояние, бывшее до выполнения активизирующего оператора, т. е. отменить транзакцию. «Переводя» все сказанное на Transact-SQL практически дословно, получаем:

if exists (select * from coaches, seats

                                                     where coach_type = 'Купе'

                                                     and seat_number > 36

                                                     and coaches.id_coach = seats.id_coach)

     rollback tran

Данный скрипт и будет телом триггеров tr_seat_num и tr_coach_seat_num. Полные скрипты реализации триггеров будут выглядеть следующим образом:

create trigger tr_seat_num

     on seats

     for insert, update

     as

     if exists (select * from coaches, seats

                                                     where coach_type = 'Купе'

                                                     and seat_number > 36

                                                     and coaches.id_coach = seats.id_coach)

     rollback tran

create trigger tr_coach_seat_num

     on coaches

     for update

     as

     if exists (select * from coaches, seats