postgresql - ¿Hay alguna manera de deshabilitar la sobrecarga de funciones en Postgres
types casting (3)
Mis usuarios y yo no utilizamos la sobrecarga de funciones en PL / pgSQL. Siempre tenemos una función por tupla (esquema, nombre). Como tal, nos gustaría descartar una función solo por nombre, cambiar su firma sin tener que descartarla primero, etc. Considere, por ejemplo, la siguiente función:
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;
Para ahorrar tiempo, nos gustaría invocarlo de la siguiente manera, sin calificar 1 con
::SMALLINT
, porque solo hay una función llamada myfunc, y tiene exactamente un parámetro llamado day_number:
SELECT * FROM myfunc(day_number := 1)
No hay ambigüedad, y el valor 1 es consistente con el tipo
SMALLINT
, pero PostgreSQL se queja:
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.
Cuando invocamos tales funciones desde Python, utilizamos un contenedor que busca las firmas de las funciones y califica los parámetros con tipos. Este enfoque funciona, pero parece haber un potencial de mejora.
¿Hay alguna manera de desactivar la sobrecarga de funciones por completo?
En realidad, esto no es directamente una cuestión de sobrecarga de funciones (que sería imposible "desactivar"). Es una cuestión de resolución de tipo de función . (Por supuesto, ese algoritmo podría ser más permisivo sin funciones sobrecargadas).
Todo esto simplemente funcionaría:
SELECT * FROM myfunc(day_number := ''1'');
SELECT * FROM myfunc(''1''); -- note the quotes
SELECT * FROM myfunc(1::smallint);
SELECT * FROM myfunc(''1''::smallint);
¿Por qué?
Los dos últimos son bastante obvios, ya lo mencionaste en tu pregunta.
Los dos primeros son más interesantes, la explicación está enterrada en la
Resolución del tipo de función
:
Se supone que los literales desconocidos son convertibles a cualquier cosa para este propósito.
Y esa debería ser la solución simple para usted: use literales de cadena .
Un literal
''1''
(con comillas) o "literal de cadena" como se define en el estándar SQL es de naturaleza diferente de un literal con
tipo
(o constante).
Una constante numérica
1
(sin comillas) se convierte en un tipo numérico
inmediatamente
.
El manual:
Inicialmente, se supone que una constante numérica que no contiene un punto decimal ni un exponente es de tipo entero si su valor cabe en tipo
integer
(32 bits); de lo contrario, se presume que es de tipobigint
si su valor cabe en tipobigint
(64 bits); de lo contrario, se toma como tiponumeric
. Las constantes que contienen puntos decimales y / o exponentes siempre se suponen inicialmente como de tiponumeric
.El tipo de datos inicialmente asignado de una constante numérica es solo un punto de partida para los algoritmos de resolución de tipos. En la mayoría de los casos, la constante se coaccionará automáticamente al tipo más apropiado según el contexto. Cuando sea necesario, puede forzar que un valor numérico se interprete como un tipo de datos específico al convertirlo.
El énfasis audaz es mío.
La asignación en la llamada de función (
day_number := 1
) es un caso especial, el tipo de datos de
day_number
es
desconocido
en este momento.
Postgres no puede derivar un tipo de datos de esta asignación y por defecto es
integer
.
En consecuencia, Postgres busca
primero
una función que tome un
integer
.
Luego, para las funciones que toman un tipo solo una
conversión implícita
del
integer
, en otras palabras:
SELECT casttarget::regtype
FROM pg_cast
WHERE castsource = ''int''::regtype
AND castcontext = ''i'';
Todo esto se encontraría, y entraría en conflicto si hubiera más de una función. Eso sería una sobrecarga de funciones , y obtendría un mensaje de error diferente. Con dos funciones candidatas como esta:
SELECT * FROM myfunc(1);
ERROR: function myfunc(integer) is not unique
Tenga en cuenta el "entero" en el mensaje: la constante numérica se ha convertido a
integer
.
Sin embargo, el reparto de
integer
a
smallint
es "solo" un
reparto de asignación
.
Y ahí es donde termina el viaje:
No function matches the given name and argument types.
Explicación más detallada en estas respuestas relacionadas:
-
ERROR PostgreSQL: la función to_tsvector (variación de caracteres, desconocida) no existe
-
Genere series de fechas, utilizando el tipo de fecha como entrada
Arreglo sucio
Puede solucionar esto "actualizando" el elenco de
integer
a
smallint
a un
elenco implícito
:
UPDATE pg_cast
SET castcontext = ''i''
WHERE castsource = ''int''::regtype
AND casttarget = ''int2''::regtype;
Pero desaconsejaría la manipulación del sistema de fundición predeterminado. Solo considere esto si sabe exactamente lo que está haciendo. Encontrarás discusiones relacionadas en las listas de Postgres. Puede tener todo tipo de efectos secundarios, comenzando con la resolución del tipo de función, pero no terminando allí.
Aparte
La resolución del tipo de función es completamente independiente del lenguaje utilizado.
Una función SQL competiría con PL / perl o PL / pgSQL o funciones "internas" de la misma manera.
La firma de la función es esencial.
Las funciones integradas solo son lo primero, porque
pg_catalog
es lo primero en la
search_path
predeterminada.
Erwin envió una respuesta correcta. Mi próxima respuesta está relacionada con la posibilidad de desactivar la sobrecarga.
No es posible deshabilitar la sobrecarga, esta es una característica básica del sistema API de la función PostgreSQL, y no se puede deshabilitar. Sabemos que hay algunos efectos secundarios, como la rigidez de la firma de función fuerte, pero es una protección contra algunos efectos secundarios desagradables cuando la función se usa en Vistas, definiciones de tabla, etc. Por lo tanto, no puede deshabilitarla.
Simplemente puede verificar si tiene o no funciones sobrecargadas:
postgres=# select count(*), proname
from pg_proc
where pronamespace <> 11
group by proname
having count(*) > 1;
count | proname
-------+---------
(0 rows)
Hay muchas funciones integradas que están sobrecargadas, por lo que simplemente no funcionaría si desactivara la sobrecarga de funciones.