CREATE FUNCTION#

Примечание

Эта страница переведена при помощи нейросети GigaChat.

CREATE FUNCTION — создание новой функции.

Синтаксис#

CREATE [ OR REPLACE ] FUNCTION
    name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
    [ RETURNS rettype
      | RETURNS TABLE ( column_name column_type [, ...] ) ]
  { LANGUAGE lang_name
    | TRANSFORM { FOR TYPE type_name } [, ... ]
    | WINDOW
    | { IMMUTABLE | STABLE | VOLATILE }
    | [ NOT ] LEAKPROOF
    | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }
    | { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }
    | PARALLEL { UNSAFE | RESTRICTED | SAFE }
    | COST execution_cost
    | ROWS result_rows
    | SUPPORT support_function
    | SET configuration_parameter { TO value | = value | FROM CURRENT }
    | AS 'definition'
    | AS 'obj_file', 'link_symbol'
    | sql_body
  } ...

Описание#

CREATE FUNCTION создает новую функцию. Команда CREATE OR REPLACE FUNCTION либо создает новую функцию, либо заменяет существующее определение. Для создания функции требуется привилегия USAGE на используемый язык программирования.

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

Для замены определения функции используется CREATE OR REPLACE FUNCTION. При этом нельзя изменить имя или типы аргументов — попытка этого приведет к созданию новой функции. Также невозможно изменить тип возвращаемого значения уже существующей функции, для этого необходимо удалить и создать функцию заново. Если применяются параметры OUT, нельзя изменить их типы без удаления функции.

При замене функции через CREATE OR REPLACE FUNCTION сохраняются ее права доступа и владелец. Остальные характеристики функции будут переопределены на основании указанных или подразумеваемых значений. Для замены функции пользователь должен быть владельцем функции или являться прямым или косвенным членом роли владельца.

Удаление функции с последующим ее созданием приводит к появлению новой сущности, отличной от исходной. В этом случае необходимо вручную удалить объекты, зависящие от прежней функции, такие как правила, представления, триггеры и другие. Используйте CREATE OR REPLACE FUNCTION, чтобы изменить определение функции без нарушения объектов, которые ссылаются на эту функцию. Кроме того, ALTER FUNCTION может использоваться для изменения большинства вспомогательных свойств существующей функции.

Владельцем функции становится пользователь, создавший ее.

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

Смотрите раздел «Пользовательские функции» для получения дополнительной информации о написании функций.

Параметры#

name

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

argmode

Задает режим аргумента: IN, OUT, INOUT или VARIADIC. По умолчанию используется IN. За единственным аргументом VARIADIC могут следовать только аргументы OUT. Кроме того, аргументы OUT и INOUT нельзя использовать с выражением RETURNS TABLE.

argname

Задает имя аргумента. Некоторые языки (включая SQL и PL/pgSQL) позволяют обращаться к аргументу по имени в теле функции. В других языках имя входного аргумента служит в основном для удобства чтения и документирования, но при вызове функции можно использовать имена для улучшения читаемости. В случае с выходными аргументами имя имеет значение — оно определяет имя столбца в результирующем наборе строк. Если имя не указано, система применит имя по умолчанию.

argtype

Задает тип(ы) данных аргументов функции, при необходимости дополненные схемой, если таковые есть. Аргументы могут быть базовыми, составными или доменными типами, либо ссылаться на тип столбца таблицы.

В зависимости от языка реализации могут быть допустимы так называемые псевдотипы, такие как cstring. Они обозначают, что тип аргумента либо не полностью определен, либо выходит за рамки обычных SQL-типов.

Тип столбца указывается как table_name.column_name%TYPE. Это позволяет сделать функцию менее зависимой от изменений структуры таблицы.

default_expr

Выражение, используемое по умолчанию, если параметры не указаны при вызове. Оно должно быть совместимо с типом параметра. Только входные параметры (IN и INOUT) могут иметь значение по умолчанию. Все входные параметры после параметра со значением по умолчанию также должны иметь значения по умолчанию.

rettype

