Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL functions returning void

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?

like image 883
Erwin Brandstetter Avatar asked Nov 30 '11 01:11

Erwin Brandstetter


People also ask

How do I return a void function in SQL?

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.

Can a PostgreSQL function return a table?

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.

What is $$ in PostgreSQL?

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.

How do I save a PostgreSQL function?

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.


1 Answers

(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.

like image 95
Mike Sherrill 'Cat Recall' Avatar answered Oct 12 '22 13:10

Mike Sherrill 'Cat Recall'