Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ
Шрифт:
Как пример, мы собираемся исправить процедуру LOG_SALES, которая обещает доставить нам неприятности, потому что мы не обратили внимание на пустые значения ключей. Вот блок, который может решить проблемы:
CREATE PROCEDURE LOG_SALES ( . . .
. . .
DO
BEGIN
IF(REP = LASTREP) THEN
/* будет иметь значение false, если оба значения null */
BEGIN
REPTOTAL = REPTOTAL + ORDTOTAL;
REP_NAME = "" ;
END
ELSE
BEGIN
REPTOTAL = ORDTOTAL;
LASTREP = REP;
SELECT FULL_NAME FROM EMPLOYEE
WHERE EMP_NO = :REP
INTO :REP_NAME;
/*
END
. . .
END ^
Мы исправили логику для обработки пустых значений (сгруппированных вместе в конце курсора, потому что набор упорядочен по этому столбцу) и используем операторы CREATE или ALTER для изменения кода:
CREATE OR ALTER PROCEDURE LOG_SALES (...
. . .
DO
BEGIN
* ************ */
IF((REP = LASTREP) OR (LASTREP IS NULL)) THEN
/* ************ */
BEGIN
REPTOTAL = REPTOTAL + ORDTOTAL;
REP_NAME = "" ;
END
ELSE
BEGIN
REPTOTAL = ORDTOTAL;
LASTREP = REP;
/* ************* */
IF (REP IS NOT NULL) THEN
SELECT FULL_NAME FROM EMPLOYEE
WHERE EMP_NO = : REP
INTO :REP_NAME;
ELSE
REP_NAME = ' Onassigned ' ;
/* ************* */
END
. . .
END ^
COMMIT ^
Подтверждение изменения вызовет пресловутую ошибку (обсуждавшуюся в предыдущей главе), если какой-нибудь пользователь в настоящий момент использует эту процедуру или любой другой объект, зависящий от нее. Даже если мы уберем это препятствие, новая версия процедуры не станет немедленно доступной в Суперсервере, если старая версия все еще находится в кэше. Все пользователи должны отключиться от базы данных, а когда они снова к ней подключатся, они смогут увидеть новую версию.
В Классическом сервере новая версия будет доступна следующему клиенту, который соединится с базой данных.
Удаление хранимых процедур
Оператор DROP PROCEDURE удаляет существующую хранимую процедуру из базы данных. Вы можете использовать этот оператор везде, где можно использовать операторы DDL.
! ! !
ПРИМЕЧАНИЕ. Операторы DDL не могут выполняться как операторы PSQL. При этом в Firebird 1.5 оператор DDL может передаваться через конструкцию EXECUTE STATEMENT. Нужно ли читающему пользователю быть осторожным в отношении использования EXECUTE STATEMENT при удалении самой процедуры?
. ! .
Синтаксис:
DROP PROCEDURE имя;
имя процедуры должно быть именем существующей процедуры. Будьте внимательны в отношении чувствительности к регистру имен объектов, если при создании процедуры были использованы идентификаторы в апострофах.
Следующий оператор удаляет процедуру LOG_SALES:
DROP PROCEDURE LOG_SALES;
Ограничения
При удалении процедуры существуют ограничения.
*
* Процедура, находящаяся в использовании в любой другой транзакции, не может быть удалена. Это является особой проблемой в системах, где процедуры вызываются в транзакциях, которые подтверждаются с использованием
CommitRetaining.
* Если другие объекты ссылаются или вызывают данную процедуру, то необходимо сначала изменить зависимые объекты, удалив такие ссылки и подтвердив работу, прежде чем удалять процедуру.
* Для удаления рекурсивной процедуры необходимо сначала удалить рекурсивные вызовы и подтвердить изменения. Похожие трудности существуют и для процедуры, вызывающей другую процедуру, которая в свою очередь вызывает процедуру, которую вы собираетесь удалить. Все подобные зависимости должны быть удалены и подтверждены, чтобы процедура стала доступной для удаления.
Тема оптимизации: использование внутренних возможностей
Firebird наследует недокументированную возможность, которая может ускорить выполнение запроса при некоторых условиях. Это RDB$DB_KEY (обычно называется просто db key), внутренний ключ, поддерживаемый сервером базы данных для внутреннего использования при оптимизации запросов и управлении версиями записей. Внутри контекста транзакции, где он используется, он представляет позицию строки в таблице8 [118] .
118
Клавдио Валдеррама (Claudio Valderrama) провел исследования по RDB$DB_KEY, именно его примеры здесь используются. Он живет в Чили, его псевдоним "robocop". Клавдио является официальным инспектором кода в проекте Firebird. Он поддерживает обширный сборник статей и кодов для Firebird и InterBase на своем сайте: http://www.cvalde.net.
Относительно RDB$DB_KEY
Первый урок заключается в том, что RDB$DB_KEY является прямым указателем, связанным с базой данных, а не с физическим адресом на диске. Второй - значения RDB$DB_KEY не следуют в предсказуемой последовательности. Не используйте вычисления, включающие их относительные позиции! Третий урок в том, что они изменчивы - они изменяются после резервного копирования и последующего восстановления, а иногда и после подтверждения транзакции. Главным является понимание мимолетности db key и отсутствие предположений о его существовании в то время, когда ссылающаяся на него операция завершается или отменяется.
Размер RDB$DB_KEY
Для таблиц RDB$DB_KEY использует 8 байт. Для просмотров он использует коэффициент умножения этих 8 байт, сколько таблиц используется в просмотре. Например, если просмотр соединяет три таблицы, его RDB$DB_KEY использует 24 байт. Это важно, когда вы работаете с хранимыми процедурами и собираетесь сохранять RDB$DB_KEY В переменных. Вы должны использовать тип данных CHAR(n) корректной длины.
По умолчанию db key возвращается в виде шестнадцатеричного числа - две шестнадцатеричные цифры представляют каждый байт: 16 шестнадцатеричных цифр возвращаются для 8 байт. Сделайте для одной из ваших таблиц в isql следующее: