Functions written in PL/pgSQL
or SQL
can be defined as RETURNS void
. I recently stumbled upon an odd difference in the result.
Consider the following 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;
The function f_sql()
uses the only possible way for a SELECT
(as last command) in a SQL function that RETURNS void
. I use it just because it is the simplest way for the purposes of this test - any other function, with UPDATE
or DELETE
for instance, shows the same behavior.
Now, void
is a fictive type. While the plpgsql
function seems to return the equivalent of an empty string as type void
, effectively ''::void
. The sql
function seems to return 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
This can have subtle and confusing side effects.
What is the reason behind the difference?
(I'm no expert in this source code. You've been warned.)
The source is online here. I've omitted the filenames; you can search for the function names to find their definitions. I left the line numbers (usually) because it's easier to cut and paste, and different line numbers will mean the source has changed.
The short story is that some "void" returns are probably empty cstrings (empty null-terminated strings), and others are null pointers.
Here are the parts of the source that look relevant.
We also have
So it makes sense to me that a user-defined function that returns through PG_RETURN_VOID() would not test equivalent to one that returns through void_out() or void_send(). I don't yet know why that is, but I have to stop and get some sleep.