PostgreSQL Exception Handling PostgreSQL Exception Handling postgresql postgresql

PostgreSQL Exception Handling


To catch the error message and its code:

do $$       begin    create table yyy(a int);    create table yyy(a int); -- this will cause an errorexception when others then     raise notice 'The transaction is in an uncommittable state. '                 'Transaction was rolled back';    raise notice '% %', SQLERRM, SQLSTATE;end; $$ language 'plpgsql';

Haven't found the line number yet

UPDATE April, 16, 2019

As suggested by Diego Scaravaggi, for Postgres 9.2 and up, use GET STACKED DIAGNOSTICS:

do language plpgsql $$declare    v_state   TEXT;    v_msg     TEXT;    v_detail  TEXT;    v_hint    TEXT;    v_context TEXT;begin    create table yyy(a int);    create table yyy(a int); -- this will cause an errorexception when others then     get stacked diagnostics        v_state   = returned_sqlstate,        v_msg     = message_text,        v_detail  = pg_exception_detail,        v_hint    = pg_exception_hint,        v_context = pg_exception_context;    raise notice E'Got exception:        state  : %        message: %        detail : %        hint   : %        context: %', v_state, v_msg, v_detail, v_hint, v_context;    raise notice E'Got exception:        SQLSTATE: %         SQLERRM: %', SQLSTATE, SQLERRM;         raise notice '%', message_text; -- invalid. message_text is contextual to GET STACKED DIAGNOSTICS onlyend; $$;

Result:

NOTICE:  Got exception:        state  : 42P07        message: relation "yyy" already exists        detail :         hint   :         context: SQL statement "create table yyy(a int)"PL/pgSQL function inline_code_block line 11 at SQL statementNOTICE:  Got exception:        SQLSTATE: 42P07         SQLERRM: relation "yyy" already existsERROR:  column "message_text" does not existLINE 1: SELECT message_text               ^QUERY:  SELECT message_textCONTEXT:  PL/pgSQL function inline_code_block line 33 at RAISESQL state: 42703

Aside from GET STACKED DIAGNOSTICS is SQL standard-compliant, its diagnostics variables (e.g., message_text) are contextual to GSD only. So if you have a field named message_text in your table, there's no chance that GSD can interfere with your field's value.

Still no line number though.


Use the DO statement, a new option in version 9.0:

DO LANGUAGE plpgsql$$BEGINCREATE TABLE "Logs"."Events"    (        EventId BIGSERIAL NOT NULL PRIMARY KEY,        PrimaryKeyId bigint NOT NULL,        EventDateTime date NOT NULL DEFAULT(now()),        Action varchar(12) NOT NULL,        UserId integer NOT NULL REFERENCES "Office"."Users"(UserId),        PrincipalUserId varchar(50) NOT NULL DEFAULT(user)    );    CREATE TABLE "Logs"."EventDetails"    (        EventDetailId BIGSERIAL NOT NULL PRIMARY KEY,        EventId bigint NOT NULL REFERENCES "Logs"."Events"(EventId),        Resource varchar(64) NOT NULL,        OldVal varchar(4000) NOT NULL,        NewVal varchar(4000) NOT NULL    );    RAISE NOTICE 'Task completed sucessfully.';    END;$$;


You could write this as a psql script, e.g.,

START TRANSACTION;CREATE TABLE ...CREATE TABLE ...COMMIT;\echo 'Task completed sucessfully.'

and run with

psql -f somefile.sql

Raising errors with parameters isn't possible in PostgreSQL directly. When porting such code, some people encode the necessary information in the error string and parse it out if necessary.

It all works a bit differently, so be prepared to relearn/rethink/rewrite a lot of things.