Project: YugabyteDB (App Definition and Development / Database)
File: assert.md

title: The PL/pgSQL "assert" statement [YSQL] headerTitle: The PL/pgSQL "assert" statement linkTitle: > "assert" statement description: Describes the syntax and semantics of the PL/pgSQL "assert" statement. [YSQL]. menu: stable: identifier: assert parent: basic-statements weight: 10 type: docs showRightNav: true {{%ebnf%}} plpgsqlassertstmt {{%/ebnf%}} The plpgsqlassertstmt evaluates its defining booleanexpression. If the result is true, then the point of execution moves silently to the next executable statement. But if the result is false, then the 'P0004' error (assertfailure) is caused. If the optional textexpression is omitted, then the system supplied error message "assertion failed" is usedin whatever national language the lcmessages run-time parameter specifies. (See the PostgreSQL documentation section .) If textexpression_ is defined, then this text is used as the error message. If an error occurs while evaluating the booleanexpression or the textexpression, then this is reported as a normal error. The textexpression_ is evaluated only when the assertion fails. {{< tip title="The 'P0004' ('assertfailure') error and the '57014' ('querycanceled') error are not caught by the 'others' handler." >}} This is a deliberate design. The idea is that these two errors should be unstoppable so that when either of them occurs, the present top-level server call from the client will be aborted. In particular, the assert statement is intended for detecting program bugs (i.e. conditions that you know are impossible in the absence of bugs). Use the when you detect a regrettable, but nevertheless possible error like a new user-supplied value that is meant to be unique but turns out to collide with an existing value. Testing of assertions can be enabled or disabled via the run-time parameter plpgsql.checkasserts, with legal values on (the default) and off_. It is possible, but generally unwise, to catch these two errors explicitly. However, if you implement a scheme to log errors in, for example, a dedicated table then you might want to catch each of these errors, log them, and then re-raise the error. See the

{{< /tip >}} First, try this simple test to demonstrate the "unstoppable by default" behavior: ```plpgsql \c :db :u drop schema if exists s cascade; create schema s; create function s.f(mode in text) returns text set searchpath = pgcatalog, pg_temp language plpgsql as $body$ declare a int not null := 0; v text not null := ''; err text not null := ''; begin case mode when 'divisionbyzero' then a := 1.0/0.0; when 'nullvaluenot_allowed' then v := null; when 'assert' then assert (1 = 2); end case; return a::text; exception when divisionbyzero then return 'Caught "divisionbyzero".'; when others then get stacked diagnostics err := returned_sqlstate; return 'Caught "Error '||err||'"'; end; $body$; ``` Test it thus. First provoke an error for which there is an explicit handler: ```plpgsql select s.f('divisionbyzero'); ``` The explicit when divisionbyzero handler catches this, bringing this result: ```output Caught "divisionbyzero". ``` Now provoke an error for which there is no explicit handler: ```plpgsql select s.f('nullvaluenot_allowed'); ``` The catch-all others handler catches this, bringing this result: ```output Caught "Error 22004" ``` Now cause an assertion failure: ```plpgsql select s.f('assert'); ``` This is the result: ```outout ERROR: P0004: assertion failed CONTEXT: PL/pgSQL function s.f(text) line 13 at ASSERT LOCATION: execstmtassert, pl_exec.c:3897 ``` Now modify the implementation of s.f()'s exception section by adding an explicit handler for assertfailure. Here, is used to emulate inserting all of the information that get stacked diagnostics_ provides into a table for subsequent off-line analysis by Support. ```plpgsql create or replace function s.f(mode in text) returns text set searchpath = pgcatalog, pg_temp language plpgsql as $body$ declare a int not null := 0; v text not null := ''; err text not null := ''; begin case mode when 'divisionbyzero' then a := 1.0/0.0; when 'nullvaluenot_allowed' then v := null; when 'assert' then assert (1 = 2); end case; return a::text; exception when divisionbyzero then return 'Caught "divisionbyzero".'; -- Generally unwise practice. But the explicit "raise" makes this acceptable. when assert_failure then raise info 'Caught "assert_failure".'; raise; when others then get stacked diagnostics err := returned_sqlstate; return 'Caught "Error '||err||'"'; end; $body$; ``` Cause the same assertion failure now: ```plpgsql \set VERBOSITY default select s.f('assert'); ``` This is the new result: ```output INFO: Caught "assert_failure". ERROR: assertion failed CONTEXT: PL/pgSQL function s.f(text) line 13 at ASSERT ```