Commit 841a5150 authored by Robert Haas's avatar Robert Haas

Add ddl_command_end support for event triggers.

Dimitri Fontaine, with slight changes by me
parent 765cbfdc
...@@ -27,8 +27,9 @@ ...@@ -27,8 +27,9 @@
<para> <para>
An event trigger fires whenever the event with which it is associated An event trigger fires whenever the event with which it is associated
occurs in the database in which it is defined. Currently, the only occurs in the database in which it is defined. Currently, the only
supported event is <literal>ddl_command_start</>. Support for supported events are <literal>ddl_command_start</>
additional events may be added in future releases. and <literal>ddl_command_end</>. Support for additional events may be
added in future releases.
</para> </para>
<para> <para>
...@@ -43,6 +44,13 @@ ...@@ -43,6 +44,13 @@
<literal>CREATE TABLE AS</literal>. <literal>CREATE TABLE AS</literal>.
</para> </para>
<para>
The <literal>ddl_command_end</> event occurs just before returning
control from the execution of a <literal>CREATE</>, <literal>ALTER</>,
or <literal>DROP</> commmand. It shares the same exceptions as
the <literal>ddl_command_start</> event.
</para>
<para> <para>
For a complete list of commands supported by the event trigger mechanism, For a complete list of commands supported by the event trigger mechanism,
see <xref linkend="event-trigger-matrix">. see <xref linkend="event-trigger-matrix">.
...@@ -84,328 +92,409 @@ ...@@ -84,328 +92,409 @@
<row> <row>
<entry>command tag</entry> <entry>command tag</entry>
<entry><literal>ddl_command_start</literal></entry> <entry><literal>ddl_command_start</literal></entry>
<entry><literal>ddl_command_end</literal></entry>
</row> </row>
</thead> </thead>
<tbody> <tbody>
<row> <row>
<entry align="left"><literal>ALTER AGGREGATE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER COLLATION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER CONVERSION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER DOMAIN</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER EXTENSION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER FOREIGN DATA WRAPPER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER FOREIGN TABLE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER FUNCTION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER LANGUAGE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER OPERATOR</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER OPERATOR CLASS</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER OPERATOR FAMILY</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER SCHEMA</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER SEQUENCE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER SERVER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER TABLE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER TEXT SEARCH CONFIGURATION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER TEXT SEARCH DICTIONARY</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER TEXT SEARCH PARSER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER TEXT SEARCH TEMPLATE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER TRIGGER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER TYPE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER USER MAPPING</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>ALTER VIEW</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE AGGREGATE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE CAST</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE COLLATION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE CONVERSION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE DOMAIN</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE EXTENSION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE FOREIGN DATA WRAPPER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE FOREIGN TABLE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE FUNCTION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE INDEX</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE LANGUAGE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE OPERATOR</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE OPERATOR CLASS</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE OPERATOR FAMILY</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE RULE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE SCHEMA</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE SEQUENCE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE SERVER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TABLE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TABLE AS</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TEXT SEARCH CONFIGURATION</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TEXT SEARCH DICTIONARY</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TEXT SEARCH PARSER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TEXT SEARCH TEMPLATE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TRIGGER</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE TYPE</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE USER MAPPING</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>CREATE VIEW</literal></entry> <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>X</literal></entry>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP AGGREGATE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP CAST</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP COLLATION</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP CONVERSION</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP DOMAIN</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP EXTENSION</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP FOREIGN DATA WRAPPER</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP FOREIGN TABLE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP FUNCTION</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP INDEX</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP LANGUAGE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP OPERATOR</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP OPERATOR CLASS</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP OPERATOR FAMILY</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP RULE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP SCHEMA</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP SEQUENCE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP SERVER</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP TABLE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP TEXT SEARCH CONFIGURATION</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP TEXT SEARCH DICTIONARY</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP TEXT SEARCH PARSER</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP TEXT SEARCH TEMPLATE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP TRIGGER</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP TYPE</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP USER MAPPING</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>DROP VIEW</literal></entry> <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>
</row> </row>
<row> <row>
<entry align="left"><literal>SELECT INTO</literal></entry> <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>X</literal></entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
......
...@@ -125,7 +125,8 @@ CreateEventTrigger(CreateEventTrigStmt *stmt) ...@@ -125,7 +125,8 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
errhint("Must be superuser to create an event trigger."))); errhint("Must be superuser to create an event trigger.")));
/* Validate event name. */ /* Validate event name. */
if (strcmp(stmt->eventname, "ddl_command_start") != 0) if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
strcmp(stmt->eventname, "ddl_command_end") != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized event name \"%s\"", errmsg("unrecognized event name \"%s\"",
...@@ -526,6 +527,39 @@ get_event_trigger_oid(const char *trigname, bool missing_ok) ...@@ -526,6 +527,39 @@ get_event_trigger_oid(const char *trigname, bool missing_ok)
return oid; return oid;
} }
/*
* Return true when we want to fire given Event Trigger and false otherwise,
* filtering on the session replication role and the event trigger registered
* tags matching.
*/
static bool
filter_event_trigger(const char **tag, EventTriggerCacheItem *item)
{
/*
* Filter by session replication role, knowing that we never see disabled
* items down here.
*/
if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
{
if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
return false;
}
else
{
if (item->enabled == TRIGGER_FIRES_ON_REPLICA)
return false;
}
/* Filter by tags, if any were specified. */
if (item->ntags != 0 && bsearch(&tag, item->tag,
item->ntags, sizeof(char *),
pg_qsort_strcmp) == NULL)
return false;
/* if we reach that point, we're not filtering out this item */
return true;
}
/* /*
* Fire ddl_command_start triggers. * Fire ddl_command_start triggers.
*/ */
...@@ -601,34 +635,105 @@ EventTriggerDDLCommandStart(Node *parsetree) ...@@ -601,34 +635,105 @@ EventTriggerDDLCommandStart(Node *parsetree)
{ {
EventTriggerCacheItem *item = lfirst(lc); EventTriggerCacheItem *item = lfirst(lc);
/* Filter by session replication role. */ if (filter_event_trigger(&tag, item))
if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
{
if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
continue;
}
else
{ {
if (item->enabled == TRIGGER_FIRES_ON_REPLICA) /* We must plan to fire this trigger. */
continue; runlist = lappend_oid(runlist, item->fnoid);
} }
}
/* Construct event trigger data. */
trigdata.type = T_EventTriggerData;
trigdata.event = "ddl_command_start";
trigdata.parsetree = parsetree;
trigdata.tag = tag;
/* Run the triggers. */
EventTriggerInvoke(runlist, &trigdata);
/* Cleanup. */
list_free(runlist);
/*
* Make sure anything the event triggers did will be visible to
* the main command.
*/
CommandCounterIncrement();
}
/*
* Fire ddl_command_end triggers.
*/
void
EventTriggerDDLCommandEnd(Node *parsetree)
{
List *cachelist;
List *runlist = NIL;
ListCell *lc;
const char *tag;
EventTriggerData trigdata;
/*
* See EventTriggerDDLCommandStart for a discussion about why event
* triggers are disabled in single user mode.
*/
if (!IsUnderPostmaster)
return;
/* Filter by tags, if any were specified. */ /*
if (item->ntags != 0 && bsearch(&tag, item->tag, * See EventTriggerDDLCommandStart for a discussion about why this check is
item->ntags, sizeof(char *), * important.
pg_qsort_strcmp) == NULL) *
continue; */
#ifdef USE_ASSERT_CHECKING
if (assert_enabled)
{
const char *dbgtag;
/* We must plan to fire this trigger. */ dbgtag = CreateCommandTag(parsetree);
runlist = lappend_oid(runlist, item->fnoid); if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
}
#endif
/* Use cache to find triggers for this event; fast exit if none. */
cachelist = EventCacheLookup(EVT_DDLCommandEnd);
if (cachelist == NULL)
return;
/* Get the command tag. */
tag = CreateCommandTag(parsetree);
/*
* Filter list of event triggers by command tag, and copy them into
* our memory context. Once we start running the command trigers, or
* indeed once we do anything at all that touches the catalogs, an
* invalidation might leave cachelist pointing at garbage, so we must
* do this before we can do much else.
*/
foreach (lc, cachelist)
{
EventTriggerCacheItem *item = lfirst(lc);
if (filter_event_trigger(&tag, item))
{
/* We must plan to fire this trigger. */
runlist = lappend_oid(runlist, item->fnoid);
}
} }
/* Construct event trigger data. */ /* Construct event trigger data. */
trigdata.type = T_EventTriggerData; trigdata.type = T_EventTriggerData;
trigdata.event = "ddl_command_start"; trigdata.event = "ddl_command_end";
trigdata.parsetree = parsetree; trigdata.parsetree = parsetree;
trigdata.tag = tag; trigdata.tag = tag;
/*
* Make sure anything the main command did will be visible to the
* event triggers.
*/
CommandCounterIncrement();
/* Run the triggers. */ /* Run the triggers. */
EventTriggerInvoke(runlist, &trigdata); EventTriggerInvoke(runlist, &trigdata);
...@@ -645,6 +750,7 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata) ...@@ -645,6 +750,7 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
MemoryContext context; MemoryContext context;
MemoryContext oldcontext; MemoryContext oldcontext;
ListCell *lc; ListCell *lc;
bool first = true;
/* /*
* Let's evaluate event triggers in their own memory context, so * Let's evaluate event triggers in their own memory context, so
...@@ -665,6 +771,17 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata) ...@@ -665,6 +771,17 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
FunctionCallInfoData fcinfo; FunctionCallInfoData fcinfo;
PgStat_FunctionCallUsage fcusage; PgStat_FunctionCallUsage fcusage;
/*
* We want each event trigger to be able to see the results of
* the previous event trigger's action. Caller is responsible
* for any command-counter increment that is needed between the
* event trigger and anything else in the transaction.
*/
if (first)
first = false;
else
CommandCounterIncrement();
/* Look up the function */ /* Look up the function */
fmgr_info(fnoid, &flinfo); fmgr_info(fnoid, &flinfo);
...@@ -677,13 +794,6 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata) ...@@ -677,13 +794,6 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
/* Reclaim memory. */ /* Reclaim memory. */
MemoryContextReset(context); MemoryContextReset(context);
/*
* We want each event trigger to be able to see the results of
* the previous event trigger's action, and we want the main
* command to be able to see the results of all event triggers.
*/
CommandCounterIncrement();
} }
/* Restore old memory context and delete the temporary one. */ /* Restore old memory context and delete the temporary one. */
......
...@@ -340,6 +340,34 @@ ProcessUtility(Node *parsetree, ...@@ -340,6 +340,34 @@ ProcessUtility(Node *parsetree,
dest, completionTag, context); dest, completionTag, context);
} }
#define InvokeDDLCommandEventTriggers(parsetree, fncall) \
do { \
if (isCompleteQuery) \
{ \
EventTriggerDDLCommandStart(parsetree); \
} \
fncall; \
if (isCompleteQuery) \
{ \
EventTriggerDDLCommandEnd(parsetree); \
} \
} while (0)
#define InvokeDDLCommandEventTriggersIfSupported(parsetree, fncall, objtype) \
do { \
bool _supported = EventTriggerSupportsObjectType(objtype); \
\
if (_supported) \
{ \
EventTriggerDDLCommandStart(parsetree); \
} \
fncall; \
if (_supported) \
{ \
EventTriggerDDLCommandEnd(parsetree); \
} \
} while (0)
void void
standard_ProcessUtility(Node *parsetree, standard_ProcessUtility(Node *parsetree,
const char *queryString, const char *queryString,
...@@ -507,10 +535,10 @@ standard_ProcessUtility(Node *parsetree, ...@@ -507,10 +535,10 @@ standard_ProcessUtility(Node *parsetree,
* relation and attribute manipulation * relation and attribute manipulation
*/ */
case T_CreateSchemaStmt: case T_CreateSchemaStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateSchemaCommand((CreateSchemaStmt *) parsetree, CreateSchemaCommand((CreateSchemaStmt *) parsetree,
queryString); queryString));
break; break;
case T_CreateStmt: case T_CreateStmt:
...@@ -583,6 +611,9 @@ standard_ProcessUtility(Node *parsetree, ...@@ -583,6 +611,9 @@ standard_ProcessUtility(Node *parsetree,
if (lnext(l) != NULL) if (lnext(l) != NULL)
CommandCounterIncrement(); CommandCounterIncrement();
} }
if (isCompleteQuery)
EventTriggerDDLCommandEnd(parsetree);
} }
break; break;
...@@ -604,63 +635,63 @@ standard_ProcessUtility(Node *parsetree, ...@@ -604,63 +635,63 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_CreateExtensionStmt: case T_CreateExtensionStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateExtension((CreateExtensionStmt *) parsetree); CreateExtension((CreateExtensionStmt *) parsetree));
break; break;
case T_AlterExtensionStmt: case T_AlterExtensionStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree); ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree));
break; break;
case T_AlterExtensionContentsStmt: case T_AlterExtensionContentsStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree); ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree));
break; break;
case T_CreateFdwStmt: case T_CreateFdwStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateForeignDataWrapper((CreateFdwStmt *) parsetree); CreateForeignDataWrapper((CreateFdwStmt *) parsetree));
break; break;
case T_AlterFdwStmt: case T_AlterFdwStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterForeignDataWrapper((AlterFdwStmt *) parsetree); AlterForeignDataWrapper((AlterFdwStmt *) parsetree));
break; break;
case T_CreateForeignServerStmt: case T_CreateForeignServerStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateForeignServer((CreateForeignServerStmt *) parsetree); CreateForeignServer((CreateForeignServerStmt *) parsetree));
break; break;
case T_AlterForeignServerStmt: case T_AlterForeignServerStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterForeignServer((AlterForeignServerStmt *) parsetree); AlterForeignServer((AlterForeignServerStmt *) parsetree));
break; break;
case T_CreateUserMappingStmt: case T_CreateUserMappingStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateUserMapping((CreateUserMappingStmt *) parsetree); CreateUserMapping((CreateUserMappingStmt *) parsetree));
break; break;
case T_AlterUserMappingStmt: case T_AlterUserMappingStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterUserMapping((AlterUserMappingStmt *) parsetree); AlterUserMapping((AlterUserMappingStmt *) parsetree));
break; break;
case T_DropUserMappingStmt: case T_DropUserMappingStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
RemoveUserMapping((DropUserMappingStmt *) parsetree); RemoveUserMapping((DropUserMappingStmt *) parsetree));
break; break;
case T_DropStmt: case T_DropStmt:
...@@ -689,6 +720,11 @@ standard_ProcessUtility(Node *parsetree, ...@@ -689,6 +720,11 @@ standard_ProcessUtility(Node *parsetree,
RemoveObjects((DropStmt *) parsetree); RemoveObjects((DropStmt *) parsetree);
break; break;
} }
if (isCompleteQuery
&& EventTriggerSupportsObjectType(stmt->removeType))
EventTriggerDDLCommandEnd(parsetree);
break; break;
} }
...@@ -736,37 +772,29 @@ standard_ProcessUtility(Node *parsetree, ...@@ -736,37 +772,29 @@ standard_ProcessUtility(Node *parsetree,
*/ */
case T_RenameStmt: case T_RenameStmt:
{ {
RenameStmt *stmt; RenameStmt *stmt = (RenameStmt *) parsetree;
stmt = (RenameStmt *) parsetree; InvokeDDLCommandEventTriggersIfSupported(parsetree,
if (isCompleteQuery && ExecRenameStmt(stmt),
EventTriggerSupportsObjectType(stmt->renameType)) stmt->renameType);
EventTriggerDDLCommandStart(parsetree);
ExecRenameStmt(stmt);
break; break;
} }
case T_AlterObjectSchemaStmt: case T_AlterObjectSchemaStmt:
{ {
AlterObjectSchemaStmt *stmt; AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
InvokeDDLCommandEventTriggersIfSupported(parsetree,
stmt = (AlterObjectSchemaStmt *) parsetree; ExecAlterObjectSchemaStmt(stmt),
if (isCompleteQuery && stmt->objectType);
EventTriggerSupportsObjectType(stmt->objectType))
EventTriggerDDLCommandStart(parsetree);
ExecAlterObjectSchemaStmt(stmt);
break; break;
} }
case T_AlterOwnerStmt: case T_AlterOwnerStmt:
{ {
AlterOwnerStmt *stmt; AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
InvokeDDLCommandEventTriggersIfSupported(parsetree,
stmt = (AlterOwnerStmt *) parsetree; ExecAlterOwnerStmt(stmt),
if (isCompleteQuery && stmt->objectType);
EventTriggerSupportsObjectType(stmt->objectType))
EventTriggerDDLCommandStart(parsetree);
ExecAlterOwnerStmt(stmt);
break; break;
} }
...@@ -889,9 +917,9 @@ standard_ProcessUtility(Node *parsetree, ...@@ -889,9 +917,9 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_AlterDefaultPrivilegesStmt: case T_AlterDefaultPrivilegesStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree); ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree));
break; break;
/* /*
...@@ -950,47 +978,46 @@ standard_ProcessUtility(Node *parsetree, ...@@ -950,47 +978,46 @@ standard_ProcessUtility(Node *parsetree,
{ {
CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree; CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineCompositeType(stmt->typevar, stmt->coldeflist));
DefineCompositeType(stmt->typevar, stmt->coldeflist);
} }
break; break;
case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */ case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineEnum((CreateEnumStmt *) parsetree); DefineEnum((CreateEnumStmt *) parsetree));
break; break;
case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */ case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineRange((CreateRangeStmt *) parsetree); DefineRange((CreateRangeStmt *) parsetree));
break; break;
case T_AlterEnumStmt: /* ALTER TYPE (enum) */ case T_AlterEnumStmt: /* ALTER TYPE (enum) */
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterEnum((AlterEnumStmt *) parsetree, isTopLevel); AlterEnum((AlterEnumStmt *) parsetree, isTopLevel));
break; break;
case T_ViewStmt: /* CREATE VIEW */ case T_ViewStmt: /* CREATE VIEW */
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineView((ViewStmt *) parsetree, queryString); DefineView((ViewStmt *) parsetree, queryString));
break; break;
case T_CreateFunctionStmt: /* CREATE FUNCTION */ case T_CreateFunctionStmt: /* CREATE FUNCTION */
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateFunction((CreateFunctionStmt *) parsetree, queryString); CreateFunction((CreateFunctionStmt *) parsetree, queryString));
break; break;
case T_AlterFunctionStmt: /* ALTER FUNCTION */ case T_AlterFunctionStmt: /* ALTER FUNCTION */
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterFunction((AlterFunctionStmt *) parsetree); AlterFunction((AlterFunctionStmt *) parsetree));
break; break;
case T_IndexStmt: /* CREATE INDEX */ case T_IndexStmt: /* CREATE INDEX */
...@@ -1019,21 +1046,21 @@ standard_ProcessUtility(Node *parsetree, ...@@ -1019,21 +1046,21 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_RuleStmt: /* CREATE RULE */ case T_RuleStmt: /* CREATE RULE */
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineRule((RuleStmt *) parsetree, queryString); DefineRule((RuleStmt *) parsetree, queryString));
break; break;
case T_CreateSeqStmt: case T_CreateSeqStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineSequence((CreateSeqStmt *) parsetree); DefineSequence((CreateSeqStmt *) parsetree));
break; break;
case T_AlterSeqStmt: case T_AlterSeqStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterSequence((AlterSeqStmt *) parsetree); AlterSequence((AlterSeqStmt *) parsetree));
break; break;
case T_DoStmt: case T_DoStmt:
...@@ -1131,10 +1158,10 @@ standard_ProcessUtility(Node *parsetree, ...@@ -1131,10 +1158,10 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_CreateTableAsStmt: case T_CreateTableAsStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
ExecCreateTableAs((CreateTableAsStmt *) parsetree, ExecCreateTableAs((CreateTableAsStmt *) parsetree,
queryString, params, completionTag); queryString, params, completionTag));
break; break;
case T_VariableSetStmt: case T_VariableSetStmt:
...@@ -1156,10 +1183,10 @@ standard_ProcessUtility(Node *parsetree, ...@@ -1156,10 +1183,10 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_CreateTrigStmt: case T_CreateTrigStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
(void) CreateTrigger((CreateTrigStmt *) parsetree, queryString, (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
InvalidOid, InvalidOid, false); InvalidOid, InvalidOid, false));
break; break;
case T_CreateEventTrigStmt: case T_CreateEventTrigStmt:
...@@ -1173,18 +1200,18 @@ standard_ProcessUtility(Node *parsetree, ...@@ -1173,18 +1200,18 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_CreatePLangStmt: case T_CreatePLangStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateProceduralLanguage((CreatePLangStmt *) parsetree); CreateProceduralLanguage((CreatePLangStmt *) parsetree));
break; break;
/* /*
* ******************************** DOMAIN statements **** * ******************************** DOMAIN statements ****
*/ */
case T_CreateDomainStmt: case T_CreateDomainStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineDomain((CreateDomainStmt *) parsetree); DefineDomain((CreateDomainStmt *) parsetree));
break; break;
/* /*
...@@ -1288,45 +1315,45 @@ standard_ProcessUtility(Node *parsetree, ...@@ -1288,45 +1315,45 @@ standard_ProcessUtility(Node *parsetree,
break; break;
case T_CreateConversionStmt: case T_CreateConversionStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateConversionCommand((CreateConversionStmt *) parsetree); CreateConversionCommand((CreateConversionStmt *) parsetree));
break; break;
case T_CreateCastStmt: case T_CreateCastStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
CreateCast((CreateCastStmt *) parsetree); CreateCast((CreateCastStmt *) parsetree));
break; break;
case T_CreateOpClassStmt: case T_CreateOpClassStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineOpClass((CreateOpClassStmt *) parsetree); DefineOpClass((CreateOpClassStmt *) parsetree));
break; break;
case T_CreateOpFamilyStmt: case T_CreateOpFamilyStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
DefineOpFamily((CreateOpFamilyStmt *) parsetree); DefineOpFamily((CreateOpFamilyStmt *) parsetree));
break; break;
case T_AlterOpFamilyStmt: case T_AlterOpFamilyStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterOpFamily((AlterOpFamilyStmt *) parsetree); AlterOpFamily((AlterOpFamilyStmt *) parsetree));
break; break;
case T_AlterTSDictionaryStmt: case T_AlterTSDictionaryStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterTSDictionary((AlterTSDictionaryStmt *) parsetree); AlterTSDictionary((AlterTSDictionaryStmt *) parsetree));
break; break;
case T_AlterTSConfigurationStmt: case T_AlterTSConfigurationStmt:
if (isCompleteQuery) InvokeDDLCommandEventTriggers(
EventTriggerDDLCommandStart(parsetree); parsetree,
AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree); AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree));
break; break;
default: default:
......
...@@ -167,6 +167,8 @@ BuildEventTriggerCache(void) ...@@ -167,6 +167,8 @@ BuildEventTriggerCache(void)
evtevent = NameStr(form->evtevent); evtevent = NameStr(form->evtevent);
if (strcmp(evtevent, "ddl_command_start") == 0) if (strcmp(evtevent, "ddl_command_start") == 0)
event = EVT_DDLCommandStart; event = EVT_DDLCommandStart;
else if (strcmp(evtevent, "ddl_command_end") == 0)
event = EVT_DDLCommandEnd;
else else
continue; continue;
......
...@@ -41,5 +41,6 @@ extern void AlterEventTriggerOwner_oid(Oid, Oid newOwnerId); ...@@ -41,5 +41,6 @@ extern void AlterEventTriggerOwner_oid(Oid, Oid newOwnerId);
extern bool EventTriggerSupportsObjectType(ObjectType obtype); extern bool EventTriggerSupportsObjectType(ObjectType obtype);
extern void EventTriggerDDLCommandStart(Node *parsetree); extern void EventTriggerDDLCommandStart(Node *parsetree);
extern void EventTriggerDDLCommandEnd(Node *parsetree);
#endif /* EVENT_TRIGGER_H */ #endif /* EVENT_TRIGGER_H */
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
typedef enum typedef enum
{ {
EVT_DDLCommandStart EVT_DDLCommandStart,
EVT_DDLCommandEnd
} EventTriggerEvent; } EventTriggerEvent;
typedef struct typedef struct
......
...@@ -16,6 +16,8 @@ ERROR: unrecognized event name "elephant_bootstrap" ...@@ -16,6 +16,8 @@ ERROR: unrecognized event name "elephant_bootstrap"
-- OK -- OK
create event trigger regress_event_trigger on ddl_command_start create event trigger regress_event_trigger on ddl_command_start
execute procedure test_event_trigger(); execute procedure test_event_trigger();
create event trigger regress_event_trigger_end on ddl_command_end
execute procedure test_event_trigger();
-- should fail, food is not a valid filter variable -- should fail, food is not a valid filter variable
create event trigger regress_event_trigger2 on ddl_command_start create event trigger regress_event_trigger2 on ddl_command_start
when food in ('sandwhich') when food in ('sandwhich')
...@@ -65,9 +67,10 @@ alter event trigger regress_event_trigger enable; ...@@ -65,9 +67,10 @@ alter event trigger regress_event_trigger enable;
alter event trigger regress_event_trigger disable; alter event trigger regress_event_trigger disable;
-- regress_event_trigger2 should fire, but not regress_event_trigger -- regress_event_trigger2 should fire, but not regress_event_trigger
create table event_trigger_fire1 (a int); create table event_trigger_fire1 (a int);
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE NOTICE: test_event_trigger: ddl_command_end CREATE TABLE
-- but nothing should fire here -- but nothing should fire here
drop table event_trigger_fire1; drop table event_trigger_fire1;
NOTICE: test_event_trigger: ddl_command_end DROP TABLE
-- alter owner to non-superuser should fail -- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regression_bob; alter event trigger regress_event_trigger owner to regression_bob;
ERROR: permission denied to change owner of event trigger "regress_event_trigger" ERROR: permission denied to change owner of event trigger "regress_event_trigger"
...@@ -92,5 +95,6 @@ drop event trigger if exists regress_event_trigger2; ...@@ -92,5 +95,6 @@ drop event trigger if exists regress_event_trigger2;
drop event trigger if exists regress_event_trigger2; drop event trigger if exists regress_event_trigger2;
NOTICE: event trigger "regress_event_trigger2" does not exist, skipping NOTICE: event trigger "regress_event_trigger2" does not exist, skipping
drop event trigger regress_event_trigger3; drop event trigger regress_event_trigger3;
drop event trigger regress_event_trigger_end;
drop function test_event_trigger(); drop function test_event_trigger();
drop role regression_bob; drop role regression_bob;
...@@ -18,6 +18,9 @@ create event trigger regress_event_trigger on elephant_bootstrap ...@@ -18,6 +18,9 @@ create event trigger regress_event_trigger on elephant_bootstrap
create event trigger regress_event_trigger on ddl_command_start create event trigger regress_event_trigger on ddl_command_start
execute procedure test_event_trigger(); execute procedure test_event_trigger();
create event trigger regress_event_trigger_end on ddl_command_end
execute procedure test_event_trigger();
-- should fail, food is not a valid filter variable -- should fail, food is not a valid filter variable
create event trigger regress_event_trigger2 on ddl_command_start create event trigger regress_event_trigger2 on ddl_command_start
when food in ('sandwhich') when food in ('sandwhich')
...@@ -96,5 +99,6 @@ drop role regression_bob; ...@@ -96,5 +99,6 @@ drop role regression_bob;
drop event trigger if exists regress_event_trigger2; drop event trigger if exists regress_event_trigger2;
drop event trigger if exists regress_event_trigger2; drop event trigger if exists regress_event_trigger2;
drop event trigger regress_event_trigger3; drop event trigger regress_event_trigger3;
drop event trigger regress_event_trigger_end;
drop function test_event_trigger(); drop function test_event_trigger();
drop role regression_bob; drop role regression_bob;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment