Пакет как программная единица, объединяющая логически связанные типы PL/SQL, идентификаторы и подпрограммы, страница 3

PL/SQL позволяет в этих случаях объявлять ссылаемые подпрограммы перед их описанием. Т.е. Вы объявляете программную единицу перед подпрограммой, которая на нее ссылается, но описываете там, где Вам удобнее. Список формальных параметров должен присутствовать в обоих описаниях.

Например, попытка откомпилировать тела пакета, в котором процедура reset_comm описана перед функцией valid_comm, завершится ошибкой, т.к. процедура reset_comm ссылается на функцию valid_comm.

SQL> CREATE OR REPLACE PACKAGE BODY comm_package

  2  IS

  3     PROCEDURE reset_comm (v_comm IN NUMBER)

  4     IS

  5        v_valid BOOLEAN;

  6     BEGIN

  7        v_valid := valid_comm(v_comm);

  8        IF v_valid = TRUE THEN g_comm := v_comm;

  9        ELSE DBMS_OUTPUT.put_line('Invalid Commission');

 10        END IF;

 11     END reset_comm;

 12 

 13     FUNCTION valid_comm (v_comm IN NUMBER)

 14     RETURN BOOLEAN

 15     IS

 16        v_max_comm NUMBER;

 17     BEGIN

 18        SELECT MAX(comm) INTO v_max_comm FROM emp;

 19        IF v_comm>v_max_comm THEN RETURN(FALSE);

 20        ELSE RETURN(TRUE);

 21        END IF;

 22     END valid_comm;

 23  END comm_package;

 24  /

Warning: Package Body created with compilation errors.

Но если функцию valid_comm объявить перед описанием процедуры reset_comm, компиляция завершится без ошибок, несмотря на то, что описана функция после процедуры.

SQL> CREATE OR REPLACE PACKAGE BODY comm_package

  2  IS

  3     FUNCTION valid_comm (v_comm IN NUMBER) RETURN BOOLEAN;

  4 

  5     PROCEDURE reset_comm (v_comm IN NUMBER)

  6     IS

  7        v_valid BOOLEAN;

  8     BEGIN

  9        v_valid := valid_comm(v_comm);

 10        IF v_valid = TRUE THEN g_comm := v_comm;

 11        ELSE DBMS_OUTPUT.put_line('Invalid Commission');

 12        END IF;

 13     END reset_comm;

 14 

 15     FUNCTION valid_comm (v_comm IN NUMBER)

 16     RETURN BOOLEAN

 17     IS

 18        v_max_comm NUMBER;

 19     BEGIN

 20        SELECT MAX(comm) INTO v_max_comm FROM emp;

 21        IF v_comm>v_max_comm THEN RETURN(FALSE);

 22        ELSE RETURN(TRUE);

 23        END IF;

 24     END valid_comm;

 25  END comm_package;

 26  /

Package body created.

Инициализация пакета

В теле пакета может содержаться программа инициализации, выполняемая один раз при загрузке пакета в память. Программа инициализации используется для инициализации общедоступных или закрытых переменных, если для этого необходимы сложные вычисления, которые не могут быть выполнены при инициализации переменной по умолчанию, или требуется извлечь данные из базы данных. Программа инициализации представляет собой блок PL/SQL, начинающийся ключевым словом BEGIN и располагающийся в конце тела пакета после всех описаний.

CREATE [OR REPLACE] PACKAGE BODY имя_пакета

IS

список_идентификаторов_и_подпрограмм;

 [BEGIN

   программа_инициализации;]

END [имя_пакета];

Например, программу инициализации можно использовать, чтобы установить начальное значение общедоступной пакетной переменной, равное среднему значению комиссионных сотрудников из таблицы emp.

SQL> CREATE OR REPLACE PACKAGE BODY comm_package

  2 IS

  3     FUNCTION valid_comm (v_comm IN NUMBER)

  4     RETURN BOOLEAN

  5     IS

           ...

 12     END valid_comm;

 13 

 14     PROCEDURE reset_comm (v_comm IN NUMBER)

 15     IS

 16        v_valid BOOLEAN;

 17     BEGIN

           ...

 22     END reset_comm;

 23 

 24  BEGIN

 25     SELECT AVG(comm) INTO g_comm FROM emp;

 26  END comm_package;

 27  /

Package body created.

SQL> VARIABLE v_comm NUMBER

SQL> EXECUTE :v_comm := comm_package.g_comm

PL/SQL procedure successfully completed.

SQL> PRINT v_comm

   V_COMM

---------

      550

Удаление пакета

Для удаления пакетной спецификации и тела пакета используется команда DDL DROP PACKAGE, для удаления только тела пакета – DROP PACKAGE BODY.

DROP PACKAGE имя_пакета;

DROP PACKAGE BODY имя_пакета;

SQL> DROP PACKAGE comm_package;

Package dropped.

Рекомендации по созданию пакетов

Старайтесь создавать наиболее общие пакеты, чтобы их можно было использовать во многих, как уже существующих, так и предполагаемых, приложениях. Не создавайте пакеты, дублирующие функциональность встроенных пакетов Oracle.

Создавайте спецификацию пакета перед его телом, т.к. спецификация предоставляет интерфейс к пакетным объектам для Ваших приложений. К тому же, тело пакета не может быть откомпилировано, если не откомпилирована соответствующая спецификация пакета.

Описывайте в спецификации пакета только те объекты, которые действительно должны быть доступны всем пользователям.

Описывайте в спецификации пакета как можно меньше объектов. Это уменьшит необходимость перекомпиляции пакета, т.к. внесение изменений в тело пакета не требует перекомпиляции зависимых объектов, в то время как изменение спецификации пакета требует перекомпиляции каждой хранимой программной единицы, которая ссылается на общедоступные объекты этого пакета.

Использование хранимых и пакетных функций в командах SQL

Вы можете использовать хранимые и пакетные функции в SQL утверждениях, но они должны быть свободны от «побочных эффектов», которые могут препятствовать выполнению запроса или привести к неопределенному результату.

Если команда SQL выполняется из функции, которая была вызвана из предложения SQL, или из триггера базы данных, она может нарушить логическую целостность уже выполняемого утверждения SQL. Чтобы этого не произошло, сервер базы данных выполняет определенные проверки функции, вызванной из предложения SQL, и выдает ошибку в том случае, если функция не отвечает следующим ограничениям:

·  Функция, вызываемая из запроса SQL или команды DML, не может выполнять команды управления транзакциями (COMMIT, ROLLBACK, SAVEPOINT) или SQL утверждения, управляющие сеансом (SET ROLE, ALTER SESSION) или системой (ALTER SYSTEM). Нельзя, также, выполнять утверждения DDL, т.к. они выполняют неявный COMMIT.