Starting with version 17, PostgreSQL provides a feature many Oracle users have been waiting for: the LOGON trigger. The idea is to make the database launch a function as soon as the user tries to log in.
Table of Contents
This post explains how this works and how such a LOGIN trigger (as it is called in the PostgreSQL world) can be implemented and used in real life.
A LOGIN trigger is defined for a database (not for an instance). To demonstrate how this works, we first create a simple database:
1 2 3 4 5 6 7 |
local_machine:~ hs$ psql postgres psql (17.2) Type "help" for help. postgres=# CREATE DATABASE login_example; CREATE DATABASE postgres=# \c login_example |
You are now connected to database "login_example" as user "hs".
The idea of this example is to write a simple log entry for each successful login attempt. Here is the definition of the table:
1 2 3 4 5 6 |
login_example=# CREATE TABLE t_user_login ( id serial, tstamp timestamptz DEFAULT now(), who text ); CREATE TABLE |
Like any trigger in PostgreSQL, we first need to create a function before identifying the trigger itself. The special aspect here is that the trigger has to be enabled to make it fire during the login process.
The following code demonstrates how this works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
BEGIN; CREATE OR REPLACE FUNCTION on_login_proc() RETURNS event_trigger AS $$ BEGIN INSERT INTO t_user_login (who) VALUES (SESSION_USER); END; $$ LANGUAGE plpgsql; CREATE EVENT TRIGGER on_login_event ON login EXECUTE FUNCTION on_login_proc(); ALTER EVENT TRIGGER on_login_event ENABLE ALWAYS; COMMIT; |
The important observation is the function returning an event_trigger variable, a special data type specifically for this purpose. The function itself is simple PL/pgSQL code.
Next, we define the event trigger. The event we want to listen for is "login"—a new feature available starting from PostgreSQL 17.
Finally, the event trigger is enabled and the transaction can commit.
Once the event trigger is deployed and enabled, we can test the code. In this example, I am simply using psql to connect to the desired database:
1 2 3 4 5 6 7 8 9 |
local_machine:~ hs$ psql login_example psql (17.2) Type "help" for help. login_example=# SELECT * FROM t_user_login; id | tstamp | who ----+-------------------------------+----- 1 | 2025-01-13 13:17:40.916489+01 | hs (1 row) |
The table already contains some data. Every time we log into the system, one log entry will be added.
However, we have to be careful. What happens when the code is causing issues?
Here is an example:
1 2 3 4 5 6 7 8 9 |
CREATE OR REPLACE FUNCTION on_login_proc() RETURNS event_trigger AS $$ BEGIN INSERT INTO t_user_login (who) VALUES (SESSION_USER); SELECT 1/0; END; $$ LANGUAGE plpgsql; |
This code will fail because at the end of the procedure, PostgreSQL will face a division by zero. The error ensures that the function will terminate, and this causes the event trigger to fail, as the next listing shows:
1 2 3 4 5 |
local_machine:~ hs$ psql login_example psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: division by zero CONTEXT: SQL statement "SELECT 1/0" PL/pgSQL function on_login_proc() line 5 at SQL statement |
The key question is: How can we log in again? Well, it's not that easy. If an event trigger fails, the only way to fix the problem is to stop the database instance and fire it up again in single-user mode.
In general, LOGIN triggers (or LOGON triggers as they are called in Oracle) can be useful. However, we strongly advise extreme caution when using this feature. A tiny bug in the server-side function can lock you out of the system entirely and cause serious issues. Therefore, carefully consider whether you really need this feature.
If you do, make sure that the code has been tested properly to avoid any risk of failure. Being able to log into a server is quite "essential", and careful precautions are necessary to avoid potential issues.
Read more about "triggers" in other blog postings.
You need to load content from reCAPTCHA to submit the form. Please note that doing so will share data with third-party providers.
More InformationYou are currently viewing a placeholder content from Facebook. To access the actual content, click the button below. Please note that doing so will share data with third-party providers.
More InformationYou are currently viewing a placeholder content from X. To access the actual content, click the button below. Please note that doing so will share data with third-party providers.
More Information
Leave a Reply