Задает тип возвращаемого значения, при необходимости дополненные схемой. Возвращаемый тип может быть базовым, составным, доменным, либо ссылаться на тип столбца. Также допустимо использовать псевдотипы (например, cstring). Если функция не возвращает значение, укажите void.

Если используются параметры OUT или INOUT, выражение RETURNS может быть опущено. При этом, если оно указано, тип должен соответствовать возвращаемому значению, определенному выходными параметрами: RECORD, если таких параметров несколько, или типу единственного параметра.

Модификатор SETOF обозначает, что функция возвращает не одно значение, а набор значений.

Тип столбца можно указать через table_name.column_name%TYPE.

column_name

Задает имя выходного столбца в конструкции RETURNS TABLE. Это по сути то же, что указание параметра OUT, но в синтаксисе RETURNS TABLE, который также подразумевает RETURNS SETOF.

column_type

Задает тип данных для выходного столбца в синтаксисе RETURNS TABLE.

lang_name

Задает язык, на котором реализована функция. Это может быть sql, c, internal или пользовательский язык, например plpgsql. Если указан sql_body, по умолчанию применяется язык sql. Использование одинарных кавычек для имени устарело и требует точного совпадения регистра.

TRANSFORM {FOR TYPE type_name} [, ... ] }

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

WINDOW

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

IMMUTABLE
STABLE
VOLATILE

Описывают поведение функции для оптимизатора. Указывается только один вариант. Если ни один не указан, по умолчанию применяется VOLATILE.

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

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

VOLATILE — результат может меняться даже внутри одного запроса. Оптимизация невозможна. Примеры: random(), currval(), timeofday(). Все функции с побочными эффектами также должны быть помечены как VOLATILE, даже если их результат предсказуем, например setval().

Дополнительные сведения смотрите в разделе Категории изменчивости функций.

LEAKPROOF

Указывает, что функция не имеет побочных эффектов и не раскрывает никакой информации о своих аргументах, за исключением возвращаемого значения. Например, функция, которая вызывает ошибку только для определенных аргументов или включает значение аргументов в сообщение об ошибке, не считается защищенной от утечек. Это влияет на поведение системы при выполнении запросов к представлениям с параметром security_barrier и таблицам с активированной защитой на уровне строк.

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

Устанавливать этот параметр может только суперпользователь.

Смотрите CREATE VIEW и раздел «Правила и привилегии».

CALLED ON NULL INPUT

Вызывает функцию даже при передаче аргументов со значением NULL. В этом случае проверка и обработка NULL лежит на создателе функции. Это поведение по умолчанию.

RETURNS NULL ON NULL INPUT
STRICT

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

[EXTERNAL] SECURITY INVOKER
[EXTERNAL] SECURITY DEFINER

Определяет, будет ли функция исполняться с правами пользователя, вызвавшего ее (SECURITY INVOKER) или владеющего ей (SECURITY DEFINER). SECURITY INVOKER является поведением по умолчанию.

Ключевое слово EXTERNAL разрешено для соответствия SQL, но необязательно, поскольку, в отличие от SQL, эта функция применяется ко всем функциям, а не только к внешним.

PARALLEL

Указывает, может ли функция использоваться в параллельных запросах:

  • PARALLEL UNSAFE — функция не может исполняться в параллельных запросах и делает план выполнения последовательным (значение по умолчанию).

  • PARALLEL RESTRICTED — допускается параллельное выполнение, но только в ведущем процессе группы.

  • PARALLEL SAFE — функция может свободно выполняться параллельно.

Функции должны считаться небезопасными для параллельной работы, если они изменяют состояние базы данных, используют под-транзакции, обращаются к последовательностям или влияют на постоянные параметры (например, setval).

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

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

COST execution_cost

Устанавливает положительное значение, отражающее оценочную затратность выполнения функции в единицах cpu_operator_cost. Для функций, возвращающих множества, это затраты на каждую строку. По умолчанию если затраты не указаны предполагается 1 — для C и встроенных функций, 100 — для функций на всех других языках. При больших значениях планировщик будет стараться не вызывать эту функцию чаще, чем это необходимо.

ROWS result_rows

