diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2013-07-03 21:06:20 -0400 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2013-07-03 21:06:20 -0400 |
commit | 0fe21ad8aab03172d4ac2e790479f17edcd3dbbe (patch) | |
tree | cb194114f6d702e00e9a79ea7d53d40053888dea | |
parent | 82b0102650cf85268145a46f0ab488bacf6599a1 (diff) | |
download | postgresql-0fe21ad8aab03172d4ac2e790479f17edcd3dbbe.tar.gz postgresql-0fe21ad8aab03172d4ac2e790479f17edcd3dbbe.zip |
doc: Add event trigger C API documentation
From: Dimitri Fontaine <dimitri@2ndQuadrant.fr>
-rw-r--r-- | doc/src/sgml/event-trigger.sgml | 224 |
1 files changed, 218 insertions, 6 deletions
diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml index 7343227d28f..8950bfde2fc 100644 --- a/doc/src/sgml/event-trigger.sgml +++ b/doc/src/sgml/event-trigger.sgml @@ -37,21 +37,27 @@ <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 @@ -76,6 +82,7 @@ </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 @@ -607,4 +614,209 @@ </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> |