postgresql types casting plpgsql postgresql-9.3

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 tipo bigint si su valor cabe en tipo bigint (64 bits); de lo contrario, se toma como tipo numeric . Las constantes que contienen puntos decimales y / o exponentes siempre se suponen inicialmente como de tipo numeric .

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.

SQL Fiddle.

Explicación más detallada en estas respuestas relacionadas:

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.