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

  2 IS

  3     FUNCTION valid_comm (v_comm IN NUMBER)

  4     RETURN BOOLEAN

  5     IS

  6        v_max_comm NUMBER;

  7     BEGIN

  8        SELECT MAX(comm) INTO v_max_comm FROM emp;

  9        IF v_comm>v_max_comm THEN RETURN(FALSE);

 10        ELSE RETURN(TRUE);

 11        END IF;

 12     END valid_comm;

 13 

 14     PROCEDURE reset_comm (v_comm IN NUMBER)

 15     IS

 16        v_valid BOOLEAN;

 17     BEGIN

 18        v_valid := valid_comm(v_comm);

 19        IF v_valid = TRUE THEN g_comm := v_comm;

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

 21        END IF;

 22     END reset_comm;

 23  END comm_package;

 24  /

Package body created.

Обратите внимание, для обращения к программным конструкциям, объявленным в этом же пакете, не требуется указывать имя пакета в качестве префикса (строка 18 – вызов закрытой функции, 19 – переназначение общедоступной переменной).

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

SQL> EXECUTE comm_package.reset_comm(2000)

Invalid Commission

PL/SQL procedure successfully completed.

SQL> EXECUTE comm_package.reset_comm(200)

PL/SQL procedure successfully completed.

SQL> VARIABLE h_comm NUMBER

SQL> EXECUTE :h_comm := comm_package.g_comm

PL/SQL procedure successfully completed.

SQL> PRINT h_comm

   H_COMM

---------

      200

Общедоступные переменные пакета

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

Создадим хранимую процедуру для отображения на экране текущего времени и значения общедоступной пакетной переменной g_comm:

SQL> CREATE OR REPLACE PROCEDURE print_var

  2  IS

  3     v_time VARCHAR2(10);

  4  BEGIN

  5     v_time := TO_CHAR(SYSDATE, 'hh24:mi:ss');

  6     DBMS_OUTPUT.put_line(v_time || ': g_comm = ' || comm_package.g_comm);

  7  END;

  8  /

Procedure created.

Откроем два сеанса SQL*Plus и посмотрим, как влияет изменение общедоступной пакетной переменной в одном сеансе на значение этой переменной в другом сеансе:

SQL> SET SERVEROUTPUT ON

SQL> EXECUTE print_var

14:20:26: g_comm = 10

PL/SQL procedure successfully completed.

SQL> EXECUTE comm_package.reset_comm(100)

PL/SQL procedure successfully completed.

SQL> EXECUTE print_var

14:20:51: g_comm = 100

PL/SQL procedure successfully completed.

SQL> EXECUTE print_var

14:22:06: g_comm = 100

PL/SQL procedure successfully completed.

SQL> SET SERVEROUTPUT ON

SQL> EXECUTE print_var

14:21:06: g_comm = 10

PL/SQL procedure successfully completed.

SQL> EXECUTE comm_package.reset_comm(300)

PL/SQL procedure successfully completed.

SQL> EXECUTE print_var

14:21:53: g_comm = 300

PL/SQL procedure successfully completed.

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

Перезагрузка подпрограмм

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

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

·  Перегружать можно только пакетные или прикладные подпрограммы. Создать несколько хранимых программных единиц с одним именем нельзя.

·  Нельзя перегружать подпрограммы, если они отличаются только именами или типами (IN, OUT, IN OUT) параметров.

·  Нельзя перегружать подпрограммы, если списки формальных параметров отличаются только типами данных, причем типы данных принадлежат одному семейству (FLOAT, INTEGER, INT).

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

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

SQL> CREATE OR REPLACE PACKAGE init_val

  2  IS

  3     FUNCTION initial(p_var IN NUMBER) RETURN NUMBER;

  4     FUNCTION initial RETURN DATE;

  5  END init_val;

  6  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY init_val

  2  IS

  3     FUNCTION initial

  4     RETURN DATE

  5     IS

  6     BEGIN

  7        RETURN SYSDATE;

  8     END;

  9 

 10     FUNCTION initial(p_var IN NUMBER)

 11     RETURN NUMBER

 12     IS

 13     BEGIN

 14        RETURN p_var;

 15     END;

 16  END init_val;

 17  /

Package body created.

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

SQL> EXECUTE DBMS_OUTPUT.put_line(init_val.initial(1000))

1000

PL/SQL procedure successfully completed.

SQL> EXECUTE DBMS_OUTPUT.put_line(init_val.initial)

10-DEC-01

PL/SQL procedure successfully completed.

Объявление вперед

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