Statement-level enforcement¶
ProcessUtility_hook is a global function pointer PostgreSQL consults for every statement that is not a plain query. This extension uses it for two things.
Creation-time handling of the options¶
permissions and retention are not registered reloptions — they cannot be, for reasons covered in How Options Are Stored. So the hook removes them from the statement before PostgreSQL sees it, validates them itself, and writes the accepted values to the catalogue once the table exists.
This is also where creation-time validation happens: unknown permission names, empty lists, insert with insertonce, retention below 1, a vault table with no permissions, the options on a non-vault table, and any combination of vault with partitioning.
A useful side effect: without the library loaded, CREATE TABLE ... WITH (permissions = ...) fails as an unrecognised parameter. A vault table cannot be created by a server that is not in a position to enforce anything about it.
Refusing ALTER TABLE¶
This must happen in the statement hook rather than the object hook, because OAT_POST_ALTER fires after the fact — and ALTER TABLE ... SET ACCESS METHOD heap has to be stopped before the rewrite begins.
"ALTER TABLE" is three node types¶
The manual's ALTER TABLE is not one thing in the parser:
| Statement | Node |
|---|---|
ALTER TABLE ... OWNER TO, SET ACCESS METHOD, ADD COLUMN … |
AlterTableStmt |
ALTER TABLE ... RENAME |
RenameStmt |
ALTER TABLE ... SET SCHEMA |
AlterObjectSchemaStmt |
Covering only the first leaves a vault table renameable and movable between schemas.
Internally generated subcommands are exempt¶
PostgreSQL builds its own AlterTableStmt for work done on a table's behalf — adding a REFERENCES constraint named in CREATE TABLE, for one — and routes it back through ProcessUtility with PROCESS_UTILITY_SUBCOMMAND.
Refusing those makes a vault table with a foreign key impossible to create. Only that context is exempt: a statement written inside a function arrives as PROCESS_UTILITY_QUERY and is still refused.
Two permitted forms¶
OWNER TO and ADD CONSTRAINT are accepted, because pg_dump emits both and without them a backup cannot be restored. A statement mixing either with anything else is refused whole.
Neither reaches the data. An owner cannot exceed the table's permissions, and a constraint can only restrict what may be stored.
What is deliberately not intercepted¶
COMMENT ON and GRANT/REVOKE pass straight through.
Enforcement sits below PostgreSQL's permission system, so a GRANT cannot widen what the access method allows. The most it can do is let a broader set of roles attempt something that is still refused.