1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! The guard that lets `pg_tviews` run its own DDL through the `ProcessUtility`
//! hook unhandled.
use pg_sys;
/// Set while `pg_tviews` runs its own work for a statement (an [`InternalDdl`] is
/// alive): the DDL it issues through SPI reaches the hook again and must pass
/// through unhandled. Never set while a user's statement runs, so DDL nested in
/// it (a function called by `EXECUTE` or `CREATE TABLE AS`) is intercepted.
static mut HOOK_IN_PROGRESS: bool = false;
/// Transaction nest level at which `HOOK_IN_PROGRESS` was set, so a (sub)transaction abort
/// that unwinds past the hook can release a guard the hook never got to reset.
static mut HOOK_GUARD_LEVEL: i32 = 0;
/// While alive, statements `pg_tviews` runs pass through the hook unhandled. The
/// hook holds one while it works on a statement (never while the statement
/// itself runs), and `pg_tviews` around its own `GRANT`s and owner changes, which
/// the hook would otherwise follow mid-way. Released when dropped, also when an
/// error unwinds past it.
pub
/// Release the reentrancy guard if the hook invocation that took it was aborted.
///
/// An `ereport(ERROR)` raised while the hook runs a statement (e.g. a CTAS inside a DO
/// block failing with "already exists", caught by the block's EXCEPTION clause) longjmps
/// past the hook before it can reset `HOOK_IN_PROGRESS`. The guard is released here when
/// the aborting (sub)transaction is at or above the level that took it; a guard taken by an
/// enclosing, still-running hook invocation (lower level) is left alone.
/// `whole_xact` is true for a top-level transaction abort. No SPI: safe in callbacks.