Page Content

Tutorials

PL/pgSQL: Advanced Features and Triggers In PostgreSQL

PL/pgSQL: Advanced Features and Triggers

The built-in procedural language for PostgreSQL function authoring, known as PL/pgSQL, is sometimes referred to as stored procedures in other database systems, such as Oracle’s PL/SQL, which had a significant influence on its design. By removing the burden of frequent client-server connection, it adds powerful procedural programming features to ordinary SQL, greatly improving server-side logic and efficiency.

Declaring and assigning variables, extensive control structures like IF-THEN-ELSIF-ELSE and CASE expressions for conditional execution, and several looping constructs like LOOP, WHILE, and FOR (for numeric ranges and query results) for iteration are some of the key advanced features; The ability to execute dynamic SQL statements using the EXECUTE command, which enables queries to be constructed and run at runtime based on variables or conditions; sophisticated exception handling using BEGIN…EXCEPTION…END blocks and the RAISE statement to trap and manage errors, preventing function abortion and allowing recovery; support for flexible return types, which can return single scalar values, composite types, or sets of records; support for cursors.

Which encapsulate SELECT queries and enable processing results row by row; and plan caching, which can reduce execution time by reusing query plans, though developers should be mindful of possible side effects, such as caching of sensitive timestamp values. In order to help the query optimiser create the best execution plans, PL/pgSQL functions can also be categorised by volatility (immutable, stable, and volatile).

Advanced Features and Triggers
Advanced Features and Triggers

Advanced PL/pgSQL Features

Control Structures: By adding procedural programming features, such as a robust collection of control structures that let programmers include intricate business logic straight into PostgreSQL operations, PL/pgSQL considerably expands on traditional SQL. Iteration, comprehensive error management, and conditional execution are all made possible by these control structures.

Conditional Statements: Conditional statements are made possible by the IF…THEN…ELSIF…ELSE…END IF construct. CASE statements can also be used to effectively handle many conditions.

Iteration: The looping mechanisms supported are LOOP…END, WHILE, and FOR. These characteristics enable integer range iteration, SQL query or cursor processing, and instruction repetition. Within loops, loop control statements such as EXIT and CONTINUE provide fine-grained execution management.

Variables and Declarations: The DECLARE portion of a PL/pgSQL block contains the definitions of variables. SELECT INTO or RETURNING INTO clauses can be used to get values from query results, or DEFAULT, :=, or = can be used to assign values.

Predefined Variables: PL/pgSQL routines automatically contain special variables. The Boolean variable FOUND determines if a recent DML query (INSERT, UPDATE, DELETE), SELECT, or PERFORM statement affected any rows.

Dynamic SQL: EXECUTE allows PL/pgSQL to dynamically build and execute SQL statements from character strings. This feature is essential in situations when variable queries or dynamic object names are needed. It’s essential to use format() or quote_literal() when creating dynamic queries to avoid SQL injection problems.

Exception Handling: To detect and fix mistakes, PL/pgSQL has EXCEPTION blocks. Additionally, the RAISE statement can be used to deliberately cause errors by specifying a MESSAGE, DETAIL, HINT, and SQLSTATE ERRCODE. A PL/pgSQL function will automatically terminate its execution and reverse any modifications performed during the call if an unhandled error occurs.

Triggers in PL/pgSQL

Triggers are active-database techniques in PostgreSQL that, when specific DML or DDL events occur on a table, view, or foreign table, automatically carry out a predefined operation. In contrast, triggers are run as part of the query executor, whereas rules are processed during the query rewrite stage.

Trigger Types and Firing Times: Triggers can start before or after an operation like INSERT, UPDATE, or DELETE. AFTER triggers propagate changes to other tables or perform post-operation integrity checks, while BEFORE triggers validate or modify data before storage. Rather than being automatically updated, views are only made updatable by using these triggers. FOR EACH ROW triggers execute once every SQL query row. In contrast, a FOR EACH STATEMENT trigger only acts once per statement, regardless of how many rows are affected (including zero).

Trigger Functions: Trigger functions are always called by a trigger; these are often written in PL/pgSQL. A TriggerData structure is used to supply the input data, therefore these functions do not require explicit parameters and must be defined to return the special trigger pseudo-type. The function in BEFORE triggers has the option to change the NEW row or return NULL to stop the action. Statement-level triggers and AFTER usually return NULL.