Задает положительное число, отражающее примерное количество строк, которое планировщик должен ожидать получить от функции. Применим только к функциям, возвращающим множества. По умолчанию предполагается 1000 строк.

SUPPORT support_function

Задает имя функции поддержки планировщика, при необходимости дополненное схемой. Может использоваться только суперпользователем. Подробнее описано в разделе «Информация об оптимизации функций».

configuration_parameter
value

Ключевое слово SET в определении функции задает значение конфигурационного параметра, которое будет автоматически установлено при входе в функцию и восстановлено после ее завершения. SET FROM CURRENT сохраняет текущее значение параметра на момент выполнения команды CREATE FUNCTION и использует его при каждом вызове функции.

Если для функции указано SET, то команда SET LOCAL, выполненная внутри этой функции для того же параметра, действует только в пределах самой функции: при выходе из нее исходное значение параметра будет восстановлено. Однако обычная команда SET (без LOCAL) отменяет эффект SET, заданного в определении функции, так же как она бы отменила предыдущее SET LOCAL: в этом случае измененное значение сохранится даже после выхода из функции, если только текущая транзакция не будет отменена.

Смотрите SET и главу «Конфигурация сервера» для подробностей о параметрах и допустимых значениях.

definition

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

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

obj_file, link_symbol

Эта форма выражения AS используется для функций на языке C, которые загружаются динамически, если имя функции в исходном коде C не совпадает с именем SQL-функции. Строка obj_file указывает имя файла разделяемой библиотеки, содержащей скомпилированную C-функцию, и обрабатывается так же, как в команде LOAD. Строка link_symbol задает имя функции в исходном коде C — это символ связи. Если link_symbol не указан, считается, что имя C-функции совпадает с именем SQL-функции.

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

Если несколько раз вызывать CREATE FUNCTION, ссылаясь на один и тот же файл библиотеки, он будет загружен только один раз за сессию. Чтобы принудительно выгрузить и повторно загрузить библиотеку (например, в процессе разработки), нужно начать новую сессию.

sql_body

Задает тело функции LANGUAGE SQL. Может быть либо выражением:

RETURN expression

либо блоком:

BEGIN ATOMIC
  statement;
  statement;
  ...
  statement;
END

Этот способ задания тела функции похож на указание текста функции в виде строковой константы (смотрите параметр definition выше), но между ними есть важные различия:

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

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

  • При использовании этой формы отслеживаются зависимости между функцией и объектами, которые она использует, поэтому DROP ... CASCADE корректно удалит зависимые объекты. В случае строковой константы такие связи не фиксируются, и можно получить неполноценные функции.

  • Кроме того, эта форма ближе к стандарту SQL и лучше совместима с другими СУБД.

Перегрузка#

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

Функции считаются одинаковыми, если у них совпадают имена и типы входных параметров — параметры OUT при этом игнорируются. Например, следующие объявления конфликтуют:

CREATE FUNCTION foo(int) ...
CREATE FUNCTION foo(int, out text) ...

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

CREATE FUNCTION foo(int) ...
CREATE FUNCTION foo(int, int default 42) ...

Вызов foo(10) приведет к ошибке, так как система не сможет однозначно определить, какую функцию вызывать.

Примечания#

При объявлении типов аргументов и возвращаемого значения можно использовать полный SQL синтаксис типов. Однако модификаторы типа в скобках (например, точность для numeric) игнорируются. Так, CREATE FUNCTION foo(varchar(10)) ... эквивалентно CREATE FUNCTION foo(varchar) ....

При замене функции с помощью CREATE OR REPLACE FUNCTION есть ограничения:

  • нельзя переименовывать входные параметры, у которых уже есть имя;

  • нельзя менять имена выходных параметров, если их больше одного — это изменит структуру результата, описываемого анонимным составным типом;

  • допустимо добавлять имена к безымянным параметрам.

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

Если функция объявлена как STRICT и использует параметр VARIADIC, то проверка строгого поведения (STRICT) проверяет только, что весь массив передан не NULL. При этом допускается наличие NULL внутри элементов массива.

Примеры#

Сложение двух целых чисел, используя функцию SQL:

