4. Функции, процедуры, пакеты
Синтаксис:
CREATE [OR REPLACE] PROCEDURE
procedureName [(
argName1 [IN | OUT | IN OUT] type1 [:= defaultValue],
argName2 [IN | OUT | IN OUT] type2 [:= defaultValue],
-- аргументы
)] IS | AS
-- локальные переменные и процедуры/функции
-- процедуры и функции должны быть написаны в самом низу
BEGIN
-- код подпрограммы
END [procedureName];
Вместо :=
можно использовать и DEFAULT
.
Режимы IN | OUT | IN OUT
:
IN
(по умолчанию): передаёт значение в подпрограмму. В подпрограмме ведёт себя как константа.OUT
: возвращает значение в вызывающую среду. В подпрограмме ведёт себя как переменная сNULL
-овым значением.IN OUT
: предоставляет входное значение, которое может быть возвращено (выведено) как изменённое значение. В подпрограмме ведёт себя как переменная.
Пример:
CREATE TABLE dept AS SELECT * FROM departments;
CREATE PROCEDURE addDept IS
deptID dept.department_id%TYPE;
deptName dept.department_name%TYPE;
BEGIN
deptID := 280;
deptName := 'ST-Curriculum';
INSERT INTO Dept(Department_ID, Department_Name)
VALUES (deptID, deptName);
DBMS_OUTPUT.PUT_LINE('Inserted '|| SQL%ROWCOUNT ||' row(s).');
END;
Подпрограмма может быть вызвана внутри BEGIN...END;
, с помощью операторов EXECUTE
и CALL
(CALL
круче — он может так же вызывать процедуры/функции, написанные на C/Java
).
-- вне блока BEGIN..END:
EXECUTE someProcedure(arg1, arg2, ...)
CALL someOtherProcedure(arg1, arg2, ...)
-- внутри блока BEGIN..END:
BEGIN
anotherProcedure(arg1, arg2, ...);
END;
Информация о процедурах/функциях/пакетах/триггерах может быть найдена в словаре USER_SOURCE
.
DESCRIBE USER_SOURCE
Name Null? Type
------------- ----- --------------
NAME VARCHAR2(128)
TYPE VARCHAR2(12)
LINE NUMBER
TEXT VARCHAR2(4000)
ORIGIN_CON_ID NUMBER
Синтаксис:
CREATE [OR REPLACE] FUNCTION
functionName [(
argName1 [IN | OUT | IN OUT] type1 [:= defaultValue],
argName2 [IN | OUT | IN OUT] type2 [:= defaultValue],
-- аргументы
)] RETURN typeName IS | AS
-- локальные переменные и процедуры/функции
-- процедуры и функции должны быть написаны в самом низу
BEGIN
-- код функции
END [functionName];
Передавать параметры в функцию/процедуру можно по очереди, а можно указать имя параметра через =>
:
BEGIN
var := someFunction(42, arg9 => 31);
-- arg1 arg9
END;
Функции так же можно использовать:
- В списке команды
SELECT
в запросе. - В условных выражениях в
WHERE
иHAVING
. - В разделах запроса
CONNECT BY
,START WITH
,ORDER BY
иGROUP BY
. - В разделе
VALUES
командыINSERT
. - В разделе
SET
командыUPDATE
.
Ограничения вызова функций из SQL-выражений:
- Пользовательские функции, которые могут быть вызваны из SQL выражений, должны:
- Храниться в базе данных.
- Получать только
IN
-параметры с допустимыми в SQL типами данных, а не специфическими типами PL/SQL. - Возвращать допустимые в SQL типы данных, а не специфические типы PL/SQL.
- При вызове функции из SQL оператора вы должны быть владельцем функции или иметь привилегию
EXECUTE
.
Контролирование сторонних эффектов при вызове функций из SQL выражений. Функции, вызываемые из:
- Команды
SELECT
, не могут содержать DML-команд. - Команд
UPDATE
иDELETE
для таблицыT
, не могут содержать запросы и DML команд к той же таблицеT
. - SQL операторов, не могут завершать транзакцию (то есть, не могут содержать команды
COMMIT
иROLLBACK
).
Вызовы подпрограмм, нарушающих данные ограничения, так же не допустимы в этих функциях.
Пакет — это объект схемы, который объединяет логически родственные PL/SQL типы данных, переменные и подпрограммы.
Синтаксис создания спецификации пакета:
CREATE [OR REPLACE] PACKAGE packageName IS | AS
-- объявление public типов данных и переменных
-- спецификация подпрограмм
END [packageName];
Все конструкции, объявленные в спецификации пакета, видны пользователям, которые имеют привилегии на пакет.
Синтаксис создания тела пакета:
CREATE [OR REPLACE] PACKAGE BODY packageName IS | AS
-- объявление private типов данных и переменных
-- тела подпрограмм
[BEGIN операторы инициализации]
END [packageName];
Пакеты можно создавать и без тела, чтоб, к примеру, хранить там переменные и константы.
Forward declaration (прямое объявление) — это private
спецификация подпрограмм, разделённых точкой с запятой (нужна для того, чтобы можно было использовать подпрограммы до их описания в пакете).
Уровень чистоты – это степень, в которой функция свободна от сторонних эффектов.
Сторонние эффекты – доступ к таблицам базы данных, переменным пакета и т.д. для чтения или записи.
Контролировать сторонние эффекты очень важно, потому что они могут:
- Препятствовать правильному распараллеливанию запроса.
- Приводить к результатам, зависящим от порядка следования и, как следствие, неопределённым.
- Требовать недопустимых действий, таких как поддержание состояния пакета между сессиями пользователя.
Чтобы быть вызываемой из SQL операторов, хранимая функция должна подчиняться следующим правилам чистоты для управления сторонними эффектами:
- При вызове из команды
SELECT
или распараллеленных DML-команд функция не может изменять таблицы базы данных. - При вызове из DML-команды функция не может выполнять запросы или изменять таблицы базы данных, которые уже изменяются данной командой.
- При вызове из команды
SELECT
или DML-команд функция не может выполнять команды контроля SQL транзакций, контроля сессии или контроля системы.
Устойчивое состояние пакета. Набор пакетных переменных и значений определяет состояние пакета. Состояние пакета:
- Инициализируется при первом обращении к компоненте пакета (его загрузке в память).
- Устойчиво (по умолчанию) в течении сессии:
- Хранится в
User Global Area
(UGA
) (в ОЗУ). - Уникально для каждой сессии.
- Может изменяться при вызове подпрограмм пакета или изменении
public
переменных.
- Хранится в
- При использовании директивы
PRAGMA SERIALLY_REUSABLE
в спецификации пакета становится неустойчивым в течении сессии, но устойчивым в течении выполнения вызова подпрограммы.