Статья основана на шестнадцатом видео из 31 темы курса SQL 2.0 — PL/pgSQL в PostgreSQL от Аристова Евгения, который является логическим продолжением курса SQL c 0. Ссылки на видео на платформах RUTUBE и VK video.
В данной статье подробно разбираются перезагрузка функции, особенности реализации, сложности отладки и выбора.
В прошлой статье разбираются кортежи, их преимущества и недостатки и когда лучше использовать ROWTYPE.
Презентация и исходники доступны по ссылке.
Перегрузка
Если нам нужен один и тот же функционал, но при этом у нас могут быть разные типы и количество входных аргументов, PostgreSQL позволяет использовать перегрузку функций, то есть, позволяет использовать одно и тоже имя функции для нескольких различных функций, если у них различаются типы входных аргументов.
То есть не нужно задавать уникальные имена и потом их указывать:
CREATE FUNCTION add_int(nt, int) …
CREATE FUNCTION add_real(real, real) …
CREATE FUNCTION add_decimal(decimal, decimal) …
PostgreSQL автоматически выберет нужную функцию. Примеры:
CREATE FUNCTION func(int) …
CREATE FUNCTION func(int, int) …
CREATE FUNCTION func(int, real) …
CREATE FUNCTION func(real) ...
Механизм работы — при вызове функции PostgreSQL проверяет в списке имеющихся функций имя, количество и тип аргументов и выбирает нужную функцию.
Особенности реализации
Две функции считаются совпадающими, если они имеют одинаковые имена и типы входных аргументов, параметры OUT игнорируются. Таким образом, например, эти объявления вызовут конфликт, так как PostgreSQL не сможет выбрать какую функцию вызвать:
CREATE FUNCTION func(int) …
CREATE FUNCTION func(int, out text) …
select func(1) ???
Ограничения
Функции, имеющие разные типы аргументов, не будут считаться конфликтующими в момент создания, но предоставленные для них значения по умолчанию могут вызвать конфликт в момент использования. Например, рассмотрите следующие определения:
CREATE FUNCTION func(int) ...
CREATE FUNCTION func(int, int default 2) …
Вызов foo(100) завершится ошибкой из-за неоднозначности в выборе вызываемой функции, а foo(1,2) вызовется без ошибки.
Сложности выбора
Возможна неоднозначность при вызове:
CREATE FUNCTION process_value(val INTEGER) RETURNS TEXT AS $$ ... $$;
CREATE FUNCTION process_value(val NUMERIC) RETURNS TEXT AS $$ ... $$;
Какую функцию выберет PostgreSQL?
SELECT process_value(10); -- INTEGER или NUMERIC?
Желательно указывать конкретный тип, но минимум функции с одинаковым именем должны реализовывать аналогичную бизнес логику!
Сложности отладки
При ошибке сложно определить, какая именно функция вызвала проблему
ERROR: function process_data(unknown, unknown) does not exist
LINE 1: SELECT process_data('test', 'invalid');
^
HINT: No function matches the given name and argument types.
Итоги
Используйте перегрузку когда:
- Функции выполняют схожую логику с разными типами данных
- Хотите создать удобный и интуитивный API
- Нужна обратная совместимость
Избегайте перегрузки когда:
- Функции выполняют принципиально разную логику
- Возможна неоднозначность при вызове
- Работаете с простыми сценариями
Примеры кода:
Напишем функцию, возвращающую большее из двух целых чисел
(Похожая функция есть в SQL и называется greatest, но мы сделаем ее сами):
CREATE OR REPLACE FUNCTION maximum(a integer, b integer) RETURNS integer AS $$
SELECT CASE WHEN a > b THEN a ELSE b END;
$$ LANGUAGE SQL;
Проверим:
SELECT maximum(100,200);
Допустим, мы решили сделать аналогичную функцию для трех чисел.
Благодаря перегрузке, не надо придумывать для нее какое-то новое название:
CREATE OR REPLACE FUNCTION maximum(a integer, b integer, c integer) RETURNS integer AS $$
SELECT CASE WHEN a > b THEN maximum(a,c) ELSE maximum(b,c) END;
$$ LANGUAGE SQL;
Теперь у нас две функции с одним именем, но разным числом параметров:
\df maximum
И обе работают:
SELECT maximum(10,20), maximum(10,20,-100);
Больше примеров доступно на гитхабе и в видео.
В следующей статье мы разберём перегрузку функций.
Добавить комментарий