From PostgreSQL wiki
Revision as of 03:36, 6 August 2019 by Ringerc (talk | contribs)
Jump to: navigation, search

TODO: Hooks, callbacks and trace points

This TODO/wishlist sub-section is intended for all users and developers to edit to add their own thoughts on desired extension points within the core PostgreSQL codebase.

Definitions with existing examples =


A "hook" is a global variable of pointer-to-function type. PostgreSQL calls the hook function *instead of* a standard postgres function if the variable is set at the relevant point in execution of some core routine. The hook variable is usually set by extension code to run new code before and/or after existing core code, usually from `shared_preload_libraries` or `session_preload_libraries`.

If the hook variable was already set when an extension loads the extension must remember the previous hook value and call it; otherwise it generally calls the original core PostgreSQL routine.

See separate article on entry points for extending PostgreSQL for list of existing hooks.

An example is the `ProcessUtility_hook` which is used to intercept and wrap, or entirely suppress, utility commands. A utility command is any "non plannable" SQL command, anything other than `SELECT`/`INSERT`/`UPDATE`/`DELETE`. An real example can be found in `contrib/pg_stat_statements/pg_stat_statements.c`, but a trivial demo is:

 1 static ProcessUtility_hook_type next_ProcessUtility_hook;
 3 static void
 4 demo_ProcessUtility_hook(PlannedStmt *pstmt,
 5                                           const char *queryString, ProcessUtilityContext context,
 6                                           ParamListInfo params,
 7                                           QueryEnvironment *queryEnv,
 8                                           DestReceiver *dest, char *completionTag)
 9 {
10   /* Do something silly to show how the hook can work */
11   if (IsA(parsetree, TransactionStmt))
12   {
13     TransactionStmt *stmt = (TransactionStatement)parsetree;
14     if (stmt->kind == TRANS_STMT_PREPARE && !is_superuser())
15         ereport(ERROR,
16                 (errmsg("MyDemoExtension prohibits non-superusers from using PREPARE TRANSACTION")));
17   }
19   /* Call next hook if registered, or original postgres stmt */
20   if (next_ProcessUtility_hook)
21     next_ProcessUtility_hook(pstmt, queryString, context, params, queryEnv, dest, completionTag);
22   else
23     standard_ProcessUtility_hook(pstmt, queryString, context, params, queryEnv, dest, completionTag);
25   if (completionTag)
26     ereport(LOG,
27             (errmsg("MyDemoExtension allowed utility statement %s to run", completionTag)));
28 }
30 void
31 _PG_init(void)
32 {
33   next_ProcessUtility_hook = ProcessUtility_hook;
34   ProcessUtility_hook = demo_ProcessUtility_hook;
35 }