Бытовая техника Холодильники Двухкамерные
Бытовая техника Холодильники Однокамерные
Бытовая техника Стиральные машины Вертикальные
Бытовая техника Стиральные машины Фронтальные Узкие
Бытовая техника Стиральные машины Фронтальные Классические
Компьютеры и комплектующие
ID_CHILD_GOOD
6
7
8
9
11
12
3
Как видите, с помощью рекурсивной хранимой процедуры мы прошлись по всему дереву категорий и вывели полное наименование категорий - "листьев", которые находятся на самых кончиках ветвей.
Заключение
На этом закончим рассмотрение основных возможностей языка хранимых процедур. Очевидно, что полностью освоить разработку хранимых процедур при чтении одной главы невозможно, однако здесь мы постарались представить и объяснить основные концепции, связанные с хранимыми процедурами. Описанные конструкции и приемы проектирования ХП могут быть применены в большинстве приложений баз данных
Часть важных вопросов, связанных с разработкой хранимых процедур, будет раскрыта в следующей главе - "Расширенные возможности языка хранимых процедур 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П и триггеров:
WHEN EXCEPTION <имя_исключения> DO
BEGIN
/*обработка исключения*/
END
Использование этой конструкции помогает избежать возвращения стандартной ошибки с текстом исключения и произвести собственные действия по обработке исключения.
Когда возбуждается исключение, происходит следующее: выполнение хранимой процедуры (или триггера) прерывается. InterBase начинает искать конструкцию WHEN EXCEPTION...DO для обработки возникшего исключения в текущем блоке BEGIN...END. Если не находит, то поднимается на уровень выше (выше в том смысле, если имеются вложенные блоки BEGIN...END или когда одна ХП вызвана из другой) и ищет обработчик исключения там и т. д., пока либо не найдет подходящий обработчик исключения, либо не закончится вложенность уровней хранимой процедуры. Если обработчик исключения так и не был найден, то возвращается стандартное сообщение об ошибке, включающее текст исключения. Если обработчик найден, то выполняются действия в его блоке BEGIN...END и управление передается на первый оператор, следующий за END обработчика.
Давайте рассмотрим пример обработки исключения, возбуждаемого в нашей процедуре SP_DIVIDE. Предположим, что мы имеем некоторую внешнюю процедуру SP_divide_all, вызывающую SPJDFVIDE для того, чтобы поделить два числа. Конечно, пример сильно утрирован, но он позволяет пояснить способ и смысл использования исключений.
Итак, вот текст нашей хранимой процедуры:
CREATE PROCEDURE sp_test_except(Delltel DOUBLE PRECISION)
RETURNS (rslt DOUBLE PRECISION, status VARCHAR(SO))
AS
BEGIN
Status='Everything is Ok';
SELECT result FROM sp_divide(12,:Delitel) INTO :rslt;
SUSPEND;
WHEN EXCEPTION Zero_divide DO
BEGIN
Status='zero value found!';
rslt=-l;
SUSPEND;
END
END
Эта процедура вызывает процедуру SP_DIVIDE. Если параметр Delitel не равен нулю, то процедура SP_DIVIDE выполняется без проблем и в возвращаемое значение rslt помещается частное от деления, а статусная переменная status принимает значение 'Everything is Ok'. В случае, если возникла исключительная ситуация деления на нуль, то результирующая переменная rslt будет равна -1, а в переменной status будет содержаться сообщение об ошибке - 'zero value found!'. Разумеется, в обработчике исключения можно произвести и более сложную обработку, например записать некорректные данные в особую таблицу или попытаться изменить данные для выполнения операции и вновь попробовать ее выполнить и т. д.