Summary: in this tutorial, you’ll learn how to use the PostgreSQL event triggers to monitor and control Data Definition Language (DDL) operations.
Overview of PostgreSQL Event Triggers #
Regular triggers are associated with a table and respond to events that occur on the table, such as INSERT, UPDATE, DELETE, and TRUNCATE.
Unlike regular triggers, event triggers are not associated with a table but a database. Event triggers respond to the database schema change events such as adding a column, dropping a table and so on.
In PostgreSQL, event triggers can track the following events:
ddl_command_start: fires at the start of any DDL command.ddl_command_end: fires at the end of any DDL command.sql_drop: fires after objects are dropped.table_rewrite: fires when a change in the table’s structure occurs.
Creating Event Triggers #
You can create event triggers using the CREATE EVENT TRIGGER statement:
CREATE EVENT TRIGGER trigger_name
ON event_name
WHEN condition
EXECUTE FUNCTION function_name();Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)In this syntax:
trigger_name: The event trigger name.event_name: The DDL event to monitor, such asddl_command_start.condition: Optional condition to filter events.function_name: The function to execute when the event occurs.
In practice, you’ll find event triggers useful for the following scenarios:
- Auditing database schema changes.
- Enforcing specific database policies.
- Preventing unauthorized database schema modifications.
- Automating notifications or logs for administrative purposes.
Example of Event Triggers #
First, create a table called event_logs to store the logs of all database structure modifications:
CREATE TABLE event_logs (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
event_type VARCHAR NOT NULL,
command_tag VARCHAR NOT NULL,
object_id OID NOT NULL,
object_name VARCHAR NOT NULL,
schema_name VARCHAR NOT NULL,
user_name VARCHAR NOT NULL,
event_time TIMESTAMPTZ NOT NULL DEFAULT NOW()
);Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Second, create a function that inserts DDL events into the event_logs table:
CREATE OR REPLACE FUNCTION log_events()
RETURNS EVENT_TRIGGER
AS
$$
BEGIN
INSERT INTO event_logs (
event_type,
command_tag,
object_id,
object_name,
schema_name,
user_name
)
SELECT
tg_event,
tg_tag,
objid,
object_identity,
schema_name,
current_user
FROM pg_event_trigger_ddl_commands();
END;
$$ LANGUAGE plpgsql;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Third, create an event trigger and associate it with the log_events function:
CREATE EVENT TRIGGER log_schema_changes
ON ddl_command_end
EXECUTE FUNCTION log_events();Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Fourth, modify the products table by adding a new column called net_weight with the type decimal:
ALTER TABLE products
ADD COLUMN net_weight DEC;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)The ALTER TABLE statement will fire the log_schema_changes trigger that inserts data into the event_logs table.
Finally, retrieve data from the event_logs table:
SELECT
event_type,
command_tag,
object_name,
user_name
FROM
event_logs;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Output:
event_type | command_tag | object_name | user_name
-----------------+-------------+-----------------+-----------
ddl_command_end | ALTER TABLE | public.products | postgresCode language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Listing Event Triggers. #
To get all event triggers, you can query from the pg_event_trigger in the PostgreSQL system catalogs:
SELECT * FROM pg_event_trigger;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Output:
oid | evtname | evtevent | evtowner | evtfoid | evtenabled | evttags
-------+--------------------+-----------------+----------+---------+------------+---------
46763 | log_schema_changes | ddl_command_end | 10 | 46762 | O |Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Disabling Event Triggers #
To turn off an event trigger, you use the ALTER EVENT TRIGGER statement:
ALTER EVENT TRIGGER event_trigger_name
DISABLE;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)For example, the following statement turns off the log_schema_changes event trigger:
ALTER EVENT TRIGGER log_schema_changes
DISABLE;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Enabling Event Triggers #
To enable an event trigger, you also use the ALTER EVENT TRIGGER statement but with the ENABLE option:
ALTER EVENT TRIGGER event_trigger_name
ENABLE;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)For example, the following statement re-enables the log_schema_changes event trigger:
ALTER EVENT TRIGGER log_schema_changes
ENABLE;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Removing Event Triggers #
If you no longer use an event trigger, you can drop it using the DROP EVENT TRIGGER statement:
DROP EVENT TRIGGER event_trigger_name;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)For example, you can use the following statement to drop the log_schema_changes event trigger:
DROP EVENT TRIGGER log_schema_changes;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Preventing unauthorized schema changes #
The following example shows how to use an event trigger to prevent unauthorized users from modifying the database structure:
Step 1. Create a function that only allows the user postgres to modify the database structure:
CREATE FUNCTION stop_ddl ()
RETURNS EVENT_TRIGGER
AS
$$
BEGIN
IF current_user <> 'postgres' THEN
RAISE EXCEPTION 'The user % does not have the authorization to change the database structure', current_user;
END IF;
END;
$$
LANGUAGE plpgsql;Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)The stop_ddl function raises an exception if the user is not postgres.
Step 2. Create a event trigger authorize_schema_change that executes the stop_ddl() function whenvever a DDL event occurs:
CREATE EVENT TRIGGER stop_executing_ddl
ON ddl_command_start
EXECUTE FUNCTION stop_ddl();Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)Only the user postgres can execute DDL commands, while others will receive an exception.
Summary #
- PostgreSQL event triggers are database-level triggers.
- Use PostgreSQL event triggers for monitoring and controlling database structure changes.
- Use the
CREATE EVENT TRIGGERstatement to create a new event trigger. - Use the
ALTER EVENT TRIGGER ... DISABLEstatement to disable an event trigger. - Use the
ALTER EVENT TRIGGER ... ENABLEstatement to enable an event trigger. - Use the
DROP EVENT TRIGGERstatement to remove an event trigger from a database.