Объектно-ориентированное программирование в PL/SQL
Пакеты языка PL/SQL
Создание пакета
Пакет - это объект схемы, который объединяет логически зависимые типы PL/SQL, данные и подпрограммы. Пакет состоит из двух частей: спецификации пакета и тела пакета .
В спецификации пакета объявляются доступные типы, переменные, константы, исключения, курсоры и подпрограммы.
В теле пакета содержится определение курсоров и реализация подпрограмм. Все элементы, объявляемые в теле пакета, невидимы для приложения, что позволяет скрывать от пользователя детали реализации подпрограмм.
Определение спецификации пакета выполняется оператором CREATE PACKAGE , который может иметь следующее формальное описание:
- Спецификация (видимая часть) CREATE PACKAGE name AS - Объявление общедоступных типов - и переменных - Спецификация подпрограмм END [name];
Определение тела пакета выполняется оператором CREATE PACKAGE BODY , который может иметь, с некоторыми сокращениями, следующее формальное описание:
- Тело пакета (скрытая часть) CREATE PACKAGE BODY name AS - Объявление локальных типов - и переменных - Тела подпрограмм END [name];
Например:
- Спецификация пакета
CREATE PACKAGE tbl_rows AS
TYPE RecTBL1 IS RECORD
(tbl1f1 INTEGER, tbl1f2 REAL);
PROCEDURE insert_tbl1
(f1 INTEGER, f2 REAL);
END tbl_rows;
- Тело пакета
CREATE PACKAGE BODY tbl_rows AS
PROCEDURE insert_tbl1
(f1 INTEGER, f2 REAL) IS
BEGIN
INSERT INTO tbl1
VALUES (f1,f2);
END insert_tbl;
END tbl_rows;На общедоступные элементы пакета - типы, переменные и методы - можно ссылаться из триггеров, хранимых подпрограмм или OCI-приложений, используя следующий синтаксис: package_name.item_name.
Вызов пакетной процедуры из встроенного SQL может быть реализован в анонимном блоке PL/SQL, для выполнения которого используется SQL-оператор EXECUTE.
Например:
EXEC SQL EXECUTE BEGIN tbl_rows.insert_tbl1(1, 200); END;
Подпрограммы
Подпрограммами называются именованные блоки PL/SQL, которые могут иметь параметры.
Язык PL/SQL позволяет создавать подпрограммы и как процедуры, и как функции PL/SQL.
Подпрограммы могут быть объявлены в любом блоке PL/SQL, подпрограмме или пакете. Любая процедура или функция должна быть объявлена до ее использования. В том случае, если одной подпрограмме требуется использовать другую подпрограмму, объявляемую позже, то следует использовать механизм предварительного объявления. При этом предварительно объявляемая подпрограмма содержит только спецификацию, а полное объявление подпрограммы может быть выполнено ниже в соответствии с обычным синтаксисом.
Для того чтобы подпрограмму пакета можно было вызвать извне, она должна быть объявлена в спецификации пакета, определяемой оператором CREATE PACKAGE .
Для того чтобы самостоятельную подпрограмму можно было вызвать извне она должна храниться в базе данных. Такие подпрограммы называются хранимыми процедурами или хранимыми функциями. Для их создания применяются SQL-операторы CREATE PROCEDURE и CREATE FUNCTION .
Определение процедуры может иметь следующее формальное описание:
PROCEDURE name
[(parameter[, parameter, ...])]
IS
[local declarations]
BEGIN
executable statements
[EXCEPTION exception handlers]
END [name];Параметры в списке параметров определяются как:
parameter_name [IN | OUT | IN OUT]
datatype [{:= | DEFAULT} expression]Параметры, используемые при объявлении процедуры или функции, называются формальными параметрами, а при вызове - фактическими параметрами .
Язык PL/SQL позволяет, чтобы количество фактических параметров было меньше, чем количество формальных параметров. В этом случае будут использованы значения по умолчанию, которые обязательно должны присутствовать для отсутствующих значений параметров.
Для определения соответствия между формальными и фактическими параметрами предусмотрены два типа нотаций:
При позиционной нотации порядок формальных и фактических параметров должен совпадать.
При именованной нотации порядок указания параметров не имеет значения, но перед значением параметра указывается имя формального параметра и символ =>. Список параметров может содержать оба типа нотаций одновременно, но именованная нотация располагается только в конце списка.
Процедура имеет две части:
- спецификацию, начинающуюся ключевым словом PROCEDURE и завершающуюся именем процедуры или списком параметров;
- тело процедуры, начинающееся ключевым словом IS и завершающееся ключевым словом END.
Тело процедуры, как и любой блок PL/SQL, имеет секцию объявлений, секцию выполняемого кода и необязательную секцию обработчиков исключений.
Определение функции может иметь следующее формальное описание:
FUNCTION name
[(parameter[, parameter, ...])]
RETURN datatype
IS
[local declarations]
BEGIN
executable statements
[EXCEPTION
exception handlers]
END [name];Параметры в списке параметров определяются как:
parameter_name [IN | OUT | IN OUT]
datatype [{:= | DEFAULT} expression]Например:
FUNCTION fun1 (f1 REAL, f2 REAL)
RETURN BOOLEAN IS
min_f1 REAL :=0;
max_f1 REAL :=1;
BEGIN
SELECT ff1min, ff2max
INTO min_f1, max_f1
FROM tbl1
WHERE ff2 = f2;
RETURN (f1 >= min_f1)
AND (f2 <= max_f1);
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO tbl2
VALUES (min_f1, max_f1);
RETURN FALSE;
END fun1;Язык PL/SQL позволяет создавать перегружаемые подпрограммы, имеющие одинаковое имя, но различный список формальных параметров. Параметры перегружаемых функций должны различаться хотя бы по одному из следующих признаков: по типу, по количеству, по порядку следования параметров.
Перегружаемые подпрограммы можно применять для реализации одних и тех же действий над переменными различных типов. Для перегружаемых подпрограмм компилятор будет искать подпрограмму с совпадающим списком фактических параметров только до тех пор, пока не просмотрит все перегружаемые подпрограммы данного блока. И только в том случае, если перегружаемых подпрограмм с указанным именем в данном блоке нет, то компилятор продолжит поиск во внешнем блоке.
Рекурсивные и взаимно рекурсивные вызовы подпрограмм
Рекурсивным вызовом называется вызов подпрограммы из тела этой же подпрограммы .
При каждом рекурсивном вызове:
- создается новый экземпляр всех элементов, объявленных в подпрограмме, включая параметры, переменные, курсоры и исключения;
- создается свой экземпляр SQL-оператора.
Рассмотрим в качестве примера рекурсивных вызовов создание последовательности Фибоначчи ( 1, 1, 2, 3, 5, 8, 13, 21, ...), в которой каждый следующий элемент является суммой двух предыдущих.
Следующая функция fibonati1 реализует формирование последовательности Фибоначчи с применением рекурсии:
FUNCTION fibonati1 (n POSITIVE)
RETURN INTEGER IS
BEGIN
IF (n = 1) OR (n = 2) THEN
RETURN 1;
ELSE
RETURN fibonati1 (n-1) +
fibonati1 (n-2);
END IF;
END fibonati1;Вместо рекурсивного способа можно использовать и итерационный способ, который менее нагляден, но требует и меньше памяти, и быстрее выполняется.
Так, следующая функция fibonati2 реализует формирование последовательности Фибоначчи итерационным способом:
FUNCTION fibonati2 (n POSITIVE)
RETURN INTEGER IS
pos1 INTEGER := 1;
pos2 INTEGER := 0;
sum INTEGER;
BEGIN
IF (n = 1) OR (n = 2) THEN
RETURN 1;
ELSE
sum := pos1 + pos2;
FOR i IN 3..n LOOP
pos2 := pos1;
pos1 := sum;
sum := pos1 + pos2;
END LOOP;
RETURN sum;
END IF;
END fibonati2;Язык PL/SQL позволяет реализовывать взаимно рекурсивные вызовы, при которых подпрограммы прямо или опосредованно вызывают друг друга.
