2011-11-30 17 views
15

Las funciones escritas en PL/pgSQL o SQL se pueden definir como RETURNS void. Recientemente me encontré con una extraña diferencia en el resultado.Funciones de PostgreSQL que devuelven nulo

Considérese la siguiente demostración:

CREATE OR REPLACE FUNCTION f_sql() 
    RETURNS void AS 
'SELECT NULL::void' -- "do nothing", no special meaning 
    LANGUAGE sql; 

CREATE OR REPLACE FUNCTION f_plpgsql() 
    RETURNS void AS 
$$ 
BEGIN 
NULL; -- "do nothing", no special meaning 
END; 
$$ LANGUAGE plpgsql; 

La función f_sql() utiliza el único camino posible para un SELECT (como último comando) en una función SQL que RETURNS void. Lo uso simplemente porque es la forma más sencilla para los fines de esta prueba: cualquier otra función, con UPDATE o DELETE por ejemplo, muestra el mismo comportamiento.

Ahora, void es un tipo ficticio. Mientras que la función plpgsql parece devolver el equivalente de una cadena vacía como tipo void, efectivamente ''::void. La función sql parece devolver NULL::void.

db=# SELECT f_sql() IS NULL; 
?column? 
---------- 
t 

db=# SELECT f_sql()::text IS NULL; 
?column? 
---------- 
t 

db=# SELECT f_plpgsql() IS NULL; 
?column? 
---------- 
f 

db=# SELECT f_plpgsql()::text = ''; 
?column? 
---------- 
t 

Esto puede tener efectos secundarios sutiles y confusos.
¿Cuál es la razón detrás de la diferencia?

+0

Están declarados como inválidos; tal vez no tengamos que ver cómo se comparan sus valores devueltos con * cualquier cosa *. (Si * realmente * deseaba disuadir a las personas de mirar el valor de retorno, podría hacer que devuelva un valor aleatorio. Podría hacerlo la próxima vez que escriba algo que debería volverse vacío.) –

+0

@Catcall: Sí, se podría argumentar que fue un error verificar un valor vacío en absoluto. Todavía se siente con errores que el valor es diferente dependiendo del idioma elegido. Eso no debería ser Archivaré un informe de error cuando lo haga y veremos qué piensa el equipo central al respecto. –

+0

Y varios años tarde [me tropiezo] (http://dba.stackexchange.com/q/65310/1396) en la misma cosa! Aún así, aprendí el útil truco de 'SELECT NULL :: void' en una función de retorno de sql vacía: por cierto, el capítulo parece haber desaparecido del enlace que proporcionó (aunque el truco aún funciona en 9.3). –

Respuesta

10

(No soy un experto en este código fuente. Usted ha sido advertido.)

La fuente está en línea here. He omitido los nombres de archivo; Puede buscar los nombres de la función para encontrar sus definiciones. Dejé los números de línea (generalmente) porque es más fácil cortar y pegar, y diferentes números de línea significarán que la fuente ha cambiado.

La historia breve es que algunos retornos "vacíos" son probablemente cadenas de texto vacías (cadenas vacías anuladas), y otras son punteros nulos.

Aquí están las partes de la fuente que parecen relevantes.

00228 /* 
00229 * void_out  - output routine for pseudo-type VOID. 
00230 * 
00231 * We allow this so that "SELECT function_returning_void(...)" works. 
00232 */ 
00233 Datum 
00234 void_out(PG_FUNCTION_ARGS) 
00235 { 
00236  PG_RETURN_CSTRING(pstrdup("")); 
00237 } 

00251 /* 
00252 * void_send - binary output routine for pseudo-type VOID. 
00253 * 
00254 * We allow this so that "SELECT function_returning_void(...)" works 
00255 * even when binary output is requested. 
00256 */ 
00257 Datum 
00258 void_send(PG_FUNCTION_ARGS) 
00259 { 
00260  StringInfoData buf; 
00261 
00262  /* send an empty string */ 
00263  pq_begintypsend(&buf); 
00264  PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 
00265 } 

También tenemos

00285 /* To return a NULL do this: */ 
00286 #define PG_RETURN_NULL() \ 
00287  do { fcinfo->isnull = true; return (Datum) 0; } while (0) 
00288 
00289 /* A few internal functions return void (which is not the same as NULL!) */ 
00290 #define PG_RETURN_VOID()  return (Datum) 0 

Así que tiene sentido para mí que una función definida por el usuario que devuelve a través PG_RETURN_VOID() no pondría a prueba equivalente a uno que vuelve a través void_out() o void_send () Todavía no sé por qué es eso, pero tengo que parar y dormir un poco.

+0

¡Muy interesante! ¿Puede este comportamiento ser intencional? Tal vez un error? –

+0

es un error - por favor, denúncielo –

+0

pero no estoy seguro de qué es la corrección - no hay un comportamiento constante y la prueba "nulo es nulo" no tiene sentido también –

Cuestiones relacionadas