Chapter 23. PL/pgSQL - SQL Procedural Language

Table of Contents
23.1. Overview
23.1.1. Advantages of Using PL/pgSQL
23.1.2. Developing in PL/pgSQL
23.2. Structure of PL/pgSQL
23.3. Declarations
23.3.1. Aliases for Function Parameters
23.3.2. Rowtypes
23.3.3. Records
23.3.4. Attributes
23.3.5. RENAME
23.4. Expressions
23.5. Basic Statements
23.5.1. Assignment
23.5.2. SELECT INTO
23.5.3. Executing an expression or query with no result
23.5.4. Executing dynamic queries
23.5.5. Obtaining result status
23.6. Control Structures
23.6.1. Returning from a function
23.6.2. Conditionals
23.6.3. Simple Loops
23.6.4. Looping Through Query Results
23.7. Cursors
23.7.1. Declaring Cursor Variables
23.7.2. Opening Cursors
23.7.3. Using Cursors
23.8. Errors and Messages
23.9. Trigger Procedures
23.10. Examples
23.11. Porting from Oracle PL/SQL
23.11.1. Main Differences
23.11.2. Porting Functions
23.11.3. Procedures
23.11.4. Packages
23.11.5. Other Things to Watch For
23.11.6. Appendix

PL/pgSQL is a loadable procedural language for the PostgreSQL database system.

This package was originally written by Jan Wieck. This documentation was in part written by Roberto Mello ().

23.1. Overview

The design goals of PL/pgSQL were to create a loadable procedural language that

The PL/pgSQL call handler parses the function's source text and produces an internal binary instruction tree the first time the function is called (within any one backend process). The instruction tree fully translates the PL/pgSQL statement structure, but individual SQL expressions and SQL queries used in the function are not translated immediately.

As each expression and SQL query is first used in the function, the PL/pgSQL interpreter creates a prepared execution plan (using the SPI manager's SPI_prepare and SPI_saveplan functions). Subsequent visits to that expression or query re-use the prepared plan. Thus, a function with conditional code that contains many statements for which execution plans might be required, will only prepare and save those plans that are really used during the lifetime of the database connection. This can provide a considerable savings of parsing activity. A disadvantage is that errors in a specific expression or query may not be detected until that part of the function is reached in execution.

Once PL/pgSQL has made a query plan for a particular query in a function, it will re-use that plan for the life of the database connection. This is usually a win for performance, but it can cause some problems if you dynamically alter your database schema. For example:

CREATE FUNCTION populate() RETURNS INTEGER AS '
DECLARE
    -- Declarations
BEGIN
    PERFORM my_function();
END;
' LANGUAGE 'plpgsql';

If you execute the above function, it will reference the OID for my_function() in the query plan produced for the PERFORM statement. Later, if you drop and re-create my_function(), then populate() will not be able to find my_function() anymore. You would then have to re-create populate(), or at least start a new database session so that it will be compiled afresh.

Because PL/pgSQL saves execution plans in this way, queries that appear directly in a PL/pgSQL function must refer to the same tables and fields on every execution; that is, you cannot use a parameter as the name of a table or field in a query. To get around this restriction, you can construct dynamic queries using the PL/pgSQL EXECUTE statement --- at the price of constructing a new query plan on every execution.

Except for input/output conversion and calculation functions for user defined types, anything that can be defined in C language functions can also be done with PL/pgSQL. It is possible to create complex conditional computation functions and later use them to define operators or use them in functional indexes.