Special Variables within Trigger Functions: Special variables created automatically for PL/pgSQL trigger functions give them context about the triggering event and the data involved:

NEW: When INSERT or UPDATE operations are performed, the new row data is stored in the NEW RECORD variable (it is NULL for DELETE actions).

OLD: The EXECUTE command in PL/pgSQL allows dynamic SQL statements (including DDL, DCL, and DML) to be generated and executed at runtime based on variables or conditions. The fact that EXECUTE queries are not cached can improve performance in some cases. PL/pgSQL has predefined variables like FOUND, a Boolean variable used in DML and PERFORM statements to check for affected, selected, inserted, updated, or deleted rows.

TG_OP:Special variable TG_OP is automatically created and available in the top-level block of PL/pgSQL trigger functions. This variable indicates the trigger-firing operation. Data manipulation language (DML) actions including INSERT, UPDATE, DELETE, and TRUNCATE can trigger TG_OP. For operation-specific logic, developers use TG_OP in conditional statements like IF-THEN-ELSIF-ELSE blocks.

TG_WHEN: In PL/pgSQL trigger functions, the TG_WHEN variable is a unique, predefined variable that gives important details about when a trigger is triggered in relation to the data change event. NAME is its data type. The timing context of the trigger execution is indicated by the value of TG_WHEN.

TG_TABLE_NAME: TG_TABLE_NAME is a unique predefined variable in PL/pgSQL trigger functions that is automatically made available within the function’s top-level block upon trigger invocation. NAME is its data type. Indicating the name of the table that triggered the trigger invocation is the main function of TG_TABLE_NAME.

TG_ARGV: TG_ARGV is a unique predefined variable used in PL/pgSQL trigger functions that operates as an array for passing arguments to a trigger function. The TG_ARGV array enables developers to add more parameters or configuration to the trigger’s logic, even if a trigger function must be declared without explicit arguments.

Code Example:

Using triggers to log table modifications for compliance, debugging, or historical tracking is a common practice in auditing. A PL/pgSQL trigger can record INSERT, UPDATE, and DELETE activities on a business table into a log table.

Define the required tables first:

CREATE OR REPLACE FUNCTION add_log_function()
RETURNS TRIGGER AS $$
DECLARE
    vDescription TEXT;
    vId INT;
BEGIN
    vDescription := TG_TABLE_NAME || ' ';
    IF (TG_OP = 'INSERT') THEN
        vId := NEW.id;
        vDescription := vDescription || 'added. Id: ' || vId;
        INSERT INTO log (table_name, table_id, description, created_at)
        VALUES (TG_TABLE_NAME, vId, vDescription, NOW());
        RETURN NEW;
    ELSIF (TG_OP = 'UPDATE') THEN
        vId := NEW.id;
        vDescription := vDescription || 'updated. Id: ' || vId;
        INSERT INTO log (table_name, table_id, description, created_at)
        VALUES (TG_TABLE_NAME, vId, vDescription, NOW());
        RETURN NEW;
    ELSIF (TG_OP = 'DELETE') THEN
        vId := OLD.id;
        vDescription := vDescription || 'deleted. Id: ' || vId;
        INSERT INTO log (table_name, table_id, description, created_at)
        VALUES (TG_TABLE_NAME, vId, vDescription, NOW());
        RETURN OLD;
    END IF;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

Output:

CREATE FUNCTION

Conclusion

By adding strong procedural features and potent trigger capabilities, PL/pgSQL takes PostgreSQL well beyond normal SQL and enables complicated business logic to run directly within the database. Developers can create effective, maintainable server-side code that minimises round-trips to the client by using PL/pgSQL’s support for variables, control structures, dynamic SQL, and sophisticated exception handling. By guaranteeing data integrity, enforcing business standards, enabling thorough auditing, and offering automated, event-driven responses to data changes, triggers further improve this. When combined, these characteristics make PL/pgSQL a flexible tool for creating database systems with lots of logic and great performance.

Kowsalya
Kowsalya
Hi, I'm Kowsalya a B.Com graduate and currently working as an Author at Govindhtech Solutions. I'm deeply passionate about publishing the latest tech news and tutorials that bringing insightful updates to readers. I enjoy creating step-by-step guides and making complex topics easier to understand for everyone.
Index