diff options
author | Michael Paquier <michael@paquier.xyz> | 2019-10-01 12:15:25 +0900 |
---|---|---|
committer | Michael Paquier <michael@paquier.xyz> | 2019-10-01 12:15:25 +0900 |
commit | e788bd924c19e296bd34316e30e3ba1b68354e64 (patch) | |
tree | dc0be40d99dc72eff1dce9ed404b6a48544101e4 /src/test/modules/test_session_hooks/test_session_hooks.c | |
parent | 41a6de41ed697df5d84f3144c6c60b4a9725381f (diff) | |
download | postgresql-e788bd924c19e296bd34316e30e3ba1b68354e64.tar.gz postgresql-e788bd924c19e296bd34316e30e3ba1b68354e64.zip |
Add hooks for session start and session end, take two
These hooks can be used in loadable modules. A simple test module is
included.
The first attempt was done with cd8ce3a but we lacked handling for
NO_INSTALLCHECK in the MSVC scripts (problem solved afterwards by
431f1599) so the buildfarm got angry. This also fixes a couple of
issues noticed upon review compared to the first attempt, so the code
has slightly changed, resulting in a more simple test module.
Author: FabrÃzio de Royes Mello, Yugo Nagata
Reviewed-by: Andrew Dunstan, Michael Paquier, Aleksandr Parfenov
Discussion: https://postgr.es/m/20170720204733.40f2b7eb.nagata@sraoss.co.jp
Discussion: https://postgr.es/m/20190823042602.GB5275@paquier.xyz
Diffstat (limited to 'src/test/modules/test_session_hooks/test_session_hooks.c')
-rw-r--r-- | src/test/modules/test_session_hooks/test_session_hooks.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/test/modules/test_session_hooks/test_session_hooks.c b/src/test/modules/test_session_hooks/test_session_hooks.c new file mode 100644 index 00000000000..d047c5d219a --- /dev/null +++ b/src/test/modules/test_session_hooks/test_session_hooks.c @@ -0,0 +1,146 @@ +/* ------------------------------------------------------------------------- + * + * test_session_hooks.c + * Code for testing start and end session hooks. + * + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/test/modules/test_session_hooks/test_session_hooks.c + * + * ------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/xact.h" +#include "commands/dbcommands.h" +#include "executor/spi.h" +#include "lib/stringinfo.h" +#include "miscadmin.h" +#include "tcop/tcopprot.h" +#include "utils/snapmgr.h" +#include "utils/builtins.h" + +PG_MODULE_MAGIC; + +/* Entry point of library loading/unloading */ +void _PG_init(void); +void _PG_fini(void); + +/* GUC variables */ +static char *session_hook_username = "postgres"; + +/* Previous hooks on stack */ +static session_start_hook_type prev_session_start_hook = NULL; +static session_end_hook_type prev_session_end_hook = NULL; + +static void +register_session_hook(const char *hook_at) +{ + const char *username; + + StartTransactionCommand(); + SPI_connect(); + PushActiveSnapshot(GetTransactionSnapshot()); + + /* Check the current user validity */ + username = GetUserNameFromId(GetUserId(), false); + + /* Register log just for configured username */ + if (strcmp(username, session_hook_username) == 0) + { + const char *dbname; + int ret; + StringInfoData buf; + + dbname = get_database_name(MyDatabaseId); + + initStringInfo(&buf); + + appendStringInfo(&buf, "INSERT INTO session_hook_log (dbname, username, hook_at) "); + appendStringInfo(&buf, "VALUES (%s, %s, %s);", + quote_literal_cstr(dbname), + quote_literal_cstr(username), + quote_literal_cstr(hook_at)); + + ret = SPI_exec(buf.data, 0); + if (ret != SPI_OK_INSERT) + elog(ERROR, "SPI_execute failed: error code %d", ret); + } + + SPI_finish(); + PopActiveSnapshot(); + CommitTransactionCommand(); +} + +/* sample session start hook function */ +static void +sample_session_start_hook(void) +{ + if (prev_session_start_hook) + prev_session_start_hook(); + + /* consider only normal backends */ + if (MyBackendId == InvalidBackendId) + return; + + /* consider backends connected to a database */ + if (!OidIsValid(MyDatabaseId)) + return; + + register_session_hook("START"); +} + +/* sample session end hook function */ +static void +sample_session_end_hook(void) +{ + if (prev_session_end_hook) + prev_session_end_hook(); + + /* consider only normal backends */ + if (MyBackendId == InvalidBackendId) + return; + + /* consider backends connected to a database */ + if (!OidIsValid(MyDatabaseId)) + return; + + register_session_hook("END"); +} + +/* + * Module load callback + */ +void +_PG_init(void) +{ + /* Save previous hooks */ + prev_session_start_hook = session_start_hook; + prev_session_end_hook = session_end_hook; + + /* Set new hooks */ + session_start_hook = sample_session_start_hook; + session_end_hook = sample_session_end_hook; + + /* Load GUCs */ + DefineCustomStringVariable("test_session_hooks.username", + "Username to register log on session start or end", + NULL, + &session_hook_username, + "postgres", + PGC_SIGHUP, + 0, NULL, NULL, NULL); +} + +/* + * Module unload callback + */ +void +_PG_fini(void) +{ + /* Uninstall hooks */ + session_start_hook = prev_session_start_hook; + session_end_hook = prev_session_end_hook; +} |