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

·  Функция, вызываемая из запроса SQL (SELECT), не может модифицировать таблицы базы данных. Т.е. команды INSERT, UPDATE, DELETE не допускаются

·  Функция, вызываемая из DML утверждения, не может читать или изменять таблицы, модифицируемые этим утверждением

SQL> CREATE OR REPLACE PACKAGE comm_package

  2  IS

  3     FUNCTION avg_comm RETURN NUMBER;

  4  END comm_package;

  5  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY comm_package

  2  IS

  3     FUNCTION avg_comm

  4     RETURN NUMBER

  5     IS

  6        l_comm NUMBER;

  7     BEGIN

  8        SELECT AVG(comm) INTO l_comm FROM emp;

  9        RETURN l_comm;

 10     END avg_comm;

 11  END comm_package;

 12  /

Package body created.

Пакетная функция avg_comm читает таблицу emp, чтобы вернуть среднее значение комиссионных. Эта функция может быть вызвана из запроса SQL, т.к. она не модифицирует таблицу emp, а только читает ее:

SQL> SELECT comm, comm_package.avg_comm FROM emp WHERE comm IS NOT NULL;

     COMM  AVG_COMM

--------- ---------

      300       550

      500       550

     1400       550

        0       550

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

SQL> UPDATE emp SET comm=comm_package.avg_comm WHERE comm IS NULL;

UPDATE emp SET comm=comm_package.avg_comm WHERE comm IS NULL

                    *

ERROR at line 1:

ORA-04091: table EMP is mutating, trigger/function may not see it

ORA-06512: at "COMM_PACKAGE", line 8

ORA-06512: at line 1

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

PRAGMA RESTRICT_REFERENCES (имя_функции, WNDS[, WNPS][, RNDS][, RNPS]);

имя_функции – имя функции, «чистоту» которой надо проверить

WNDS – функция не может изменять таблицы базы данных (Writes No Database State) – обязательный уровень «чистоты»

WNPS – функция не может изменять значения пакетных переменных (Writes No Package State)

RNDS – функция не может читать таблицы базы данных (Reads No Database State)

RNPS – функция не может ссылаться на пакетные переменные (Reads No Package State)

Директива PRAGMA RESTRICT_REFERENCES указывается в спецификации пакета, после объявления функции. «чистоту» которой она предписывает проверять.

Например, предполагая, что пакетная функция avg_comm будет использоваться для модификации таблицы, укажем директиву PRAGMA RESTRICT_REFERENCES в спецификации пакета comm_package, предписывающую проверять функцию, не читает ли она таблицы базы данных:

SQL> CREATE OR REPLACE PACKAGE comm_package

  2  IS

  3     FUNCTION avg_comm RETURN NUMBER;

  4     PRAGMA RESTRICT_REFERENCES(avg_comm, WNDS, RNDS);

  5  END comm_package;

  6  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY comm_package

  2  IS

  3     FUNCTION avg_comm

  4     RETURN NUMBER

  5     IS

  6        l_comm NUMBER;

  7     BEGIN

  8        SELECT AVG(comm) INTO l_comm FROM emp;

  9        RETURN l_comm;

 10     END avg_comm;

 11  END comm_package;

 12  /

Warning: Package Body created with compilation errors.

SQL> SHOW ERROR

Errors for PACKAGE BODY COMM_PACKAGE:

LINE/COL ERROR

-------- -----------------------------------------------------------------

0/0      PL/SQL: Compilation unit analysis terminated

3/4      PLS-00452: Subprogram 'AVG_COMM' violates its associated pragma

Ошибка, связанная с нарушением «чистоты от побочных эффектов», возникла на этапе компиляции тела пакета.

Управление пакетами

Для создания, выполнения, модификации и удаления пакетов требуются соответствующие системные и объектные привилегии.

Чтобы пользователь мог создавать пакеты в собственной схеме, необходима системная привилегия: Пакеты в собственной схеме можно перекомпилировать, выполнить или удалить, для этого привилегии не нужны.

·  CREATE (ANY) PROCEDURE – право создавать хранимые программные единицы в собственной (или любой) схеме

·  ALTER ANY PROCEDURE – право перекомпилировать программные единицы в любой схеме

·  DROP ANY PROCEDURE – право удалять программные единицы в любой схеме

·  EXECUTE ANY PROCEDURE – право выполнять любые программные единицы

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

·  EXECUTE имя_пакета

По умолчанию подпрограммы пакета выполняются с привилегиями пользователя, который его создал.

Информация о пакетах

При компиляции спецификаций и тел пакетов исходный программный код, скомпилированные программы, статистические сведения и ошибки сохраняются в словаре данных, и информацию о них Вы можете получить через различные представления, колонка OBJECT_TYPE которых для спецификации пакета имеет значение PACKAGE, для тела – PACKAGE BODY:

Представление

Описание

USER_SOURCE

Исходные тексты программ для всех хранимых программных модулей

USER_ERRORS

Список сообщений об ошибках компиляции по всем хранимым программным единицам

USER_OBJECTS

Общая информация о хранимых программных единицах в текущей схеме