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 | postgres
Code 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 TRIGGER
statement to create a new event trigger. - Use the
ALTER EVENT TRIGGER ... DISABLE
statement to disable an event trigger. - Use the
ALTER EVENT TRIGGER ... ENABLE
statement to enable an event trigger. - Use the
DROP EVENT TRIGGER
statement to remove an event trigger from a database.