<para>
The <literal>ddl_command_start</> event occurs just before the
execution of a <literal>CREATE</>, <literal>ALTER</>, or <literal>DROP</>
- command. As an exception, however, this event does not occur for
+ 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 command targeting event triggers themselves. The event trigger
+ — 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>. The <literal>ddl_command_end</>
- event occurs just after the execution of this same set of commands.
+ <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 your
+ 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
</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
</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>tg_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>
</chapter>