Todo:HooksAndTracePoints

From PostgreSQL wiki
Revision as of 03:31, 6 August 2019 by Ringerc (talk | contribs) (Created page with "# 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 point...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
  1. 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.


  1. Definitions
    1. Hook

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:

``` static ProcessUtility_hook_type next_ProcessUtility_hook;

static void demo_ProcessUtility_hook(PlannedStmt *pstmt,

                                         const char *queryString, ProcessUtilityContext context,
                                         ParamListInfo params,
                                         QueryEnvironment *queryEnv,
                                         DestReceiver *dest, char *completionTag)

{

 /* Do something silly to show how the hook can work */
 if (IsA(parsetree, TransactionStmt))
 {
   TransactionStmt *stmt = (TransactionStatement)parsetree;
   if (stmt->kind == TRANS_STMT_PREPARE && !is_superuser())
       ereport(ERROR,
               (errmsg("MyDemoExtension prohibits non-superusers from using PREPARE TRANSACTION")));
 }
 /* Call next hook if registered, or original postgres stmt */
 if (next_ProcessUtility_hook)
   next_ProcessUtility_hook(pstmt, queryString, context, params, queryEnv, dest, completionTag);
 else
   standard_ProcessUtility_hook(pstmt, queryString, context, params, queryEnv, dest, completionTag);
 if (completionTag)
   ereport(LOG,
           (errmsg("MyDemoExtension allowed utility statement %s to run", completionTag)));

}

void _PG_init(void) {

 next_ProcessUtility_hook = ProcessUtility_hook;
 ProcessUtility_hook = demo_ProcessUtility_hook;

}

```