<!--
Les sources pour ce sujet sont :

* https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=e83d1b0c40ccda8955f1245087f0697652c4df86

Discussion :

https://postgr.es/m/0d46d29f-4558-3af9-9c85-7774e14a7709%40postgrespro.ru

-->

<div class="slide-content">

  * Syntaxe
    + `CREATE EVENT TRIGGER ... ON LOGIN ...`
  * Permet le déclenchement d'une _fonction_ lorsqu'une connexion est réussie
  * Option `event_triggers` pour activer/désactiver leurs déclenchement
    + intéressant quand la fonction trigger ne fonctionne pas

</div>

<div class="notes">

Il est désormais possible de positionner des _triggers_ sur une connexion. La
fonction associée sera exécutée juste après que l'authentification de
l'utilisateur soit réussie. L'utilisation est la même que pour les autres
_triggers_, dont voici un exemple.

Création d'une table d'historisation des connexions :

```sql
postgres=# create table t1 (utilisateur text, connexions timestamp);
CREATE TABLE
```

Création de la fonction `log_connexions` qui insère dans la table `t1`
l'utilisateur utilisé dans la session ainsi que l’horodatage. La clause
`SECURITY DEFINER` permet d'indiquer que cette fonction sera exécutée avec les
droits associés à son propriétaire.

```sql
postgres=# create function log_connexions() returns event_trigger as $$ 
begin
insert into t1 values (session_user, current_timestamp);
end
$$ language plpgsql security definer;
CREATE FUNCTION
```

Petit rappel : une fonction `security definer` s'exécute avec les droits de
son propriétaire. Dans le cas présent, cela permet d'interdire les écritures
dans la table de log pour tous les utilisateurs, sauf celui qui a créé la
fonction, empêchant ainsi aux autres utilisateurs de supprimer les traces de
leurs connexions.

Création du _trigger_ `trigger_connexions` qui sera exécuté sur un évènement
de type `login`.

```sql
postgres=# CREATE EVENT TRIGGER trigger_connexions ON login EXECUTE PROCEDURE log_connexions();
CREATE EVENT TRIGGER
```

Désormais, en nous connectant, la table `t1` est bien complétée.

```sql
postgres=# \c postgres postgres
You are now connected to database "postgres" as user "postgres".
postgres=# select * from t1 ;
 utilisateur |         connexions         
-------------+----------------------------
 postgres    | 2024-07-09 11:25:35.357863
(1 row)

postgres=# \c postgres dalibo
You are now connected to database "postgres" as user "dalibo".

postgres=> \c postgres postgres
You are now connected to database "postgres" as user "postgres".

postgres=# select * from t1 ;
 utilisateur |         connexions         
-------------+----------------------------
 postgres    | 2024-07-09 11:25:35.357863
 dalibo      | 2024-07-09 11:25:40.914802
 postgres    | 2024-07-09 11:25:45.52029
(3 rows)
```

Une nouvelle colonne apparaît dans le catalogue `pg_database`. Il s'agit de
`dathasloginevt` qui indique si la base de données en question possède ou non un
_trigger_ sur un évènement de type `login`.

```sql
postgres=# select datname, dathasloginevt from pg_database;
  datname  | dathasloginevt 
-----------+----------------
 template1 | f
 template0 | f
 postgres  | t
(3 rows)
```

::: warning

Si la fonction utilisée renvoie une erreur, il vous sera **impossible** de vous
connecter à votre base de données.

Il existe deux solutions pour contourner ce problème.
La première solution serait d'arrêter votre instance, de la relancer en
mode `single-server`, de corriger la fonction ou de supprimer le _trigger_, puis
d'arrêter l'instance et la redémarrer normalement.

Les développeurs de PostgreSQL ont pensé à une solution un peu moins radicale.
Un nouveau paramètre existe désormais : `event_triggers`. Passée à `off`, il permet
de désactiver l'exécution des _triggers sur événement_. La deuxième solution de contournement consiste
donc à modifier ce paramètre et à recharger la configuration de PostgreSQL.

En bref, soyez attentifs !

:::

</div>
