PL/pgSQL syntax and semantics
This page documents the preview version (v2.21). Preview includes features under active development and is for development and testing only. For production, use the stable version (v2024.1). To learn more, see Versioning.
PostgreSQL, and therefore YSQL, natively support both language sql and language plpgsql functions and procedures. But the implementation of a do statement can only be language plpgsql. PL/pgSQL source text is governed by the plpgsql_block_stmt rule. See these sections:
The syntax diagrams in these three sections show that the PL/pgSQL source text must be enquoted. Yugabyte recommends that, for consistency, you use dollar quoting around the source text and that you spell this as $body$. Notice that PL/pgSQL's dynamic SQL feature lets you write a user-defined procedure that will create a user-defined subprogram. If you take advantage of this, then you'll have to use different enquoting syntax around the source text of the to-be-created subprogram.
This section, and its subsections, specify:
- the grammar of the plpgsql_block_stmt rule
- its decomposition down to terminal rules
- the associated semantics.
plpgsql_block_stmt ::= [ << label >> ]
[ plpgsql_declaration_section ]
plpgsql_executable_section
[ plpgsql_exception_section ] END [ label ] ;
plpgsql_declaration_section ::= DECLARE
[ plpgsql_declaration [ ... ] ]
plpgsql_executable_section ::= BEGIN
[ plpgsql_executable_stmt [ ... ] ]
plpgsql_exception_section ::= EXCEPTION { plpgsql_handler [ ... ] }
The minimal PL/pgSQL source text
The executable section can include a block statement—and this implies the possibility of an arbitrarily deep nesting. It's this that underpins this characterization of PL/pgSQL at the start of this overall section on language plpgsql subprograms:
PL/pgSQL is a conventional, block-structured, imperative programming language [whose] basic syntax conventions and repertoire of simple and compound statements seem to be inspired by Ada.
The executable section is mandatory. This, therefore, is the minimal form of a PL/pgSQL source text:
$body$
begin
end;
$body$;
It's useful to know this because each of create function and create procedure, when it completes without error, inevitably creates a subprogram upon which the execute privilege has already been granted to public. See these tips in the sections that describe these two create statements:
Each tip recommends that you always revoke this privilege immediately after creating a subprogram. However, even this might expose a momentary security risk. Here is the watertight secure approach:
create schema s;
create procedure s.p()
language plpgsql
as $body$
begin
null; -- Implementation to follow.
end;
$body$;
revoke execute on procedure s.p() from public;
-- "create or replace" leaves the extant privileges on "s.p" unchanged.
create or replace procedure s.p()
set search_path = pg_catalog, pg_temp
security definer
language plpgsql
as $body$
declare
-- (Optionally) the intended declarations.
-- ...
begin
-- The intended implementation.
-- ...
exception
-- (Optionally) the intended handlers.
-- ...
end;
$body$;
Notice that null; is a legal PL/pgSQL executable statement. Of course, it does nothing at all. You might prefer to write null; explicitly to emphasize your intention. Now you can grant execute on s.p to the role(s) that you intend.
Each section is described in a dedicated subsection: