返回void的PostgreSQL函数

svmlkihl  于 2023-01-30  发布在  PostgreSQL
关注(0)|答案(1)|浏览(235)

PL/pgSQLSQL编写的函数可以定义为RETURNS void。我最近偶然发现了结果中的一个奇怪的差异。
请看下面的演示:

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

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

函数f_sql()使用RETURNS void的SQL函数中SELECT(作为最后一个命令)的唯一可能的方法。我使用它只是因为它是用于此测试的最简单的方法-任何其他函数,例如UPDATEDELETE,都显示相同的行为。
现在,void是一个虚构的类型,而plpgsql函数似乎返回了一个空字符串作为类型void的等价物--实际上是''::voidsql函数似乎返回了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

这可能会产生微妙而令人困惑的副作用。
差异背后的原因是什么?

toiithl6

toiithl61#

(我不是这方面的Maven,我已经警告过你了。)
源代码是在线的here。我省略了文件名;你可以通过搜索函数名来找到它们的定义。我保留了行号(通常是这样),因为这样更容易剪切和粘贴,不同的行号意味着源代码已经改变。
简单地说,一些"void"返回可能是空的cstring(空的以null结尾的字符串),而另一些则是null指针。
以下是源代码中看起来相关的部分。

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 }

我们还有

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

因此,通过PG_RETURN_VOID()返回的用户定义函数与通过void_out()或void_send()返回的函数测试结果不等价,这对我来说是有意义的,我还不知道为什么会这样,但我必须停下来睡一觉。

相关问题