CREATE FUNCTION add(integer, integer) RETURNS integer
    AS 'select $1 + $2;'
    LANGUAGE SQL
    IMMUTABLE
    RETURNS NULL ON NULL INPUT;

Та же самая функция, написанная более соответствующим SQL стилем, с использованием имен аргументов и неквалифицированного тела:

CREATE FUNCTION add(a integer, b integer) RETURNS integer
    LANGUAGE SQL
    IMMUTABLE
    RETURNS NULL ON NULL INPUT
    RETURN a + b;

Увеличение целого числа на 1, используя имя аргумента, на языке PL/pgSQL:

CREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$
        BEGIN
                RETURN i + 1;
        END;
$$ LANGUAGE plpgsql;

Возвращение записи, содержащей несколько выходных параметров:

CREATE FUNCTION dup(in int, out f1 int, out f2 text)
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);

То же самое можно сделать более развернуто, явно объявив составной тип:

CREATE TYPE dup_result AS (f1 int, f2 text);

CREATE FUNCTION dup(int) RETURNS dup_result
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);

Другой способ вернуть несколько столбцов — использовать функцию TABLE:

CREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);

Однако пример с функцией TABLE отличается от предыдущих, так как в нем функция на самом деле возвращает не одну, а набор записей.

Безопасное написание функций SECURITY DEFINER#

Функции с параметром SECURITY DEFINER выполняются с привилегиями владельца функции, поэтому важно обеспечить безопасное поведение таких функций. Одним из главных требований является настройка параметра search_path так, чтобы он исключал схемы, доступные для записи недоверенными пользователями. Это защищает от атак, при которых вредоносный объект (например, функция, оператор или таблица), созданный в доступной схеме, может быть использован вместо оригинального объекта.

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

CREATE FUNCTION check_password(uname TEXT, pass TEXT)
RETURNS BOOLEAN AS $$
DECLARE passed BOOLEAN;
BEGIN
        SELECT  (pwd = $2) INTO passed
        FROM    pwds
        WHERE   username = $1;

        RETURN passed;
END;
$$  LANGUAGE plpgsql
    SECURITY DEFINER
    -- Set a secure search_path: trusted schema(s), then 'pg_temp'.
    SET search_path = admin, pg_temp;

Функция должна обращаться к таблице admin.pwds. Однако, если в search_path отсутствует явное указание схемы или указана только admin, то возможно создание временной таблицы с тем же именем pwds, что позволит перехватить обращение функции.

До PostgreSQL 8.3 выражение SET не поддерживалось, и для управления search_path приходилось вручную сохранять и восстанавливать значения. В современных версиях использование SET делает это значительно проще и надежнее.

Также необходимо помнить, что по умолчанию функциям предоставляется право выполнения (EXECUTE) для всех пользователей (PUBLIC). Чтобы ограничить доступ, рекомендуется сразу после создания функции отозвать это право и назначить его только нужным ролям. Эту операцию лучше выполнять в рамках одной транзакции:

BEGIN;
CREATE FUNCTION check_password(uname TEXT, pass TEXT) ... SECURITY DEFINER;
REVOKE ALL ON FUNCTION check_password(uname TEXT, pass TEXT) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION check_password(uname TEXT, pass TEXT) TO admins;
COMMIT;

Совместимость#

Команда CREATE FUNCTION входит в стандарт SQL, однако реализация в PostgreSQL включает множество расширений. Некоторые из них:

  • Ключевое слово OR REPLACE является расширением PostgreSQL.

  • Для совместимости с другими СУБД допускается указание argmode как до, так и после имени аргумента, но стандартом считается только первое расположение.

  • Стандарт SQL предусматривает задание значений по умолчанию только с помощью DEFAULT. Использование = характерно для T-SQL и Firebird.

  • SETOF не является частью стандарта.

  • Из языков стандартизирован только SQL.

  • Все параметры, кроме CALLED ON NULL INPUT и RETURNS NULL ON NULL INPUT, являются нестандартизированными.

  • В теле функции допустим только формат sql_body по стандарту.

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

Смотрите также#

ALTER FUNCTION, DROP FUNCTION, GRANT, LOAD, REVOKE