На этом закончим рассмотрение основных возможностей языка хранимых процедур. Очевидно, что полностью освоить разработку хранимых процедур при чтении одной главы невозможно, однако здесь мы постарались представить и объяснить основные концепции, связанные с хранимыми процедурами. Описанные конструкции и приемы проектирования ХП могут быть применены в большинстве приложений баз данных
Часть важных вопросов, связанных с разработкой хранимых процедур, будет раскрыта в следующей главе - "Расширенные возможности языка хранимых процедур InterBase", которая посвящена обработке исключений, разрешению ошибочных ситуаций в хранимых процедурах и работе с массивами.
Расширенные возможности языка хранимых процедур InterBase
Эта глава посвящена тем возможностям языка хранимых процедур InteiBase, которые позволяют эффективно реализовывать бизнес-логику на уровне базы данных и разрабатывать устойчивые и высокопроизводительные приложения баз данных
Обработка исключений и ошибок
Исключения
Первой из рассматриваемых особенностей языка хранимых процедур (ХП) и триггеров InterBase является возможность использовать "исключения"
Исключения InterBase во многом похожи на исключения других языков высокого уровня, однако имеют свои особенности Фактически исключение InterBase - это сообщение об ошибке, которое имеет собственное, задаваемое программистом имя и текст сообщения об ошибке. Создается исключение следующим образом:
СРЕАТЕ EXCEPTION <имя_исключения> <текст_исключения>;
Например, мы можем создать исключение такого вида:
CREATE EXCEPTION test_except 'Test exception';
Исключение легко удалить или изменить - удаление совершается командой DROP EXCEPTION <имя_удаляемого_исключения>, а изменение - ALTER EXCEPTION <имя_исключения> <текст_исключения>
Чтобы использовать исключение в хранимой процедуре или триггере, необходимо воспользоваться командой следующего вида:
EXCEPTION <имя_исключения>;
Давайте рассмотрим применение исключений на простом примере хранимой процедуры, выполняющей деление одного числа на другое и возвращающей результат Нам необходимо отследить случай деления на нуль и возбудить исключение, если делитель равен нулю.
Для нашего примера создадим следующее исключение:
CREATE EXCEPTION zero_divide 'Cannot divide by zero!';
Создадим хранимую процедуру, использующую это исключение:
CREATE PROCEDURE SP_DIVIDE (
DELIMOE DOUBLE PRECISION,
DELITEL DOUBLE PRECISION)
RETURNS (
RESULT DOUBLE PRECISION)
AS
BEGIN
if (Delitel<0.0000001) then
BEGIN
EXCEPTION zero_divide;
Result=0;
END
ELSE
BEGIN
Result=Delimoe/Delitel;
END
SUSPEND;
END
Как видите, текст ХП тривиален - на входе получаем Delitel и Delimoe, затем сравниваем Delitel с 0.0000001, т. е. фактически с нулем, в пределах выбранной погрешности в одну десятимиллионную (так как вещественные числа невозможно непосредственно сравнивать из-за погрешностей в дробной части). Если Delitel близок к нулю в пределах выбранной погрешности, то мы возбуждаем исключение zero_divide. Что же происходит в случае возникновения исключения? Если мы попробуем вызвать исключение, выполняя процедуру SP_divide с нулевым делителем в isql. то получим следующее
SQL> select * from sp_divide(300,0);
RESULT
==========
Statement failed, SQLCODE = -836
exception 1
-Cannot divide by zero!
Если мы вызовем эту ХП с нулевым делителем в каком-либо другом приложении, то скорее всего получим сообщение об ошибке следующего вида:
Рис 1.4. Сообщение о возникновении исключения
Другими словами, сообщение об ошибке - это результат обработки нашего исключения сервером InterBase. Когда InterBase обнаруживает возникшее в ХП или триггере исключение он прерывает работу этой хранимой процедуры и откатывает все изменения, сделанные в текущем блоке BEGIN END, причем если ХП является процедурой-выборкой, то отменяются действия лишь до последнего оператора SUSPEND.
Это значит, что если в процедуре-выборке есть цикл, в котором производятся какие-то действия, и в теле цикла есть SUSPEND, то при возбуждении исключения О1меня1ся все дейс1вия, выполненные в этом цикле до последнего оператора SUSPEND.
Надо сказать, что в исключениях было бы мало пользы, если бы у разработчика СУБД не было возможности обработать их на уровне базы данных. Чтобы разработчик смог обработать возникшее исключение, применяется следующая конструкция языка XП и триггеров: