mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Event Trigger for table_rewrite
Generate a table_rewrite event when ALTER TABLE attempts to rewrite a table. Provide helper functions to identify table and reason. Intended use case is to help assess or to react to schema changes that might hold exclusive locks for long periods. Dimitri Fontaine, triggering an edit by Simon Riggs Reviewed in detail by Michael Paquier
This commit is contained in:
parent
b8e33a85d4
commit
618c9430a8
@ -64,6 +64,16 @@
|
|||||||
system catalogs, so it's not possible to look them up anymore.
|
system catalogs, so it's not possible to look them up anymore.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <literal>table_rewrite</> event occurs just before a table is
|
||||||
|
rewritten by the command <literal>ALTER TABLE</literal>. While other
|
||||||
|
control statements are available to rewrite a table,
|
||||||
|
like <literal>CLUSTER</literal> and <literal>VACUUM</literal>,
|
||||||
|
the <literal>table_rewrite</> event is currently only triggered by
|
||||||
|
the <literal>ALTER TABLE</literal> command, and only when that command
|
||||||
|
attempts to rewrite the table.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Event triggers (like other functions) cannot be executed in an aborted
|
Event triggers (like other functions) cannot be executed in an aborted
|
||||||
transaction. Thus, if a DDL command fails with an error, any associated
|
transaction. Thus, if a DDL command fails with an error, any associated
|
||||||
@ -120,6 +130,7 @@
|
|||||||
<entry><literal>ddl_command_start</literal></entry>
|
<entry><literal>ddl_command_start</literal></entry>
|
||||||
<entry><literal>ddl_command_end</literal></entry>
|
<entry><literal>ddl_command_end</literal></entry>
|
||||||
<entry><literal>sql_drop</literal></entry>
|
<entry><literal>sql_drop</literal></entry>
|
||||||
|
<entry><literal>table_rewrite</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -128,510 +139,595 @@
|
|||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER COLLATION</literal></entry>
|
<entry align="left"><literal>ALTER COLLATION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER CONVERSION</literal></entry>
|
<entry align="left"><literal>ALTER CONVERSION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER DOMAIN</literal></entry>
|
<entry align="left"><literal>ALTER DOMAIN</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER EXTENSION</literal></entry>
|
<entry align="left"><literal>ALTER EXTENSION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER FOREIGN DATA WRAPPER</literal></entry>
|
<entry align="left"><literal>ALTER FOREIGN DATA WRAPPER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER FOREIGN TABLE</literal></entry>
|
<entry align="left"><literal>ALTER FOREIGN TABLE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER FUNCTION</literal></entry>
|
<entry align="left"><literal>ALTER FUNCTION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER LANGUAGE</literal></entry>
|
<entry align="left"><literal>ALTER LANGUAGE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER OPERATOR</literal></entry>
|
<entry align="left"><literal>ALTER OPERATOR</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER OPERATOR CLASS</literal></entry>
|
<entry align="left"><literal>ALTER OPERATOR CLASS</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER OPERATOR FAMILY</literal></entry>
|
<entry align="left"><literal>ALTER OPERATOR FAMILY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER POLICY</literal></entry>
|
<entry align="left"><literal>ALTER POLICY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER SCHEMA</literal></entry>
|
<entry align="left"><literal>ALTER SCHEMA</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER SEQUENCE</literal></entry>
|
<entry align="left"><literal>ALTER SEQUENCE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER SERVER</literal></entry>
|
<entry align="left"><literal>ALTER SERVER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER TABLE</literal></entry>
|
<entry align="left"><literal>ALTER TABLE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>X</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER TEXT SEARCH CONFIGURATION</literal></entry>
|
<entry align="left"><literal>ALTER TEXT SEARCH CONFIGURATION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER TEXT SEARCH DICTIONARY</literal></entry>
|
<entry align="left"><literal>ALTER TEXT SEARCH DICTIONARY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER TEXT SEARCH PARSER</literal></entry>
|
<entry align="left"><literal>ALTER TEXT SEARCH PARSER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER TEXT SEARCH TEMPLATE</literal></entry>
|
<entry align="left"><literal>ALTER TEXT SEARCH TEMPLATE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER TRIGGER</literal></entry>
|
<entry align="left"><literal>ALTER TRIGGER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER TYPE</literal></entry>
|
<entry align="left"><literal>ALTER TYPE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER USER MAPPING</literal></entry>
|
<entry align="left"><literal>ALTER USER MAPPING</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>ALTER VIEW</literal></entry>
|
<entry align="left"><literal>ALTER VIEW</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE AGGREGATE</literal></entry>
|
<entry align="left"><literal>CREATE AGGREGATE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE CAST</literal></entry>
|
<entry align="left"><literal>CREATE CAST</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE COLLATION</literal></entry>
|
<entry align="left"><literal>CREATE COLLATION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE CONVERSION</literal></entry>
|
<entry align="left"><literal>CREATE CONVERSION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE DOMAIN</literal></entry>
|
<entry align="left"><literal>CREATE DOMAIN</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE EXTENSION</literal></entry>
|
<entry align="left"><literal>CREATE EXTENSION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE FOREIGN DATA WRAPPER</literal></entry>
|
<entry align="left"><literal>CREATE FOREIGN DATA WRAPPER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE FOREIGN TABLE</literal></entry>
|
<entry align="left"><literal>CREATE FOREIGN TABLE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE FUNCTION</literal></entry>
|
<entry align="left"><literal>CREATE FUNCTION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE INDEX</literal></entry>
|
<entry align="left"><literal>CREATE INDEX</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE LANGUAGE</literal></entry>
|
<entry align="left"><literal>CREATE LANGUAGE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE OPERATOR</literal></entry>
|
<entry align="left"><literal>CREATE OPERATOR</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE OPERATOR CLASS</literal></entry>
|
<entry align="left"><literal>CREATE OPERATOR CLASS</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE OPERATOR FAMILY</literal></entry>
|
<entry align="left"><literal>CREATE OPERATOR FAMILY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE POLICY</literal></entry>
|
<entry align="left"><literal>CREATE POLICY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE RULE</literal></entry>
|
<entry align="left"><literal>CREATE RULE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE SCHEMA</literal></entry>
|
<entry align="left"><literal>CREATE SCHEMA</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE SEQUENCE</literal></entry>
|
<entry align="left"><literal>CREATE SEQUENCE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE SERVER</literal></entry>
|
<entry align="left"><literal>CREATE SERVER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TABLE</literal></entry>
|
<entry align="left"><literal>CREATE TABLE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TABLE AS</literal></entry>
|
<entry align="left"><literal>CREATE TABLE AS</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TEXT SEARCH CONFIGURATION</literal></entry>
|
<entry align="left"><literal>CREATE TEXT SEARCH CONFIGURATION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TEXT SEARCH DICTIONARY</literal></entry>
|
<entry align="left"><literal>CREATE TEXT SEARCH DICTIONARY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TEXT SEARCH PARSER</literal></entry>
|
<entry align="left"><literal>CREATE TEXT SEARCH PARSER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TEXT SEARCH TEMPLATE</literal></entry>
|
<entry align="left"><literal>CREATE TEXT SEARCH TEMPLATE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TRIGGER</literal></entry>
|
<entry align="left"><literal>CREATE TRIGGER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE TYPE</literal></entry>
|
<entry align="left"><literal>CREATE TYPE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE USER MAPPING</literal></entry>
|
<entry align="left"><literal>CREATE USER MAPPING</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>CREATE VIEW</literal></entry>
|
<entry align="left"><literal>CREATE VIEW</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP AGGREGATE</literal></entry>
|
<entry align="left"><literal>DROP AGGREGATE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP CAST</literal></entry>
|
<entry align="left"><literal>DROP CAST</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP COLLATION</literal></entry>
|
<entry align="left"><literal>DROP COLLATION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP CONVERSION</literal></entry>
|
<entry align="left"><literal>DROP CONVERSION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP DOMAIN</literal></entry>
|
<entry align="left"><literal>DROP DOMAIN</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP EXTENSION</literal></entry>
|
<entry align="left"><literal>DROP EXTENSION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP FOREIGN DATA WRAPPER</literal></entry>
|
<entry align="left"><literal>DROP FOREIGN DATA WRAPPER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP FOREIGN TABLE</literal></entry>
|
<entry align="left"><literal>DROP FOREIGN TABLE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP FUNCTION</literal></entry>
|
<entry align="left"><literal>DROP FUNCTION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP INDEX</literal></entry>
|
<entry align="left"><literal>DROP INDEX</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP LANGUAGE</literal></entry>
|
<entry align="left"><literal>DROP LANGUAGE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP OPERATOR</literal></entry>
|
<entry align="left"><literal>DROP OPERATOR</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP OPERATOR CLASS</literal></entry>
|
<entry align="left"><literal>DROP OPERATOR CLASS</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP OPERATOR FAMILY</literal></entry>
|
<entry align="left"><literal>DROP OPERATOR FAMILY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP OWNED</literal></entry>
|
<entry align="left"><literal>DROP OWNED</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP POLICY</literal></entry>
|
<entry align="left"><literal>DROP POLICY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP RULE</literal></entry>
|
<entry align="left"><literal>DROP RULE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP SCHEMA</literal></entry>
|
<entry align="left"><literal>DROP SCHEMA</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP SEQUENCE</literal></entry>
|
<entry align="left"><literal>DROP SEQUENCE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP SERVER</literal></entry>
|
<entry align="left"><literal>DROP SERVER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP TABLE</literal></entry>
|
<entry align="left"><literal>DROP TABLE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP TEXT SEARCH CONFIGURATION</literal></entry>
|
<entry align="left"><literal>DROP TEXT SEARCH CONFIGURATION</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP TEXT SEARCH DICTIONARY</literal></entry>
|
<entry align="left"><literal>DROP TEXT SEARCH DICTIONARY</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP TEXT SEARCH PARSER</literal></entry>
|
<entry align="left"><literal>DROP TEXT SEARCH PARSER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP TEXT SEARCH TEMPLATE</literal></entry>
|
<entry align="left"><literal>DROP TEXT SEARCH TEMPLATE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP TRIGGER</literal></entry>
|
<entry align="left"><literal>DROP TRIGGER</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP TYPE</literal></entry>
|
<entry align="left"><literal>DROP TYPE</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP USER MAPPING</literal></entry>
|
<entry align="left"><literal>DROP USER MAPPING</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>DROP VIEW</literal></entry>
|
<entry align="left"><literal>DROP VIEW</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>IMPORT FOREIGN SCHEMA</literal></entry>
|
<entry align="left"><literal>IMPORT FOREIGN SCHEMA</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry align="left"><literal>SELECT INTO</literal></entry>
|
<entry align="left"><literal>SELECT INTO</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>X</literal></entry>
|
<entry align="center"><literal>X</literal></entry>
|
||||||
<entry align="center"><literal>-</literal></entry>
|
<entry align="center"><literal>-</literal></entry>
|
||||||
|
<entry align="center"><literal>-</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
@ -843,4 +939,58 @@ COMMIT;
|
|||||||
event triggers.)
|
event triggers.)
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="event-trigger-table-rewrite-example">
|
||||||
|
<title>A Table Rewrite Event Trigger Example</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Thanks to the <literal>table_rewrite</> event, it is possible to implement
|
||||||
|
a table rewriting policy only allowing the rewrite in maintenance windows.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here's an example implementing such a policy.
|
||||||
|
<programlisting>
|
||||||
|
CREATE OR REPLACE FUNCTION no_rewrite()
|
||||||
|
RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql AS
|
||||||
|
$$
|
||||||
|
---
|
||||||
|
--- Implement local Table Rewriting policy:
|
||||||
|
--- public.foo is not allowed rewriting, ever
|
||||||
|
--- other tables are only allowed rewriting between 1am and 6am
|
||||||
|
--- unless they have more than 100 blocks
|
||||||
|
---
|
||||||
|
DECLARE
|
||||||
|
table_oid oid := pg_event_trigger_table_rewrite_oid();
|
||||||
|
current_hour integer := extract('hour' from current_time);
|
||||||
|
pages integer;
|
||||||
|
max_pages integer := 100;
|
||||||
|
BEGIN
|
||||||
|
IF pg_event_trigger_table_rewrite_oid() = 'public.foo'::regclass
|
||||||
|
THEN
|
||||||
|
RAISE EXCEPTION 'you''re not allowed to rewrite the table %',
|
||||||
|
table_oid::regclass;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT INTO pages relpages FROM pg_class WHERE oid = table_oid;
|
||||||
|
IF pages > max_pages
|
||||||
|
THEN
|
||||||
|
RAISE EXCEPTION 'rewrites only allowed for table with less than % pages',
|
||||||
|
max_pages;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF current_hour NOT BETWEEN 1 AND 6
|
||||||
|
THEN
|
||||||
|
RAISE EXCEPTION 'rewrites only allowed between 1am and 6am';
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE EVENT TRIGGER no_rewrite_allowed
|
||||||
|
ON table_rewrite
|
||||||
|
EXECUTE PROCEDURE no_rewrite();
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
@ -17607,15 +17607,23 @@ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
|
|||||||
<sect1 id="functions-event-triggers">
|
<sect1 id="functions-event-triggers">
|
||||||
<title>Event Trigger Functions</title>
|
<title>Event Trigger Functions</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<productname>PostgreSQL</> provides these helper functions
|
||||||
|
to retrieve information from event triggers.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For more information about event triggers,
|
||||||
|
see <xref linkend="event-triggers">.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2 id="pg-event-trigger-sql-drop-functions">
|
||||||
|
<title>Processing objects dropped by a DDL command.</title>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>pg_event_trigger_dropped_objects</primary>
|
<primary>pg_event_trigger_dropped_objects</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
|
||||||
Currently <productname>PostgreSQL</> provides one built-in event trigger
|
|
||||||
helper function, <function>pg_event_trigger_dropped_objects</>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<function>pg_event_trigger_dropped_objects</> returns a list of all objects
|
<function>pg_event_trigger_dropped_objects</> returns a list of all objects
|
||||||
dropped by the command in whose <literal>sql_drop</> event it is called.
|
dropped by the command in whose <literal>sql_drop</> event it is called.
|
||||||
@ -17709,11 +17717,72 @@ CREATE EVENT TRIGGER test_event_trigger_for_drops
|
|||||||
EXECUTE PROCEDURE test_event_trigger_for_drops();
|
EXECUTE PROCEDURE test_event_trigger_for_drops();
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="pg-event-trigger-table-rewrite-functions">
|
||||||
|
<title>Handling a Table Rewrite Event</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For more information about event triggers,
|
The functions shown in
|
||||||
see <xref linkend="event-triggers">.
|
<xref linkend="functions-event-trigger-table-rewrite">
|
||||||
|
provide information about a table for which a
|
||||||
|
<literal>table_rewrite</> event has just been called.
|
||||||
|
If called in any other context, an error is raised.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<table id="functions-event-trigger-table-rewrite">
|
||||||
|
<title>Table Rewrite information</title>
|
||||||
|
<tgroup cols="3">
|
||||||
|
<thead>
|
||||||
|
<row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<indexterm><primary>pg_event_trigger_table_rewrite_oid</primary></indexterm>
|
||||||
|
<literal><function>pg_event_trigger_table_rewrite_oid()</function></literal>
|
||||||
|
</entry>
|
||||||
|
<entry><type>Oid</type></entry>
|
||||||
|
<entry>The Oid of the table about to be rewritten.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<indexterm><primary>pg_event_trigger_table_rewrite_reason</primary></indexterm>
|
||||||
|
<literal><function>pg_event_trigger_table_rewrite_reason()</function></literal>
|
||||||
|
</entry>
|
||||||
|
<entry><type>int</type></entry>
|
||||||
|
<entry>
|
||||||
|
The reason code(s) explaining the reason for rewriting. The exact
|
||||||
|
meaning of the codes is release dependent.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <function>pg_event_trigger_table_rewrite_oid</> function can be used
|
||||||
|
in an event trigger like this:
|
||||||
|
<programlisting>
|
||||||
|
CREATE FUNCTION test_event_trigger_table_rewrite_oid()
|
||||||
|
RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql AS
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
RAISE NOTICE 'rewriting table % for reason %',
|
||||||
|
pg_event_trigger_table_rewrite_oid()::regclass,
|
||||||
|
pg_event_trigger_table_rewrite_reason();
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE EVENT TRIGGER test_table_rewrite_oid
|
||||||
|
ON table_rewrite
|
||||||
|
EXECUTE PROCEDURE test_event_trigger_table_rewrite_oid();
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
@ -42,11 +42,16 @@
|
|||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "tcop/utility.h"
|
#include "tcop/utility.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct EventTriggerQueryState
|
typedef struct EventTriggerQueryState
|
||||||
{
|
{
|
||||||
|
/* sql_drop */
|
||||||
slist_head SQLDropList;
|
slist_head SQLDropList;
|
||||||
bool in_sql_drop;
|
bool in_sql_drop;
|
||||||
|
|
||||||
|
/* table_rewrite */
|
||||||
|
Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite event */
|
||||||
|
int table_rewrite_reason; /* AT_REWRITE reason */
|
||||||
|
|
||||||
MemoryContext cxt;
|
MemoryContext cxt;
|
||||||
struct EventTriggerQueryState *previous;
|
struct EventTriggerQueryState *previous;
|
||||||
} EventTriggerQueryState;
|
} EventTriggerQueryState;
|
||||||
@ -119,11 +124,14 @@ static void AlterEventTriggerOwner_internal(Relation rel,
|
|||||||
HeapTuple tup,
|
HeapTuple tup,
|
||||||
Oid newOwnerId);
|
Oid newOwnerId);
|
||||||
static event_trigger_command_tag_check_result check_ddl_tag(const char *tag);
|
static event_trigger_command_tag_check_result check_ddl_tag(const char *tag);
|
||||||
|
static event_trigger_command_tag_check_result check_table_rewrite_ddl_tag(
|
||||||
|
const char *tag);
|
||||||
static void error_duplicate_filter_variable(const char *defname);
|
static void error_duplicate_filter_variable(const char *defname);
|
||||||
static Datum filter_list_to_array(List *filterlist);
|
static Datum filter_list_to_array(List *filterlist);
|
||||||
static Oid insert_event_trigger_tuple(char *trigname, char *eventname,
|
static Oid insert_event_trigger_tuple(char *trigname, char *eventname,
|
||||||
Oid evtOwner, Oid funcoid, List *tags);
|
Oid evtOwner, Oid funcoid, List *tags);
|
||||||
static void validate_ddl_tags(const char *filtervar, List *taglist);
|
static void validate_ddl_tags(const char *filtervar, List *taglist);
|
||||||
|
static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
|
||||||
static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
|
static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -154,7 +162,8 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
|
|||||||
/* Validate event name. */
|
/* Validate event name. */
|
||||||
if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
|
if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
|
||||||
strcmp(stmt->eventname, "ddl_command_end") != 0 &&
|
strcmp(stmt->eventname, "ddl_command_end") != 0 &&
|
||||||
strcmp(stmt->eventname, "sql_drop") != 0)
|
strcmp(stmt->eventname, "sql_drop") != 0 &&
|
||||||
|
strcmp(stmt->eventname, "table_rewrite") != 0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("unrecognized event name \"%s\"",
|
errmsg("unrecognized event name \"%s\"",
|
||||||
@ -183,6 +192,9 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
|
|||||||
strcmp(stmt->eventname, "sql_drop") == 0)
|
strcmp(stmt->eventname, "sql_drop") == 0)
|
||||||
&& tags != NULL)
|
&& tags != NULL)
|
||||||
validate_ddl_tags("tag", tags);
|
validate_ddl_tags("tag", tags);
|
||||||
|
else if (strcmp(stmt->eventname, "table_rewrite") == 0
|
||||||
|
&& tags != NULL)
|
||||||
|
validate_table_rewrite_tags("tag", tags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Give user a nice error message if an event trigger of the same name
|
* Give user a nice error message if an event trigger of the same name
|
||||||
@ -280,6 +292,38 @@ check_ddl_tag(const char *tag)
|
|||||||
return EVENT_TRIGGER_COMMAND_TAG_OK;
|
return EVENT_TRIGGER_COMMAND_TAG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate DDL command tags for event table_rewrite.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
validate_table_rewrite_tags(const char *filtervar, List *taglist)
|
||||||
|
{
|
||||||
|
ListCell *lc;
|
||||||
|
|
||||||
|
foreach(lc, taglist)
|
||||||
|
{
|
||||||
|
const char *tag = strVal(lfirst(lc));
|
||||||
|
event_trigger_command_tag_check_result result;
|
||||||
|
|
||||||
|
result = check_table_rewrite_ddl_tag(tag);
|
||||||
|
if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
/* translator: %s represents an SQL statement name */
|
||||||
|
errmsg("event triggers are not supported for %s",
|
||||||
|
tag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static event_trigger_command_tag_check_result
|
||||||
|
check_table_rewrite_ddl_tag(const char *tag)
|
||||||
|
{
|
||||||
|
if (pg_strcasecmp(tag, "ALTER TABLE") == 0)
|
||||||
|
return EVENT_TRIGGER_COMMAND_TAG_OK;
|
||||||
|
|
||||||
|
return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Complain about a duplicate filter variable.
|
* Complain about a duplicate filter variable.
|
||||||
*/
|
*/
|
||||||
@ -641,9 +685,19 @@ EventTriggerCommonSetup(Node *parsetree,
|
|||||||
const char *dbgtag;
|
const char *dbgtag;
|
||||||
|
|
||||||
dbgtag = CreateCommandTag(parsetree);
|
dbgtag = CreateCommandTag(parsetree);
|
||||||
|
if (event == EVT_DDLCommandStart ||
|
||||||
|
event == EVT_DDLCommandEnd ||
|
||||||
|
event == EVT_SQLDrop)
|
||||||
|
{
|
||||||
if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
|
if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
|
||||||
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
|
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
|
||||||
}
|
}
|
||||||
|
else if (event == EVT_TableRewrite)
|
||||||
|
{
|
||||||
|
if (check_table_rewrite_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
|
||||||
|
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Use cache to find triggers for this event; fast exit if none. */
|
/* Use cache to find triggers for this event; fast exit if none. */
|
||||||
@ -838,6 +892,80 @@ EventTriggerSQLDrop(Node *parsetree)
|
|||||||
list_free(runlist);
|
list_free(runlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fire table_rewrite triggers.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
|
||||||
|
{
|
||||||
|
List *runlist;
|
||||||
|
EventTriggerData trigdata;
|
||||||
|
|
||||||
|
elog(DEBUG1, "EventTriggerTableRewrite(%u)", tableOid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event Triggers are completely disabled in standalone mode. There are
|
||||||
|
* (at least) two reasons for this:
|
||||||
|
*
|
||||||
|
* 1. A sufficiently broken event trigger might not only render the
|
||||||
|
* database unusable, but prevent disabling itself to fix the situation.
|
||||||
|
* In this scenario, restarting in standalone mode provides an escape
|
||||||
|
* hatch.
|
||||||
|
*
|
||||||
|
* 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
|
||||||
|
* therefore will malfunction if pg_event_trigger's indexes are damaged.
|
||||||
|
* To allow recovery from a damaged index, we need some operating mode
|
||||||
|
* wherein event triggers are disabled. (Or we could implement
|
||||||
|
* heapscan-and-sort logic for that case, but having disaster recovery
|
||||||
|
* scenarios depend on code that's otherwise untested isn't appetizing.)
|
||||||
|
*/
|
||||||
|
if (!IsUnderPostmaster)
|
||||||
|
return;
|
||||||
|
|
||||||
|
runlist = EventTriggerCommonSetup(parsetree,
|
||||||
|
EVT_TableRewrite,
|
||||||
|
"table_rewrite",
|
||||||
|
&trigdata);
|
||||||
|
if (runlist == NIL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure pg_event_trigger_table_rewrite_oid only works when running
|
||||||
|
* these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
|
||||||
|
* when one trigger fails. (This is perhaps not necessary, as the
|
||||||
|
* currentState variable will be removed shortly by our caller, but it
|
||||||
|
* seems better to play safe.)
|
||||||
|
*/
|
||||||
|
currentEventTriggerState->table_rewrite_oid = tableOid;
|
||||||
|
currentEventTriggerState->table_rewrite_reason = reason;
|
||||||
|
|
||||||
|
/* Run the triggers. */
|
||||||
|
PG_TRY();
|
||||||
|
{
|
||||||
|
EventTriggerInvoke(runlist, &trigdata);
|
||||||
|
}
|
||||||
|
PG_CATCH();
|
||||||
|
{
|
||||||
|
currentEventTriggerState->table_rewrite_oid = InvalidOid;
|
||||||
|
currentEventTriggerState->table_rewrite_reason = 0;
|
||||||
|
PG_RE_THROW();
|
||||||
|
}
|
||||||
|
PG_END_TRY();
|
||||||
|
|
||||||
|
currentEventTriggerState->table_rewrite_oid = InvalidOid;
|
||||||
|
currentEventTriggerState->table_rewrite_reason = 0;
|
||||||
|
|
||||||
|
/* Cleanup. */
|
||||||
|
list_free(runlist);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure anything the event triggers did will be visible to the main
|
||||||
|
* command.
|
||||||
|
*/
|
||||||
|
CommandCounterIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invoke each event trigger in a list of event triggers.
|
* Invoke each event trigger in a list of event triggers.
|
||||||
*/
|
*/
|
||||||
@ -871,6 +999,8 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
|
|||||||
FunctionCallInfoData fcinfo;
|
FunctionCallInfoData fcinfo;
|
||||||
PgStat_FunctionCallUsage fcusage;
|
PgStat_FunctionCallUsage fcusage;
|
||||||
|
|
||||||
|
elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want each event trigger to be able to see the results of the
|
* We want each event trigger to be able to see the results of the
|
||||||
* previous event trigger's action. Caller is responsible for any
|
* previous event trigger's action. Caller is responsible for any
|
||||||
@ -1026,8 +1156,9 @@ EventTriggerBeginCompleteQuery(void)
|
|||||||
MemoryContext cxt;
|
MemoryContext cxt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently, sql_drop events are the only reason to have event trigger
|
* Currently, sql_drop and table_rewrite events are the only reason to
|
||||||
* state at all; so if there are none, don't install one.
|
* have event trigger state at all; so if there are none, don't install
|
||||||
|
* one.
|
||||||
*/
|
*/
|
||||||
if (!trackDroppedObjectsNeeded())
|
if (!trackDroppedObjectsNeeded())
|
||||||
return false;
|
return false;
|
||||||
@ -1041,6 +1172,7 @@ EventTriggerBeginCompleteQuery(void)
|
|||||||
state->cxt = cxt;
|
state->cxt = cxt;
|
||||||
slist_init(&(state->SQLDropList));
|
slist_init(&(state->SQLDropList));
|
||||||
state->in_sql_drop = false;
|
state->in_sql_drop = false;
|
||||||
|
state->table_rewrite_oid = InvalidOid;
|
||||||
|
|
||||||
state->previous = currentEventTriggerState;
|
state->previous = currentEventTriggerState;
|
||||||
currentEventTriggerState = state;
|
currentEventTriggerState = state;
|
||||||
@ -1080,8 +1212,9 @@ EventTriggerEndCompleteQuery(void)
|
|||||||
bool
|
bool
|
||||||
trackDroppedObjectsNeeded(void)
|
trackDroppedObjectsNeeded(void)
|
||||||
{
|
{
|
||||||
/* true if any sql_drop event trigger exists */
|
/* true if any sql_drop or table_rewrite event trigger exists */
|
||||||
return list_length(EventCacheLookup(EVT_SQLDrop)) > 0;
|
return list_length(EventCacheLookup(EVT_SQLDrop)) > 0 ||
|
||||||
|
list_length(EventCacheLookup(EVT_TableRewrite)) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1297,3 +1430,46 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pg_event_trigger_table_rewrite_oid
|
||||||
|
*
|
||||||
|
* Make the Oid of the table going to be rewritten available to the user
|
||||||
|
* function run by the Event Trigger.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Protect this function from being called out of context
|
||||||
|
*/
|
||||||
|
if (!currentEventTriggerState ||
|
||||||
|
currentEventTriggerState->table_rewrite_oid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("%s can only be called in a table_rewrite event trigger function",
|
||||||
|
"pg_event_trigger_table_rewrite_oid()")));
|
||||||
|
|
||||||
|
PG_RETURN_OID(currentEventTriggerState->table_rewrite_oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pg_event_trigger_table_rewrite_reason
|
||||||
|
*
|
||||||
|
* Make the rewrite reason available to the user.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Protect this function from being called out of context
|
||||||
|
*/
|
||||||
|
if (!currentEventTriggerState ||
|
||||||
|
currentEventTriggerState->table_rewrite_reason == 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("%s can only be called in a table_rewrite event trigger function",
|
||||||
|
"pg_event_trigger_table_rewrite_reason()")));
|
||||||
|
|
||||||
|
PG_RETURN_INT32(currentEventTriggerState->table_rewrite_reason);
|
||||||
|
}
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "commands/cluster.h"
|
#include "commands/cluster.h"
|
||||||
#include "commands/comment.h"
|
#include "commands/comment.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
|
#include "commands/event_trigger.h"
|
||||||
#include "commands/policy.h"
|
#include "commands/policy.h"
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
@ -153,7 +154,7 @@ typedef struct AlteredTableInfo
|
|||||||
List *constraints; /* List of NewConstraint */
|
List *constraints; /* List of NewConstraint */
|
||||||
List *newvals; /* List of NewColumnValue */
|
List *newvals; /* List of NewColumnValue */
|
||||||
bool new_notnull; /* T if we added new NOT NULL constraints */
|
bool new_notnull; /* T if we added new NOT NULL constraints */
|
||||||
bool rewrite; /* T if a rewrite is forced */
|
int rewrite; /* Reason for forced rewrite, if any */
|
||||||
Oid newTableSpace; /* new tablespace; 0 means no change */
|
Oid newTableSpace; /* new tablespace; 0 means no change */
|
||||||
bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
|
bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
|
||||||
char newrelpersistence; /* if above is true */
|
char newrelpersistence; /* if above is true */
|
||||||
@ -303,13 +304,15 @@ static void validateForeignKeyConstraint(char *conname,
|
|||||||
static void createForeignKeyTriggers(Relation rel, Oid refRelOid,
|
static void createForeignKeyTriggers(Relation rel, Oid refRelOid,
|
||||||
Constraint *fkconstraint,
|
Constraint *fkconstraint,
|
||||||
Oid constraintOid, Oid indexOid);
|
Oid constraintOid, Oid indexOid);
|
||||||
static void ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
|
static void ATController(AlterTableStmt *parsetree,
|
||||||
|
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
|
||||||
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
||||||
bool recurse, bool recursing, LOCKMODE lockmode);
|
bool recurse, bool recursing, LOCKMODE lockmode);
|
||||||
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode);
|
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode);
|
||||||
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||||
AlterTableCmd *cmd, LOCKMODE lockmode);
|
AlterTableCmd *cmd, LOCKMODE lockmode);
|
||||||
static void ATRewriteTables(List **wqueue, LOCKMODE lockmode);
|
static void ATRewriteTables(AlterTableStmt *parsetree,
|
||||||
|
List **wqueue, LOCKMODE lockmode);
|
||||||
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
|
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
|
||||||
static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
|
static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
|
||||||
static void ATSimplePermissions(Relation rel, int allowed_targets);
|
static void ATSimplePermissions(Relation rel, int allowed_targets);
|
||||||
@ -2724,7 +2727,8 @@ AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
|
|||||||
|
|
||||||
CheckTableNotInUse(rel, "ALTER TABLE");
|
CheckTableNotInUse(rel, "ALTER TABLE");
|
||||||
|
|
||||||
ATController(rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt),
|
ATController(stmt,
|
||||||
|
rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt),
|
||||||
lockmode);
|
lockmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2747,7 +2751,7 @@ AlterTableInternal(Oid relid, List *cmds, bool recurse)
|
|||||||
|
|
||||||
rel = relation_open(relid, lockmode);
|
rel = relation_open(relid, lockmode);
|
||||||
|
|
||||||
ATController(rel, cmds, recurse, lockmode);
|
ATController(NULL, rel, cmds, recurse, lockmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3015,8 +3019,15 @@ AlterTableGetLockLevel(List *cmds)
|
|||||||
return lockmode;
|
return lockmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ATController provides top level control over the phases.
|
||||||
|
*
|
||||||
|
* parsetree is passed in to allow it to be passed to event triggers
|
||||||
|
* when requested.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
|
ATController(AlterTableStmt *parsetree,
|
||||||
|
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
List *wqueue = NIL;
|
List *wqueue = NIL;
|
||||||
ListCell *lcmd;
|
ListCell *lcmd;
|
||||||
@ -3036,7 +3047,7 @@ ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
|
|||||||
ATRewriteCatalogs(&wqueue, lockmode);
|
ATRewriteCatalogs(&wqueue, lockmode);
|
||||||
|
|
||||||
/* Phase 3: scan/rewrite tables as needed */
|
/* Phase 3: scan/rewrite tables as needed */
|
||||||
ATRewriteTables(&wqueue, lockmode);
|
ATRewriteTables(parsetree, &wqueue, lockmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3195,7 +3206,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
|||||||
/* force rewrite if necessary; see comment in ATRewriteTables */
|
/* force rewrite if necessary; see comment in ATRewriteTables */
|
||||||
if (tab->chgPersistence)
|
if (tab->chgPersistence)
|
||||||
{
|
{
|
||||||
tab->rewrite = true;
|
tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
|
||||||
tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
|
tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
|
||||||
}
|
}
|
||||||
pass = AT_PASS_MISC;
|
pass = AT_PASS_MISC;
|
||||||
@ -3206,7 +3217,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
|||||||
/* force rewrite if necessary; see comment in ATRewriteTables */
|
/* force rewrite if necessary; see comment in ATRewriteTables */
|
||||||
if (tab->chgPersistence)
|
if (tab->chgPersistence)
|
||||||
{
|
{
|
||||||
tab->rewrite = true;
|
tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
|
||||||
tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
|
tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
|
||||||
}
|
}
|
||||||
pass = AT_PASS_MISC;
|
pass = AT_PASS_MISC;
|
||||||
@ -3607,7 +3618,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
|||||||
* ATRewriteTables: ALTER TABLE phase 3
|
* ATRewriteTables: ALTER TABLE phase 3
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ATRewriteTables(List **wqueue, LOCKMODE lockmode)
|
ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
ListCell *ltab;
|
ListCell *ltab;
|
||||||
|
|
||||||
@ -3634,7 +3645,7 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
|
|||||||
* constraints, so it's not necessary/appropriate to enforce them just
|
* constraints, so it's not necessary/appropriate to enforce them just
|
||||||
* during ALTER.)
|
* during ALTER.)
|
||||||
*/
|
*/
|
||||||
if (tab->newvals != NIL || tab->rewrite)
|
if (tab->newvals != NIL || tab->rewrite > 0)
|
||||||
{
|
{
|
||||||
Relation rel;
|
Relation rel;
|
||||||
|
|
||||||
@ -3655,7 +3666,7 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
|
|||||||
* and assigns a new relfilenode, we automatically create or drop an
|
* and assigns a new relfilenode, we automatically create or drop an
|
||||||
* init fork for the relation as appropriate.
|
* init fork for the relation as appropriate.
|
||||||
*/
|
*/
|
||||||
if (tab->rewrite)
|
if (tab->rewrite > 0)
|
||||||
{
|
{
|
||||||
/* Build a temporary relation and copy data */
|
/* Build a temporary relation and copy data */
|
||||||
Relation OldHeap;
|
Relation OldHeap;
|
||||||
@ -3709,6 +3720,21 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
|
|||||||
|
|
||||||
heap_close(OldHeap, NoLock);
|
heap_close(OldHeap, NoLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fire off an Event Trigger now, before actually rewriting the
|
||||||
|
* table.
|
||||||
|
*
|
||||||
|
* We don't support Event Trigger for nested commands anywhere,
|
||||||
|
* here included, and parsetree is given NULL when coming from
|
||||||
|
* AlterTableInternal.
|
||||||
|
*
|
||||||
|
* And fire it only once.
|
||||||
|
*/
|
||||||
|
if (parsetree)
|
||||||
|
EventTriggerTableRewrite((Node *)parsetree,
|
||||||
|
tab->relid,
|
||||||
|
tab->rewrite);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create transient table that will receive the modified data.
|
* Create transient table that will receive the modified data.
|
||||||
*
|
*
|
||||||
@ -4002,7 +4028,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
|
|||||||
|
|
||||||
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
if (tab->rewrite)
|
if (tab->rewrite > 0)
|
||||||
{
|
{
|
||||||
Oid tupOid = InvalidOid;
|
Oid tupOid = InvalidOid;
|
||||||
|
|
||||||
@ -4828,7 +4854,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
|||||||
newval->expr = expression_planner(defval);
|
newval->expr = expression_planner(defval);
|
||||||
|
|
||||||
tab->newvals = lappend(tab->newvals, newval);
|
tab->newvals = lappend(tab->newvals, newval);
|
||||||
tab->rewrite = true;
|
tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4845,7 +4871,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
|||||||
* table to fix that.
|
* table to fix that.
|
||||||
*/
|
*/
|
||||||
if (isOid)
|
if (isOid)
|
||||||
tab->rewrite = true;
|
tab->rewrite |= AT_REWRITE_ALTER_OID;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add needed dependency entries for the new column.
|
* Add needed dependency entries for the new column.
|
||||||
@ -5657,7 +5683,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
|
|||||||
tab = ATGetQueueEntry(wqueue, rel);
|
tab = ATGetQueueEntry(wqueue, rel);
|
||||||
|
|
||||||
/* Tell Phase 3 to physically remove the OID column */
|
/* Tell Phase 3 to physically remove the OID column */
|
||||||
tab->rewrite = true;
|
tab->rewrite |= AT_REWRITE_ALTER_OID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5683,7 +5709,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
|
|||||||
/* suppress schema rights check when rebuilding existing index */
|
/* suppress schema rights check when rebuilding existing index */
|
||||||
check_rights = !is_rebuild;
|
check_rights = !is_rebuild;
|
||||||
/* skip index build if phase 3 will do it or we're reusing an old one */
|
/* skip index build if phase 3 will do it or we're reusing an old one */
|
||||||
skip_build = tab->rewrite || OidIsValid(stmt->oldNode);
|
skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
|
||||||
/* suppress notices when rebuilding existing index */
|
/* suppress notices when rebuilding existing index */
|
||||||
quiet = is_rebuild;
|
quiet = is_rebuild;
|
||||||
|
|
||||||
@ -7686,7 +7712,7 @@ ATPrepAlterColumnType(List **wqueue,
|
|||||||
|
|
||||||
tab->newvals = lappend(tab->newvals, newval);
|
tab->newvals = lappend(tab->newvals, newval);
|
||||||
if (ATColumnChangeRequiresRewrite(transform, attnum))
|
if (ATColumnChangeRequiresRewrite(transform, attnum))
|
||||||
tab->rewrite = true;
|
tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
|
||||||
}
|
}
|
||||||
else if (transform)
|
else if (transform)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -8431,7 +8457,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
|
|||||||
con->old_pktable_oid = refRelId;
|
con->old_pktable_oid = refRelId;
|
||||||
/* rewriting neither side of a FK */
|
/* rewriting neither side of a FK */
|
||||||
if (con->contype == CONSTR_FOREIGN &&
|
if (con->contype == CONSTR_FOREIGN &&
|
||||||
!rewrite && !tab->rewrite)
|
!rewrite && tab->rewrite == 0)
|
||||||
TryReuseForeignKey(oldId, con);
|
TryReuseForeignKey(oldId, con);
|
||||||
cmd->subtype = AT_ReAddConstraint;
|
cmd->subtype = AT_ReAddConstraint;
|
||||||
tab->subcmds[AT_PASS_OLD_CONSTR] =
|
tab->subcmds[AT_PASS_OLD_CONSTR] =
|
||||||
|
2
src/backend/utils/cache/evtcache.c
vendored
2
src/backend/utils/cache/evtcache.c
vendored
@ -169,6 +169,8 @@ BuildEventTriggerCache(void)
|
|||||||
event = EVT_DDLCommandEnd;
|
event = EVT_DDLCommandEnd;
|
||||||
else if (strcmp(evtevent, "sql_drop") == 0)
|
else if (strcmp(evtevent, "sql_drop") == 0)
|
||||||
event = EVT_SQLDrop;
|
event = EVT_SQLDrop;
|
||||||
|
else if (strcmp(evtevent, "table_rewrite") == 0)
|
||||||
|
event = EVT_TableRewrite;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -5045,6 +5045,10 @@ DESCR("peek at binary changes from replication slot");
|
|||||||
/* event triggers */
|
/* event triggers */
|
||||||
DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,25,25,25,25}" "{o,o,o,o,o,o,o}" "{classid, objid, objsubid, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
|
DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,25,25,25,25}" "{o,o,o,o,o,o,o}" "{classid, objid, objsubid, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
|
||||||
DESCR("list objects dropped by the current command");
|
DESCR("list objects dropped by the current command");
|
||||||
|
DATA(insert OID = 4566 ( pg_event_trigger_table_rewrite_oid PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 26 "" "{26}" "{o}" "{oid}" _null_ pg_event_trigger_table_rewrite_oid _null_ _null_ _null_ ));
|
||||||
|
DESCR("return Oid of the table getting rewritten");
|
||||||
|
DATA(insert OID = 4567 ( pg_event_trigger_table_rewrite_reason PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ pg_event_trigger_table_rewrite_reason _null_ _null_ _null_ ));
|
||||||
|
DESCR("return reason code for table getting rewritten");
|
||||||
|
|
||||||
/* generic transition functions for ordered-set aggregates */
|
/* generic transition functions for ordered-set aggregates */
|
||||||
DATA(insert OID = 3970 ( ordered_set_transition PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 2276" _null_ _null_ _null_ _null_ ordered_set_transition _null_ _null_ _null_ ));
|
DATA(insert OID = 3970 ( ordered_set_transition PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 2276" _null_ _null_ _null_ _null_ ordered_set_transition _null_ _null_ _null_ ));
|
||||||
|
@ -26,6 +26,11 @@ typedef struct EventTriggerData
|
|||||||
const char *tag; /* command tag */
|
const char *tag; /* command tag */
|
||||||
} EventTriggerData;
|
} EventTriggerData;
|
||||||
|
|
||||||
|
#define AT_REWRITE_ALTER_PERSISTENCE 0x01
|
||||||
|
#define AT_REWRITE_DEFAULT_VAL 0x02
|
||||||
|
#define AT_REWRITE_COLUMN_REWRITE 0x04
|
||||||
|
#define AT_REWRITE_ALTER_OID 0x08
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EventTriggerData is the node type that is passed as fmgr "context" info
|
* EventTriggerData is the node type that is passed as fmgr "context" info
|
||||||
* when a function is called by the event trigger manager.
|
* when a function is called by the event trigger manager.
|
||||||
@ -46,6 +51,7 @@ extern bool EventTriggerSupportsObjectClass(ObjectClass objclass);
|
|||||||
extern void EventTriggerDDLCommandStart(Node *parsetree);
|
extern void EventTriggerDDLCommandStart(Node *parsetree);
|
||||||
extern void EventTriggerDDLCommandEnd(Node *parsetree);
|
extern void EventTriggerDDLCommandEnd(Node *parsetree);
|
||||||
extern void EventTriggerSQLDrop(Node *parsetree);
|
extern void EventTriggerSQLDrop(Node *parsetree);
|
||||||
|
extern void EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason);
|
||||||
|
|
||||||
extern bool EventTriggerBeginCompleteQuery(void);
|
extern bool EventTriggerBeginCompleteQuery(void);
|
||||||
extern void EventTriggerEndCompleteQuery(void);
|
extern void EventTriggerEndCompleteQuery(void);
|
||||||
|
@ -1200,6 +1200,8 @@ extern Datum unique_key_recheck(PG_FUNCTION_ARGS);
|
|||||||
|
|
||||||
/* commands/event_trigger.c */
|
/* commands/event_trigger.c */
|
||||||
extern Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS);
|
extern Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
/* commands/extension.c */
|
/* commands/extension.c */
|
||||||
extern Datum pg_available_extensions(PG_FUNCTION_ARGS);
|
extern Datum pg_available_extensions(PG_FUNCTION_ARGS);
|
||||||
|
@ -20,7 +20,8 @@ typedef enum
|
|||||||
{
|
{
|
||||||
EVT_DDLCommandStart,
|
EVT_DDLCommandStart,
|
||||||
EVT_DDLCommandEnd,
|
EVT_DDLCommandEnd,
|
||||||
EVT_SQLDrop
|
EVT_SQLDrop,
|
||||||
|
EVT_TableRewrite
|
||||||
} EventTriggerEvent;
|
} EventTriggerEvent;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -294,3 +294,41 @@ SELECT * FROM dropped_objects WHERE type = 'schema';
|
|||||||
DROP ROLE regression_bob;
|
DROP ROLE regression_bob;
|
||||||
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
||||||
DROP EVENT TRIGGER undroppable;
|
DROP EVENT TRIGGER undroppable;
|
||||||
|
-- only allowed from within an event trigger function, should fail
|
||||||
|
select pg_event_trigger_table_rewrite_oid();
|
||||||
|
ERROR: pg_event_trigger_table_rewrite_oid() can only be called in a table_rewrite event trigger function
|
||||||
|
-- test Table Rewrite Event Trigger
|
||||||
|
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RAISE EXCEPTION 'I''m sorry Sir, No Rewrite Allowed.';
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
create event trigger no_rewrite_allowed on table_rewrite
|
||||||
|
execute procedure test_evtrig_no_rewrite();
|
||||||
|
create table rewriteme (id serial primary key, foo float);
|
||||||
|
insert into rewriteme
|
||||||
|
select x * 1.001 from generate_series(1, 500) as t(x);
|
||||||
|
alter table rewriteme alter column foo type numeric;
|
||||||
|
ERROR: I'm sorry Sir, No Rewrite Allowed.
|
||||||
|
alter table rewriteme add column baz int default 0;
|
||||||
|
ERROR: I'm sorry Sir, No Rewrite Allowed.
|
||||||
|
-- test with more than one reason to rewrite a single table
|
||||||
|
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RAISE NOTICE 'Table ''%'' is being rewritten (reason = %)',
|
||||||
|
pg_event_trigger_table_rewrite_oid()::regclass,
|
||||||
|
pg_event_trigger_table_rewrite_reason();
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
alter table rewriteme
|
||||||
|
add column onemore int default 0,
|
||||||
|
add column another int default -1,
|
||||||
|
alter column foo type numeric(10,4);
|
||||||
|
NOTICE: Table 'rewriteme' is being rewritten (reason = 6)
|
||||||
|
-- shouldn't trigger a table_rewrite event
|
||||||
|
alter table rewriteme alter column foo type numeric(12,4);
|
||||||
|
drop table rewriteme;
|
||||||
|
drop event trigger no_rewrite_allowed;
|
||||||
|
drop function test_evtrig_no_rewrite();
|
||||||
|
@ -92,8 +92,6 @@ test: alter_generic misc psql async
|
|||||||
|
|
||||||
# rules cannot run concurrently with any test that creates a view
|
# rules cannot run concurrently with any test that creates a view
|
||||||
test: rules
|
test: rules
|
||||||
# event triggers cannot run concurrently with any test that runs DDL
|
|
||||||
test: event_trigger
|
|
||||||
|
|
||||||
# ----------
|
# ----------
|
||||||
# Another group of parallel tests
|
# Another group of parallel tests
|
||||||
@ -106,5 +104,8 @@ test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combo
|
|||||||
# ----------
|
# ----------
|
||||||
test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
|
test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
|
||||||
|
|
||||||
|
# event triggers cannot run concurrently with any test that runs DDL
|
||||||
|
test: event_trigger
|
||||||
|
|
||||||
# run stats by itself because its delay may be insufficient under heavy load
|
# run stats by itself because its delay may be insufficient under heavy load
|
||||||
test: stats
|
test: stats
|
||||||
|
@ -111,7 +111,6 @@ test: misc
|
|||||||
test: psql
|
test: psql
|
||||||
test: async
|
test: async
|
||||||
test: rules
|
test: rules
|
||||||
test: event_trigger
|
|
||||||
test: select_views
|
test: select_views
|
||||||
test: portals_p2
|
test: portals_p2
|
||||||
test: foreign_key
|
test: foreign_key
|
||||||
@ -150,4 +149,5 @@ test: returning
|
|||||||
test: largeobject
|
test: largeobject
|
||||||
test: with
|
test: with
|
||||||
test: xml
|
test: xml
|
||||||
|
test: event_trigger
|
||||||
test: stats
|
test: stats
|
||||||
|
@ -206,3 +206,45 @@ DROP ROLE regression_bob;
|
|||||||
|
|
||||||
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
||||||
DROP EVENT TRIGGER undroppable;
|
DROP EVENT TRIGGER undroppable;
|
||||||
|
|
||||||
|
-- only allowed from within an event trigger function, should fail
|
||||||
|
select pg_event_trigger_table_rewrite_oid();
|
||||||
|
|
||||||
|
-- test Table Rewrite Event Trigger
|
||||||
|
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RAISE EXCEPTION 'I''m sorry Sir, No Rewrite Allowed.';
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
create event trigger no_rewrite_allowed on table_rewrite
|
||||||
|
execute procedure test_evtrig_no_rewrite();
|
||||||
|
|
||||||
|
create table rewriteme (id serial primary key, foo float);
|
||||||
|
insert into rewriteme
|
||||||
|
select x * 1.001 from generate_series(1, 500) as t(x);
|
||||||
|
alter table rewriteme alter column foo type numeric;
|
||||||
|
alter table rewriteme add column baz int default 0;
|
||||||
|
|
||||||
|
-- test with more than one reason to rewrite a single table
|
||||||
|
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RAISE NOTICE 'Table ''%'' is being rewritten (reason = %)',
|
||||||
|
pg_event_trigger_table_rewrite_oid()::regclass,
|
||||||
|
pg_event_trigger_table_rewrite_reason();
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
alter table rewriteme
|
||||||
|
add column onemore int default 0,
|
||||||
|
add column another int default -1,
|
||||||
|
alter column foo type numeric(10,4);
|
||||||
|
|
||||||
|
-- shouldn't trigger a table_rewrite event
|
||||||
|
alter table rewriteme alter column foo type numeric(12,4);
|
||||||
|
|
||||||
|
drop table rewriteme;
|
||||||
|
drop event trigger no_rewrite_allowed;
|
||||||
|
drop function test_evtrig_no_rewrite();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user