2011-11-30 6 views
15

Le funzioni scritte in PL/pgSQL o SQL possono essere definite come RETURNS void. Recentemente ho incappato in una strana differenza nel risultato.Funzioni PostgreSQL restituite void

Si consideri il seguente demo:

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 funzione f_sql() usa l'unica via possibile per un SELECT (come ultimo comando) in una funzione SQL che RETURNS void. Lo uso solo perché è il modo più semplice per gli scopi di questo test - qualsiasi altra funzione, con UPDATE o DELETE per esempio, mostra lo stesso comportamento.

Ora, void è un tipo fittizio. Mentre la funzione plpgsql sembra restituire l'equivalente di una stringa vuota come tipo void, efficacemente ''::void. La funzione sql sembra restituire 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 

Questo può avere effetti secondari sottili e confusi.
Qual è la ragione della differenza?

+0

Sono dichiarati a rendere nulla; forse non abbiamo alcun problema a vedere come i loro valori restituiti siano paragonabili a * qualsiasi cosa *. (Se * davvero * volesse scoraggiare le persone dal considerare il valore restituito, potresti farlo restituire un valore casuale. Potrei farlo la prossima volta che scriverò qualcosa che dovrebbe restituire nulla.) –

+0

@Catcall: Sì, si potrebbe discutere che è stato un errore controllare il valore di un vuoto. Tuttavia, sembra che il valore sia diverso a seconda della lingua scelta. Questo non dovrebbe essere. Inserirò una segnalazione di bug quando andrò in giro per farlo e vedremo cosa ne pensa la squadra centrale. –

+0

E diversi anni in ritardo [inciampo] (http://dba.stackexchange.com/q/65310/1396) sulla stessa cosa! Ho comunque imparato il tuo utile trucco di 'SELECT NULL :: void' in una funzione sql di restituzione vuota: btw il capitolo sembra essere andato via dal link che hai dato (anche se il trucco funziona ancora in 9.3). –

risposta

10

(io non sono un esperto in questo codice sorgente. Siete stati avvertiti.)

La fonte è in linea here. Ho omesso i nomi dei file; è possibile cercare i nomi della funzione per trovare le loro definizioni. Ho lasciato i numeri di linea (di solito) perché è più facile da tagliare e incollare, e numeri di linea diversi significano che la fonte è cambiata.

La storia breve è che alcuni ritorni "nulli" sono probabilmente cstrings vuoti (stringhe vuote terminate da null) e altri sono puntatori nulli.

Ecco le parti della sorgente che sembrano rilevanti.

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 } 

Abbiamo anche

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 

Quindi ha senso per me che una funzione definita dall'utente che restituisce attraverso PG_RETURN_VOID() non prova equivalente a quella che ritorna attraverso void_out() o void_send (). Non so ancora perché sia ​​così, ma devo fermarmi e dormire un po '.

+0

Molto interessante! Questo comportamento può essere intenzionale? Forse un bug? –

+0

è un bug - per favore, segnalalo –

+0

ma non sono sicuro di cosa sia la correzione - non c'è un comportamento coerente e il test "void è nullo" non ha senso anche –