PL/pgSQL is the preferred way to write stored procedures in PostgreSQL. Of course there are more languages to write code available but most people still use PL/pgSQL to get the job done. However, debugging PL/pgSQL code can be a bit tricky. Tools are around but it is still not a fun experience. One thing to make debugging easier is GET STACKED DIAGNOSTICS which is unfortunately not widely known. This post will show what it does and how you can make use of it.

Debugging PostgreSQL stored procedures

To show you how GET STACKED DIAGNOSTICS worked I have written some broken code which executes a division by zero which is forbidden in any sane database:

CREATE OR REPLACE FUNCTION broken_function()
	RETURNS void AS $$
BEGIN
	SELECT 1 / 0;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION simple_function()
	RETURNS numeric AS $$
DECLARE
BEGIN
	RAISE NOTICE 'crazy function called ...';
	PERFORM broken_function();
	RETURN 0;
END;
$$ LANGUAGE 'plpgsql';

The question now is: How can we get a backtrace and debug the code? One way is to wrap the code into one more function call and see where things fail:

CREATE OR REPLACE FUNCTION get_stack() 
	RETURNS void AS $$
DECLARE
	v_sqlstate text;
	v_message text;
	v_context text;
BEGIN
  	PERFORM simple_function();

EXCEPTION WHEN OTHERS THEN 
	GET STACKED DIAGNOSTICS
		v_sqlstate = returned_sqlstate,
		v_message = message_text,
		v_context = pg_exception_context;
	RAISE NOTICE 'sqlstate: %', v_sqlstate;
	RAISE NOTICE 'message: %', v_message;
	RAISE NOTICE 'context: %', v_context;
END;
$$ LANGUAGE 'plpgsql';

My function catches the error causes by simple_function() and calls GET STACKED DIAGNOSTICS to display all the information we can possibly extract from the system. The output looks as follows:

test=# SELECT get_stack();
NOTICE: crazy function called ...
NOTICE: sqlstate: 22012
NOTICE: message: division by zero
NOTICE: context: SQL statement "SELECT 1 / 0"
PL/pgSQL function broken_function() line 3 at SQL statement
SQL statement "SELECT broken_function()"
PL/pgSQL function simple_function() line 5 at PERFORM
SQL statement "SELECT simple_function()"
PL/pgSQL function get_stack() line 7 at PERFORM
get_stack
-----------

(1 row)

As you can see the stack trace is displayed and we can easily figure out where the problem has happened. In this case “broken_function” line 3 is the root cause of all evil.

Finally …

If you want to learn more about PostgreSQL consider checking out one of my posts dealing with database performance.