mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
997 lines
41 KiB
Plaintext
997 lines
41 KiB
Plaintext
<!-- doc/src/sgml/event-trigger.sgml -->
|
|
|
|
<chapter id="event-triggers">
|
|
<title>Event Triggers</title>
|
|
|
|
<indexterm zone="event-triggers">
|
|
<primary>event trigger</primary>
|
|
</indexterm>
|
|
|
|
<para>
|
|
To supplement the trigger mechanism discussed in <xref linkend="triggers">,
|
|
<productname>PostgreSQL</> also provides event triggers. Unlike regular
|
|
triggers, which are attached to a single table and capture only DML events,
|
|
event triggers are global to a particular database and are capable of
|
|
capturing DDL events.
|
|
</para>
|
|
|
|
<para>
|
|
Like regular triggers, event triggers can be written in any procedural
|
|
language that includes event trigger support, or in C, but not in plain
|
|
SQL.
|
|
</para>
|
|
|
|
<sect1 id="event-trigger-definition">
|
|
<title>Overview of Event Trigger Behavior</title>
|
|
|
|
<para>
|
|
An event trigger fires whenever the event with which it is associated
|
|
occurs in the database in which it is defined. Currently, the only
|
|
supported events are
|
|
<literal>ddl_command_start</>,
|
|
<literal>ddl_command_end</>
|
|
and <literal>sql_drop</>.
|
|
Support for additional events may be added in future releases.
|
|
</para>
|
|
|
|
<para>
|
|
The <literal>ddl_command_start</> event occurs just before the
|
|
execution of a <literal>CREATE</>, <literal>ALTER</>, or <literal>DROP</>
|
|
command. No check whether the affected object exists or doesn't exist is
|
|
performed before the event trigger fires.
|
|
As an exception, however, this event does not occur for
|
|
DDL commands targeting shared objects — databases, roles, and tablespaces
|
|
— or for commands targeting event triggers themselves. The event trigger
|
|
mechanism does not support these object types.
|
|
<literal>ddl_command_start</> also occurs just before the execution of a
|
|
<literal>SELECT INTO</literal> command, since this is equivalent to
|
|
<literal>CREATE TABLE AS</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
The <literal>ddl_command_end</> event occurs just after the execution of
|
|
this same set of commands.
|
|
</para>
|
|
|
|
<para>
|
|
The <literal>sql_drop</> event occurs just before the
|
|
<literal>ddl_command_end</> event trigger for any operation that drops
|
|
database objects. To list the objects that have been dropped, use the
|
|
set-returning function <literal>pg_event_trigger_dropped_objects()</> from the
|
|
<literal>sql_drop</> event trigger code (see
|
|
<xref linkend="functions-event-triggers">). Note that
|
|
the trigger is executed after the objects have been deleted from the
|
|
system catalogs, so it's not possible to look them up anymore.
|
|
</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>
|
|
Event triggers (like other functions) cannot be executed in an aborted
|
|
transaction. Thus, if a DDL command fails with an error, any associated
|
|
<literal>ddl_command_end</> triggers will not be executed. Conversely,
|
|
if a <literal>ddl_command_start</> trigger fails with an error, no
|
|
further event triggers will fire, and no attempt will be made to execute
|
|
the command itself. Similarly, if a <literal>ddl_command_end</> trigger
|
|
fails with an error, the effects of the DDL statement will be rolled
|
|
back, just as they would be in any other case where the containing
|
|
transaction aborts.
|
|
</para>
|
|
|
|
<para>
|
|
For a complete list of commands supported by the event trigger mechanism,
|
|
see <xref linkend="event-trigger-matrix">.
|
|
</para>
|
|
|
|
<para>
|
|
Event triggers are created using the command <xref linkend="sql-createeventtrigger">.
|
|
In order to create an event trigger, you must first create a function with
|
|
the special return type <literal>event_trigger</literal>. This function
|
|
need not (and may not) return a value; the return type serves merely as
|
|
a signal that the function is to be invoked as an event trigger.
|
|
</para>
|
|
|
|
<para>
|
|
If more than one event trigger is defined for a particular event, they will
|
|
fire in alphabetical order by trigger name.
|
|
</para>
|
|
|
|
<para>
|
|
A trigger definition can also specify a <literal>WHEN</literal>
|
|
condition so that, for example, a <literal>ddl_command_start</literal>
|
|
trigger can be fired only for particular commands which the user wishes
|
|
to intercept. A common use of such triggers is to restrict the range of
|
|
DDL operations which users may perform.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="event-trigger-matrix">
|
|
<title>Event Trigger Firing Matrix</title>
|
|
|
|
<para>
|
|
<xref linkend="event-trigger-by-command-tag"> lists all commands
|
|
for which event triggers are supported.
|
|
</para>
|
|
|
|
<table id="event-trigger-by-command-tag">
|
|
<title>Event Trigger Support by Command Tag</title>
|
|
<tgroup cols="5">
|
|
<thead>
|
|
<row>
|
|
<entry>command tag</entry>
|
|
<entry><literal>ddl_command_start</literal></entry>
|
|
<entry><literal>ddl_command_end</literal></entry>
|
|
<entry><literal>sql_drop</literal></entry>
|
|
<entry><literal>table_rewrite</literal></entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry align="left"><literal>ALTER AGGREGATE</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>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
<row>
|
|
<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>-</literal></entry>
|
|
<entry align="center"><literal>-</literal></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</sect1>
|
|
|
|
<sect1 id="event-trigger-interface">
|
|
<title>Writing Event Trigger Functions in C</title>
|
|
|
|
<indexterm zone="event-trigger-interface">
|
|
<primary>event trigger</primary>
|
|
<secondary>in C</secondary>
|
|
</indexterm>
|
|
|
|
<para>
|
|
This section describes the low-level details of the interface to an
|
|
event trigger function. This information is only needed when writing
|
|
event trigger functions in C. If you are using a higher-level language
|
|
then these details are handled for you. In most cases you should
|
|
consider using a procedural language before writing your event triggers
|
|
in C. The documentation of each procedural language explains how to
|
|
write an event trigger in that language.
|
|
</para>
|
|
|
|
<para>
|
|
Event trigger functions must use the <quote>version 1</> function
|
|
manager interface.
|
|
</para>
|
|
|
|
<para>
|
|
When a function is called by the event trigger manager, it is not passed
|
|
any normal arguments, but it is passed a <quote>context</> pointer
|
|
pointing to a <structname>EventTriggerData</> structure. C functions can
|
|
check whether they were called from the event trigger manager or not by
|
|
executing the macro:
|
|
<programlisting>
|
|
CALLED_AS_EVENT_TRIGGER(fcinfo)
|
|
</programlisting>
|
|
which expands to:
|
|
<programlisting>
|
|
((fcinfo)->context != NULL && IsA((fcinfo)->context, EventTriggerData))
|
|
</programlisting>
|
|
If this returns true, then it is safe to cast
|
|
<literal>fcinfo->context</> to type <literal>EventTriggerData
|
|
*</literal> and make use of the pointed-to
|
|
<structname>EventTriggerData</> structure. The function must
|
|
<emphasis>not</emphasis> alter the <structname>EventTriggerData</>
|
|
structure or any of the data it points to.
|
|
</para>
|
|
|
|
<para>
|
|
<structname>struct EventTriggerData</structname> is defined in
|
|
<filename>commands/event_trigger.h</filename>:
|
|
|
|
<programlisting>
|
|
typedef struct EventTriggerData
|
|
{
|
|
NodeTag type;
|
|
const char *event; /* event name */
|
|
Node *parsetree; /* parse tree */
|
|
const char *tag; /* command tag */
|
|
} EventTriggerData;
|
|
</programlisting>
|
|
|
|
where the members are defined as follows:
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><structfield>type</></term>
|
|
<listitem>
|
|
<para>
|
|
Always <literal>T_EventTriggerData</literal>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><structfield>event</></term>
|
|
<listitem>
|
|
<para>
|
|
Describes the event for which the function is called, one of
|
|
<literal>"ddl_command_start"</literal>, <literal>"ddl_command_end"</literal>,
|
|
<literal>"sql_drop"</literal>.
|
|
See <xref linkend="event-trigger-definition"> for the meaning of these
|
|
events.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><structfield>parsetree</></term>
|
|
<listitem>
|
|
<para>
|
|
A pointer to the parse tree of the command. Check the PostgreSQL
|
|
source code for details. The parse tree structure is subject to change
|
|
without notice.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><structfield>tag</></term>
|
|
<listitem>
|
|
<para>
|
|
The command tag associated with the event for which the event trigger
|
|
is run, for example <literal>"CREATE FUNCTION"</literal>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</para>
|
|
|
|
<para>
|
|
An event trigger function must return a <symbol>NULL</> pointer
|
|
(<emphasis>not</> an SQL null value, that is, do not
|
|
set <parameter>isNull</parameter> true).
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="event-trigger-example">
|
|
<title>A Complete Event Trigger Example</title>
|
|
|
|
<para>
|
|
Here is a very simple example of an event trigger function written in C.
|
|
(Examples of triggers written in procedural languages can be found in
|
|
the documentation of the procedural languages.)
|
|
</para>
|
|
|
|
<para>
|
|
The function <function>noddl</> raises an exception each time it is called.
|
|
The event trigger definition associated the function with
|
|
the <literal>ddl_command_start</literal> event. The effect is that all DDL
|
|
commands (with the exceptions mentioned
|
|
in <xref linkend="event-trigger-definition">) are prevented from running.
|
|
</para>
|
|
|
|
<para>
|
|
This is the source code of the trigger function:
|
|
<programlisting><![CDATA[
|
|
#include "postgres.h"
|
|
#include "commands/event_trigger.h"
|
|
|
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
Datum noddl(PG_FUNCTION_ARGS);
|
|
|
|
PG_FUNCTION_INFO_V1(noddl);
|
|
|
|
Datum
|
|
noddl(PG_FUNCTION_ARGS)
|
|
{
|
|
EventTriggerData *trigdata;
|
|
|
|
if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) /* internal error */
|
|
elog(ERROR, "not fired by event trigger manager");
|
|
|
|
trigdata = (EventTriggerData *) fcinfo->context;
|
|
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("command \"%s\" denied", trigdata->tag)));
|
|
|
|
PG_RETURN_NULL();
|
|
}
|
|
]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
After you have compiled the source code (see <xref linkend="dfunc">),
|
|
declare the function and the triggers:
|
|
<programlisting>
|
|
CREATE FUNCTION noddl() RETURNS event_trigger
|
|
AS 'noddl' LANGUAGE C;
|
|
|
|
CREATE EVENT TRIGGER noddl ON ddl_command_start
|
|
EXECUTE PROCEDURE noddl();
|
|
</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Now you can test the operation of the trigger:
|
|
<screen>
|
|
=# \dy
|
|
List of event triggers
|
|
Name | Event | Owner | Enabled | Procedure | Tags
|
|
-------+-------------------+-------+---------+-----------+------
|
|
noddl | ddl_command_start | dim | enabled | noddl |
|
|
(1 row)
|
|
|
|
=# CREATE TABLE foo(id serial);
|
|
ERROR: command "CREATE TABLE" denied
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
In this situation, in order to be able to run some DDL commands when you
|
|
need to do so, you have to either drop the event trigger or disable it. It
|
|
can be convenient to disable the trigger for only the duration of a
|
|
transaction:
|
|
<programlisting>
|
|
BEGIN;
|
|
ALTER EVENT TRIGGER noddl DISABLE;
|
|
CREATE TABLE foo (id serial);
|
|
ALTER EVENT TRIGGER noddl ENABLE;
|
|
COMMIT;
|
|
</programlisting>
|
|
(Recall that DDL commands on event triggers themselves are not affected by
|
|
event triggers.)
|
|
</para>
|
|
</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>
|