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?
A SQL function lets you perform a query or series of queries inside a function, returning the data from the final query in the function. Functions can return VOID if there is no useful data to return, as in a SQL DELETE , INSERT , or UPDATE statement.
PostgreSQL returns a table with one column that holds the array of films. In practice, you often process each individual row before appending it in the function's result set.
In PostgreSQL, the dollar-quoted string constants ($$) is used in user-defined functions and stored procedures. In PostgreSQL, you use single quotes for a string constant like this: select 'String constant'; When a string constant contains a single quote ('), you need to escape it by doubling up the single quote.
Use pg_dump -s to save only the schema of your application. This will create one large file in which you will have to look for the stored procedures and save them to individual files. This may be OK for you.
(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.
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 }
We also have
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With