用PL/pgSQL
或SQL
编写的函数可以定义为RETURNS void
。我最近偶然发现了结果的奇怪差异。
考虑以下演示:
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;
函数f_sql()
在SELECT
的SQL函数中使用RETURNS void
(作为最后一个命令)的唯一可能方式。我使用它只是因为它是用于此测试目的的最简单方法 - 例如,UPDATE
或DELETE
的任何其他函数都显示相同的行为。
现在,void
是一种虚构类型。虽然plpgsql
函数似乎返回类型为void
的空字符串,但实际上是''::void
。 sql
函数似乎返回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
这可能会产生微妙而混乱的副作用 差异背后的原因是什么?
答案 0 :(得分:11)
(我不是这个源代码的专家。你已经被警告了。)
来源是在线here。我省略了文件名;你可以搜索这个功能 命名以找到他们的定义。我留下了行号(通常),因为它更容易剪切和粘贴,不同的行号意味着源已经改变。
短篇小说是一些“void”返回可能是空的cstrings(空的以空字符结尾的字符串),而其他的是空指针。
以下是相关内容的部分内容。
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()返回的函数。我还不知道为什么会这样,但我必须停下来睡一觉。