<secondary>in PL/Python</secondary>
</indexterm>
+ <para>
+ <application>PL/Python</application> can be used to define trigger
+ functions.
+ <productname>PostgreSQL</productname> requires that a function that is to
+ be called as a trigger must be declared as a function with no arguments and
+ a return type of <literal>trigger</literal>.
+ </para>
+
<para>
When a function is used as a trigger, the dictionary
<literal>TD</literal> contains trigger-related values:
</para>
</sect1>
+ <sect1 id="plpython-event-trigger">
+ <title>Event Trigger Functions</title>
+
+ <indexterm zone="plpython-event-trigger">
+ <primary>event trigger</primary>
+ <secondary>in PL/Python</secondary>
+ </indexterm>
+
+ <para>
+ <application>PL/Python</application> can be used to define event triggers
+ (see also <xref linkend="event-triggers"/>).
+ <productname>PostgreSQL</productname> requires that a function that is to
+ be called as an event trigger must be declared as a function with no
+ arguments and a return type of <literal>event_trigger</literal>.
+ </para>
+
+ <para>
+ When a function is used as an event trigger, the dictionary
+ <literal>TD</literal> contains trigger-related values:
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>TD["event"]</varname></term>
+ <listitem>
+ <para>
+ The event the trigger was fired for, as a string, for example
+ <literal>ddl_command_start</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>TD["tag"]</varname></term>
+ <listitem>
+ <para>
+ The command tag for which the trigger was fired, as a string, for
+ example <literal>DROP TABLE</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ <xref linkend="plpython-event-trigger-example"/> shows an example of an
+ event trigger function in <application>PL/Python</application>.
+ </para>
+
+ <example id="plpython-event-trigger-example">
+ <title>A <application>PL/Python</application> Event Trigger Function</title>
+
+ <para>
+ This example trigger simply raises a <literal>NOTICE</literal> message
+ each time a supported command is executed.
+ </para>
+
+<programlisting>
+CREATE OR REPLACE FUNCTION pysnitch() RETURNS event_trigger
+LANGUAGE plpython3u
+AS $$
+ plpy.notice("TD[event] => " + TD["event"] + " ; TD[tag] => " + TD["tag"]);
+$$;
+
+CREATE EVENT TRIGGER pysnitch ON ddl_command_start EXECUTE FUNCTION pysnitch();
+</programlisting>
+ </example>
+ </sect1>
+
<sect1 id="plpython-database">
<title>Database Access</title>
1 | 2
(2 rows)
+-- event triggers
+CREATE OR REPLACE FUNCTION pysnitch() RETURNS event_trigger
+LANGUAGE plpython3u
+AS $$
+ plpy.notice("TD[event] => " + TD["event"] + " ; TD[tag] => " + TD["tag"]);
+$$;
+CREATE EVENT TRIGGER python_a_snitch ON ddl_command_start
+ EXECUTE PROCEDURE pysnitch();
+CREATE EVENT TRIGGER python_b_snitch ON ddl_command_end
+ EXECUTE PROCEDURE pysnitch();
+CREATE OR REPLACE FUNCTION foobar() RETURNS int LANGUAGE sql AS $$SELECT 1;$$;
+NOTICE: TD[event] => ddl_command_start ; TD[tag] => CREATE FUNCTION
+NOTICE: TD[event] => ddl_command_end ; TD[tag] => CREATE FUNCTION
+ALTER FUNCTION foobar() COST 77;
+NOTICE: TD[event] => ddl_command_start ; TD[tag] => ALTER FUNCTION
+NOTICE: TD[event] => ddl_command_end ; TD[tag] => ALTER FUNCTION
+DROP FUNCTION foobar();
+NOTICE: TD[event] => ddl_command_start ; TD[tag] => DROP FUNCTION
+NOTICE: TD[event] => ddl_command_end ; TD[tag] => DROP FUNCTION
+CREATE TABLE foo();
+NOTICE: TD[event] => ddl_command_start ; TD[tag] => CREATE TABLE
+NOTICE: TD[event] => ddl_command_end ; TD[tag] => CREATE TABLE
+DROP TABLE foo;
+NOTICE: TD[event] => ddl_command_start ; TD[tag] => DROP TABLE
+NOTICE: TD[event] => ddl_command_end ; TD[tag] => DROP TABLE
+DROP EVENT TRIGGER python_a_snitch;
+DROP EVENT TRIGGER python_b_snitch;
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
+#include "commands/event_trigger.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "funcapi.h"
return rv;
}
+/*
+ * event trigger subhandler
+ */
+void
+PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
+{
+ EventTriggerData *tdata;
+ PyObject *volatile pltdata = NULL;
+
+ Assert(CALLED_AS_EVENT_TRIGGER(fcinfo));
+ tdata = (EventTriggerData *) fcinfo->context;
+
+ PG_TRY();
+ {
+ PyObject *pltevent,
+ *plttag;
+
+ pltdata = PyDict_New();
+ if (!pltdata)
+ PLy_elog(ERROR, NULL);
+
+ pltevent = PLyUnicode_FromString(tdata->event);
+ PyDict_SetItemString(pltdata, "event", pltevent);
+ Py_DECREF(pltevent);
+
+ plttag = PLyUnicode_FromString(GetCommandTagName(tdata->tag));
+ PyDict_SetItemString(pltdata, "tag", plttag);
+ Py_DECREF(plttag);
+
+ PLy_procedure_call(proc, "TD", pltdata);
+
+ if (SPI_finish() != SPI_OK_FINISH)
+ elog(ERROR, "SPI_finish() failed");
+ }
+ PG_FINALLY();
+ {
+ Py_XDECREF(pltdata);
+ }
+ PG_END_TRY();
+}
+
/* helper functions for Python code execution */
static PyObject *
extern Datum PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc);
extern HeapTuple PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc);
+extern void PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc);
#endif /* PLPY_EXEC_H */
#include "access/htup_details.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
+#include "commands/event_trigger.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "miscadmin.h"
trv = PLy_exec_trigger(fcinfo, proc);
retval = PointerGetDatum(trv);
}
+ else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
+ {
+ proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_EVENT_TRIGGER);
+ exec_ctx->curr_proc = proc;
+ PLy_exec_event_trigger(fcinfo, proc);
+ retval = (Datum) 0;
+ }
else
{
proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_NOT_TRIGGER);
case TRIGGEROID:
ret = PLPY_TRIGGER;
break;
+ case EVENT_TRIGGEROID:
+ ret = PLPY_EVENT_TRIGGER;
+ break;
default:
ret = PLPY_NOT_TRIGGER;
break;
typedef enum PLyTrigType
{
PLPY_TRIGGER,
+ PLPY_EVENT_TRIGGER,
PLPY_NOT_TRIGGER,
} PLyTrigType;
INSERT INTO recursive_trigger_test VALUES (0, 0);
UPDATE recursive_trigger_test SET a = 11 WHERE b = 0;
SELECT * FROM recursive_trigger_test;
+
+
+-- event triggers
+
+CREATE OR REPLACE FUNCTION pysnitch() RETURNS event_trigger
+LANGUAGE plpython3u
+AS $$
+ plpy.notice("TD[event] => " + TD["event"] + " ; TD[tag] => " + TD["tag"]);
+$$;
+
+CREATE EVENT TRIGGER python_a_snitch ON ddl_command_start
+ EXECUTE PROCEDURE pysnitch();
+CREATE EVENT TRIGGER python_b_snitch ON ddl_command_end
+ EXECUTE PROCEDURE pysnitch();
+
+CREATE OR REPLACE FUNCTION foobar() RETURNS int LANGUAGE sql AS $$SELECT 1;$$;
+ALTER FUNCTION foobar() COST 77;
+DROP FUNCTION foobar();
+
+CREATE TABLE foo();
+DROP TABLE foo;
+
+DROP EVENT TRIGGER python_a_snitch;
+DROP EVENT TRIGGER python_b_snitch;