CREATE PACKAGE

CREATE PACKAGE — создать пакет

Синтаксис

CREATE [ OR REPLACE ] PACKAGE имя_пакета элемент_пакета [ ... ]

Описание

CREATE PACKAGE создаёт новый пакет в текущей базе данных.

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

CREATE OR REPLACE PACKAGE либо создаст новый пакет, либо заменит существующее определение. Вы можете заменить существующий пакет, если он содержит только функции и типы, другие объекты должны быть предварительно удалены. Если при замене пакета не меняются сигнатуры содержащихся в нём функций, их содержимое заменяется, а зависимые объекты остаются. Если же сигнатура функции меняется, фактически создаётся отдельная функция. Новая функция будет создана успешно только при отсутствии объектов, зависящих от предыдущей, в противном случае CREATE OR REPLACE PACKAGE завершается ошибкой. То же ограничение действует при замене типов. При замене пакетов убедитесь, что никакие другие сеансы не используют их (другими словами, перед заменой пакетов остановите использующее их приложение).

Параметры

имя_пакета

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

элемент_пакета

Оператор SQL, определяющий объект, который будет создан в пакете. В настоящее время внутри CREATE PACKAGE допускаются только операторы CREATE FUNCTION, CREATE TYPE и CREATE PROCEDURE. Подкоманды обрабатываются по существу так же, как и отдельные команды, выполняемые после создания пакета. По умолчанию все переменные, объявленные в функции инициализации пакета, а также функции и процедуры пакета являются публичными, поэтому с помощью записи с точкой к ним могут обращаться функции, процедуры и анонимные блоки, импортирующие пакет. Модификатор #private определяет функции и процедуры как внутренние, а модификатор #export определяет, какие переменные пакета являются публичными. Более подробно функции и модификаторы пакетов описаны в Разделе 45.11.

Замечания

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

Примеры

Создание пакета counter с функциями:

CREATE PACKAGE counter
    CREATE FUNCTION __init__() RETURNS void AS $$ -- инициализация пакета
    #export on
    DECLARE
        n int := 1; -- публичная пакетная переменная n
        k int := 3; -- публичная пакетная переменная k
    BEGIN
        FOR i IN 1..10 LOOP
            n := n + n;
        END LOOP;
    END;
    $$

    CREATE FUNCTION inc() RETURNS int AS $$ -- публичная пакетная функция inc()
    BEGIN
        n := n + 1;
        RETURN n;
    END;
    $$
;

Заметьте, что отдельные подкоманды не заканчиваются точкой с запятой, так же как в CREATE SCHEMA, и при создании функций не указывается язык.

Если в функции инициализации пакета указан модификатор #export on, все объявленные переменные являются публичными, то есть они доступны снаружи пакета. Отсутствие в пакете модификатора #export (значение по умолчанию) приводит к тому же результату. Функция inc() по умолчанию является публичной и доступна снаружи пакета, как и любая другая функция или процедура пакета.

Следующий пример показывает как можно использовать описанный выше пакет.

DO $$
#import counter
BEGIN
    RAISE NOTICE '%', counter.n;
    RAISE NOTICE '%', counter.inc();
END;
$$;

NOTICE:  1024
NOTICE:  1025

Другой вариант предыдущего примера:

CREATE PACKAGE foo
  CREATE TYPE footype AS (a int, b int)

  CREATE FUNCTION __init__() RETURNS void AS $$
  #export y
  DECLARE
    x int := 1; -- внутренняя пакетная переменная x
    y int := 5; -- публичная пакетная переменная y
  BEGIN
    RAISE NOTICE 'foo initialized';
  END;
  $$

  CREATE FUNCTION get_x() RETURNS int AS $$ -- публичная пакетная функция get_x()
  BEGIN
    RETURN x;
  END;
  $$

  CREATE PROCEDURE set_x(val int) AS $$ -- публичная пакетная процедура set_x()
  BEGIN
    x := val;
    CALL foo.check_x();
  END;
  $$

  CREATE PROCEDURE check_x() AS $$ -- внутренняя пакетная процедура check_x()
  #private
  BEGIN
    IF x <= 0 THEN
      RAISE INFO 'now x is not natural number';
    ELSE
      RAISE INFO 'now x is natural number';
    END IF;
  END;
  $$
;

В этом примере переменная y, функция get_x() и процедура set_x(int) из пакета foo являются публичными.

Другой вариант предыдущего примера:

DO $$
#import foo
BEGIN
  RAISE INFO 'y = %', foo.y;
  RAISE INFO 'x = %', foo.get_x();
  CALL foo.set_x(25);
  RAISE INFO 'x = %', foo.get_x();
END;
$$;

INFO:  y = 5
INFO:  x = 1
INFO:  x set to natural value
INFO:  x = 25

Ниже показано, как можно добиться того же результата командой CREATE SCHEMA:

CREATE SCHEMA foo;
CREATE TYPE foo.footype AS (a int, b int);

CREATE FUNCTION foo.__init__() RETURNS void AS $$
#export y
DECLARE
  x int := 1; -- внутренняя пакетная переменная x
  y int := 5; -- публичная пакетная переменная y
BEGIN
  RAISE NOTICE 'foo initialized';
END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION foo.get_x() RETURNS int AS $$ -- публичная пакетная функция get_x()
#package
BEGIN
  RETURN x;
END;
$$ LANGUAGE plpgsql;

CREATE PROCEDURE foo.set_x(val int) AS $$ -- публичная пакетная процедура set_x()
#package
BEGIN
  x := val;
  CALL foo.check_x();
END;
$$ LANGUAGE plpgsql;

CREATE PROCEDURE foo.check_x() AS $$ -- внутренняя пакетная процедура check_x()
#package
#private
BEGIN
  IF x <= 0 THEN
    RAISE INFO 'x set to not natural value';
  ELSE
    RAISE INFO 'x set to natural value';
  END IF;
END;
$$ LANGUAGE plpgsql;

Обратите внимание, что в этом случае вы должны использовать модификаторы #package.

См. также

DROP PACKAGE