*** a/doc/src/sgml/event-trigger.sgml --- b/doc/src/sgml/event-trigger.sgml *************** *** 607,610 **** --- 607,861 ---- + + Writing Event Trigger Functions in C + + + event trigger + in C + + + + 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. + + + + Event trigger functions must use the version 1 function + manager interface. + + + + When a function is called by the event trigger manager, it is not passed + any normal arguments, but it is passed a context pointer + pointing to a EventTriggerData structure. C functions can + check whether they were called from the event trigger manager or not by + executing the macro: + + CALLED_AS_EVENT_TRIGGER(fcinfo) + + which expands to: + + ((fcinfo)->context != NULL && IsA((fcinfo)->context, EventTriggerData)) + + If this returns true, then it is safe to cast + fcinfo->context to type EventTriggerData + * and make use of the pointed-to + EventTriggerData structure. The function must + not alter the EventTriggerData + structure or any of the data it points to. + + + + struct EventTriggerData is defined in + commands/event_trigger.h: + + + typedef struct EventTriggerData + { + NodeTag type; + const char *event; /* event name */ + Node *parsetree; /* parse tree */ + const char *tag; /* command tag */ + } EventTriggerData; + + + where the members are defined as follows: + + + + type + + + Always T_EventTriggerData. + + + + + + tg_event + + + Describes the event for which the function is called. On of: + + + + "ddl_command_start" + + + The event trigger is run first thing in the command + implementation, nothing did happen yet (no object is locked, the + system didn't check if the object(s) still exist, etc). + + + + + + "ddl_command_end" + + + The event trigger is run as the last step in the command + implementation, while the locks are still kept when locks have + been taken. + + + + + + "sql_drop" + + + The event trigger is run at the last step in the command + implementation, unless there's + a "ddl_command_end" event trigger registered + against the same command too. This event is only fired when + a DROP command did occur. + + + + + + + + + + + parsetree + + + A pointer to a structure describing the relation that the trigger fired for. + Look at utils/rel.h for details about + this structure. The most interesting things are + tg_relation->rd_att (descriptor of the relation + tuples) and tg_relation->rd_rel->relname + (relation name; the type is not char* but + NameData; use + SPI_getrelname(tg_relation) to get a char* if you + need a copy of the name). + + + + + + tag + + + The command tag against which the Event Trigger is run. + + + + + + + + + An event trigger function must return a NULL pointer + (not an SQL null value, that is, do not + set isNull true). + + + + + A Complete Event Trigger Example + + + 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.) + + + + The function noddl raises an exception each time it's + called, preventing the command to run, whatever the + command is. + + + + This is the source code of the trigger function: + context; + + if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) /* internal error */ + elog(ERROR, "not fired by event trigger manager"); + + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("command %s denied", trigdata->tag))); + + PG_RETURN_NULL(); + } + ]]> + + + + + After you have compiled the source code (see ), declare the function and the triggers: + + CREATE FUNCTION noddl() + RETURNS pg_catalog.event_trigger + AS 'noddl' + LANGUAGE C; + + CREATE EVENT TRIGGER noddl on ddl_command_start + execute procedure noddl(); + + + + + Now you can test the operation of the trigger: + + =# \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 + + + + + In order to be able to run some DDL commands when you need to do so, + either DROP the event trigger or just disable it in + the DDL transaction, like so: + + BEGIN; + ALTER EVENT TRIGGER noddl DISABLE; + CREATE TABLE foo(id serial); + COMMIT; + + +