Есть ли способ отключить перегрузку функций в Postgres

Мои пользователи и я не используем перегрузку функций в PL/pgSQL. У нас всегда есть одна функция для (схема, имя) кортежа. Таким образом, мы хотели бы отказаться от функции только по имени, изменить ее подпись, не отбрасывая ее сначала и т.д. Рассмотрим, например, следующую функцию:

CREATE OR REPLACE FUNCTION myfunc(day_number SMALLINT)
RETURNS TABLE(a INT)
AS
$BODY$
BEGIN
  RETURN QUERY (SELECT 1 AS a);
END;
$BODY$
LANGUAGE plpgsql;

Чтобы сэкономить время, мы хотели бы вызвать его следующим образом, без квалификации 1 с ::SMALLINT, потому что есть только одна функция с именем myfunc, и она имеет ровно один параметр с именем day_number:

SELECT * FROM myfunc(day_number := 1)

Нет двусмысленности, а значение 1 соответствует типу SMALLINT, но PostgreSQL жалуется:

SELECT * FROM myfunc(day_number := 1);
ERROR:  function myfunc(day_number := integer) does not exist
LINE 12: SELECT * FROM myfunc(day_number := 1);
                       ^
HINT:  No function matches the given name and argument types.
You might need to add explicit type casts.

Когда мы вызываем такие функции из Python, мы используем оболочку, которая ищет сигнатуры функций и определяет параметры с типами. Этот подход работает, но, похоже, есть потенциал для улучшения.

Есть ли способ полностью отключить перегрузку функций?

Ответ 1

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

Все это будет работать:

SELECT * FROM myfunc(day_number := '1');
SELECT * FROM myfunc('1');               -- note the quotes

SELECT * FROM myfunc(1::smallint);
SELECT * FROM myfunc('1'::smallint);

Зачем?

Последние два довольно очевидны, вы уже упоминали об этом в своем вопросе.
Первые два более интересны, объяснение скрыто в Резолюции Типа Функции:

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

И это должно быть простым решением для вас: использовать строковые литералы.

Нетипизированный литерал '1' (с кавычками) или "строковый литерал", как определено в стандарте SQL, по своей природе отличается от типизированного литерала (или константы).

Числовая константа 1 (без кавычек) сразу преобразуется в числовой тип. Руководство:

Числовая константа, которая не содержит ни десятичной точки, ни экспоненты, изначально считается типом integer, если ее значение соответствует типу integer (32 бита); в противном случае предполагается, что это тип bigint если его значение соответствует типу bigint (64 бита); в противном случае он считается типом numeric. Константы, которые содержат десятичные точки и/или показатели, всегда изначально считаются numeric.

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

Жирный акцент мой.

Назначение в вызове функции (day_number := 1) является особым случаем, тип данных day_number неизвестен на данный момент. Postgres не может получить тип данных из этого присваивания, и по умолчанию используется integer.

Следовательно, Postgres ищет функцию, которая сначала принимает integer. Тогда для функций, принимающих тип только неявное приведение от integer, другими словами:

SELECT casttarget::regtype
FROM   pg_cast
WHERE  castsource = 'int'::regtype
AND    castcontext = 'i';

Все они будут найдены - и конфликтуют, если существует более одной функции. Это будет перегрузкой функции, и вы получите другое сообщение об ошибке. С двумя функциями-кандидатами:

SELECT * FROM myfunc(1);
ERROR:  function myfunc(integer) is not unique

Обратите внимание на "целое число" в сообщении: числовая константа была приведена к integer.

Однако приведение от integer к smallint является "только" приведением присваивания. И это, где путешествие заканчивается:

No function matches the given name and argument types.

SQL Fiddle.

Более подробное объяснение в этих связанных ответах:

Грязная починка

Вы можете исправить это, "обновив" приведение от integer до smallint к неявному приведению:

UPDATE pg_cast
SET    castcontext = 'i'
WHERE  castsource = 'int'::regtype
AND    casttarget  = 'int2'::regtype;

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

В сторону

Разрешение типа функции полностью не зависит от используемого языка. Функция SQL будет конкурировать с PL/perl или PL/pgSQL или "внутренними" функциями точно так же. Подпись функции имеет важное значение. Встроенные функции pg_catalog первыми, потому что pg_catalog стоит первым в стандартном search_path.

Ответ 2

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

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

Вы можете просто проверить, есть ли у вас или нет перегруженные функции:

postgres=# select count(*), proname 
               from pg_proc 
              where pronamespace <> 11 
              group by proname 
              having count(*) > 1;
 count | proname 
-------+---------
(0 rows)

Ответ 3

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