├── .gitignore
├── Detailed.md
├── License.md
├── Readme.md
├── generate.py
├── requirements.txt
└── templates
├── Detailed.md
├── DetailedHeader.md
├── Header.md
├── Hook.md
├── Readme.md
└── hooks
├── ClientAuthentication_hook.md
├── ExecutorCheckPerms_hook.md
├── ExecutorEnd_hook.md
├── ExecutorFinish_hook.md
├── ExecutorRun_hook.md
├── ExecutorStart_hook.md
├── ExplainOneQuery_hook.md
├── ProcessUtility_hook.md
├── check_password_hook.md
├── create_upper_paths_hook.md
├── emit_log_hook.md
├── explain_get_index_name_hook.md
├── fmgr_hook.md
├── func_beg.md
├── func_end.md
├── func_setup.md
├── get_attavgwidth_hook.md
├── get_index_stats_hook.md
├── get_relation_info_hook.md
├── get_relation_stats_hook.md
├── join_search_hook.md
├── needs_fmgr_hook.md
├── object_access_hook.md
├── planner_hook.md
├── post_parse_analyze_hook.md
├── row_security_policy_hook_permissive.md
├── row_security_policy_hook_restrictive.md
├── set_join_pathlist_hook.md
├── set_rel_pathlist_hook.md
├── shmem_startup_hook.md
├── stmt_beg.md
└── stmt_end.md
/.gitignore:
--------------------------------------------------------------------------------
1 | venv/
2 | bin
3 | include
4 | lib
5 | .Python
6 | pip-selfcheck.json
7 | .idea
--------------------------------------------------------------------------------
/Detailed.md:
--------------------------------------------------------------------------------
1 | # Postgresql hooks documentation
2 |
3 | PostgreSQL hooks are a simple way to extend functionality of the database.
4 | They allow extensions to introspect database state, react to events and
5 | interfere with database operations.
6 |
7 | Every hook is a pointer to a function, initially set to `NULL`.
8 |
9 | When postgres wants to call a hook, it checks whether the pointer for that
10 | hook is not null and if that's the case, calls the registered function.
11 |
12 | Extensions can update these pointers during the init procedure
13 | in order to register a new handler for a hook.
14 |
15 | That is, when extension is loaded, postgres calls its `_PG_init` function.
16 | Once called, it can alter hook variables which are a part of the public binary
17 | interface.
18 |
19 | A usual setup would include saving the previous value of the hook variable
20 | and writing pointer to a handler defined by extension.
21 |
22 | Saving the previous value is important because another extension could've
23 | registered its own hook handler. If that's the case, we'd like to call it in
24 | our hook so that this extension can operate without errors. Any well-designed
25 | plugin will do such hook chaining.
26 |
27 | To pop the state of the hook created by one extension `_PG_fini` function must be implemented,
28 | which is basically recovers hook to it's value before `_PG_init`.
29 |
30 | A standard example on how to use hooks is the `auth_delay` plugin.
31 | This plugin delays error report in case of user authentication failure,
32 | which is useful to block password brute-forcing.
33 |
34 | ```c
35 | // We store previously assigned hook pointer in a global variable.
36 | static ClientAuthentication_hook_type original_client_auth_hook = NULL;
37 |
38 | // Our hook implementation.
39 | static void auth_delay_checks(Port *port, int status)
40 | {
41 | // If any other extension registered its own hook handler,
42 | // call it before performing our own logic.
43 | if (original_client_auth_hook)
44 | original_client_auth_hook(port, status);
45 |
46 | // If authentication failed, we wait for one second before returning
47 | // control to the caller.
48 | if (status != STATUS_OK)
49 | {
50 | pg_usleep(1000000L);
51 | }
52 | }
53 |
54 | // Called upon extension load.
55 | void _PG_init(void)
56 | {
57 | // Save the original hook value.
58 | original_client_auth_hook = ClientAuthentication_hook;
59 | // Register our handler.
60 | ClientAuthentication_hook = auth_delay_checks;
61 | }
62 |
63 | // Called with extension unload.
64 | void _PG_fini(void)
65 | {
66 | // Return back the original hook value.
67 | ClientAuthentication_hook = original_client_auth_hook;
68 | }
69 |
70 | ```
71 |
72 | ## Table of contents
73 |
74 | * [General Hooks](#general-hooks)
75 | * [Security Hooks](#security-hooks)
76 | * [Function Manager Hooks](#function-manager-hooks)
77 | * [Planner Hooks](#planner-hooks)
78 | * [Executor Hooks](#executor-hooks)
79 | * [PL/pgsql Hooks](#plpgsql-hooks)
80 |
81 |
82 | ## General Hooks
83 |
84 |
85 |
86 |
87 | # void emit_log_hook(edata) [<>](https://github.com/postgres/postgres/blob/master/src/include/utils/elog.h#L415 "Source")
88 |
89 | Hook for intercepting messages before they are sent to the server log.
90 |
91 | This hook is called just before sending an error message to the server log
92 | and to the client. The purpose of this hook is to invoke an additional
93 | logic and possibly prevent this error message from being added to the
94 | server log.
95 |
96 | This hook is useful for implementing custom logging process.
97 |
98 | *Inputs:*
99 |
100 | * ErrorData * edata — a structure which holds a complete info
101 | about the error message. Despite `edata` is a non-const pointer, the only
102 | supported change in the given structure is setting `output_to_server` to
103 | `false`. That is, any other change, including setting `output_to_server` to
104 | `true`, considered not supported.
105 |
106 | Note: despite any other changes to the edata are not officially supported
107 | (as per comment [on line 1455 of the elog.c][emit_log_hook_1])),
108 | postgres actually checks for both `output_to_server` and `output_to_client`
109 | flags.
110 |
111 | [emit_log_hook_1]: https://github.com/postgres/postgres/blob/master/src/backend/utils/error/elog.c#L1456
112 |
113 |
114 | # void shmem_startup_hook() [<>](https://github.com/postgres/postgres/blob/master/src/include/storage/ipc.h#L78 "Source")
115 |
116 | Hook for extensions to initialize their shared memory.
117 |
118 | This hook is called by postmaster or by a standalone backend
119 | right after postgres initializes its shared memory and semaphores
120 | so that extensions have chance to initialize their shared state.
121 |
122 | It also may be called by a backend forked from the postmaster.
123 | In this situation, the shared memory segment already exists, so you only have
124 | to initialize the local memory state (check `!IsUnderPostmaster`
125 | to determine if that's the case).
126 |
127 | Note that you can bind a callback for shared state teardown
128 | via `on_shmem_exit`.
129 |
130 | Check out the `pg_stat_statements` code to get the idea on how to implement
131 | this hook correctly.
132 |
133 |
134 | ## Security Hooks
135 |
136 |
137 |
138 |
139 | # void check_password_hook(username, shadow_pass, password_type, validuntil_time, validuntil_null) [<>](https://github.com/postgres/postgres/blob/master/src/include/commands/user.h#L25 "Source")
140 |
141 | Hook for enforcing password constraints and performing action on password change.
142 |
143 | This hook is called whenever a new role is created via the `CREATE ROLE`
144 | statement or a password for an existing role is changed via the `ALTER ROLE`
145 | statement. Given a shadow password and some additional info, this hook can
146 | raise an error using the standard `ereport` mechanism if the password
147 | isn't strong enough.
148 |
149 | *Inputs:*
150 |
151 | * const char * username — name of the created/altered role.
152 | * const char * shadow_pass — a shadow pass, i.e. a plain password
153 | or a password hash.
154 | * PasswordType password_type — type of the password.
155 | `PASSWORD_TYPE_MD5` for an md5-encrypted password,
156 | `PASSWORD_TYPE_SCRAM_SHA_256` for a sha-256-encrypted password,
157 | `PASSWORD_TYPE_PLAINTEXT` for a plaintext password.
158 | * Datum validuntil_time — date upon which this password expires.
159 | * bool validuntil_null — a flag that is true if and only if
160 | the password have no expiration date (i.e. a null date is passed).
161 |
162 |
163 | # void ClientAuthentication_hook(port, status) [<>](https://github.com/postgres/postgres/blob/master/src/include/libpq/auth.h#L29 "Source")
164 |
165 | Hook for controlling the authentication process.
166 |
167 | Called after finishing user authentication (regardless of whether authentication
168 | succeed or not).
169 |
170 | This hook will be called for every connection that passed authentication.
171 | However, it is not guaranteed to be called if there are issues with the
172 | connection itself. For example, SSL verification failure or pg_hba.conf
173 | check failure will close the connection without calling this hook.
174 |
175 | *Inputs:*
176 |
177 | * Port * port — full info about the connection and
178 | the connected user.
179 | * int status — a standard status code. `STATUS_OK` (`0`)
180 | if authentication successful.
181 |
182 |
183 | # bool ExecutorCheckPerms_hook(rangeTabls, abort) [<>](https://github.com/postgres/postgres/blob/master/src/include/executor/executor.h#L85 "Source")
184 |
185 | Hook for adding additional security checks on the per-relation level.
186 |
187 | Given a relations list, this hook should return `true` if access is granted.
188 | `false`, if access is not granted and `abort` is `false`. If `abort` is `true`
189 | and access is not granted, it should throw an appropriate error.
190 |
191 | This hook is not called if the standard permission check procedure denies
192 | access to any relation in the list. Therefore, there is no way to actually
193 | raise user privileges.
194 |
195 | Theoretically, only plain-relation RTEs need to be checked in this hook.
196 | Function RTEs are checked during the function preparation procedure.
197 | Join, subquery, and special RTEs need no checks.
198 |
199 | *Inputs:*
200 |
201 | * List * rangeTabls — list of `RangeTblEntry` objects that needs
202 | checking.
203 | * bool abort — if `true`, raise `aclcheck_error` instead of
204 | returning `false` from the hook.
205 |
206 | *Output:*
207 |
208 | `true` if user have privileges to access given relations, `false` or raise an
209 | error otherwise, depending on the `abort` flag.
210 |
211 |
212 | # void object_access_hook(access, classId, objectId, subId, arg) [<>](https://github.com/postgres/postgres/blob/master/src/include/catalog/objectaccess.h#L138 "Source")
213 |
214 | Hook to monitor accesses to objects.
215 |
216 | Object access hooks are called just before or just after performing certain
217 | actions on an SQL object. This is intended as infrastructure for security
218 | or logging extensions.
219 |
220 | There are several types of actions defined in `ObjectAccessType`:
221 |
222 | `OAT_POST_CREATE`: hook is invoked just after the object is created.
223 | Typically, this is done after inserting the primary catalog records and
224 | associated dependencies.
225 |
226 | `OAT_DROP`: hook is invoked just before deletion of objects.
227 |
228 | `OAT_POST_ALTER`: hook is invoked just after the object is altered,
229 | but before the command counter is incremented. An extension using the
230 | hook can use a current MVCC snapshot to get the old version of the tuple,
231 | and can use `SnapshotSelf` to get the new version of the tuple.
232 |
233 | `OAT_NAMESPACE_SEARCH`: hook is invoked prior to object name lookup under
234 | a particular namespace. This event is equivalent to usage permission
235 | on a schema under the default access control mechanism.
236 |
237 | `OAT_FUNCTION_EXECUTE`: hook is invoked prior to function execution.
238 | This event is almost equivalent to execute permission on functions,
239 | except for the case when execute permission is checked during object
240 | creation or altering, because `OAT_POST_CREATE` or `OAT_POST_ALTER` are
241 | sufficient for extensions to track these kind of checks.
242 |
243 | Other types may be added in the future.
244 |
245 | *Inputs:*
246 |
247 | For different access types, inputs of this hook mean different things.
248 |
249 | * ObjectAccessType access — access type.
250 | * Oid classId — id of a relation which contains this object.
251 | You can determine type of an object by this parameter.
252 | * Oid objectId — object that is being accessed.
253 | * int subId — subitem within object (e.g. column), or 0.
254 | * void * arg — access type specific argument.
255 |
256 | For `OAT_POST_CREATE`, `arg` is a pointer to `ObjectAccessPostCreate`
257 | structure, which contain a single field, namely `is_internal`. This field
258 | describes whether the context of this creation is invoked by user's
259 | operations, or not. As for `subId`, I've counted two cases when it's non-zero.
260 | The first is when creating a column, and the second one is when creating
261 | a default expression on a column. In either case, `subId` is
262 | an `AttrNumber` of a column.
263 |
264 | For `OAT_DROP` type, `arg` is a pointer to `ObjectAccessPostCreate` structure.
265 | It contains a single field called `dropflags`. They inform extensions the
266 | context of this deletion.
267 |
268 | For `OAT_POST_ALTER` type, `arg` is a pointer to `ObjectAccessPostAlter`
269 | structure. It contains an `is_internal` flag (see `OAT_POST_CREATE`) and an
270 | `auxiliary_id`. The latter is used when system catalog takes two IDs to
271 | identify a particular tuple of the catalog. It is only used when the caller want
272 | to identify an entry of pg_inherits, pg_db_role_setting or pg_user_mapping.
273 | Elsewhere, InvalidOid is be set.
274 |
275 | For `OAT_NAMESPACE_SEARCH` type, `subId` is unused, `classId` is always
276 | `NamespaceRelationId`, and `arg` is a pointer to `ObjectAccessNamespaceSearch`.
277 |
278 | `ObjectAccessNamespaceSearch` structure contain two fields. The first one,
279 | `ereport_on_violation`, indicates that the hook should raise an error when
280 | permission to search this schema is denied. The second one, `result`, is in fact
281 | an out parameter. Core code should initialize this to true, and any extension
282 | that wants to deny access should reset it to false. But an extension should be
283 | careful never to store a true value here, so that in case there are multiple
284 | extensions access is only allowed if all extensions agree.
285 |
286 | For `OAT_FUNCTION_EXECUTE` type, `subId` and `arg` are unused, and
287 | `classId` is always `ProcedureRelationId`.
288 |
289 |
290 | # List * row_security_policy_hook_permissive(cmdtype, relation) [<>](https://github.com/postgres/postgres/blob/master/src/include/rewrite/rowsecurity.h#L40 "Source")
291 |
292 | Hook to add policies which are combined with the other permissive policies.
293 |
294 | This hook, along with the `row_security_policy_hook_restrictive`, allows adding
295 | custom security policies. It is called to build a list of policies for the given
296 | command applied to the given relation.
297 |
298 | Access is granted to an object if and only if no restrictive policies deny
299 | access and any permissive policy grant access.
300 |
301 | *Inputs:*
302 |
303 | * CmdType cmdtype — command type.
304 | * Relation relation — relation id.
305 |
306 | *Output:*
307 |
308 | List of additional permissive policies that will be added to the list of
309 | default permissive policies.
310 |
311 |
312 | # List * row_security_policy_hook_restrictive(cmdtype, relation) [<>](https://github.com/postgres/postgres/blob/master/src/include/rewrite/rowsecurity.h#L42 "Source")
313 |
314 | Hook to add policies which are enforced, regardless of other policies.
315 |
316 | See `row_security_policy_hook_permissive` for a detailed description.
317 |
318 | Unlike for permissive policies, postgres guarantees that restrictive policies
319 | will be executed in a predefined order. That is, first postgres executes the
320 | default policies sorted by their name, than postgres executes custom policies,
321 | also sorted by their name.
322 |
323 | *Inputs:*
324 |
325 | * CmdType cmdtype — command type.
326 | * Relation relation — relation id.
327 |
328 |
329 | ## Function Manager Hooks
330 |
331 |
332 |
333 |
334 | # bool needs_fmgr_hook(fn_oid) [<>](https://github.com/postgres/postgres/blob/master/src/include/fmgr.h#L775 "Source")
335 |
336 | Auxiliary hook which decides whether `fmgr_hook` should be applied to a function.
337 |
338 | Given a function id, decide whether `fmgr_hook` should be called upon executing
339 | this function.
340 |
341 | The result of this hook should be combined with the result of a previously
342 | registered `needs_fmgr_hook` via the `OR` clause. This is required to ensure
343 | that other extensions can hook function even though this very extension does
344 | not hook them. Such behavior is vital for proper work of the security extensions.
345 |
346 | Note that hooked functions are not inlined.
347 |
348 | *Inputs:*
349 |
350 | * Oid fn_oid — id of a function which needs hooking.
351 |
352 | *Output:*
353 |
354 | Return `true` if you want to hook enter/exit event for this function.
355 |
356 |
357 | # void fmgr_hook(event, flinfo, arg) [<>](https://github.com/postgres/postgres/blob/master/src/include/fmgr.h#L776 "Source")
358 |
359 | Hook for controlling function execution process.
360 |
361 | This hook is intended as support for loadable security policy modules, which may
362 | want to perform additional privilege checks on function entry or exit,
363 | or to do other internal bookkeeping.
364 |
365 | It is invoked whenever postgres executes a function which was explicitly
366 | marked as hookable by `needs_fmgr_hook`. For each execution this hook is fired
367 | exactly twice: first time before invoking the function, second time after
368 | the function returns/throws.
369 |
370 | Note that there is a change that this hook will be called even if a function
371 | is not of interest of your extension (maybe some other extension made it
372 | hookable via its `needs_fmgr_hook`).
373 |
374 | *Inputs:*
375 |
376 | * FmgrHookEventType event — event type, can be one of
377 | `FHET_START`, `FHET_END`, `FHET_ABORT`.
378 | * FmgrInfo * flinfo — function info, including its id and
379 | arguments specification.
380 | * Datum * arg — function arguments.
381 |
382 |
383 | ## Planner Hooks
384 |
385 |
386 |
387 |
388 | # const char * explain_get_index_name_hook(indexId) [<>](https://github.com/postgres/postgres/blob/master/src/include/commands/explain.h#L76 "Source")
389 |
390 | Hook for altering index names in explain statements.
391 |
392 | Extensions may override the default name generation mechanism
393 | so that plans involving hypothetical indexes can be explained.
394 |
395 | *Inputs:*
396 |
397 | * Oid indexId — index id.
398 |
399 | *Output:*
400 |
401 | Name of the index or `NULL`. In the later case, a default name
402 | will be generated.
403 |
404 |
405 | # void ExplainOneQuery_hook(query, cursorOptions, into, es, queryString, params, queryEnv) [<>](https://github.com/postgres/postgres/blob/master/src/include/commands/explain.h#L72 "Source")
406 |
407 | Hook for overriding explain procedure for a single query.
408 |
409 | This hook, if present, should generate explanation for the given query
410 | using other `Explain*` functions and modifying the explain state.
411 |
412 | The default behaviour is to plan query using `pg_plan_query()` and than
413 | delegate printing to the `ExplainOnePlan()` function.
414 |
415 | *Inputs:*
416 |
417 | * Query * query — query that needs explanation.
418 | * int cursorOptions — cursor options in form of a per-bit enum.
419 | See `CURSOR_OPT_*` macros for detailed documentations.
420 | * IntoClause * into — target information for `SELECT INTO`,
421 | `CREATE TABLE AS`, and `CREATE MATERIALIZED VIEW`. `NULL` unless
422 | explaining the contents of a `CreateTableAsStmt`.
423 | * ExplainState * es — current explain state. The hook is free to
424 | modify it in order to produce output.
425 | * const char * queryString — an actual query string.
426 | * ParamListInfo params — plan parameters.
427 | * QueryEnvironment * queryEnv — context-specific values.
428 |
429 | *Output:*
430 |
431 | This hook does not produce any output.
432 |
433 |
434 |
435 | # int32 get_attavgwidth_hook(relid, attnum) [<>](https://github.com/postgres/postgres/blob/master/src/include/utils/lsyscache.h#L66 "Source")
436 |
437 | Hook for controlling an algorithm for predicting the average width of entries in the column.
438 |
439 | This hook, if set, should return the average width of entries in the column.
440 | If returned value is greater than `0`, it is returned to the planner.
441 | Otherwise, the default algorithm is invoked.
442 |
443 | *Inputs:*
444 |
445 | * Oid relid — relation id.
446 | * AttrNumber attnum — column number.
447 |
448 | *Output:*
449 |
450 | Average width of entries in the given column of the given relation or zero
451 | to fall back to the default algorithm.
452 |
453 |
454 | # bool get_index_stats_hook(root, indexOid, indexattnum, vardata) [<>](https://github.com/postgres/postgres/blob/master/src/include/utils/selfuncs.h#L146 "Source")
455 |
456 | Hook for overriding index stats lookup.
457 |
458 | Given the planner state and an index, the hook should decide if it can provide
459 | any useful stats. If yes, it should supply a `statsTuple` and a `freefunc` and
460 | return `true`. If no, it should return `false`.
461 |
462 | Note that `freefunc` must be set if `statsTuple` is set.
463 |
464 | Note also that `vardata` should not be changed if `false` is returned.
465 | Postgres will not check whether `statsTuple` and `freefunc` are set.
466 | It will simply overwrite them.
467 |
468 | *Inputs:*
469 |
470 | * PlannerInfo * root — current planner info.
471 | * Oid indexOid — id of the index that we are looking stats for.
472 | * AttrNumber indexattnum — index column.
473 | * VariableStatData * vardata — container for the return value.
474 |
475 |
476 | # void get_relation_info_hook(root, relationObjectId, inhparent, rel) [<>](https://github.com/postgres/postgres/blob/master/src/include/optimizer/plancat.h#L25 "Source")
477 |
478 | Hook for altering results of the relation info lookup.
479 |
480 | This hook allow plugins to editorialize on the info that was obtained from the
481 | catalogs by the default relation info lookup. Actions might include altering
482 | the assumed relation size, removing an index, or adding a hypothetical
483 | index to the `indexlist`.
484 |
485 | *Inputs:*
486 |
487 | * PlannerInfo * root — current planner info.
488 | * Oid relationObjectId — id of the relation that we are looking
489 | info for.
490 | * bool inhparent — if true, all we need to do is set up the attr
491 | arrays: the `RelOptInfo` actually represents the `appendrel` formed by an
492 | inheritance tree, and so the parent rel's physical size and index information
493 | isn't important for it.
494 | * RelOptInfo * rel — relation info that can be adjusted.
495 |
496 |
497 | # bool get_relation_stats_hook(root, rte, attnum, vardata) [<>](https://github.com/postgres/postgres/blob/master/src/include/utils/selfuncs.h#L141 "Source")
498 |
499 | Hook for overriding relation stats lookup.
500 |
501 | Similar to `get_index_stats_hook`, this hook should either return `false`
502 | or take control over relation stats lookup, write output the the `vardata`
503 | container, and return `true`.
504 |
505 | See `get_index_stats_hook` for more details.
506 |
507 | *Inputs:*
508 |
509 | * PlannerInfo * root — current planner info.
510 | * Oid indexOid — id of the index that we are looking stats for.
511 | * AttrNumber indexattnum — index column.
512 | * VariableStatData * vardata — container for the return value.
513 |
514 |
515 | # PlannedStmt * planner_hook(parse, query_string, cursorOptions, boundParams) [<>](https://github.com/postgres/postgres/blob/master/src/include/optimizer/planner.h#L30 "Source")
516 |
517 | Called in query optimizer entry point.
518 |
519 | If set, replaces standard planner. Consider inclusion of the standard planner to hook
520 | if this hook assuming just pre-process or post-process for builtin planner.
521 |
522 | *Inputs:*
523 |
524 | * Query * parse — parsed query text.
525 | * const char * query_string — original query text.
526 | * int cursorOptions
527 | * ParamListInfo boundParams
528 |
529 |
530 | # RelOptInfo * join_search_hook(root, levels_needed, initial_rels) [<>](https://github.com/postgres/postgres/blob/master/src/include/optimizer/paths.h#L49 "Source")
531 |
532 | Called when optimiser chooses order for join relations.
533 |
534 | When the hook is set, replaces GEQO or standard join search.
535 |
536 | *Inputs:*
537 |
538 | * PlannerInfo * root — query plan root.
539 | * int levels_needed — the number of child joinlist nodes.
540 | * List * initial_rels — list of join relations.
541 |
542 |
543 | # void set_rel_pathlist_hook(root, rel, rti, rte) [<>](https://github.com/postgres/postgres/blob/master/src/include/optimizer/paths.h#L34 "Source")
544 |
545 | Called at the end of building access paths for a base relation.
546 |
547 | The hook can apply changes to set of paths by adding new paths or deleting them.
548 |
549 | *Inputs:*
550 |
551 | * PlannerInfo * root
552 | * RelOptInfo * rel - relation info.
553 | * Index rti - range table index.
554 | * RangeTblEntry * rte range table entry.
555 |
556 |
557 | # void set_join_pathlist_hook(root, joinrel, outerrel, innerrel, jointype, extra) [<>](https://github.com/postgres/postgres/blob/master/src/include/optimizer/paths.h#L43 "Source")
558 |
559 | Called at the end of the process of joinrel modification to contain the best paths.
560 |
561 | The hook can manipulate path list to perform a postprocess for best paths.
562 |
563 | *Inputs:*
564 |
565 | * PlannerInfo * root — query plan root.
566 | * RelOptInfo * joinrel — list of paths.
567 | * RelOptInfo * outerrel - list of outer relation paths.
568 | * RelOptInfo * innerrel - list of inner relation paths.
569 | * JoinType jointype - the type of a join.
570 | * JoinPathExtraData * extra
571 |
572 |
573 | # void create_upper_paths_hook(root, stage, input_rel, output_rel) [<>](https://github.com/postgres/postgres/blob/master/src/include/optimizer/planner.h#L38 "Source")
574 |
575 | Called when postprocess of the path of set operations occurs.
576 |
577 | It's a possibility for extensions to contribute path in relation.
578 |
579 | *Inputs:*
580 |
581 | * PlannerInfo * root — query plan root.
582 | * UpperRelationKind stage
583 | * RelOptInfo * input_rel
584 | * RelOptInfo * output_rel
585 |
586 |
587 | # void post_parse_analyze_hook(pstate, query) [<>](https://github.com/postgres/postgres/blob/master/src/include/parser/analyze.h#L25 "Source")
588 |
589 | Called when parse analyze goes, right after performing transformTopLevelStmt().
590 |
591 | Used in several internal methods:
592 | [pg_analyze_and_rewrite_params()](https://github.com/postgres/postgres/blob/src/backend/tcop/postgres.c#L686),
593 | [parse_analyze()](https://github.com/postgres/postgres/blob/src/backend/parser/analyze.c#L100).
594 |
595 | *Inputs:*
596 |
597 | * ParseState * pstate — parse state filled by query_string and queryEnv.
598 | * Query * query — output result of the transformTopLevelStmt().
599 |
600 |
601 | ## Executor Hooks
602 |
603 |
604 |
605 |
606 | # void ExecutorStart_hook(queryDesc, eflags) [<>](https://github.com/postgres/postgres/blob/master/src/include/executor/executor.h#L66 "Source")
607 |
608 | Called at the beginning of any execution of any query plan.
609 |
610 | Note: when it set, replaces the [standard_ExecutorStart()](https://github.com/postgres/postgres/blob/src/backend/executor/execMain.c#L149),
611 | which contains a lot of predefined logic.
612 | Consider inclusion of the standard executor to the hook handler
613 | if you assume adding your logic atop.
614 |
615 | *Inputs:*
616 |
617 | * QueryDesc * queryDesc — created by CreateQueryDesc,
618 | tupDesc field of the QueryDesc is filled in to describe the tuples that will be
619 | returned, and the internal fields (estate and planstate) are set up.
620 | * int eflags — contains flag bits as described in executor.h.
621 |
622 |
623 | # void ExecutorRun_hook(queryDesc, direction, count, execute_once) [<>](https://github.com/postgres/postgres/blob/master/src/include/executor/executor.h#L73 "Source")
624 |
625 | Called at any plan execution, after ExecutorStart.
626 |
627 | Replaces [standard_ExecutorRun()](https://github.com/postgres/postgres/blob/src/backend/executor/execMain.c#L308)
628 |
629 | *Inputs:*
630 |
631 | * QueryDesc * queryDesc — query descriptor from the traffic cop.
632 | * ScanDirection direction - if value is NoMovementScanDirection then nothing is done
633 | except to start up/shut down the destination.
634 | * uint64 count — count = 0 is interpreted as no portal limit, i.e.,
635 | run to completion. Also note that the count limit is only applied to
636 | retrieved tuples, not for instance to those inserted/updated/deleted by a ModifyTable plan node.
637 | * bool execute_once — becomes equal to true after first execution.
638 |
639 | *Output:*
640 |
641 | This hook should not provide any output. However output tuples (if any) are sent to
642 | the destination receiver specified in the QueryDesc.
643 | The number of tuples processed at the top level can be found in estate->es_processed.
644 |
645 |
646 | # void ExecutorFinish_hook(queryDesc) [<>](https://github.com/postgres/postgres/blob/master/src/include/executor/executor.h#L77 "Source")
647 |
648 | Called after the last ExecutorRun call
649 |
650 | Replaces [standard_ExecutorFinish()](https://github.com/postgres/postgres/blob/src/backend/executor/execMain.c#L408)
651 |
652 | *Inputs:*
653 |
654 | * QueryDesc * queryDesc — query descriptor from the traffic cop.
655 |
656 |
657 | # void ExecutorEnd_hook(queryDesc) [<>](https://github.com/postgres/postgres/blob/master/src/include/executor/executor.h#L81 "Source")
658 |
659 | Called at the end of execution of any query plan.
660 |
661 | * QueryDesc * queryDesc — query descriptor from the traffic cop.
662 |
663 |
664 | # void ProcessUtility_hook(pstmt, queryString, context, params, queryEnv, dest, completionTag) [<>](https://github.com/postgres/postgres/blob/master/src/include/tcop/utility.h#L78 "Source")
665 |
666 | Hook for the ProcessUtility.
667 |
668 | Replaces [standard_ProcessUtility()](https://github.com/postgres/postgres/blob/src/backend/tcop/utility.c#L375)
669 |
670 | This hook should not provide any output.
671 |
672 | *Inputs:*
673 |
674 | * PlannedStmt * pstmt — PlannedStmt wrapper for the utility statement
675 | * const char * queryString — original source text of command,
676 | may be passed multiple times when processing a query string
677 | containing multiple semicolon-separated statements. pstmt->stmt_location and pstmt->stmt_len
678 | indicates the substring containing the current statement.
679 | * ProcessUtilityContext context — identifies source of statement
680 | (toplevel client command, non-toplevel client command, subcommand of a larger utility command)
681 | * ParamListInfo params — parameters of an execution.
682 | * QueryEnvironment * queryEnv — execution environment, optional, can be NULL.
683 | * DestReceiver * dest — results receiver.
684 | * char * completionTag — points to a buffer of size COMPLETION_TAG_BUFSIZE
685 | in which to store a command completion status string
686 |
687 |
688 | ## PL/pgsql Hooks
689 |
690 |
691 |
692 |
693 | # void func_setup(estate, func) [<>](https://github.com/postgres/postgres/blob/master/src/pl/plpgsql/src/plpgsql.h#L1136 "Source")
694 |
695 | Hook for intercepting PLpgSQL function pre-init phase.
696 |
697 | This hook is called when we start a function before we've initialized
698 | the local variables defined by the function.
699 | Can be useful for time measuring of а function initialization in tandem
700 | with [func_beg()](Detailed.md#func_beg) and for measuring total execution time
701 | with the help of [func_end()](Detailed.md#func_end).
702 |
703 | Before any call to func_setup, PLpgSQL fills in the error_callback
704 | and assign_expr fields with pointers to its own plpgsql_exec_error_callback
705 | and exec_assign_expr functions.
706 |
707 | *Inputs:*
708 |
709 | * PLpgSQL_execstate * estate — runtime execution data.
710 | * PLpgSQL_function * func — PLpgSQL compiled function.
711 |
712 |
713 | # void func_beg(estate, func) [<>](https://github.com/postgres/postgres/blob/master/src/pl/plpgsql/src/plpgsql.h#L1137 "Source")
714 |
715 | Hook for intercepting post-init phase.
716 |
717 | This hook is called when we start PLpgSQL function, after we've initialized
718 | the local variables.
719 | The hook can be used for pre-validation of a function arguments.
720 |
721 | *Inputs:*
722 |
723 | * PLpgSQL_execstate * estate — runtime execution data.
724 | * PLpgSQL_function * func — PLpgSQL compiled function.
725 |
726 |
727 | # void func_end(estate, func) [<>](https://github.com/postgres/postgres/blob/master/src/pl/plpgsql/src/plpgsql.h#L1138 "Source")
728 |
729 | Hook for intercepting end of a function.
730 |
731 | This hook is called at the end of PLpgSQL function.
732 | Can be used as a function callback.
733 |
734 | *Inputs:*
735 |
736 | * PLpgSQL_execstate * estate — runtime execution data.
737 | * PLpgSQL_function * func — PLpgSQL compiled function.
738 |
739 |
740 | # void stmt_beg(estate, stmt) [<>](https://github.com/postgres/postgres/blob/master/src/pl/plpgsql/src/plpgsql.h#L1139 "Source")
741 |
742 | Called before each statement of a function.
743 |
744 | *Inputs:*
745 |
746 | * PLpgSQL_execstate * estate — runtime execution data.
747 | * PLpgSQL_stmt * stmt — execution node.
748 |
749 |
750 | # void stmt_end(estate, stmt) [<>](https://github.com/postgres/postgres/blob/master/src/pl/plpgsql/src/plpgsql.h#L1140 "Source")
751 |
752 | Called after each statement of a function.
753 |
754 | *Inputs:*
755 |
756 | * PLpgSQL_execstate * estate — runtime execution data.
757 | * PLpgSQL_stmt * stmt — execution node.
758 |
759 |
760 |
--------------------------------------------------------------------------------
/License.md:
--------------------------------------------------------------------------------
1 | Unofficial documentation for PostgreSQL hooks.
2 |
3 | Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
4 |
5 | Portions Copyright (c) 1994, The Regents of the University of California
6 |
7 | Permission to use, copy, modify, and distribute this software and its
8 | documentation for any purpose, without fee, and without a written agreement
9 | is hereby granted, provided that the above copyright notice and this
10 | paragraph and the following two paragraphs appear in all copies.
11 |
12 | IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
13 | DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
14 | LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
15 | DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
16 | POSSIBILITY OF SUCH DAMAGE.
17 |
18 | THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 | AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 | ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
22 | PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Postgresql hooks documentation
2 |
3 | Unofficial documentation for PostgreSQL hooks.
4 |
5 | > *Denial of responsibility:*
6 | >
7 | > This work is not a part of the official PostgreSQL documentation.
8 | >
9 | > Contents of this repository were compiled by Begishev Nikita and
10 | > Goncharov Vladimir, neither of whom appear to be a developer or a maintainer
11 | > of the PostgreSQL Database Management System.
12 | >
13 | > Use this documentation at your own risk.
14 | >
15 | >
16 | > *Copyright notice:*
17 | >
18 | > This work combines some research made by contributors with
19 | > information acquired from the postgres source code, comments and
20 | > documentation. Some contents of this work were copied from source code
21 | > comments as is, others were written from scratch.
22 | >
23 | > In no way we (Begishev Nikita and Goncharov Vladimir) claim copyright on texts
24 | > that were copied or adapted from the sources described above.
25 | >
26 | > This work is distributed under the terms of the PostgreSQL License, a copy of
27 | > which may be found in the file called 'License.md'.
28 |
29 | PostgreSQL hooks are a simple way to extend functionality of the database.
30 | They allow extensions to introspect database state, react to events and
31 | interfere with database operations.
32 |
33 | In terms of the programming language, each hook is a pointer to a function
34 | of a specific type, initially set to be `NULL`.
35 |
36 | Upon init, database extensions are free to overwrite those function pointers
37 | with their own values. A previous value of the overwritten pointer is usually
38 | stored withing the extension local memory.
39 |
40 | During its work, postgres checks whether certain function pointers are not null
41 | and if that's the case, calls them.
42 |
43 | See the [detailed description](Detailed.md) for an explanation on
44 | how to implement a hook and an example.
45 |
46 | * [General Hooks](#general-hooks)
47 | * [Security Hooks](#security-hooks)
48 | * [Function Manager Hooks](#function-manager-hooks)
49 | * [Planner Hooks](#planner-hooks)
50 | * [Executor Hooks](#executor-hooks)
51 | * [PL/pgsql Hooks](#plpgsql-hooks)
52 |
53 |
54 | ## [General Hooks](Detailed.md#general-hooks)
55 |
56 |
57 |
58 | * [emit_log_hook](Detailed.md#emit_log_hook) — hook for intercepting messages before they are sent to the server log.
59 | * [shmem_startup_hook](Detailed.md#shmem_startup_hook) — hook for extensions to initialize their shared memory.
60 |
61 | ## [Security Hooks](Detailed.md#security-hooks)
62 |
63 |
64 |
65 | * [check_password_hook](Detailed.md#check_password_hook) — hook for enforcing password constraints and performing action on password change.
66 | * [ClientAuthentication_hook](Detailed.md#ClientAuthentication_hook) — hook for controlling the authentication process.
67 | * [ExecutorCheckPerms_hook](Detailed.md#ExecutorCheckPerms_hook) — hook for adding additional security checks on the per-relation level.
68 | * [object_access_hook](Detailed.md#object_access_hook) — hook to monitor accesses to objects.
69 | * [row_security_policy_hook_permissive](Detailed.md#row_security_policy_hook_permissive) — hook to add policies which are combined with the other permissive policies.
70 | * [row_security_policy_hook_restrictive](Detailed.md#row_security_policy_hook_restrictive) — hook to add policies which are enforced, regardless of other policies.
71 |
72 | ## [Function Manager Hooks](Detailed.md#function-manager-hooks)
73 |
74 |
75 |
76 | * [needs_fmgr_hook](Detailed.md#needs_fmgr_hook) — auxiliary hook which decides whether `fmgr_hook` should be applied to a function.
77 | * [fmgr_hook](Detailed.md#fmgr_hook) — hook for controlling function execution process.
78 |
79 | ## [Planner Hooks](Detailed.md#planner-hooks)
80 |
81 |
82 |
83 | * [explain_get_index_name_hook](Detailed.md#explain_get_index_name_hook) — hook for altering index names in explain statements.
84 | * [ExplainOneQuery_hook](Detailed.md#ExplainOneQuery_hook) — hook for overriding explain procedure for a single query.
85 | * [get_attavgwidth_hook](Detailed.md#get_attavgwidth_hook) — hook for controlling an algorithm for predicting the average width of entries in the column.
86 | * [get_index_stats_hook](Detailed.md#get_index_stats_hook) — hook for overriding index stats lookup.
87 | * [get_relation_info_hook](Detailed.md#get_relation_info_hook) — hook for altering results of the relation info lookup.
88 | * [get_relation_stats_hook](Detailed.md#get_relation_stats_hook) — hook for overriding relation stats lookup.
89 | * [planner_hook](Detailed.md#planner_hook) — called in query optimizer entry point.
90 | * [join_search_hook](Detailed.md#join_search_hook) — called when optimiser chooses order for join relations.
91 | * [set_rel_pathlist_hook](Detailed.md#set_rel_pathlist_hook) — called at the end of building access paths for a base relation.
92 | * [set_join_pathlist_hook](Detailed.md#set_join_pathlist_hook) — called at the end of the process of joinrel modification to contain the best paths.
93 | * [create_upper_paths_hook](Detailed.md#create_upper_paths_hook) — called when postprocess of the path of set operations occurs.
94 | * [post_parse_analyze_hook](Detailed.md#post_parse_analyze_hook) — called when parse analyze goes, right after performing transformTopLevelStmt().
95 |
96 | ## [Executor Hooks](Detailed.md#executor-hooks)
97 |
98 |
99 |
100 | * [ExecutorStart_hook](Detailed.md#ExecutorStart_hook) — called at the beginning of any execution of any query plan.
101 | * [ExecutorRun_hook](Detailed.md#ExecutorRun_hook) — called at any plan execution, after ExecutorStart.
102 | * [ExecutorFinish_hook](Detailed.md#ExecutorFinish_hook) — called after the last ExecutorRun call
103 | * [ExecutorEnd_hook](Detailed.md#ExecutorEnd_hook) — called at the end of execution of any query plan.
104 | * [ProcessUtility_hook](Detailed.md#ProcessUtility_hook) — hook for the ProcessUtility.
105 |
106 | ## [PL/pgsql Hooks](Detailed.md#plpgsql-hooks)
107 |
108 |
109 |
110 | * [func_setup](Detailed.md#func_setup) — hook for intercepting PLpgSQL function pre-init phase.
111 | * [func_beg](Detailed.md#func_beg) — hook for intercepting post-init phase.
112 | * [func_end](Detailed.md#func_end) — hook for intercepting end of a function.
113 | * [stmt_beg](Detailed.md#stmt_beg) — called before each statement of a function.
114 | * [stmt_end](Detailed.md#stmt_end) — called after each statement of a function.
115 |
116 |
--------------------------------------------------------------------------------
/generate.py:
--------------------------------------------------------------------------------
1 | from collections import namedtuple
2 |
3 | import os
4 |
5 | import jinja2
6 |
7 | HookType = namedtuple('HookType', 'name output inputs')
8 | HookInput = namedtuple('HookInput', 'type name')
9 | Hook = namedtuple('Hook', 'type name source_link')
10 | HookSection = namedtuple('HookSection', 'name slug short_desc long_desc hooks')
11 |
12 |
13 | def link(path):
14 | return 'https://github.com/postgres/postgres/blob/master/' + path
15 |
16 |
17 | set_rel_pathlist_hook_type = HookType(
18 | name='set_rel_pathlist_hook_type',
19 | output='void',
20 | inputs=[
21 | HookInput('PlannerInfo *', 'root'),
22 | HookInput('RelOptInfo *', 'rel'),
23 | HookInput('Index', 'rti'),
24 | HookInput('RangeTblEntry *', 'rte'),
25 | ]
26 | )
27 | set_join_pathlist_hook_type = HookType(
28 | name='set_join_pathlist_hook_type',
29 | output='void',
30 | inputs=[
31 | HookInput('PlannerInfo *', 'root'),
32 | HookInput('RelOptInfo *', 'joinrel'),
33 | HookInput('RelOptInfo *', 'outerrel'),
34 | HookInput('RelOptInfo *', 'innerrel'),
35 | HookInput('JoinType', 'jointype'),
36 | HookInput('JoinPathExtraData *', 'extra'),
37 | ]
38 | )
39 | needs_fmgr_hook_type = HookType(
40 | name='needs_fmgr_hook_type',
41 | output='bool',
42 | inputs=[
43 | HookInput('Oid', 'fn_oid'),
44 | ]
45 | )
46 | fmgr_hook_type = HookType(
47 | name='fmgr_hook_type',
48 | output='void',
49 | inputs=[
50 | HookInput('FmgrHookEventType', 'event'),
51 | HookInput('FmgrInfo *', 'flinfo'),
52 | HookInput('Datum *', 'arg'),
53 | ]
54 | )
55 | object_access_hook_type = HookType(
56 | name='object_access_hook_type',
57 | output='void',
58 | inputs=[
59 | HookInput('ObjectAccessType', 'access'),
60 | HookInput('Oid', 'classId'),
61 | HookInput('Oid', 'objectId'),
62 | HookInput('int', 'subId'),
63 | HookInput('void *', 'arg'),
64 | ]
65 | )
66 | ExplainOneQuery_hook_type = HookType(
67 | name='ExplainOneQuery_hook_type',
68 | output='void',
69 | inputs=[
70 | HookInput('Query *', 'query'),
71 | HookInput('int', 'cursorOptions'),
72 | HookInput('IntoClause *', 'into'),
73 | HookInput('ExplainState *', 'es'),
74 | HookInput('const char *', 'queryString'),
75 | HookInput('ParamListInfo', 'params'),
76 | HookInput('QueryEnvironment *', 'queryEnv'),
77 | ]
78 | )
79 | explain_get_index_name_hook_type = HookType(
80 | name='explain_get_index_name_hook_type',
81 | output='const char *',
82 | inputs=[
83 | HookInput('Oid', 'indexId'),
84 | ]
85 | )
86 | check_password_hook_type = HookType(
87 | name='check_password_hook_type',
88 | output='void',
89 | inputs=[
90 | HookInput('const char *', 'username'),
91 | HookInput('const char *', 'shadow_pass'),
92 | HookInput('PasswordType', 'password_type'),
93 | HookInput('Datum', 'validuntil_time'),
94 | HookInput('bool', 'validuntil_null'),
95 | ]
96 | )
97 | ExecutorStart_hook_type = HookType(
98 | name='ExecutorStart_hook_type',
99 | output='void',
100 | inputs=[
101 | HookInput('QueryDesc *', 'queryDesc'),
102 | HookInput('int', 'eflags'),
103 | ]
104 | )
105 | ExecutorRun_hook_type = HookType(
106 | name='ExecutorRun_hook_type',
107 | output='void',
108 | inputs=[
109 | HookInput('QueryDesc *', 'queryDesc'),
110 | HookInput('ScanDirection', 'direction'),
111 | HookInput('uint64', 'count'),
112 | HookInput('bool', 'execute_once'),
113 | ]
114 | )
115 | ExecutorFinish_hook_type = HookType(
116 | name='ExecutorFinish_hook_type',
117 | output='void',
118 | inputs=[
119 | HookInput('QueryDesc *', 'queryDesc'),
120 | ]
121 | )
122 | ExecutorEnd_hook_type = HookType(
123 | name='ExecutorEnd_hook_type',
124 | output='void',
125 | inputs=[
126 | HookInput('QueryDesc *', 'queryDesc'),
127 | ]
128 | )
129 | ExecutorCheckPerms_hook_type = HookType(
130 | name='ExecutorCheckPerms_hook_type',
131 | output='bool',
132 | inputs=[
133 | HookInput('List *', 'rangeTabls'),
134 | HookInput('bool', 'abort'),
135 | ]
136 | )
137 | ClientAuthentication_hook_type = HookType(
138 | name='ClientAuthentication_hook_type',
139 | output='void',
140 | inputs=[
141 | HookInput('Port *', 'port'),
142 | HookInput('int', 'status'),
143 | ]
144 | )
145 | join_search_hook_type = HookType(
146 | name='join_search_hook_type',
147 | output='RelOptInfo *',
148 | inputs=[
149 | HookInput('PlannerInfo *', 'root'),
150 | HookInput('int', 'levels_needed'),
151 | HookInput('List *', 'initial_rels'),
152 | ]
153 | )
154 | get_relation_info_hook_type = HookType(
155 | name='get_relation_info_hook_type',
156 | output='void',
157 | inputs=[
158 | HookInput('PlannerInfo *', 'root'),
159 | HookInput('Oid', 'relationObjectId'),
160 | HookInput('bool', 'inhparent'),
161 | HookInput('RelOptInfo *', 'rel'),
162 | ]
163 | )
164 | planner_hook_type = HookType(
165 | name='planner_hook_type',
166 | output='PlannedStmt *',
167 | inputs=[
168 | HookInput('Query *', 'parse'),
169 | HookInput('const char *', 'query_string'),
170 | HookInput('int', 'cursorOptions'),
171 | HookInput('ParamListInfo', 'boundParams'),
172 | ]
173 | )
174 | create_upper_paths_hook_type = HookType(
175 | name='create_upper_paths_hook_type',
176 | output='void',
177 | inputs=[
178 | HookInput('PlannerInfo *', 'root'),
179 | HookInput('UpperRelationKind', 'stage'),
180 | HookInput('RelOptInfo *', 'input_rel'),
181 | HookInput('RelOptInfo *', 'output_rel'),
182 | ]
183 | )
184 | post_parse_analyze_hook_type = HookType(
185 | name='post_parse_analyze_hook_type',
186 | output='void',
187 | inputs=[
188 | HookInput('ParseState *', 'pstate'),
189 | HookInput('Query *', 'query'),
190 | ]
191 | )
192 | row_security_policy_hook_type = HookType(
193 | name='row_security_policy_hook_type',
194 | output='List *',
195 | inputs=[
196 | HookInput('CmdType', 'cmdtype'),
197 | HookInput('Relation', 'relation'),
198 | ]
199 | )
200 | shmem_startup_hook_type = HookType(
201 | name='shmem_startup_hook_type',
202 | output='void',
203 | inputs=[
204 | ]
205 | )
206 | ProcessUtility_hook_type = HookType(
207 | name='ProcessUtility_hook_type',
208 | output='void',
209 | inputs=[
210 | HookInput('PlannedStmt *', 'pstmt'),
211 | HookInput('const char *', 'queryString'),
212 | HookInput('ProcessUtilityContext', 'context'),
213 | HookInput('ParamListInfo', 'params'),
214 | HookInput('QueryEnvironment *', 'queryEnv'),
215 | HookInput('DestReceiver *', 'dest'),
216 | HookInput('char *', 'completionTag'),
217 | ]
218 | )
219 | emit_log_hook_type = HookType(
220 | name='emit_log_hook_type',
221 | output='void',
222 | inputs=[
223 | HookInput('ErrorData *', 'edata'),
224 | ]
225 | )
226 | get_attavgwidth_hook_type = HookType(
227 | name='get_attavgwidth_hook_type',
228 | output='int32',
229 | inputs=[
230 | HookInput('Oid', 'relid'),
231 | HookInput('AttrNumber', 'attnum'),
232 | ]
233 | )
234 | get_relation_stats_hook_type = HookType(
235 | name='get_relation_stats_hook_type',
236 | output='bool',
237 | inputs=[
238 | HookInput('PlannerInfo *', 'root'),
239 | HookInput('RangeTblEntry *', 'rte'),
240 | HookInput('AttrNumber', 'attnum'),
241 | HookInput('VariableStatData *', 'vardata'),
242 | ]
243 | )
244 | get_index_stats_hook_type = HookType(
245 | name='get_index_stats_hook_type',
246 | output='bool',
247 | inputs=[
248 | HookInput('PlannerInfo *', 'root'),
249 | HookInput('Oid', 'indexOid'),
250 | HookInput('AttrNumber', 'indexattnum'),
251 | HookInput('VariableStatData *', 'vardata'),
252 | ]
253 | )
254 | func_hook_type = HookType(
255 | name='func_hook_type',
256 | output='void',
257 | inputs=[
258 | HookInput('PLpgSQL_execstate *', 'estate'),
259 | HookInput('PLpgSQL_function *', 'func'),
260 | ]
261 | )
262 | stmt_hook_type = HookType(
263 | name='stmt_hook_type',
264 | output='void',
265 | inputs=[
266 | HookInput('PLpgSQL_execstate *', 'estate'),
267 | HookInput('PLpgSQL_stmt *', 'stmt'),
268 | ]
269 | )
270 |
271 | sections = [
272 | HookSection(
273 | 'General Hooks',
274 | 'general-hooks',
275 | '',
276 | '',
277 | [
278 | Hook(
279 | emit_log_hook_type,
280 | 'emit_log_hook',
281 | link('src/include/utils/elog.h#L415')
282 | ),
283 | Hook(
284 | shmem_startup_hook_type,
285 | 'shmem_startup_hook',
286 | link('src/include/storage/ipc.h#L78')
287 | ),
288 | ]
289 | ),
290 | HookSection(
291 | 'Security Hooks',
292 | 'security-hooks',
293 | '',
294 | '',
295 | [
296 | Hook(
297 | check_password_hook_type,
298 | 'check_password_hook',
299 | link('src/include/commands/user.h#L25')
300 | ),
301 | Hook(
302 | ClientAuthentication_hook_type,
303 | 'ClientAuthentication_hook',
304 | link('src/include/libpq/auth.h#L29')
305 | ),
306 | Hook(
307 | ExecutorCheckPerms_hook_type,
308 | 'ExecutorCheckPerms_hook',
309 | link('src/include/executor/executor.h#L85')
310 | ),
311 | Hook(
312 | object_access_hook_type,
313 | 'object_access_hook',
314 | link('src/include/catalog/objectaccess.h#L138')
315 | ),
316 | Hook(
317 | row_security_policy_hook_type,
318 | 'row_security_policy_hook_permissive',
319 | link('src/include/rewrite/rowsecurity.h#L40')
320 | ),
321 | Hook(
322 | row_security_policy_hook_type,
323 | 'row_security_policy_hook_restrictive',
324 | link('src/include/rewrite/rowsecurity.h#L42')
325 | ),
326 | ]
327 | ),
328 | HookSection(
329 | 'Function Manager Hooks',
330 | 'function-manager-hooks',
331 | '',
332 | '',
333 | [
334 | Hook(
335 | needs_fmgr_hook_type,
336 | 'needs_fmgr_hook',
337 | link('src/include/fmgr.h#L775')
338 | ),
339 | Hook(
340 | fmgr_hook_type,
341 | 'fmgr_hook',
342 | link('src/include/fmgr.h#L776')
343 | ),
344 | ]
345 | ),
346 | HookSection(
347 | 'Planner Hooks',
348 | 'planner-hooks',
349 | '',
350 | '',
351 | [
352 | Hook(
353 | explain_get_index_name_hook_type,
354 | 'explain_get_index_name_hook',
355 | link('src/include/commands/explain.h#L76')
356 | ),
357 | Hook(
358 | ExplainOneQuery_hook_type,
359 | 'ExplainOneQuery_hook',
360 | link('src/include/commands/explain.h#L72')
361 | ),
362 | Hook(
363 | get_attavgwidth_hook_type,
364 | 'get_attavgwidth_hook',
365 | link('src/include/utils/lsyscache.h#L66')
366 | ),
367 | Hook(
368 | get_index_stats_hook_type,
369 | 'get_index_stats_hook',
370 | link('src/include/utils/selfuncs.h#L146')
371 | ),
372 | Hook(
373 | get_relation_info_hook_type,
374 | 'get_relation_info_hook',
375 | link('src/include/optimizer/plancat.h#L25')
376 | ),
377 | Hook(
378 | get_relation_stats_hook_type,
379 | 'get_relation_stats_hook',
380 | link('src/include/utils/selfuncs.h#L141')
381 | ),
382 | Hook(
383 | planner_hook_type,
384 | 'planner_hook',
385 | link('src/include/optimizer/planner.h#L30')
386 | ),
387 | Hook(
388 | join_search_hook_type,
389 | 'join_search_hook',
390 | link('src/include/optimizer/paths.h#L49')
391 | ),
392 | Hook( # TODO: does it really belong to this section?
393 | set_rel_pathlist_hook_type,
394 | 'set_rel_pathlist_hook',
395 | link('src/include/optimizer/paths.h#L34')
396 | ),
397 | Hook( # TODO: does it really belong to this section?
398 | set_join_pathlist_hook_type,
399 | 'set_join_pathlist_hook',
400 | link('src/include/optimizer/paths.h#L43')
401 | ),
402 | Hook( # TODO: does it really belong to this section?
403 | create_upper_paths_hook_type,
404 | 'create_upper_paths_hook',
405 | link('src/include/optimizer/planner.h#L38')
406 | ),
407 | Hook( # TODO: does it really belongs to this section
408 | post_parse_analyze_hook_type,
409 | 'post_parse_analyze_hook',
410 | link('src/include/parser/analyze.h#L25')
411 | ),
412 | ]
413 | ),
414 | HookSection(
415 | 'Executor Hooks',
416 | 'executor-hooks',
417 | '',
418 | '',
419 | [
420 | Hook(
421 | ExecutorStart_hook_type,
422 | 'ExecutorStart_hook',
423 | link('src/include/executor/executor.h#L66')
424 | ),
425 | Hook(
426 | ExecutorRun_hook_type,
427 | 'ExecutorRun_hook',
428 | link('src/include/executor/executor.h#L73')
429 | ),
430 | Hook(
431 | ExecutorFinish_hook_type,
432 | 'ExecutorFinish_hook',
433 | link('src/include/executor/executor.h#L77')
434 | ),
435 | Hook(
436 | ExecutorEnd_hook_type,
437 | 'ExecutorEnd_hook',
438 | link('src/include/executor/executor.h#L81')
439 | ),
440 | Hook(
441 | ProcessUtility_hook_type,
442 | 'ProcessUtility_hook',
443 | link('src/include/tcop/utility.h#L78')
444 | ),
445 | ]
446 | ),
447 | HookSection(
448 | 'PL/pgsql Hooks',
449 | 'plpgsql-hooks',
450 | '',
451 | '',
452 | [
453 | Hook(
454 | func_hook_type,
455 | 'func_setup',
456 | link('src/pl/plpgsql/src/plpgsql.h#L1136')
457 | ),
458 | Hook(
459 | func_hook_type,
460 | 'func_beg',
461 | link('src/pl/plpgsql/src/plpgsql.h#L1137')
462 | ),
463 | Hook(
464 | func_hook_type,
465 | 'func_end',
466 | link('src/pl/plpgsql/src/plpgsql.h#L1138')
467 | ),
468 | Hook(
469 | stmt_hook_type,
470 | 'stmt_beg',
471 | link('src/pl/plpgsql/src/plpgsql.h#L1139')
472 | ),
473 | Hook(
474 | stmt_hook_type,
475 | 'stmt_end',
476 | link('src/pl/plpgsql/src/plpgsql.h#L1140')
477 | ),
478 | ]
479 | ),
480 | ]
481 |
482 |
483 | def make_short_description(hook):
484 | path = 'templates/hooks/' + hook.name + '.md'
485 |
486 | if not os.path.exists(path):
487 | return ''
488 |
489 | with open(path, encoding='utf-8') as hook_text:
490 | for line in hook_text:
491 | line = line.strip()
492 | if line:
493 | return line[0].lower() + line[1:]
494 |
495 |
496 | def move_before_generation(output_path):
497 | if not os.path.exists(output_path):
498 | return
499 |
500 | path, ext = os.path.splitext(output_path)
501 |
502 | i = 1
503 | while os.path.exists(path + '.old.' + str(i) + ext):
504 | i += 1
505 |
506 | os.rename(output_path, path + '.old.' + str(i) + ext)
507 |
508 |
509 | def write_template(template_path, output_path, **context):
510 | with open(template_path, encoding='utf-8') as template_text:
511 | environment = jinja2.Environment(loader=jinja2.FileSystemLoader('.'))
512 | environment.globals['make_short_description'] = make_short_description
513 | template = environment.from_string(template_text.read())
514 | with open(output_path, 'w', encoding='utf-8') as f:
515 | f.write(template.render(**context))
516 |
517 |
518 | def main():
519 | for section in sections:
520 | for hook in section.hooks:
521 | path = 'templates/hooks/' + hook.name + '.md'
522 | if os.path.exists(path):
523 | continue
524 | write_template('templates/Hook.md', path, hook=hook)
525 |
526 | move_before_generation('Readme.md')
527 | write_template('templates/Readme.md', 'Readme.md', sections=sections)
528 |
529 | move_before_generation('Detailed.md')
530 | write_template('templates/Detailed.md', 'Detailed.md', sections=sections)
531 |
532 |
533 | if __name__ == '__main__':
534 | main()
535 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | jinja2
2 |
--------------------------------------------------------------------------------
/templates/Detailed.md:
--------------------------------------------------------------------------------
1 | # Postgresql hooks documentation
2 |
3 | {% include "templates/DetailedHeader.md" %}
4 |
5 | ## Table of contents
6 |
7 | {% for section in sections -%}
8 | * [{{ section.name }}](#{{ section.slug }})
9 | {% endfor %}
10 |
11 | {% for section in sections -%}
12 | ## {{ section.name }}
13 |
14 | {{ section.long_desc }}
15 |
16 | {% for hook in section.hooks %}
17 | # {{ hook.type.output }} {{ hook.name }}({% for input in hook.type.inputs %}{{ input.name }}{% if loop.nextitem is defined %}, {% endif %}{% endfor %}) [<>]({{ hook.source_link }} "Source")
18 |
19 | {% include "templates/hooks/" + hook.name + ".md" %}
20 |
21 | {% endfor %}
22 | {% endfor %}
23 |
--------------------------------------------------------------------------------
/templates/DetailedHeader.md:
--------------------------------------------------------------------------------
1 | PostgreSQL hooks are a simple way to extend functionality of the database.
2 | They allow extensions to introspect database state, react to events and
3 | interfere with database operations.
4 |
5 | Every hook is a pointer to a function, initially set to `NULL`.
6 |
7 | When postgres wants to call a hook, it checks whether the pointer for that
8 | hook is not null and if that's the case, calls the registered function.
9 |
10 | Extensions can update these pointers during the init procedure
11 | in order to register a new handler for a hook.
12 |
13 | That is, when extension is loaded, postgres calls its `_PG_init` function.
14 | Once called, it can alter hook variables which are a part of the public binary
15 | interface.
16 |
17 | A usual setup would include saving the previous value of the hook variable
18 | and writing pointer to a handler defined by extension.
19 |
20 | Saving the previous value is important because another extension could've
21 | registered its own hook handler. If that's the case, we'd like to call it in
22 | our hook so that this extension can operate without errors. Any well-designed
23 | plugin will do such hook chaining.
24 |
25 | To pop the state of the hook created by one extension `_PG_fini` function must be implemented,
26 | which is basically recovers hook to it's value before `_PG_init`.
27 |
28 | A standard example on how to use hooks is the `auth_delay` plugin.
29 | This plugin delays error report in case of user authentication failure,
30 | which is useful to block password brute-forcing.
31 |
32 | ```c
33 | // We store previously assigned hook pointer in a global variable.
34 | static ClientAuthentication_hook_type original_client_auth_hook = NULL;
35 |
36 | // Our hook implementation.
37 | static void auth_delay_checks(Port *port, int status)
38 | {
39 | // If any other extension registered its own hook handler,
40 | // call it before performing our own logic.
41 | if (original_client_auth_hook)
42 | original_client_auth_hook(port, status);
43 |
44 | // If authentication failed, we wait for one second before returning
45 | // control to the caller.
46 | if (status != STATUS_OK)
47 | {
48 | pg_usleep(1000000L);
49 | }
50 | }
51 |
52 | // Called upon extension load.
53 | void _PG_init(void)
54 | {
55 | // Save the original hook value.
56 | original_client_auth_hook = ClientAuthentication_hook;
57 | // Register our handler.
58 | ClientAuthentication_hook = auth_delay_checks;
59 | }
60 |
61 | // Called with extension unload.
62 | void _PG_fini(void)
63 | {
64 | // Return back the original hook value.
65 | ClientAuthentication_hook = original_client_auth_hook;
66 | }
67 |
68 | ```
69 |
--------------------------------------------------------------------------------
/templates/Header.md:
--------------------------------------------------------------------------------
1 | Unofficial documentation for PostgreSQL hooks.
2 |
3 | > *Denial of responsibility:*
4 | >
5 | > This work is not a part of the official PostgreSQL documentation.
6 | >
7 | > Contents of this repository were compiled by Begishev Nikita and
8 | > Goncharov Vladimir, neither of whom appear to be a developer or a maintainer
9 | > of the PostgreSQL Database Management System.
10 | >
11 | > Use this documentation at your own risk.
12 | >
13 | >
14 | > *Copyright notice:*
15 | >
16 | > This work combines some research made by contributors with
17 | > information acquired from the postgres source code, comments and
18 | > documentation. Some contents of this work were copied from source code
19 | > comments as is, others were written from scratch.
20 | >
21 | > In no way we (Begishev Nikita and Goncharov Vladimir) claim copyright on texts
22 | > that were copied or adapted from the sources described above.
23 | >
24 | > This work is distributed under the terms of the PostgreSQL License, a copy of
25 | > which may be found in the file called 'License.md'.
26 |
27 | PostgreSQL hooks are a simple way to extend functionality of the database.
28 | They allow extensions to introspect database state, react to events and
29 | interfere with database operations.
30 |
31 | In terms of the programming language, each hook is a pointer to a function
32 | of a specific type, initially set to be `NULL`.
33 |
34 | Upon init, database extensions are free to overwrite those function pointers
35 | with their own values. A previous value of the overwritten pointer is usually
36 | stored withing the extension local memory.
37 |
38 | During its work, postgres checks whether certain function pointers are not null
39 | and if that's the case, calls them.
40 |
41 | See the [detailed description](Detailed.md) for an explanation on
42 | how to implement a hook and an example.
43 |
--------------------------------------------------------------------------------
/templates/Hook.md:
--------------------------------------------------------------------------------
1 | Short description of this hook.
2 |
3 | Remember to mention when it's called, what should it do, what inputs supplied to this hook,
4 | what output is expected and (shortly) how postgres changes its behavior based on received output.
5 | It may be helpful to mention any common use-cases for this hook or some
6 | extensions that are using this hook.
7 |
8 | *Inputs:*
9 |
10 | {% if hook.type.inputs -%}
11 | Briefly describe hook inputs. Are inputs preprocessed somehow before calling the hook?
12 | Are there any special input states? Can they be null (e.g. `nullptr`)?
13 |
14 | {% for input in hook.type.inputs -%}
15 | * {{ input.type }} {{ input.name }} — ...
16 | {% endfor %}
17 | {%- else -%}
18 | There are no inputs for this hook. Is there a global state this hook should introspect?
19 | {%- endif %}
20 | *Output:*
21 |
22 | {% if hook.type.output != 'void' -%}
23 | Describe hook output. Are there any constraints for the output value?
24 | How postgres changes its behavior based on received output?
25 | Are there any special cases for output, e.g. returning `-1` or `nullptr`?
26 | Are there any mutable inputs this hook should change?
27 | {%- endif %}
28 |
--------------------------------------------------------------------------------
/templates/Readme.md:
--------------------------------------------------------------------------------
1 | # Postgresql hooks documentation
2 |
3 | {% include "templates/Header.md" %}
4 |
5 | {% for section in sections -%}
6 | * [{{ section.name }}](#{{ section.slug }})
7 | {% endfor %}
8 |
9 | {% for section in sections -%}
10 | ## [{{ section.name }}](Detailed.md#{{ section.slug }})
11 |
12 | {{ section.short_desc }}
13 |
14 | {% for hook in section.hooks -%}
15 | * [{{ hook.name }}](Detailed.md#{{ hook.name }}) — {{ make_short_description(hook) }}
16 | {% endfor %}
17 | {% endfor %}
18 |
--------------------------------------------------------------------------------
/templates/hooks/ClientAuthentication_hook.md:
--------------------------------------------------------------------------------
1 | Hook for controlling the authentication process.
2 |
3 | Called after finishing user authentication (regardless of whether authentication
4 | succeed or not).
5 |
6 | This hook will be called for every connection that passed authentication.
7 | However, it is not guaranteed to be called if there are issues with the
8 | connection itself. For example, SSL verification failure or pg_hba.conf
9 | check failure will close the connection without calling this hook.
10 |
11 | *Inputs:*
12 |
13 | * Port * port — full info about the connection and
14 | the connected user.
15 | * int status — a standard status code. `STATUS_OK` (`0`)
16 | if authentication successful.
17 |
--------------------------------------------------------------------------------
/templates/hooks/ExecutorCheckPerms_hook.md:
--------------------------------------------------------------------------------
1 | Hook for adding additional security checks on the per-relation level.
2 |
3 | Given a relations list, this hook should return `true` if access is granted.
4 | `false`, if access is not granted and `abort` is `false`. If `abort` is `true`
5 | and access is not granted, it should throw an appropriate error.
6 |
7 | This hook is not called if the standard permission check procedure denies
8 | access to any relation in the list. Therefore, there is no way to actually
9 | raise user privileges.
10 |
11 | Theoretically, only plain-relation RTEs need to be checked in this hook.
12 | Function RTEs are checked during the function preparation procedure.
13 | Join, subquery, and special RTEs need no checks.
14 |
15 | *Inputs:*
16 |
17 | * List * rangeTabls — list of `RangeTblEntry` objects that needs
18 | checking.
19 | * bool abort — if `true`, raise `aclcheck_error` instead of
20 | returning `false` from the hook.
21 |
22 | *Output:*
23 |
24 | `true` if user have privileges to access given relations, `false` or raise an
25 | error otherwise, depending on the `abort` flag.
26 |
--------------------------------------------------------------------------------
/templates/hooks/ExecutorEnd_hook.md:
--------------------------------------------------------------------------------
1 | Called at the end of execution of any query plan.
2 |
3 | * QueryDesc * queryDesc — query descriptor from the traffic cop.
4 |
--------------------------------------------------------------------------------
/templates/hooks/ExecutorFinish_hook.md:
--------------------------------------------------------------------------------
1 | Called after the last ExecutorRun call
2 |
3 | Replaces [standard_ExecutorFinish()](https://github.com/postgres/postgres/blob/src/backend/executor/execMain.c#L408)
4 |
5 | *Inputs:*
6 |
7 | * QueryDesc * queryDesc — query descriptor from the traffic cop.
--------------------------------------------------------------------------------
/templates/hooks/ExecutorRun_hook.md:
--------------------------------------------------------------------------------
1 | Called at any plan execution, after ExecutorStart.
2 |
3 | Replaces [standard_ExecutorRun()](https://github.com/postgres/postgres/blob/src/backend/executor/execMain.c#L308)
4 |
5 | *Inputs:*
6 |
7 | * QueryDesc * queryDesc — query descriptor from the traffic cop.
8 | * ScanDirection direction - if value is NoMovementScanDirection then nothing is done
9 | except to start up/shut down the destination.
10 | * uint64 count — count = 0 is interpreted as no portal limit, i.e.,
11 | run to completion. Also note that the count limit is only applied to
12 | retrieved tuples, not for instance to those inserted/updated/deleted by a ModifyTable plan node.
13 | * bool execute_once — becomes equal to true after first execution.
14 |
15 | *Output:*
16 |
17 | This hook should not provide any output. However output tuples (if any) are sent to
18 | the destination receiver specified in the QueryDesc.
19 | The number of tuples processed at the top level can be found in estate->es_processed.
--------------------------------------------------------------------------------
/templates/hooks/ExecutorStart_hook.md:
--------------------------------------------------------------------------------
1 | Called at the beginning of any execution of any query plan.
2 |
3 | Note: when it set, replaces the [standard_ExecutorStart()](https://github.com/postgres/postgres/blob/src/backend/executor/execMain.c#L149),
4 | which contains a lot of predefined logic.
5 | Consider inclusion of the standard executor to the hook handler
6 | if you assume adding your logic atop.
7 |
8 | *Inputs:*
9 |
10 | * QueryDesc * queryDesc — created by CreateQueryDesc,
11 | tupDesc field of the QueryDesc is filled in to describe the tuples that will be
12 | returned, and the internal fields (estate and planstate) are set up.
13 | * int eflags — contains flag bits as described in executor.h.
14 |
--------------------------------------------------------------------------------
/templates/hooks/ExplainOneQuery_hook.md:
--------------------------------------------------------------------------------
1 | Hook for overriding explain procedure for a single query.
2 |
3 | This hook, if present, should generate explanation for the given query
4 | using other `Explain*` functions and modifying the explain state.
5 |
6 | The default behaviour is to plan query using `pg_plan_query()` and than
7 | delegate printing to the `ExplainOnePlan()` function.
8 |
9 | *Inputs:*
10 |
11 | * Query * query — query that needs explanation.
12 | * int cursorOptions — cursor options in form of a per-bit enum.
13 | See `CURSOR_OPT_*` macros for detailed documentations.
14 | * IntoClause * into — target information for `SELECT INTO`,
15 | `CREATE TABLE AS`, and `CREATE MATERIALIZED VIEW`. `NULL` unless
16 | explaining the contents of a `CreateTableAsStmt`.
17 | * ExplainState * es — current explain state. The hook is free to
18 | modify it in order to produce output.
19 | * const char * queryString — an actual query string.
20 | * ParamListInfo params — plan parameters.
21 | * QueryEnvironment * queryEnv — context-specific values.
22 |
23 | *Output:*
24 |
25 | This hook does not produce any output.
26 |
27 |
--------------------------------------------------------------------------------
/templates/hooks/ProcessUtility_hook.md:
--------------------------------------------------------------------------------
1 | Hook for the ProcessUtility.
2 |
3 | Replaces [standard_ProcessUtility()](https://github.com/postgres/postgres/blob/src/backend/tcop/utility.c#L375)
4 |
5 | This hook should not provide any output.
6 |
7 | *Inputs:*
8 |
9 | * PlannedStmt * pstmt — PlannedStmt wrapper for the utility statement
10 | * const char * queryString — original source text of command,
11 | may be passed multiple times when processing a query string
12 | containing multiple semicolon-separated statements. pstmt->stmt_location and pstmt->stmt_len
13 | indicates the substring containing the current statement.
14 | * ProcessUtilityContext context — identifies source of statement
15 | (toplevel client command, non-toplevel client command, subcommand of a larger utility command)
16 | * ParamListInfo params — parameters of an execution.
17 | * QueryEnvironment * queryEnv — execution environment, optional, can be NULL.
18 | * DestReceiver * dest — results receiver.
19 | * char * completionTag — points to a buffer of size COMPLETION_TAG_BUFSIZE
20 | in which to store a command completion status string
--------------------------------------------------------------------------------
/templates/hooks/check_password_hook.md:
--------------------------------------------------------------------------------
1 | Hook for enforcing password constraints and performing action on password change.
2 |
3 | This hook is called whenever a new role is created via the `CREATE ROLE`
4 | statement or a password for an existing role is changed via the `ALTER ROLE`
5 | statement. Given a shadow password and some additional info, this hook can
6 | raise an error using the standard `ereport` mechanism if the password
7 | isn't strong enough.
8 |
9 | *Inputs:*
10 |
11 | * const char * username — name of the created/altered role.
12 | * const char * shadow_pass — a shadow pass, i.e. a plain password
13 | or a password hash.
14 | * PasswordType password_type — type of the password.
15 | `PASSWORD_TYPE_MD5` for an md5-encrypted password,
16 | `PASSWORD_TYPE_SCRAM_SHA_256` for a sha-256-encrypted password,
17 | `PASSWORD_TYPE_PLAINTEXT` for a plaintext password.
18 | * Datum validuntil_time — date upon which this password expires.
19 | * bool validuntil_null — a flag that is true if and only if
20 | the password have no expiration date (i.e. a null date is passed).
21 |
--------------------------------------------------------------------------------
/templates/hooks/create_upper_paths_hook.md:
--------------------------------------------------------------------------------
1 | Called when postprocess of the path of set operations occurs.
2 |
3 | It's a possibility for extensions to contribute path in relation.
4 |
5 | *Inputs:*
6 |
7 | * PlannerInfo * root — query plan root.
8 | * UpperRelationKind stage
9 | * RelOptInfo * input_rel
10 | * RelOptInfo * output_rel
--------------------------------------------------------------------------------
/templates/hooks/emit_log_hook.md:
--------------------------------------------------------------------------------
1 | Hook for intercepting messages before they are sent to the server log.
2 |
3 | This hook is called just before sending an error message to the server log
4 | and to the client. The purpose of this hook is to invoke an additional
5 | logic and possibly prevent this error message from being added to the
6 | server log.
7 |
8 | This hook is useful for implementing custom logging process.
9 |
10 | *Inputs:*
11 |
12 | * ErrorData * edata — a structure which holds a complete info
13 | about the error message. Despite `edata` is a non-const pointer, the only
14 | supported change in the given structure is setting `output_to_server` to
15 | `false`. That is, any other change, including setting `output_to_server` to
16 | `true`, considered not supported.
17 |
18 | Note: despite any other changes to the edata are not officially supported
19 | (as per comment [on line 1455 of the elog.c][emit_log_hook_1])),
20 | postgres actually checks for both `output_to_server` and `output_to_client`
21 | flags.
22 |
23 | [emit_log_hook_1]: https://github.com/postgres/postgres/blob/master/src/backend/utils/error/elog.c#L1456
24 |
--------------------------------------------------------------------------------
/templates/hooks/explain_get_index_name_hook.md:
--------------------------------------------------------------------------------
1 | Hook for altering index names in explain statements.
2 |
3 | Extensions may override the default name generation mechanism
4 | so that plans involving hypothetical indexes can be explained.
5 |
6 | *Inputs:*
7 |
8 | * Oid indexId — index id.
9 |
10 | *Output:*
11 |
12 | Name of the index or `NULL`. In the later case, a default name
13 | will be generated.
14 |
--------------------------------------------------------------------------------
/templates/hooks/fmgr_hook.md:
--------------------------------------------------------------------------------
1 | Hook for controlling function execution process.
2 |
3 | This hook is intended as support for loadable security policy modules, which may
4 | want to perform additional privilege checks on function entry or exit,
5 | or to do other internal bookkeeping.
6 |
7 | It is invoked whenever postgres executes a function which was explicitly
8 | marked as hookable by `needs_fmgr_hook`. For each execution this hook is fired
9 | exactly twice: first time before invoking the function, second time after
10 | the function returns/throws.
11 |
12 | Note that there is a change that this hook will be called even if a function
13 | is not of interest of your extension (maybe some other extension made it
14 | hookable via its `needs_fmgr_hook`).
15 |
16 | *Inputs:*
17 |
18 | * FmgrHookEventType event — event type, can be one of
19 | `FHET_START`, `FHET_END`, `FHET_ABORT`.
20 | * FmgrInfo * flinfo — function info, including its id and
21 | arguments specification.
22 | * Datum * arg — function arguments.
23 |
--------------------------------------------------------------------------------
/templates/hooks/func_beg.md:
--------------------------------------------------------------------------------
1 | Hook for intercepting post-init phase.
2 |
3 | This hook is called when we start PLpgSQL function, after we've initialized
4 | the local variables.
5 | The hook can be used for pre-validation of a function arguments.
6 |
7 | *Inputs:*
8 |
9 | * PLpgSQL_execstate * estate — runtime execution data.
10 | * PLpgSQL_function * func — PLpgSQL compiled function.
--------------------------------------------------------------------------------
/templates/hooks/func_end.md:
--------------------------------------------------------------------------------
1 | Hook for intercepting end of a function.
2 |
3 | This hook is called at the end of PLpgSQL function.
4 | Can be used as a function callback.
5 |
6 | *Inputs:*
7 |
8 | * PLpgSQL_execstate * estate — runtime execution data.
9 | * PLpgSQL_function * func — PLpgSQL compiled function.
--------------------------------------------------------------------------------
/templates/hooks/func_setup.md:
--------------------------------------------------------------------------------
1 | Hook for intercepting PLpgSQL function pre-init phase.
2 |
3 | This hook is called when we start a function before we've initialized
4 | the local variables defined by the function.
5 | Can be useful for time measuring of а function initialization in tandem
6 | with [func_beg()](Detailed.md#func_beg) and for measuring total execution time
7 | with the help of [func_end()](Detailed.md#func_end).
8 |
9 | Before any call to func_setup, PLpgSQL fills in the error_callback
10 | and assign_expr fields with pointers to its own plpgsql_exec_error_callback
11 | and exec_assign_expr functions.
12 |
13 | *Inputs:*
14 |
15 | * PLpgSQL_execstate * estate — runtime execution data.
16 | * PLpgSQL_function * func — PLpgSQL compiled function.
--------------------------------------------------------------------------------
/templates/hooks/get_attavgwidth_hook.md:
--------------------------------------------------------------------------------
1 | Hook for controlling an algorithm for predicting the average width of entries in the column.
2 |
3 | This hook, if set, should return the average width of entries in the column.
4 | If returned value is greater than `0`, it is returned to the planner.
5 | Otherwise, the default algorithm is invoked.
6 |
7 | *Inputs:*
8 |
9 | * Oid relid — relation id.
10 | * AttrNumber attnum — column number.
11 |
12 | *Output:*
13 |
14 | Average width of entries in the given column of the given relation or zero
15 | to fall back to the default algorithm.
16 |
--------------------------------------------------------------------------------
/templates/hooks/get_index_stats_hook.md:
--------------------------------------------------------------------------------
1 | Hook for overriding index stats lookup.
2 |
3 | Given the planner state and an index, the hook should decide if it can provide
4 | any useful stats. If yes, it should supply a `statsTuple` and a `freefunc` and
5 | return `true`. If no, it should return `false`.
6 |
7 | Note that `freefunc` must be set if `statsTuple` is set.
8 |
9 | Note also that `vardata` should not be changed if `false` is returned.
10 | Postgres will not check whether `statsTuple` and `freefunc` are set.
11 | It will simply overwrite them.
12 |
13 | *Inputs:*
14 |
15 | * PlannerInfo * root — current planner info.
16 | * Oid indexOid — id of the index that we are looking stats for.
17 | * AttrNumber indexattnum — index column.
18 | * VariableStatData * vardata — container for the return value.
19 |
--------------------------------------------------------------------------------
/templates/hooks/get_relation_info_hook.md:
--------------------------------------------------------------------------------
1 | Hook for altering results of the relation info lookup.
2 |
3 | This hook allow plugins to editorialize on the info that was obtained from the
4 | catalogs by the default relation info lookup. Actions might include altering
5 | the assumed relation size, removing an index, or adding a hypothetical
6 | index to the `indexlist`.
7 |
8 | *Inputs:*
9 |
10 | * PlannerInfo * root — current planner info.
11 | * Oid relationObjectId — id of the relation that we are looking
12 | info for.
13 | * bool inhparent — if true, all we need to do is set up the attr
14 | arrays: the `RelOptInfo` actually represents the `appendrel` formed by an
15 | inheritance tree, and so the parent rel's physical size and index information
16 | isn't important for it.
17 | * RelOptInfo * rel — relation info that can be adjusted.
18 |
--------------------------------------------------------------------------------
/templates/hooks/get_relation_stats_hook.md:
--------------------------------------------------------------------------------
1 | Hook for overriding relation stats lookup.
2 |
3 | Similar to `get_index_stats_hook`, this hook should either return `false`
4 | or take control over relation stats lookup, write output the the `vardata`
5 | container, and return `true`.
6 |
7 | See `get_index_stats_hook` for more details.
8 |
9 | *Inputs:*
10 |
11 | * PlannerInfo * root — current planner info.
12 | * Oid indexOid — id of the index that we are looking stats for.
13 | * AttrNumber indexattnum — index column.
14 | * VariableStatData * vardata — container for the return value.
15 |
--------------------------------------------------------------------------------
/templates/hooks/join_search_hook.md:
--------------------------------------------------------------------------------
1 | Called when optimiser chooses order for join relations.
2 |
3 | When the hook is set, replaces GEQO or standard join search.
4 |
5 | *Inputs:*
6 |
7 | * PlannerInfo * root — query plan root.
8 | * int levels_needed — the number of child joinlist nodes.
9 | * List * initial_rels — list of join relations.
--------------------------------------------------------------------------------
/templates/hooks/needs_fmgr_hook.md:
--------------------------------------------------------------------------------
1 | Auxiliary hook which decides whether `fmgr_hook` should be applied to a function.
2 |
3 | Given a function id, decide whether `fmgr_hook` should be called upon executing
4 | this function.
5 |
6 | The result of this hook should be combined with the result of a previously
7 | registered `needs_fmgr_hook` via the `OR` clause. This is required to ensure
8 | that other extensions can hook function even though this very extension does
9 | not hook them. Such behavior is vital for proper work of the security extensions.
10 |
11 | Note that hooked functions are not inlined.
12 |
13 | *Inputs:*
14 |
15 | * Oid fn_oid — id of a function which needs hooking.
16 |
17 | *Output:*
18 |
19 | Return `true` if you want to hook enter/exit event for this function.
20 |
--------------------------------------------------------------------------------
/templates/hooks/object_access_hook.md:
--------------------------------------------------------------------------------
1 | Hook to monitor accesses to objects.
2 |
3 | Object access hooks are called just before or just after performing certain
4 | actions on an SQL object. This is intended as infrastructure for security
5 | or logging extensions.
6 |
7 | There are several types of actions defined in `ObjectAccessType`:
8 |
9 | `OAT_POST_CREATE`: hook is invoked just after the object is created.
10 | Typically, this is done after inserting the primary catalog records and
11 | associated dependencies.
12 |
13 | `OAT_DROP`: hook is invoked just before deletion of objects.
14 |
15 | `OAT_POST_ALTER`: hook is invoked just after the object is altered,
16 | but before the command counter is incremented. An extension using the
17 | hook can use a current MVCC snapshot to get the old version of the tuple,
18 | and can use `SnapshotSelf` to get the new version of the tuple.
19 |
20 | `OAT_NAMESPACE_SEARCH`: hook is invoked prior to object name lookup under
21 | a particular namespace. This event is equivalent to usage permission
22 | on a schema under the default access control mechanism.
23 |
24 | `OAT_FUNCTION_EXECUTE`: hook is invoked prior to function execution.
25 | This event is almost equivalent to execute permission on functions,
26 | except for the case when execute permission is checked during object
27 | creation or altering, because `OAT_POST_CREATE` or `OAT_POST_ALTER` are
28 | sufficient for extensions to track these kind of checks.
29 |
30 | Other types may be added in the future.
31 |
32 | *Inputs:*
33 |
34 | For different access types, inputs of this hook mean different things.
35 |
36 | * ObjectAccessType access — access type.
37 | * Oid classId — id of a relation which contains this object.
38 | You can determine type of an object by this parameter.
39 | * Oid objectId — object that is being accessed.
40 | * int subId — subitem within object (e.g. column), or 0.
41 | * void * arg — access type specific argument.
42 |
43 | For `OAT_POST_CREATE`, `arg` is a pointer to `ObjectAccessPostCreate`
44 | structure, which contain a single field, namely `is_internal`. This field
45 | describes whether the context of this creation is invoked by user's
46 | operations, or not. As for `subId`, I've counted two cases when it's non-zero.
47 | The first is when creating a column, and the second one is when creating
48 | a default expression on a column. In either case, `subId` is
49 | an `AttrNumber` of a column.
50 |
51 | For `OAT_DROP` type, `arg` is a pointer to `ObjectAccessPostCreate` structure.
52 | It contains a single field called `dropflags`. They inform extensions the
53 | context of this deletion.
54 |
55 | For `OAT_POST_ALTER` type, `arg` is a pointer to `ObjectAccessPostAlter`
56 | structure. It contains an `is_internal` flag (see `OAT_POST_CREATE`) and an
57 | `auxiliary_id`. The latter is used when system catalog takes two IDs to
58 | identify a particular tuple of the catalog. It is only used when the caller want
59 | to identify an entry of pg_inherits, pg_db_role_setting or pg_user_mapping.
60 | Elsewhere, InvalidOid is be set.
61 |
62 | For `OAT_NAMESPACE_SEARCH` type, `subId` is unused, `classId` is always
63 | `NamespaceRelationId`, and `arg` is a pointer to `ObjectAccessNamespaceSearch`.
64 |
65 | `ObjectAccessNamespaceSearch` structure contain two fields. The first one,
66 | `ereport_on_violation`, indicates that the hook should raise an error when
67 | permission to search this schema is denied. The second one, `result`, is in fact
68 | an out parameter. Core code should initialize this to true, and any extension
69 | that wants to deny access should reset it to false. But an extension should be
70 | careful never to store a true value here, so that in case there are multiple
71 | extensions access is only allowed if all extensions agree.
72 |
73 | For `OAT_FUNCTION_EXECUTE` type, `subId` and `arg` are unused, and
74 | `classId` is always `ProcedureRelationId`.
75 |
--------------------------------------------------------------------------------
/templates/hooks/planner_hook.md:
--------------------------------------------------------------------------------
1 | Called in query optimizer entry point.
2 |
3 | If set, replaces standard planner. Consider inclusion of the standard planner to hook
4 | if this hook assuming just pre-process or post-process for builtin planner.
5 |
6 | *Inputs:*
7 |
8 | * Query * parse — parsed query text.
9 | * const char * query_string — original query text.
10 | * int cursorOptions
11 | * ParamListInfo boundParams
12 |
--------------------------------------------------------------------------------
/templates/hooks/post_parse_analyze_hook.md:
--------------------------------------------------------------------------------
1 | Called when parse analyze goes, right after performing transformTopLevelStmt().
2 |
3 | Used in several internal methods:
4 | [pg_analyze_and_rewrite_params()](https://github.com/postgres/postgres/blob/src/backend/tcop/postgres.c#L686),
5 | [parse_analyze()](https://github.com/postgres/postgres/blob/src/backend/parser/analyze.c#L100).
6 |
7 | *Inputs:*
8 |
9 | * ParseState * pstate — parse state filled by query_string and queryEnv.
10 | * Query * query — output result of the transformTopLevelStmt().
--------------------------------------------------------------------------------
/templates/hooks/row_security_policy_hook_permissive.md:
--------------------------------------------------------------------------------
1 | Hook to add policies which are combined with the other permissive policies.
2 |
3 | This hook, along with the `row_security_policy_hook_restrictive`, allows adding
4 | custom security policies. It is called to build a list of policies for the given
5 | command applied to the given relation.
6 |
7 | Access is granted to an object if and only if no restrictive policies deny
8 | access and any permissive policy grant access.
9 |
10 | *Inputs:*
11 |
12 | * CmdType cmdtype — command type.
13 | * Relation relation — relation id.
14 |
15 | *Output:*
16 |
17 | List of additional permissive policies that will be added to the list of
18 | default permissive policies.
19 |
--------------------------------------------------------------------------------
/templates/hooks/row_security_policy_hook_restrictive.md:
--------------------------------------------------------------------------------
1 | Hook to add policies which are enforced, regardless of other policies.
2 |
3 | See `row_security_policy_hook_permissive` for a detailed description.
4 |
5 | Unlike for permissive policies, postgres guarantees that restrictive policies
6 | will be executed in a predefined order. That is, first postgres executes the
7 | default policies sorted by their name, than postgres executes custom policies,
8 | also sorted by their name.
9 |
10 | *Inputs:*
11 |
12 | * CmdType cmdtype — command type.
13 | * Relation relation — relation id.
14 |
--------------------------------------------------------------------------------
/templates/hooks/set_join_pathlist_hook.md:
--------------------------------------------------------------------------------
1 | Called at the end of the process of joinrel modification to contain the best paths.
2 |
3 | The hook can manipulate path list to perform a postprocess for best paths.
4 |
5 | *Inputs:*
6 |
7 | * PlannerInfo * root — query plan root.
8 | * RelOptInfo * joinrel — list of paths.
9 | * RelOptInfo * outerrel - list of outer relation paths.
10 | * RelOptInfo * innerrel - list of inner relation paths.
11 | * JoinType jointype - the type of a join.
12 | * JoinPathExtraData * extra
13 |
--------------------------------------------------------------------------------
/templates/hooks/set_rel_pathlist_hook.md:
--------------------------------------------------------------------------------
1 | Called at the end of building access paths for a base relation.
2 |
3 | The hook can apply changes to set of paths by adding new paths or deleting them.
4 |
5 | *Inputs:*
6 |
7 | * PlannerInfo * root
8 | * RelOptInfo * rel - relation info.
9 | * Index rti - range table index.
10 | * RangeTblEntry * rte range table entry.
--------------------------------------------------------------------------------
/templates/hooks/shmem_startup_hook.md:
--------------------------------------------------------------------------------
1 | Hook for extensions to initialize their shared memory.
2 |
3 | This hook is called by postmaster or by a standalone backend
4 | right after postgres initializes its shared memory and semaphores
5 | so that extensions have chance to initialize their shared state.
6 |
7 | It also may be called by a backend forked from the postmaster.
8 | In this situation, the shared memory segment already exists, so you only have
9 | to initialize the local memory state (check `!IsUnderPostmaster`
10 | to determine if that's the case).
11 |
12 | Note that you can bind a callback for shared state teardown
13 | via `on_shmem_exit`.
14 |
15 | Check out the `pg_stat_statements` code to get the idea on how to implement
16 | this hook correctly.
17 |
--------------------------------------------------------------------------------
/templates/hooks/stmt_beg.md:
--------------------------------------------------------------------------------
1 | Called before each statement of a function.
2 |
3 | *Inputs:*
4 |
5 | * PLpgSQL_execstate * estate — runtime execution data.
6 | * PLpgSQL_stmt * stmt — execution node.
--------------------------------------------------------------------------------
/templates/hooks/stmt_end.md:
--------------------------------------------------------------------------------
1 | Called after each statement of a function.
2 |
3 | *Inputs:*
4 |
5 | * PLpgSQL_execstate * estate — runtime execution data.
6 | * PLpgSQL_stmt * stmt — execution node.
--------------------------------------------------------------------------------