2011-11-30 17 views
15

PL/pgSQL veya SQL ile yazılan işlevler RETURNS void olarak tanımlanabilir. Son zamanlarda sonuçta garip bir farkla karşılaştım.PostgreSQL işlevleri dönen void

aşağıdaki demo düşünü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; 

işlevi f_sql()RETURNS void bir SQL işlevinde (son komutu gibi) SELECT için tek olası yol kullanır. Ben sadece bu testin amaçlarının en basit yolu olduğu için kullanıyorum - örneğin UPDATE veya DELETE ile başka bir işlev, aynı davranışı gösterir.

Şimdi, void, kurgusal bir türüdür. plpgsql işlevi, void türünde boş bir dize eşdeğerini, ''::void etkin olarak döndürür gibi görünüyor. sql işlevi NULL::void döndürüyor gibi görünüyor.

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 

Bu, ince ve kafa karıştırıcı yan etkilere sahip olabilir.
Farkın arkasındaki sebep nedir?

+0

Boşlukları iade ettikleri bildirildi; belki de iade edilen değerlerin * bir şeyle * nasıl kıyaslandığına bakmaktan hiç bir işimiz yoktur. (Eğer * gerçekten * insanların geri dönüş değerine bakmasını engellemeyi tercih ederseniz, onu rastgele bir değer getirebilirdiniz. Bir dahaki sefere boşa dönmesi gereken bir şey yazabilirim.) –

+0

@Catcall: Evet, biri tartışabilir Hiç bir boşluk değerini kontrol etmek bir hataydı. Yine de, seçilen dile bağlı olarak değerin farklı olduğuna dair buggy hissediyor. Bu olmamalı. Bunu yapmak için uğraştığımda bir hata raporu göndereceğim ve çekirdek ekibin ne düşündüğünü göreceğiz. –

+0

Ve birkaç yıl geç [Ben yanıltıcı] (http://dba.stackexchange.com/q/65310/1396) aynı şeyde! Yine de, SELECT NULL :: void'in boş bir sql fonksiyonunda işe yaradığı hile işlevini öğrendim: btw bölümü verdiğiniz bağlantıdan (trick hala 9.3'te çalışmasına rağmen) gitmiş gibi görünüyor. –

cevap

10

(bu kaynak kodunda uzman değilim. Eğer uyardı.)

kaynak here yayında. Dosya isimlerini atladım; Tanımlarını bulmak için isimlerini arayabilirsiniz. Satır numaralarını (genellikle) bıraktım çünkü kesmesi ve yapıştırması daha kolaydır ve farklı satır numaraları, kaynağın değiştiği anlamına gelir.

Kısa öykü, bazı "boşluk" değerlerinin büyük olasılıkla boş değerlerin boş olması (boş boş sonlandırılmış dizeler) ve diğerlerinin boş göstericiler olmasıdır.

İlgili olan kaynakların bölümleri aşağıda verilmiştir.

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 } 

Ayrıca Yani PG_RETURN_VOID() aracılığıyla döndüren kullanıcı tanımlı bir işlev (void_out aracılığıyla döndüren biri() veya void_send eşdeğer sınamak olmaz bana mantıklı

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 

var). Bunun nedenini henüz bilmiyorum ama durup biraz uyumaya ihtiyacım var.

+0

Çok ilginç! Bu davranış kasıtlı olabilir mi? Belki bir böcek? –

+0

Hata - lütfen –

+0

numaralı telefonu bildirin, ancak neyin düzeltildiğini bilmiyorum - tutarlı olmayan davranışlar var ve test "void is null" da mantıklı değil –