event_triggers_v1.7--v1.8.patch
text/x-patch
Filename: event_triggers_v1.7--v1.8.patch
Type: text/x-patch
Part: 0
Message:
Re: Event Triggers reduced, v1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| doc/src/sgml/catalogs.sgml | 20 | 11 |
| doc/src/sgml/event-trigger.sgml | 466 | 0 |
| doc/src/sgml/filelist.sgml | 1 | 0 |
| doc/src/sgml/plperl.sgml | 7 | 7 |
| doc/src/sgml/plpgsql.sgml | 10 | 14 |
| doc/src/sgml/plpython.sgml | 6 | 6 |
| doc/src/sgml/pltcl.sgml | 4 | 4 |
| doc/src/sgml/postgres.sgml | 1 | 0 |
| doc/src/sgml/ref/alter_event_trigger.sgml | 5 | 5 |
| doc/src/sgml/ref/create_event_trigger.sgml | 43 | 172 |
| doc/src/sgml/ref/drop_event_trigger.sgml | 9 | 7 |
| doc/src/sgml/trigger.sgml | 0 | 18 |
| src/backend/catalog/aclchk.c | 40 | 0 |
| src/backend/catalog/Makefile | 1 | 2 |
| src/backend/catalog/objectaddress.c | 5 | 1 |
| src/backend/catalog/pg_event_trigger.c | 0 | 409 |
| src/backend/commands/alter.c | 4 | 4 |
| src/backend/commands/dropcmds.c | 4 | 0 |
| src/backend/commands/event_trigger.c | 107 | 630 |
| src/backend/parser/gram.y | 3 | 24 |
| src/backend/tcop/utility.c | 66 | 6 |
| src/backend/utils/adt/pseudotypes.c | 27 | 0 |
| src/backend/utils/adt/ruleutils.c | 1 | 2 |
| src/backend/utils/cache/evtcache.c | 1241 | 30 |
| src/bin/pg_dump/common.c | 3 | 3 |
| src/bin/pg_dump/pg_dump.c | 32 | 30 |
| src/bin/pg_dump/pg_dump.h | 2 | 2 |
| src/bin/pg_dump/pg_dump_sort.c | 4 | 3 |
| src/bin/psql/command.c | 1 | 1 |
| src/bin/psql/describe.c | 5 | 6 |
| src/bin/psql/describe.h | 1 | 1 |
| src/bin/psql/help.c | 1 | 1 |
| src/include/catalog/pg_event_trigger.h | 0 | 118 |
| src/include/catalog/pg_proc.h | 5 | 0 |
| src/include/catalog/pg_type.h | 1 | 1 |
| src/include/commands/event_trigger.h | 6 | 1 |
| src/include/utils/acl.h | 2 | 0 |
| src/include/utils/builtins.h | 2 | 1 |
| src/include/utils/evtcache.h | 130 | 0 |
| src/pl/plperl/expected/plperl_trigger.out | 2 | 2 |
| src/pl/plperl/plperl.c | 10 | 4 |
| src/pl/plperl/sql/plperl_trigger.sql | 2 | 2 |
| src/pl/plpgsql/src/pl_comp.c | 20 | 4 |
| src/pl/plpgsql/src/pl_exec.c | 28 | 4 |
| src/pl/plpgsql/src/plpgsql.h | 3 | 0 |
| src/pl/plpython/expected/plpython_trigger.out | 2 | 2 |
| src/pl/plpython/plpy_exec.c | 24 | 4 |
| src/pl/plpython/sql/plpython_trigger.sql | 2 | 2 |
| src/pl/tcl/expected/pltcl_setup.out | 2 | 2 |
| src/pl/tcl/pltcl.c | 4 | 2 |
| src/pl/tcl/sql/pltcl_setup.sql | 2 | 2 |
| src/test/regress/expected/event_triggers.out | 250 | 247 |
| src/test/regress/expected/type_sanity.out | 8 | 10 |
| src/test/regress/sql/event_triggers.sql | 14 | 15 |
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 2b46b75..b100a42 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -99,11 +99,6 @@
</row>
<row>
- <entry><link linkend="catalog-pg-event-trigger"><structname>pg_event_trigger</structname></link></entry>
- <entry>event triggers</entry>
- </row>
-
- <row>
<entry><link linkend="catalog-pg-constraint"><structname>pg_constraint</structname></link></entry>
<entry>check constraints, unique constraints, primary key constraints, foreign key constraints</entry>
</row>
@@ -149,6 +144,11 @@
</row>
<row>
+ <entry><link linkend="catalog-pg-event-trigger"><structname>pg_event_trigger</structname></link></entry>
+ <entry>event triggers</entry>
+ </row>
+
+ <row>
<entry><link linkend="catalog-pg-extension"><structname>pg_extension</structname></link></entry>
<entry>installed extensions</entry>
</row>
@@ -1871,6 +1871,7 @@
<para>
The catalog <structname>pg_event_trigger</structname> stores event triggers.
+ See <xref linkend="event-triggers"> for more information.
</para>
<table>
@@ -1891,23 +1892,28 @@
<entry><structfield>evtname</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
- <entry>Trigger name (unique)</entry>
+ <entry>Trigger name (must be unique)</entry>
</row>
<row>
<entry><structfield>evtevent</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
- <entry>The event this trigger fires for.</entry>
+ <entry>Identifies the event for which this trigger fires</entry>
+ </row>
+
+ <row>
+ <entry><structfield>evtowner</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+ <entry>Owner of the event trigger</entry>
</row>
<row>
<entry><structfield>evtfoid</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
- <entry>
- The OID of the function called by this event trigger.
- </entry>
+ <entry>The function to be called</entry>
</row>
<row>
@@ -1928,7 +1934,10 @@
<entry><structfield>evttags</structfield></entry>
<entry><type>text[]</type></entry>
<entry></entry>
- <entry>Command tags of the commands this trigger is restricted to.</entry>
+ <entry>
+ Command tags for which this trigger will fire. If NULL, the firing
+ of this trigger is not restricted on the basis of the command tag.
+ </entry>
</row>
</tbody>
</tgroup>
diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml
new file mode 100644
index 0000000..52e9764
--- /dev/null
+++ b/doc/src/sgml/event-trigger.sgml
@@ -0,0 +1,466 @@
+<!-- doc/src/sgml/event-trigger.sgml -->
+
+ <chapter id="event-triggers">
+ <title>Event Triggers</title>
+
+ <indexterm zone="event-triggers">
+ <primary>event trigger</primary>
+ </indexterm>
+
+ <para>
+ To supplement the trigger mechanism discussed in <xref linkend="triggers">,
+ <productname>PostgreSQL</> also provides event triggers. Unlike regular
+ triggers, which are attached to a single table and capture only DML events,
+ event triggers are global to a particular database and are capable of
+ capturing DDL events.
+ </para>
+
+ <para>
+ Like regular triggers, event triggers can be written in any procedural
+ language that includes event trigger support, or in C, but not in plain
+ SQL.
+ </para>
+
+ <sect1 id="event-trigger-definition">
+ <title>Overview of Event Trigger Behavior</title>
+
+ <para>
+ An event trigger fires whenever the event with which it is
+ associated occurs in the database in which it is defined. Currently,
+ the only supported event is <literal>command_start</>. Support for
+ additional events may be added in future releases.
+ </para>
+
+ <para>
+ The <literal>command_start</> event occurs just before the execution of
+ many SQL commands, most of which can be broadly described as
+ <link linkend="ddl">DDL</link>. There are a number of commands that,
+ for various reasons, are specifically excluded from the event trigger
+ system:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The <literal>command_start</> event does not occur for commands that
+ access or modify data within a particular table, such
+ <xref linkend="sql-select">, <xref linkend="sql-insert">,
+ <xref linkend="sql-update">, <xref linkend="sql-delete">, and
+ <xref linkend="sql-truncate">. This also includes commands related
+ to prepared plans, such as <xref linkend="sql-prepare">,
+ <xref linkend="sql-deallocate">, <xref linkend="sql-declare">,
+ and <xref linkend="sql-fetch">. Ordinary triggers or rules should
+ be used in these cases.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>command_start</> event does not occur for commands that
+ create, alter, or drop global objects. Unlike the event trigger, these
+ objects are not part of the current database; they are accessible from
+ all databases in the cluster, and are therefore unaffected by event
+ triggers. Such objects include databases, tablespaces, and roles.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>command_start</> event does not occur for commands where
+ firing a trigger might result either result in system instability or
+ interfere with the administrator's ability to regain control of the
+ database. These include transaction control commands, such as
+ <xref linkend="sql-begin"> or <xref linkend="sql-commit">; configuration
+ commands, such as <xref linkend="sql-set"> or <xref linkend="sql-show">;
+ and commands related to the event trigger mechanism itself, such as
+ <xref linkend="sql-createeventtrigger">,
+ <xref linkend="sql-altereventtrigger">, and
+ <xref linkend="sql-dropeventtrigger">.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ For a complete list of commands supported by the event trigger mechanism,
+ see <xref linkend="event-trigger-matrix">.
+ </para>
+
+ <para>
+ 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
+ a signal that the function is to be invoked as an event trigger.
+ </para>
+
+ <para>
+ If more than one event trigger is defined for a particular event, they will
+ fire in alphabetical order by trigger name.
+ </para>
+
+ <para>
+ A trigger definition can also specify a <literal>WHEN</literal>
+ condition so that, for example, a <literal>command_start</literal>
+ trigger can be fired only for particular commands which the user wishes
+ to intercept. A common use of such triggers is to restrict the range of
+ DDL operations which users may perform.
+ </para>
+ </sect1>
+
+ <sect1 id="event-trigger-matrix">
+ <title>Event Trigger Firing Matrix</title>
+
+ <para>
+ <xref linkend="event-trigger-by-command-tag"> lists all commands
+ for which event triggers are supported.
+ </para>
+
+ <table id="event-trigger-by-command-tag">
+ <title>Event Trigger Support by Command Tag</title>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>command tag</entry>
+ <entry><literal>command_start</literal></entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry align="left"><literal>ALTER AGGREGATE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER COLLATION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER CONVERSION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER DOMAIN</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER EXTENSION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER FOREIGN DATA WRAPPER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER FOREIGN TABLE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER FUNCTION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER LANGUAGE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER OPERATOR</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER OPERATOR CLASS</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER OPERATOR FAMILY</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER SCHEMA</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER SEQUENCE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER SERVER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER TABLE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER TEXT SEARCH CONFIGURATION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER TEXT SEARCH DICTIONARY</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER TEXT SEARCH PARSER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER TEXT SEARCH TEMPLATE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER TRIGGER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER TYPE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER USER MAPPING</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>ALTER VIEW</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CLUSTER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE AGGREGATE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE CAST</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE COLLATION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE CONVERSION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE DOMAIN</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE EXTENSION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE FOREIGN DATA WRAPPER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE FOREIGN TABLE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE FUNCTION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE INDEX</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE LANGUAGE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE OPERATOR</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE OPERATOR CLASS</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE OPERATOR FAMILY</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE RULE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE SCHEMA</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE SEQUENCE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE SERVER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TABLE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TABLE AS</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TEXT SEARCH CONFIGURATION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TEXT SEARCH DICTIONARY</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TEXT SEARCH PARSER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TEXT SEARCH TEMPLATE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TRIGGER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE TYPE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE USER MAPPING</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>CREATE VIEW</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP AGGREGATE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP CAST</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP COLLATION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP CONVERSION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP DOMAIN</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP EXTENSION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP FOREIGN DATA WRAPPER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP FOREIGN TABLE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP FUNCTION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP INDEX</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP LANGUAGE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP OPERATOR</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP OPERATOR CLASS</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP OPERATOR FAMILY</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP RULE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP SCHEMA</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP SEQUENCE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP SERVER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP TABLE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP TEXT SEARCH CONFIGURATION</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP TEXT SEARCH DICTIONARY</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP TEXT SEARCH PARSER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP TEXT SEARCH TEMPLATE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP TRIGGER</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP TYPE</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP USER MAPPING</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>DROP VIEW</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>LOAD</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>REINDEX</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>SELECT INTO</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ <row>
+ <entry align="left"><literal>VACUUM</literal></entry>
+ <entry align="center"><literal>X</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+</chapter>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 82b9e39..db4cc3a 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -61,6 +61,7 @@
<!ENTITY rules SYSTEM "rules.sgml">
<!ENTITY spi SYSTEM "spi.sgml">
<!ENTITY trigger SYSTEM "trigger.sgml">
+<!ENTITY event-trigger SYSTEM "event-trigger.sgml">
<!ENTITY xaggr SYSTEM "xaggr.sgml">
<!ENTITY xfunc SYSTEM "xfunc.sgml">
<!ENTITY xindex SYSTEM "xindex.sgml">
diff --git a/doc/src/sgml/plperl.sgml b/doc/src/sgml/plperl.sgml
index b783e86..e490086 100644
--- a/doc/src/sgml/plperl.sgml
+++ b/doc/src/sgml/plperl.sgml
@@ -634,7 +634,7 @@ SELECT init_hosts_query();
SELECT query_hosts('192.168.1.0/30');
SELECT release_hosts_query();
- query_hosts
+ query_hosts
-----------------
(1,192.168.1.1)
(2,192.168.1.2)
@@ -1220,7 +1220,7 @@ CREATE TRIGGER test_valid_id_trig
</sect2>
<sect2 id="plperl-event-trigger">
- <title>Trigger Procedures on Events in PL/Perl </title>
+ <title>Trigger Procedures on Events in PL/Perl</title>
<indexterm>
<primary>event trigger</primary>
@@ -1229,9 +1229,9 @@ CREATE TRIGGER test_valid_id_trig
<para>
Event trigger procedures can be written in PL/Perl.
- <productname>PostgreSQL</productname> requires that a procedure that is to be called
- as a trigger must be declared as a function with no arguments
- and a return type of <literal>event_trigger</>.
+ <productname>PostgreSQL</productname> requires that a procedure 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</>.
</para>
<para>
@@ -1272,7 +1272,7 @@ CREATE TRIGGER test_valid_id_trig
<term><varname>$_TD->{objectname}</varname></term>
<listitem>
<para>
- The name of the objectthat caused the trigger procedure
+ The name of the object that caused the trigger procedure
to be invoked.
</para>
</listitem>
@@ -1289,7 +1289,7 @@ CREATE TRIGGER test_valid_id_trig
</varlistentry>
</variablelist>
</para>
- </sect2>
+ </sect2>
</sect1>
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index fadd5d7..a21aaf2 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -3378,7 +3378,7 @@ RAISE unique_violation USING MESSAGE = 'Duplicate user ID: ' || user_id;
</indexterm>
<sect2 id="plpgsql-dml-trigger">
- <title>Triggers on data change</title>
+ <title>Triggers on data changes</title>
<para>
<application>PL/pgSQL</application> can be used to define trigger
@@ -3930,19 +3930,19 @@ SELECT * FROM sales_summary_bytime;
</sect2>
<sect2 id="plpgsql-event-trigger">
- <title>Triggers on event</title>
+ <title>Triggers on events</title>
<para>
- <application>PL/pgSQL</application> can be used to define command
- trigger procedures. An event trigger procedure is created with the
- <command>CREATE FUNCTION</> command, declaring it as a function with
- no arguments and a return type of <type>event trigger</type>.
+ <application>PL/pgSQL</application> can be used to define event
+ triggers. <productname>PostgreSQL</> requires that a procedure 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</>.
</para>
- <para>
- When a <application>PL/pgSQL</application> function is called as a
- event trigger, several special variables are created automatically
- in the top-level block. They are:
+ <para>
+ When a <application>PL/pgSQL</application> function is called as a
+ event trigger, several special variables are created automatically
+ in the top-level block. They are:
<variablelist>
<varlistentry>
@@ -3999,10 +3999,6 @@ SELECT * FROM sales_summary_bytime;
</variablelist>
</para>
- <para>
- The event trigger function's return value is not used.
- </para>
-
<para>
<xref linkend="plpgsql-event-trigger-example"> shows an example of a
event trigger procedure in <application>PL/pgSQL</application>.
diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
index 07f017a..99ce8f9 100644
--- a/doc/src/sgml/plpython.sgml
+++ b/doc/src/sgml/plpython.sgml
@@ -441,7 +441,7 @@ return (1, 2, 3, 4, 5)
$$ LANGUAGE plpythonu;
SELECT return_arr();
- return_arr
+ return_arr
-------------
{1,2,3,4,5}
(1 row)
@@ -872,7 +872,7 @@ $$ LANGUAGE plpythonu;
</sect2>
<sect2 id="plpython-event-trigger">
- <title>Trigger Procedures on Events in PL/Python </title>
+ <title>Trigger Procedures on Events in PL/Python</title>
<indexterm>
<primary>event trigger</primary>
@@ -881,9 +881,9 @@ $$ LANGUAGE plpythonu;
<para>
Event trigger procedures can be written in PL/Python.
- <productname>PostgreSQL</productname> requires that a procedure that is to be called
- as a trigger must be declared as a function with no arguments
- and a return type of <literal>event_trigger</>.
+ <productname>PostgreSQL</productname> requires that a procedure 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</>.
</para>
<para>
@@ -924,7 +924,7 @@ $$ LANGUAGE plpythonu;
<term><varname>TD["objectname"]</varname></term>
<listitem>
<para>
- The name of the objectthat caused the trigger procedure
+ The name of the object that caused the trigger procedure
to be invoked.
</para>
</listitem>
diff --git a/doc/src/sgml/pltcl.sgml b/doc/src/sgml/pltcl.sgml
index c9a4e4c..c932ddb 100644
--- a/doc/src/sgml/pltcl.sgml
+++ b/doc/src/sgml/pltcl.sgml
@@ -725,9 +725,9 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
<para>
Event trigger procedures can be written in PL/Tcl.
- <productname>PostgreSQL</productname> requires that a procedure that is to be called
- as a trigger must be declared as a function with no arguments
- and a return type of <literal>event_trigger</>.
+ <productname>PostgreSQL</productname> requires that a procedure 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</>.
</para>
<para>
@@ -768,7 +768,7 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
<term><varname>$TG_objectname</varname></term>
<listitem>
<para>
- The name of the objectthat caused the trigger procedure
+ The name of the object that caused the trigger procedure
to be invoked.
</para>
</listitem>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 7e80265..4ef1fc1 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -208,6 +208,7 @@
&extend;
&trigger;
+ &event-trigger;
&rules;
&xplang;
diff --git a/doc/src/sgml/ref/alter_event_trigger.sgml b/doc/src/sgml/ref/alter_event_trigger.sgml
index e236921..db4727b 100644
--- a/doc/src/sgml/ref/alter_event_trigger.sgml
+++ b/doc/src/sgml/ref/alter_event_trigger.sgml
@@ -12,7 +12,7 @@ PostgreSQL documentation
<refnamediv>
<refname>ALTER EVENT TRIGGER</refname>
- <refpurpose>change the definition of a trigger</refpurpose>
+ <refpurpose>change the definition of an event trigger</refpurpose>
</refnamediv>
<indexterm zone="sql-altereventtrigger">
@@ -46,7 +46,7 @@ ALTER EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable> RENAME TO
</para>
<para>
- You must be superuser to alter a event trigger.
+ You must be superuser to alter an event trigger.
</para>
</refsect1>
@@ -93,12 +93,12 @@ ALTER EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable> RENAME TO
</variablelist>
</refsect1>
- <refsect1>
+ <refsect1 id="sql-alterventtrigger-compatibility">
<title>Compatibility</title>
<para>
- <command>ALTER EVENT TRIGGER</command> is a <productname>PostgreSQL</>
- extension of the SQL standard.
+ There is no <command>ALTER EVENT TRIGGER</command> statement in the
+ SQL standard.
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/create_event_trigger.sgml b/doc/src/sgml/ref/create_event_trigger.sgml
index af06c88..3b3d474 100644
--- a/doc/src/sgml/ref/create_event_trigger.sgml
+++ b/doc/src/sgml/ref/create_event_trigger.sgml
@@ -12,7 +12,7 @@ PostgreSQL documentation
<refnamediv>
<refname>CREATE EVENT TRIGGER</refname>
- <refpurpose>define a new trigger</refpurpose>
+ <refpurpose>define a new event trigger</refpurpose>
</refnamediv>
<indexterm zone="sql-createeventtrigger">
@@ -23,100 +23,8 @@ PostgreSQL documentation
<synopsis>
CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
ON <replaceable class="PARAMETER">event</replaceable>
- [ WHEN <replaceable class="PARAMETER">variable</replaceable> IN (tag [, tag [, ...] ] ) ]
- EXECUTE PROCEDURE <replaceable class="PARAMETER">function_name</replaceable> ()
-
-<phrase>where <replaceable class="parameter">event</replaceable> can be one of:</phrase>
-
- command_start
-
-<phrase>where <replaceable class="parameter">tag</replaceable> can be one of:</phrase>
-
- ALTER AGGREGATE
- ALTER COLLATION
- ALTER CONVERSION
- ALTER DOMAIN
- ALTER EXTENSION
- ALTER FOREIGN DATA WRAPPER
- ALTER FOREIGN TABLE
- ALTER FUNCTION
- ALTER LANGUAGE
- ALTER OPERATOR
- ALTER OPERATOR CLASS
- ALTER OPERATOR FAMILY
- ALTER SCHEMA
- ALTER SEQUENCE
- ALTER SERVER
- ALTER TABLE
- ALTER TEXT SEARCH CONFIGURATION
- ALTER TEXT SEARCH DICTIONARY
- ALTER TEXT SEARCH PARSER
- ALTER TEXT SEARCH TEMPLATE
- ALTER TRIGGER
- ALTER TYPE
- ALTER USER MAPPING
- ALTER VIEW
- CLUSTER
- CREATE AGGREGATE
- CREATE CAST
- CREATE COLLATION
- CREATE CONVERSION
- CREATE DOMAIN
- CREATE EXTENSION
- CREATE FOREIGN DATA WRAPPER
- CREATE FOREIGN TABLE
- CREATE FUNCTION
- CREATE INDEX
- CREATE LANGUAGE
- CREATE OPERATOR
- CREATE OPERATOR CLASS
- CREATE OPERATOR FAMILY
- CREATE RULE
- CREATE SCHEMA
- CREATE SEQUENCE
- CREATE SERVER
- CREATE TABLE
- CREATE TABLE AS
- CREATE TEXT SEARCH CONFIGURATION
- CREATE TEXT SEARCH DICTIONARY
- CREATE TEXT SEARCH PARSER
- CREATE TEXT SEARCH TEMPLATE
- CREATE TRIGGER
- CREATE TYPE
- CREATE USER MAPPING
- CREATE VIEW
- DROP AGGREGATE
- DROP CAST
- DROP COLLATION
- DROP CONVERSION
- DROP DOMAIN
- DROP EXTENSION
- DROP FOREIGN DATA WRAPPER
- DROP FOREIGN TABLE
- DROP FUNCTION
- DROP INDEX
- DROP LANGUAGE
- DROP OPERATOR
- DROP OPERATOR CLASS
- DROP OPERATOR FAMILY
- DROP RULE
- DROP SCHEMA
- DROP SEQUENCE
- DROP SERVER
- DROP TABLE
- DROP TEXT SEARCH CONFIGURATION
- DROP TEXT SEARCH DICTIONARY
- DROP TEXT SEARCH PARSER
- DROP TEXT SEARCH TEMPLATE
- DROP TRIGGER
- DROP TYPE
- DROP USER MAPPING
- DROP VIEW
- LOAD
- REINDEX
- SELECT INTO
- VACUUM
-
+ [ WHEN <replaceable class="PARAMETER">filter_variable</replaceable> IN (filter_value [ , ... ] ) ]
+ EXECUTE PROCEDURE <replaceable class="PARAMETER">function_name</replaceable>()
</synopsis>
</refsynopsisdiv>
@@ -125,35 +33,11 @@ CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
<para>
<command>CREATE EVENT TRIGGER</command> creates a new event trigger.
- The trigger will be associated with the specified event and will
- execute the specified
- function <replaceable class="parameter">function_name</replaceable> when
- that event is run.
- </para>
-
- <para>
- The command trigger gives a procedure to fire before the event is
- executed. In some cases the procedure can be fired instead of the event
- code PostgreSQL would run itself. A command trigger's function must
- return <literal>event_trigger</literal> data type. It can then only
- abort the execution of the command by raising an exception.
- </para>
-
- <para>
- If multiple triggers of the same kind are defined for the same event,
- they will be fired in alphabetical order by name.
- </para>
-
- <para>
- Note that objects dropped by the effect of <literal>DROP
- CASCADE</literal> will not result in a event trigger firing, only the
- top-level event for the main object will fire a event trigger. That
- also applies to other dependencies following, as in <literal>DROP OWNED
- BY</literal>.
- </para>
-
- <para>
- Refer to <xref linkend="triggers"> for more information about triggers.
+ Whenever the designated event occurs and the <literal>WHEN</> condition
+ associated with the trigger, if any, is satisfied, the trigger function
+ will be executed. For a general introduction to event triggers, see
+ <xref linkend="event-triggers">. The user who creates an event trigger
+ becomes its owner.
</para>
</refsect1>
@@ -165,52 +49,44 @@ CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
- The name to give the new trigger. This must be distinct from the name
- of any other trigger for the same table. The name cannot be
- schema-qualified.
+ The name to give the new trigger. This name must be unique within
+ the database.
</para>
</listitem>
</varlistentry>
<varlistentry>
- <term><replaceable class="parameter">tag</replaceable></term>
+ <term><replaceable class="parameter">event</replaceable></term>
<listitem>
<para>
- The tag of the command the trigger is for. Supported commands are
- mainly those acting on database objects, plus some more facilities.
- That leaves out the following list of non supported commands.
- </para>
- <para>
- Commands that refer to global objects, such as databases, tablespaces
- and roles, are not supported.
- </para>
- <para>
- The command <literal>ALTER TYPE ... ADD VALUE ...</literal> prevents
- transaction control entirely, thus no command trigger will get fired
- when it's used.
- </para>
- <para>
- Commands that are related to transaction control (such
- as <literal>BEGIN</literal> or <literal>COMMIT</literal>), related to
- prepared plans
- (e.g. <literal>PREPARE</literal>, <literal>DEALLOCATE</literal>),
- cursors management
- (e.g. <literal>DECLARE</literal>, <literal>FETCH</literal>), setting
- variables (<literal>SET</literal>), the <literal>LISTEN</literal>
- feature, and security are not supported either.
+ The name of the event that triggers a call to the given function.
+ See <xref linkend="event-trigger-definition"> for more information
+ on event names.
</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">filter_variable</replaceable></term>
+ <listitem>
<para>
- Event triggers on <literal>CREATE EVENT
- TRIGGER</literal>, <literal>ALTER EVENT TRIGGER</literal>
- and <literal>DROP EVENT TRIGGER</literal> are not supported so as
- not to be able to take over control from a superuser.
+ The name of a variable used to filter events. This makes it possible
+ to restrict the firing of the trigger to a subset of the cases in which
+ it is supported. Currently the only suppoted
+ <replaceable class="parameter">filter_variable</replaceable>
+ is <literal>TAG</literal>.
</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">filter_value</replaceable></term>
+ <listitem>
<para>
- Triggers on <literal>ANY</literal> command support more commands than
- just this list, and will only provide the <literal>command
- tag</literal> argument as <literal>NOT NULL</literal>. Supporting more
- commands is made so that you can actually block <xref linkend="ddl">
- commands in one go.
+ A list of values for the
+ associated <replaceable class="parameter">filter_variable</replaceable>
+ for which the trigger should fire. For <literal>TAG</>, this means a
+ list of command tags (e.g. <literal>'DROP FUNCTION'</>).
</para>
</listitem>
</varlistentry>
@@ -220,7 +96,7 @@ CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
<listitem>
<para>
A user-supplied function that is declared as taking no argument and
- returning type <literal>event trigger</literal>.
+ returning type <literal>event_trigger</literal>.
</para>
<para>
If your event trigger is implemented in <literal>C</literal> then it
@@ -234,24 +110,20 @@ CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
</variablelist>
</refsect1>
- <refsect1 id="SQL-CREATEEVENTTRIGGER-notes">
+ <refsect1 id="sql-createeventtrigger-notes">
<title>Notes</title>
<para>
To create a trigger on a event, the user must be superuser.
</para>
-
- <para>
- Use <xref linkend="sql-dropeventtrigger"> to remove a event trigger.
- </para>
</refsect1>
- <refsect1 id="SQL-CREATEEVENTTRIGGER-examples">
+ <refsect1 id="sql-createeventtrigger-examples">
<title>Examples</title>
<para>
- Forbids the execution of any command supported by the event trigger
- mechanism, which includes all commands listed above:
+ Forbid the execution of any command supported by the event trigger
+ mechanism:
<programlisting>
CREATE OR REPLACE FUNCTION abort_any_command()
@@ -291,13 +163,12 @@ $$;
</para>
</refsect1>
- <refsect1 id="SQL-CREATEEVENTTRIGGER-compatibility">
+ <refsect1 id="sql-createeventtrigger-compatibility">
<title>Compatibility</title>
<para>
- <command>CREATE EVENT TRIGGER</command> is a
- <productname>PostgreSQL</productname> extension of the <acronym>SQL</>
- standard.
+ There is no <command>CREATE EVENT TRIGGER</command> statement in the
+ SQL standard.
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/drop_event_trigger.sgml b/doc/src/sgml/ref/drop_event_trigger.sgml
index fc45dff..86f9628 100644
--- a/doc/src/sgml/ref/drop_event_trigger.sgml
+++ b/doc/src/sgml/ref/drop_event_trigger.sgml
@@ -12,7 +12,7 @@ PostgreSQL documentation
<refnamediv>
<refname>DROP EVENT TRIGGER</refname>
- <refpurpose>remove a event trigger</refpurpose>
+ <refpurpose>remove an event trigger</refpurpose>
</refnamediv>
<indexterm zone="sql-dropeventtrigger">
@@ -29,8 +29,9 @@ DROP EVENT TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceabl
<title>Description</title>
<para>
- <command>DROP EVENT TRIGGER</command> removes an existing trigger definition.
- To execute this command, the current user must be superuser.
+ <command>DROP EVENT TRIGGER</command> removes an existing event trigger.
+ To execute this command, the current user must be the owner of the event
+ trigger.
</para>
</refsect1>
@@ -79,7 +80,7 @@ DROP EVENT TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceabl
</variablelist>
</refsect1>
- <refsect1 id="SQL-DROPEVENTTRIGGER-examples">
+ <refsect1 id="sql-dropeventtrigger-examples">
<title>Examples</title>
<para>
@@ -90,13 +91,14 @@ DROP EVENT TRIGGER snitch;
</programlisting></para>
</refsect1>
- <refsect1 id="SQL-DROPEVENTTRIGGER-compatibility">
+ <refsect1 id="sql-dropeventtrigger-compatibility">
<title>Compatibility</title>
<para>
- The <command>DROP EVENT TRIGGER</command> statement is a
- <productname>PostgreSQL</productname> extension.
+ There is no <command>DROP EVENT TRIGGER</command> statement in the
+ SQL standard.
</para>
+
</refsect1>
<refsect1>
diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml
index 32994b9..f579340 100644
--- a/doc/src/sgml/trigger.sgml
+++ b/doc/src/sgml/trigger.sgml
@@ -27,24 +27,6 @@
plain SQL function language.
</para>
- <para>
- <productname>PostgreSQL</productname> offers both triggers on commands
- (see <xref linkend="ddl">) and triggers on data manipulation
- (see <xref linkend="dml">).
- </para>
-
- <sect1 id="command-triggers">
- <title>Overview of Event Trigger Behavior</title>
-
- <para>
- A trigger is a specification that the database should automatically
- execute a particular function whenever a certain command is performed.
- The whole set of <productname>PostgreSQL</productname> commands is not
- supported for triggers, see <xref linkend="sql-createeventtrigger">
- for details.
- </para>
- </sect1>
-
<sect1 id="trigger-definition">
<title>Overview of Trigger Behavior</title>
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 6e29758..df6da1f 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -12,8 +12,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
- pg_depend.o pg_enum.o pg_event_trigger.o pg_inherits.o pg_largeobject.o \
- pg_namespace.o \
+ pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
pg_type.o storage.o toasting.o
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 56c40b1..b097813 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -29,6 +29,7 @@
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
+#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
@@ -277,6 +278,10 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
case ACL_KIND_FOREIGN_SERVER:
whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
break;
+ case ACL_KIND_EVENT_TRIGGER:
+ elog(ERROR, "grantable rights not supported for event triggers");
+ /* not reached, but keep compiler quiet */
+ return ACL_NO_RIGHTS;
case ACL_KIND_TYPE:
whole_mask = ACL_ALL_RIGHTS_TYPE;
break;
@@ -3286,6 +3291,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
gettext_noop("permission denied for foreign-data wrapper %s"),
/* ACL_KIND_FOREIGN_SERVER */
gettext_noop("permission denied for foreign server %s"),
+ /* ACL_KIND_EVENT_TRIGGER */
+ gettext_noop("permission denied for event trigger %s"),
/* ACL_KIND_EXTENSION */
gettext_noop("permission denied for extension %s"),
};
@@ -3330,6 +3337,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
gettext_noop("must be owner of foreign-data wrapper %s"),
/* ACL_KIND_FOREIGN_SERVER */
gettext_noop("must be owner of foreign server %s"),
+ /* ACL_KIND_EVENT_TRIGGER */
+ gettext_noop("must be owner of event trigger %s"),
/* ACL_KIND_EXTENSION */
gettext_noop("must be owner of extension %s"),
};
@@ -3455,6 +3464,10 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_FOREIGN_SERVER:
return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
+ case ACL_KIND_EVENT_TRIGGER:
+ elog(ERROR, "grantable rights not supported for event triggers");
+ /* not reached, but keep compiler quiet */
+ return ACL_NO_RIGHTS;
case ACL_KIND_TYPE:
return pg_type_aclmask(table_oid, roleid, mask, how);
default:
@@ -4876,6 +4889,33 @@ pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
}
/*
+ * Ownership check for an event trigger (specified by OID).
+ */
+bool
+pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
+{
+ HeapTuple tuple;
+ Oid ownerId;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("event trigger with OID %u does not exist",
+ et_oid)));
+
+ ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
+
+ ReleaseSysCache(tuple);
+
+ return has_privs_of_role(roleid, ownerId);
+}
+
+/*
* Ownership check for a database (specified by OID).
*/
bool
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 40ae60d..5b8140b 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -997,6 +997,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
NameListToString(objname));
break;
+ case OBJECT_EVENT_TRIGGER:
+ if (!pg_event_trigger_ownercheck(address.objectId, roleid))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+ NameListToString(objname));
+ break;
case OBJECT_LANGUAGE:
if (!pg_language_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
@@ -1075,7 +1080,6 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
break;
case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
- case OBJECT_EVENT_TRIGGER:
/* We treat these object types as being owned by superusers */
if (!superuser_arg(roleid))
ereport(ERROR,
diff --git a/src/backend/catalog/pg_event_trigger.c b/src/backend/catalog/pg_event_trigger.c
deleted file mode 100644
index 4995d2b..0000000
--- a/src/backend/catalog/pg_event_trigger.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_event_trigger.c
- * routines to support manipulation of the pg_event_trigger relation
- *
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * src/backend/catalog/pg_event_trigger.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "catalog/pg_event_trigger.h"
-#include "utils/builtins.h"
-
-char *
-event_to_string(TrigEvent event)
-{
- switch (event)
- {
- case E_CommandStart:
- return "command_start";
- }
- return NULL;
-}
-
-TrigEvent
-parse_event_name(char *event)
-{
- if (pg_strcasecmp(event, "command_start") == 0)
- return E_CommandStart;
- else
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("unrecognized event \"%s\"", event)));
-
- /* make compiler happy */
- return -1;
-}
-
-TrigEventCommand
-parse_event_tag(char *command, bool noerror)
-{
- if (pg_strcasecmp(command, "ALTER AGGREGATE") == 0)
- return E_AlterAggregate;
- else if (pg_strcasecmp(command, "ALTER COLLATION") == 0)
- return E_AlterCollation;
- else if (pg_strcasecmp(command, "ALTER CONVERSION") == 0)
- return E_AlterConversion;
- else if (pg_strcasecmp(command, "ALTER DOMAIN") == 0)
- return E_AlterDomain;
- else if (pg_strcasecmp(command, "ALTER EXTENSION") == 0)
- return E_AlterExtension;
- else if (pg_strcasecmp(command, "ALTER FOREIGN DATA WRAPPER") == 0)
- return E_AlterForeignDataWrapper;
- else if (pg_strcasecmp(command, "ALTER FOREIGN TABLE") == 0)
- return E_AlterForeignTable;
- else if (pg_strcasecmp(command, "ALTER FUNCTION") == 0)
- return E_AlterFunction;
- else if (pg_strcasecmp(command, "ALTER LANGUAGE") == 0)
- return E_AlterLanguage;
- else if (pg_strcasecmp(command, "ALTER OPERATOR") == 0)
- return E_AlterOperator;
- else if (pg_strcasecmp(command, "ALTER OPERATOR CLASS") == 0)
- return E_AlterOperatorClass;
- else if (pg_strcasecmp(command, "ALTER OPERATOR FAMILY") == 0)
- return E_AlterOperatorFamily;
- else if (pg_strcasecmp(command, "ALTER SEQUENCE") == 0)
- return E_AlterSequence;
- else if (pg_strcasecmp(command, "ALTER SERVER") == 0)
- return E_AlterServer;
- else if (pg_strcasecmp(command, "ALTER SCHEMA") == 0)
- return E_AlterSchema;
- else if (pg_strcasecmp(command, "ALTER TABLE") == 0)
- return E_AlterTable;
- else if (pg_strcasecmp(command, "ALTER TEXT SEARCH CONFIGURATION") == 0)
- return E_AlterTextSearchConfiguration;
- else if (pg_strcasecmp(command, "ALTER TEXT SEARCH DICTIONARY") == 0)
- return E_AlterTextSearchDictionary;
- else if (pg_strcasecmp(command, "ALTER TEXT SEARCH PARSER") == 0)
- return E_AlterTextSearchParser;
- else if (pg_strcasecmp(command, "ALTER TEXT SEARCH TEMPLATE") == 0)
- return E_AlterTextSearchTemplate;
- else if (pg_strcasecmp(command, "ALTER TRIGGER") == 0)
- return E_AlterTrigger;
- else if (pg_strcasecmp(command, "ALTER TYPE") == 0)
- return E_AlterType;
- else if (pg_strcasecmp(command, "ALTER USER MAPPING") == 0)
- return E_AlterUserMapping;
- else if (pg_strcasecmp(command, "ALTER VIEW") == 0)
- return E_AlterView;
- else if (pg_strcasecmp(command, "CLUSTER") == 0)
- return E_Cluster;
- else if (pg_strcasecmp(command, "CREATE AGGREGATE") == 0)
- return E_CreateAggregate;
- else if (pg_strcasecmp(command, "CREATE CAST") == 0)
- return E_CreateCast;
- else if (pg_strcasecmp(command, "CREATE COLLATION") == 0)
- return E_CreateCollation;
- else if (pg_strcasecmp(command, "CREATE CONVERSION") == 0)
- return E_CreateConversion;
- else if (pg_strcasecmp(command, "CREATE DOMAIN") == 0)
- return E_CreateDomain;
- else if (pg_strcasecmp(command, "CREATE EXTENSION") == 0)
- return E_CreateExtension;
- else if (pg_strcasecmp(command, "CREATE FOREIGN DATA WRAPPER") == 0)
- return E_CreateForeignDataWrapper;
- else if (pg_strcasecmp(command, "CREATE FOREIGN TABLE") == 0)
- return E_CreateForeignTable;
- else if (pg_strcasecmp(command, "CREATE FUNCTION") == 0)
- return E_CreateFunction;
- else if (pg_strcasecmp(command, "CREATE INDEX") == 0)
- return E_CreateIndex;
- else if (pg_strcasecmp(command, "CREATE LANGUAGE") == 0)
- return E_CreateLanguage;
- else if (pg_strcasecmp(command, "CREATE OPERATOR") == 0)
- return E_CreateOperator;
- else if (pg_strcasecmp(command, "CREATE OPERATOR CLASS") == 0)
- return E_CreateOperatorClass;
- else if (pg_strcasecmp(command, "CREATE OPERATOR FAMILY") == 0)
- return E_CreateOperatorFamily;
- else if (pg_strcasecmp(command, "CREATE RULE") == 0)
- return E_CreateRule;
- else if (pg_strcasecmp(command, "CREATE SEQUENCE") == 0)
- return E_CreateSequence;
- else if (pg_strcasecmp(command, "CREATE SERVER") == 0)
- return E_CreateServer;
- else if (pg_strcasecmp(command, "CREATE SCHEMA") == 0)
- return E_CreateSchema;
- else if (pg_strcasecmp(command, "CREATE TABLE") == 0)
- return E_CreateTable;
- else if (pg_strcasecmp(command, "CREATE TABLE AS") == 0)
- return E_CreateTableAs;
- else if (pg_strcasecmp(command, "CREATE TEXT SEARCH CONFIGURATION") == 0)
- return E_CreateTextSearchConfiguration;
- else if (pg_strcasecmp(command, "CREATE TEXT SEARCH DICTIONARY") == 0)
- return E_CreateTextSearchDictionary;
- else if (pg_strcasecmp(command, "CREATE TEXT SEARCH PARSER") == 0)
- return E_CreateTextSearchParser;
- else if (pg_strcasecmp(command, "CREATE TEXT SEARCH TEMPLATE") == 0)
- return E_CreateTextSearchTemplate;
- else if (pg_strcasecmp(command, "CREATE TRIGGER") == 0)
- return E_CreateTrigger;
- else if (pg_strcasecmp(command, "CREATE TYPE") == 0)
- return E_CreateType;
- else if (pg_strcasecmp(command, "CREATE USER MAPPING") == 0)
- return E_CreateUserMapping;
- else if (pg_strcasecmp(command, "CREATE VIEW") == 0)
- return E_CreateView;
- else if (pg_strcasecmp(command, "DROP AGGREGATE") == 0)
- return E_DropAggregate;
- else if (pg_strcasecmp(command, "DROP CAST") == 0)
- return E_DropCast;
- else if (pg_strcasecmp(command, "DROP COLLATION") == 0)
- return E_DropCollation;
- else if (pg_strcasecmp(command, "DROP CONVERSION") == 0)
- return E_DropConversion;
- else if (pg_strcasecmp(command, "DROP DOMAIN") == 0)
- return E_DropDomain;
- else if (pg_strcasecmp(command, "DROP EXTENSION") == 0)
- return E_DropExtension;
- else if (pg_strcasecmp(command, "DROP FOREIGN DATA WRAPPER") == 0)
- return E_DropForeignDataWrapper;
- else if (pg_strcasecmp(command, "DROP FOREIGN TABLE") == 0)
- return E_DropForeignTable;
- else if (pg_strcasecmp(command, "DROP FUNCTION") == 0)
- return E_DropFunction;
- else if (pg_strcasecmp(command, "DROP INDEX") == 0)
- return E_DropIndex;
- else if (pg_strcasecmp(command, "DROP LANGUAGE") == 0)
- return E_DropLanguage;
- else if (pg_strcasecmp(command, "DROP OPERATOR") == 0)
- return E_DropOperator;
- else if (pg_strcasecmp(command, "DROP OPERATOR CLASS") == 0)
- return E_DropOperatorClass;
- else if (pg_strcasecmp(command, "DROP OPERATOR FAMILY") == 0)
- return E_DropOperatorFamily;
- else if (pg_strcasecmp(command, "DROP RULE") == 0)
- return E_DropRule;
- else if (pg_strcasecmp(command, "DROP SCHEMA") == 0)
- return E_DropSchema;
- else if (pg_strcasecmp(command, "DROP SEQUENCE") == 0)
- return E_DropSequence;
- else if (pg_strcasecmp(command, "DROP SERVER") == 0)
- return E_DropServer;
- else if (pg_strcasecmp(command, "DROP TABLE") == 0)
- return E_DropTable;
- else if (pg_strcasecmp(command, "DROP TEXT SEARCH CONFIGURATION") == 0)
- return E_DropTextSearchConfiguration;
- else if (pg_strcasecmp(command, "DROP TEXT SEARCH DICTIONARY") == 0)
- return E_DropTextSearchDictionary;
- else if (pg_strcasecmp(command, "DROP TEXT SEARCH PARSER") == 0)
- return E_DropTextSearchParser;
- else if (pg_strcasecmp(command, "DROP TEXT SEARCH TEMPLATE") == 0)
- return E_DropTextSearchTemplate;
- else if (pg_strcasecmp(command, "DROP TRIGGER") == 0)
- return E_DropTrigger;
- else if (pg_strcasecmp(command, "DROP TYPE") == 0)
- return E_DropType;
- else if (pg_strcasecmp(command, "DROP USER MAPPING") == 0)
- return E_DropUserMapping;
- else if (pg_strcasecmp(command, "DROP VIEW") == 0)
- return E_DropView;
- else if (pg_strcasecmp(command, "LOAD") == 0)
- return E_Load;
- else if (pg_strcasecmp(command, "REINDEX") == 0)
- return E_Reindex;
- else if (pg_strcasecmp(command, "SELECT INTO") == 0)
- return E_SelectInto;
- else if (pg_strcasecmp(command, "VACUUM") == 0)
- return E_Vacuum;
- else
- {
- if (!noerror)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("unrecognized command \"%s\"", command)));
- }
- return E_UNKNOWN;
-}
-
-char *
-command_to_string(TrigEventCommand command)
-{
- switch (command)
- {
- case E_UNKNOWN:
- return "UNKNOWN";
- case E_ANY:
- return "ANY";
- case E_AlterCast:
- return "ALTER CAST";
- case E_AlterIndex:
- return "ALTER INDEX";
- case E_AlterAggregate:
- return "ALTER AGGREGATE";
- case E_AlterCollation:
- return "ALTER COLLATION";
- case E_AlterConversion:
- return "ALTER CONVERSION";
- case E_AlterDomain:
- return "ALTER DOMAIN";
- case E_AlterExtension:
- return "ALTER EXTENSION";
- case E_AlterForeignDataWrapper:
- return "ALTER FOREIGN DATA WRAPPER";
- case E_AlterForeignTable:
- return "ALTER FOREIGN TABLE";
- case E_AlterFunction:
- return "ALTER FUNCTION";
- case E_AlterLanguage:
- return "ALTER LANGUAGE";
- case E_AlterOperator:
- return "ALTER OPERATOR";
- case E_AlterOperatorClass:
- return "ALTER OPERATOR CLASS";
- case E_AlterOperatorFamily:
- return "ALTER OPERATOR FAMILY";
- case E_AlterSequence:
- return "ALTER SEQUENCE";
- case E_AlterServer:
- return "ALTER SERVER";
- case E_AlterSchema:
- return "ALTER SCHEMA";
- case E_AlterTable:
- return "ALTER TABLE";
- case E_AlterTextSearchConfiguration:
- return "ALTER TEXT SEARCH CONFIGURATION";
- case E_AlterTextSearchDictionary:
- return "ALTER TEXT SEARCH DICTIONARY";
- case E_AlterTextSearchParser:
- return "ALTER TEXT SEARCH PARSER";
- case E_AlterTextSearchTemplate:
- return "ALTER TEXT SEARCH TEMPLATE";
- case E_AlterTrigger:
- return "ALTER TRIGGER";
- case E_AlterType:
- return "ALTER TYPE";
- case E_AlterUserMapping:
- return "ALTER USER MAPPING";
- case E_AlterView:
- return "ALTER VIEW";
- case E_Cluster:
- return "CLUSTER";
- case E_CreateAggregate:
- return "CREATE AGGREGATE";
- case E_CreateCast:
- return "CREATE CAST";
- case E_CreateCollation:
- return "CREATE COLLATION";
- case E_CreateConversion:
- return "CREATE CONVERSION";
- case E_CreateDomain:
- return "CREATE DOMAIN";
- case E_CreateExtension:
- return "CREATE EXTENSION";
- case E_CreateForeignDataWrapper:
- return "CREATE FOREIGN DATA WRAPPER";
- case E_CreateForeignTable:
- return "CREATE FOREIGN TABLE";
- case E_CreateFunction:
- return "CREATE FUNCTION";
- case E_CreateIndex:
- return "CREATE INDEX";
- case E_CreateLanguage:
- return "CREATE LANGUAGE";
- case E_CreateOperator:
- return "CREATE OPERATOR";
- case E_CreateOperatorClass:
- return "CREATE OPERATOR CLASS";
- case E_CreateOperatorFamily:
- return "CREATE OPERATOR FAMILY";
- case E_CreateRule:
- return "CREATE RULE";
- case E_CreateSequence:
- return "CREATE SEQUENCE";
- case E_CreateServer:
- return "CREATE SERVER";
- case E_CreateSchema:
- return "CREATE SCHEMA";
- case E_CreateTable:
- return "CREATE TABLE";
- case E_CreateTableAs:
- return "CREATE TABLE AS";
- case E_CreateTextSearchConfiguration:
- return "CREATE TEXT SEARCH CONFIGURATION";
- case E_CreateTextSearchDictionary:
- return "CREATE TEXT SEARCH DICTIONARY";
- case E_CreateTextSearchParser:
- return "CREATE TEXT SEARCH PARSER";
- case E_CreateTextSearchTemplate:
- return "CREATE TEXT SEARCH TEMPLATE";
- case E_CreateTrigger:
- return "CREATE TRIGGER";
- case E_CreateType:
- return "CREATE TYPE";
- case E_CreateUserMapping:
- return "CREATE USER MAPPING";
- case E_CreateView:
- return "CREATE VIEW";
- case E_DropAggregate:
- return "DROP AGGREGATE";
- case E_DropCast:
- return "DROP CAST";
- case E_DropCollation:
- return "DROP COLLATION";
- case E_DropConversion:
- return "DROP CONVERSION";
- case E_DropDomain:
- return "DROP DOMAIN";
- case E_DropExtension:
- return "DROP EXTENSION";
- case E_DropForeignDataWrapper:
- return "DROP FOREIGN DATA WRAPPER";
- case E_DropForeignTable:
- return "DROP FOREIGN TABLE";
- case E_DropFunction:
- return "DROP FUNCTION";
- case E_DropIndex:
- return "DROP INDEX";
- case E_DropLanguage:
- return "DROP LANGUAGE";
- case E_DropOperator:
- return "DROP OPERATOR";
- case E_DropOperatorClass:
- return "DROP OPERATOR CLASS";
- case E_DropOperatorFamily:
- return "DROP OPERATOR FAMILY";
- case E_DropRule:
- return "DROP RULE";
- case E_DropSchema:
- return "DROP SCHEMA";
- case E_DropSequence:
- return "DROP SEQUENCE";
- case E_DropServer:
- return "DROP SERVER";
- case E_DropTable:
- return "DROP TABLE";
- case E_DropTextSearchConfiguration:
- return "DROP TEXT SEARCH CONFIGURATION";
- case E_DropTextSearchDictionary:
- return "DROP TEXT SEARCH DICTIONARY";
- case E_DropTextSearchParser:
- return "DROP TEXT SEARCH PARSER";
- case E_DropTextSearchTemplate:
- return "DROP TEXT SEARCH TEMPLATE";
- case E_DropTrigger:
- return "DROP TRIGGER";
- case E_DropType:
- return "DROP TYPE";
- case E_DropUserMapping:
- return "DROP USER MAPPING";
- case E_DropView:
- return "DROP VIEW";
- case E_Load:
- return "LOAD";
- case E_Reindex:
- return "REINDEX";
- case E_SelectInto:
- return "SELECT INTO";
- case E_Vacuum:
- return "VACUUM";
- }
- return NULL;
-}
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 78ef831..19f9895 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -70,10 +70,6 @@ ExecRenameStmt(RenameStmt *stmt)
RenameDatabase(stmt->subname, stmt->newname);
break;
- case OBJECT_EVENT_TRIGGER:
- RenameEventTrigger(stmt->subname, stmt->newname);
- break;
-
case OBJECT_FDW:
RenameForeignDataWrapper(stmt->subname, stmt->newname);
break;
@@ -82,6 +78,10 @@ ExecRenameStmt(RenameStmt *stmt)
RenameForeignServer(stmt->subname, stmt->newname);
break;
+ case OBJECT_EVENT_TRIGGER:
+ RenameEventTrigger(stmt->subname, stmt->newname);
+ break;
+
case OBJECT_FUNCTION:
RenameFunction(stmt->object, stmt->objarg, stmt->newname);
break;
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index 1b8529e..8f5d7e0 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -206,6 +206,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
args = NameListToString(list_truncate(objname,
list_length(objname) - 1));
break;
+ case OBJECT_EVENT_TRIGGER:
+ msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
case OBJECT_RULE:
msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
name = strVal(llast(objname));
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 4ea2848..502e34b 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -32,7 +32,6 @@
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h"
-#include "utils/evtcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -49,23 +48,6 @@ static void AlterEventTriggerOwner_internal(Relation rel,
Oid newOwnerId);
/*
- * Check permission: command triggers are only available for superusers. Raise
- * an exception when requirements are not fullfilled.
- *
- * It's not clear how to accept that database owners be able to create command
- * triggers, a superuser could run a command that fires a trigger's procedure
- * written by the database owner and now running with superuser privileges.
- */
-static void
-CheckEventTriggerPrivileges()
-{
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- (errmsg("must be superuser to use command triggers"))));
-}
-
-/*
* Insert Command Trigger Tuple
*
* Insert the new pg_event_trigger row, and return the OID assigned to the new
@@ -111,7 +93,7 @@ InsertEventTriggerTuple(char *trigname, TrigEvent event, Oid evtOwner,
{
TrigEventCommand cmd = lfirst_int(lc);
char *cmdstr = command_to_string(cmd);
- if (cmd == E_UNKNOWN || cmdstr == NULL)
+ if (cmd == ETC_UNKNOWN || cmdstr == NULL)
elog(ERROR, "Unknown command %d", cmd);
tags[i++] = PointerGetDatum(cstring_to_text(cmdstr));
}
@@ -158,7 +140,16 @@ CreateEventTrigger(CreateEventTrigStmt *stmt, const char *queryString)
Oid funcrettype;
Oid evtowner = GetUserId();
- CheckEventTriggerPrivileges();
+ /*
+ * It would be nice to allow database owners or even regular users to do
+ * this, but there are obvious privilege escalation risks which would have
+ * to somehow be plugged first.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errmsg("permission denied to create event trigger \"%s\"",
+ stmt->trigname),
+ errhint("Must be superuser to create an event trigger.")));
/*
* Find and validate the trigger function.
@@ -171,7 +162,7 @@ CreateEventTrigger(CreateEventTrigStmt *stmt, const char *queryString)
if (funcrettype != EVTTRIGGEROID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("function \"%s\" must return type \"command_trigger\"",
+ errmsg("function \"%s\" must return type \"event_trigger\"",
NameListToString(stmt->funcname))));
/*
@@ -214,7 +205,7 @@ RemoveEventTriggerById(Oid trigOid)
}
/*
- * ALTER EVENT TRIGGER foo ON COMMAND ... ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
+ * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
*/
void
AlterEventTrigger(AlterEventTrigStmt *stmt)
@@ -224,15 +215,18 @@ AlterEventTrigger(AlterEventTrigStmt *stmt)
Form_pg_event_trigger evtForm;
char tgenabled = stmt->tgenabled;
- CheckEventTriggerPrivileges();
-
tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
- tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
+ tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
+ CStringGetDatum(stmt->trigname));
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("event trigger \"%s\" does not exist", stmt->trigname)));
+ errmsg("event trigger \"%s\" does not exist",
+ stmt->trigname)));
+ if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+ stmt->trigname);
/* tuple is a copy, so we can modify it below */
evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
@@ -248,7 +242,7 @@ AlterEventTrigger(AlterEventTrigStmt *stmt)
/*
- * Rename command trigger
+ * Rename event trigger
*/
void
RenameEventTrigger(const char *trigname, const char *newname)
@@ -257,8 +251,6 @@ RenameEventTrigger(const char *trigname, const char *newname)
Relation rel;
Form_pg_event_trigger evtForm;
- CheckEventTriggerPrivileges();
-
rel = heap_open(EventTriggerRelationId, RowExclusiveLock);
/* newname must be available */
@@ -273,6 +265,9 @@ RenameEventTrigger(const char *trigname, const char *newname)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("event trigger \"%s\" does not exist", trigname)));
+ if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+ trigname);
evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
@@ -344,22 +339,31 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
{
Form_pg_event_trigger form;
- CheckEventTriggerPrivileges();
-
form = (Form_pg_event_trigger) GETSTRUCT(tup);
- if (form->evtowner != newOwnerId)
- {
- form->evtowner = newOwnerId;
+ if (form->evtowner == newOwnerId)
+ return;
- simple_heap_update(rel, &tup->t_self, tup);
- CatalogUpdateIndexes(rel, tup);
+ if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+ NameStr(form->evtname));
- /* Update owner dependency reference */
- changeDependencyOnOwner(EventTriggerRelationId,
- HeapTupleGetOid(tup),
- newOwnerId);
- }
+ /* New owner must be a superuser */
+ if (!superuser_arg(newOwnerId))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to change owner of event trigger \"%s\"",
+ NameStr(form->evtname)),
+ errhint("The owner of an event trigger must be a superuser.")));
+
+ form->evtowner = newOwnerId;
+ simple_heap_update(rel, &tup->t_self, tup);
+ CatalogUpdateIndexes(rel, tup);
+
+ /* Update owner dependency reference */
+ changeDependencyOnOwner(EventTriggerRelationId,
+ HeapTupleGetOid(tup),
+ newOwnerId);
}
/*
@@ -382,9 +386,9 @@ get_event_trigger_oid(const char *trigname, bool missing_ok)
}
/*
- * Functions to execute the command triggers.
+ * Functions to execute the event triggers.
*
- * We call the functions that matches the command triggers definitions in
+ * We call the functions that matches the event triggers definitions in
* alphabetical order, and give them those arguments:
*
* toplevel command tag, text
@@ -394,7 +398,7 @@ get_event_trigger_oid(const char *trigname, bool missing_ok)
* objectname, text
*
* Those are passed down as special "context" magic variables and need specific
- * support in each PL that wants to support command triggers. All core PL do.
+ * support in each PL that wants to support event triggers. All core PL do.
*/
static void
@@ -409,17 +413,27 @@ call_event_trigger_procedure(EventContext ev_ctx, TrigEvent tev,
fmgr_info(proc, &flinfo);
/*
- * Prepare the command trigger function context from the Command Context.
+ * Prepare the event trigger function context from the Command Context.
* We prepare a dedicated Node here so as not to publish internal data.
*/
- trigdata.type = T_EventTriggerData;
- trigdata.toplevel = ev_ctx->toplevel;
- trigdata.tag = ev_ctx->tag;
- trigdata.objectId = ev_ctx->objectId;
+ trigdata.type = T_EventTriggerData;
+ trigdata.event = pstrdup(event_to_string(tev));
+ trigdata.toplevel = ev_ctx->toplevel;
+ trigdata.tag = ev_ctx->tag;
+ trigdata.objectId = ev_ctx->objectId;
trigdata.schemaname = ev_ctx->schemaname;
trigdata.objectname = ev_ctx->objectname;
- trigdata.parsetree = ev_ctx->parsetree;
- trigdata.when = pstrdup(event_to_string(tev));
+ trigdata.parsetree = ev_ctx->parsetree;
+
+ if (ev_ctx->operation == NULL)
+ trigdata.operation = NULL;
+ else
+ trigdata.operation = pstrdup(ev_ctx->operation);
+
+ if (ev_ctx->objecttype == -1)
+ trigdata.objecttype = NULL;
+ else
+ trigdata.objecttype = pstrdup(objecttype_to_string(ev_ctx->objecttype));
/*
* Call the function, passing no arguments but setting a context.
@@ -436,599 +450,55 @@ call_event_trigger_procedure(EventContext ev_ctx, TrigEvent tev,
/*
* Routine to call to setup a EventContextData evt.
+ *
+ * The fields 'objecttype' must be set before calling other entry points. The
+ * fields 'operation', 'objectId', 'objectname' and 'schemaname' might be set
+ * to interesting values.
*/
void
InitEventContext(EventContext evt, const Node *parsetree)
{
- evt->command = E_UNKNOWN;
- evt->toplevel = NULL;
- evt->tag = (char *) CreateCommandTag((Node *)parsetree);
- evt->parsetree = (Node *)parsetree;
- evt->objectId = InvalidOid;
+ evt->command = ETC_UNSET;
+ evt->toplevel = NULL;
+ evt->tag = (char *) CreateCommandTag((Node *)parsetree);
+ evt->parsetree = (Node *)parsetree;
+ evt->operation = NULL;
+ evt->objecttype = -1;
+ evt->objectId = InvalidOid;
evt->objectname = NULL;
evt->schemaname = NULL;
- /*
- * Fill in the event command, which is an enum constant to match against
- * what's stored into catalogs. As we are storing that on disk, we need the
- * enum values to be stable, see src/include/catalog/pg_event_trigger.h for
- * details.
- */
- switch (nodeTag(parsetree))
- {
- case T_CreateSchemaStmt:
- evt->command = E_CreateSchema;
- break;
-
- case T_CreateStmt:
- evt->command = E_CreateTable;
- break;
-
- case T_CreateForeignTableStmt:
- evt->command = E_CreateForeignTable;
- break;
-
- case T_CreateExtensionStmt:
- evt->command = E_CreateExtension;
- break;
-
- case T_AlterExtensionStmt:
- case T_AlterExtensionContentsStmt:
- evt->command = E_AlterExtension;
- break;
-
- case T_CreateFdwStmt:
- evt->command = E_CreateForeignDataWrapper;
- break;
-
- case T_AlterFdwStmt:
- evt->command = E_AlterForeignDataWrapper;
- break;
-
- case T_CreateForeignServerStmt:
- evt->command = E_CreateServer;
- break;
-
- case T_AlterForeignServerStmt:
- evt->command = E_AlterServer;
- break;
-
- case T_CreateUserMappingStmt:
- evt->command = E_CreateUserMapping;
- break;
-
- case T_AlterUserMappingStmt:
- evt->command = E_AlterUserMapping;
- break;
-
- case T_DropUserMappingStmt:
- evt->command = E_DropUserMapping;
- break;
-
- case T_DropStmt:
- switch (((DropStmt *) parsetree)->removeType)
- {
- case OBJECT_AGGREGATE:
- evt->command = E_DropAggregate;
- break;
- case OBJECT_CAST:
- evt->command = E_DropCast;
- break;
- case OBJECT_COLLATION:
- evt->command = E_DropCollation;
- break;
- case OBJECT_CONVERSION:
- evt->command = E_DropConversion;
- break;
- case OBJECT_DOMAIN:
- evt->command = E_DropDomain;
- break;
- case OBJECT_EXTENSION:
- evt->command = E_DropExtension;
- break;
- case OBJECT_FDW:
- evt->command = E_DropForeignDataWrapper;
- break;
- case OBJECT_FOREIGN_SERVER:
- evt->command = E_DropServer;
- break;
- case OBJECT_FOREIGN_TABLE:
- evt->command = E_DropForeignTable;
- break;
- case OBJECT_FUNCTION:
- evt->command = E_DropFunction;
- break;
- case OBJECT_INDEX:
- evt->command = E_DropIndex;
- break;
- case OBJECT_LANGUAGE:
- evt->command = E_DropLanguage;
- break;
- case OBJECT_OPCLASS:
- evt->command = E_DropOperatorClass;
- break;
- case OBJECT_OPERATOR:
- evt->command = E_DropOperator;
- break;
- case OBJECT_OPFAMILY:
- evt->command = E_DropOperatorFamily;
- break;
- case OBJECT_SCHEMA:
- evt->command = E_DropSchema;
- break;
- case OBJECT_SEQUENCE:
- evt->command = E_DropSequence;
- break;
- case OBJECT_TABLE:
- evt->command = E_DropTable;
- break;
- case OBJECT_TRIGGER:
- evt->command = E_DropTrigger;
- break;
- case OBJECT_TSCONFIGURATION:
- evt->command = E_DropTextSearchConfiguration;
- break;
- case OBJECT_TSDICTIONARY:
- evt->command = E_DropTextSearchDictionary;
- break;
- case OBJECT_TSPARSER:
- evt->command = E_DropTextSearchParser;
- break;
- case OBJECT_TSTEMPLATE:
- evt->command = E_DropTextSearchTemplate;
- break;
- case OBJECT_TYPE:
- evt->command = E_DropType;
- break;
- case OBJECT_VIEW:
- evt->command = E_DropView;
- break;
- case OBJECT_ROLE:
- case OBJECT_EVENT_TRIGGER:
- case OBJECT_ATTRIBUTE:
- case OBJECT_COLUMN:
- case OBJECT_CONSTRAINT:
- case OBJECT_DATABASE:
- case OBJECT_LARGEOBJECT:
- case OBJECT_RULE:
- case OBJECT_TABLESPACE:
- /* no support for specific command triggers */
- break;
- }
- break;
-
- case T_RenameStmt:
- switch (((RenameStmt *) parsetree)->renameType)
- {
- case OBJECT_ATTRIBUTE:
- evt->command = E_AlterType;
- break;
- case OBJECT_AGGREGATE:
- evt->command = E_AlterAggregate;
- break;
- case OBJECT_CAST:
- evt->command = E_AlterCast;
- break;
- case OBJECT_COLLATION:
- evt->command = E_AlterCollation;
- break;
- case OBJECT_COLUMN:
- evt->command = E_AlterTable;
- break;
- case OBJECT_CONVERSION:
- evt->command = E_AlterConversion;
- break;
- case OBJECT_DOMAIN:
- evt->command = E_AlterDomain;
- break;
- case OBJECT_EXTENSION:
- evt->command = E_AlterExtension;
- break;
- case OBJECT_FDW:
- evt->command = E_AlterForeignDataWrapper;
- break;
- case OBJECT_FOREIGN_SERVER:
- evt->command = E_AlterServer;
- break;
- case OBJECT_FOREIGN_TABLE:
- evt->command = E_AlterForeignTable;
- break;
- case OBJECT_FUNCTION:
- evt->command = E_AlterFunction;
- break;
- case OBJECT_INDEX:
- evt->command = E_AlterIndex;
- break;
- case OBJECT_LANGUAGE:
- evt->command = E_AlterLanguage;
- break;
- case OBJECT_OPCLASS:
- evt->command = E_AlterOperatorClass;
- break;
- case OBJECT_OPERATOR:
- evt->command = E_AlterOperator;
- break;
- case OBJECT_OPFAMILY:
- evt->command = E_AlterOperatorFamily;
- break;
- case OBJECT_SCHEMA:
- evt->command = E_AlterSchema;
- break;
- case OBJECT_SEQUENCE:
- evt->command = E_AlterSequence;
- break;
- case OBJECT_TABLE:
- evt->command = E_AlterTable;
- break;
- case OBJECT_TRIGGER:
- evt->command = E_AlterTrigger;
- break;
- case OBJECT_TSCONFIGURATION:
- evt->command = E_AlterTextSearchConfiguration;
- break;
- case OBJECT_TSDICTIONARY:
- evt->command = E_AlterTextSearchDictionary;
- break;
- case OBJECT_TSPARSER:
- evt->command = E_AlterTextSearchParser;
- break;
- case OBJECT_TSTEMPLATE:
- evt->command = E_AlterTextSearchTemplate;
- break;
- case OBJECT_TYPE:
- evt->command = E_AlterType;
- break;
- case OBJECT_VIEW:
- evt->command = E_AlterView;
- break;
- case OBJECT_ROLE:
- case OBJECT_EVENT_TRIGGER:
- case OBJECT_CONSTRAINT:
- case OBJECT_DATABASE:
- case OBJECT_LARGEOBJECT:
- case OBJECT_RULE:
- case OBJECT_TABLESPACE:
- /* no support for specific command triggers */
- break;
- }
- break;
-
- case T_AlterObjectSchemaStmt:
- switch (((AlterObjectSchemaStmt *) parsetree)->objectType)
- {
- case OBJECT_AGGREGATE:
- evt->command = E_AlterAggregate;
- break;
- case OBJECT_CAST:
- evt->command = E_AlterCast;
- break;
- case OBJECT_COLLATION:
- evt->command = E_AlterCollation;
- break;
- case OBJECT_CONVERSION:
- evt->command = E_AlterConversion;
- break;
- case OBJECT_DOMAIN:
- evt->command = E_AlterDomain;
- break;
- case OBJECT_EXTENSION:
- evt->command = E_AlterExtension;
- break;
- case OBJECT_FDW:
- evt->command = E_AlterForeignDataWrapper;
- break;
- case OBJECT_FOREIGN_SERVER:
- evt->command = E_AlterServer;
- break;
- case OBJECT_FOREIGN_TABLE:
- evt->command = E_AlterForeignTable;
- break;
- case OBJECT_FUNCTION:
- evt->command = E_AlterFunction;
- break;
- case OBJECT_INDEX:
- evt->command = E_AlterIndex;
- break;
- case OBJECT_LANGUAGE:
- evt->command = E_AlterLanguage;
- break;
- case OBJECT_OPCLASS:
- evt->command = E_AlterOperatorClass;
- break;
- case OBJECT_OPERATOR:
- evt->command = E_AlterOperator;
- break;
- case OBJECT_OPFAMILY:
- evt->command = E_AlterOperatorFamily;
- break;
- case OBJECT_SCHEMA:
- evt->command = E_AlterSchema;
- break;
- case OBJECT_SEQUENCE:
- evt->command = E_AlterSequence;
- break;
- case OBJECT_TABLE:
- evt->command = E_AlterTable;
- break;
- case OBJECT_TRIGGER:
- evt->command = E_AlterTrigger;
- break;
- case OBJECT_TSCONFIGURATION:
- evt->command = E_AlterTextSearchConfiguration;
- break;
- case OBJECT_TSDICTIONARY:
- evt->command = E_AlterTextSearchDictionary;
- break;
- case OBJECT_TSPARSER:
- evt->command = E_AlterTextSearchParser;
- break;
- case OBJECT_TSTEMPLATE:
- evt->command = E_AlterTextSearchTemplate;
- break;
- case OBJECT_TYPE:
- evt->command = E_AlterType;
- break;
- case OBJECT_VIEW:
- evt->command = E_AlterView;
- break;
- case OBJECT_ROLE:
- case OBJECT_EVENT_TRIGGER:
- case OBJECT_ATTRIBUTE:
- case OBJECT_COLUMN:
- case OBJECT_CONSTRAINT:
- case OBJECT_DATABASE:
- case OBJECT_LARGEOBJECT:
- case OBJECT_RULE:
- case OBJECT_TABLESPACE:
- /* no support for specific command triggers */
- break;
- }
- break;
-
- case T_AlterOwnerStmt:
- switch (((AlterOwnerStmt *) parsetree)->objectType)
- {
- case OBJECT_AGGREGATE:
- evt->command = E_AlterAggregate;
- break;
- case OBJECT_CAST:
- evt->command = E_AlterCast;
- break;
- case OBJECT_COLLATION:
- evt->command = E_AlterCollation;
- break;
- case OBJECT_CONVERSION:
- evt->command = E_AlterConversion;
- break;
- case OBJECT_DOMAIN:
- evt->command = E_AlterDomain;
- break;
- case OBJECT_EXTENSION:
- evt->command = E_AlterExtension;
- break;
- case OBJECT_FDW:
- evt->command = E_AlterForeignDataWrapper;
- break;
- case OBJECT_FOREIGN_SERVER:
- evt->command = E_AlterServer;
- break;
- case OBJECT_FOREIGN_TABLE:
- evt->command = E_AlterForeignTable;
- break;
- case OBJECT_FUNCTION:
- evt->command = E_AlterFunction;
- break;
- case OBJECT_INDEX:
- evt->command = E_AlterIndex;
- break;
- case OBJECT_LANGUAGE:
- evt->command = E_AlterLanguage;
- break;
- case OBJECT_OPCLASS:
- evt->command = E_AlterOperatorClass;
- break;
- case OBJECT_OPERATOR:
- evt->command = E_AlterOperator;
- break;
- case OBJECT_OPFAMILY:
- evt->command = E_AlterOperatorFamily;
- break;
- case OBJECT_SCHEMA:
- evt->command = E_AlterSchema;
- break;
- case OBJECT_SEQUENCE:
- evt->command = E_AlterSequence;
- break;
- case OBJECT_TABLE:
- evt->command = E_AlterTable;
- break;
- case OBJECT_TRIGGER:
- evt->command = E_AlterTrigger;
- break;
- case OBJECT_TSCONFIGURATION:
- evt->command = E_AlterTextSearchConfiguration;
- break;
- case OBJECT_TSDICTIONARY:
- evt->command = E_AlterTextSearchDictionary;
- break;
- case OBJECT_TSPARSER:
- evt->command = E_AlterTextSearchParser;
- break;
- case OBJECT_TSTEMPLATE:
- evt->command = E_AlterTextSearchTemplate;
- break;
- case OBJECT_TYPE:
- evt->command = E_AlterType;
- break;
- case OBJECT_VIEW:
- evt->command = E_AlterView;
- break;
- case OBJECT_ROLE:
- case OBJECT_EVENT_TRIGGER:
- case OBJECT_ATTRIBUTE:
- case OBJECT_COLUMN:
- case OBJECT_CONSTRAINT:
- case OBJECT_DATABASE:
- case OBJECT_LARGEOBJECT:
- case OBJECT_RULE:
- case OBJECT_TABLESPACE:
- /* no support for specific command triggers */
- break;
- }
- break;
-
- case T_AlterTableStmt:
- evt->command = E_AlterTable;
- break;
-
- case T_AlterDomainStmt:
- evt->command = E_AlterDomain;
- break;
-
- case T_DefineStmt:
- switch (((DefineStmt *) parsetree)->kind)
- {
- case OBJECT_AGGREGATE:
- evt->command = E_CreateAggregate;
- break;
- case OBJECT_OPERATOR:
- evt->command = E_CreateOperator;
- break;
- case OBJECT_TYPE:
- evt->command = E_CreateType;
- break;
- case OBJECT_TSPARSER:
- evt->command = E_CreateTextSearchParser;
- break;
- case OBJECT_TSDICTIONARY:
- evt->command = E_CreateTextSearchDictionary;;
- break;
- case OBJECT_TSTEMPLATE:
- evt->command = E_CreateTextSearchTemplate;
- break;
- case OBJECT_TSCONFIGURATION:
- evt->command = E_CreateTextSearchConfiguration;
- break;
- case OBJECT_COLLATION:
- evt->command = E_CreateCollation;
- break;
- default:
- elog(ERROR, "unrecognized define stmt type: %d",
- (int) ((DefineStmt *) parsetree)->kind);
- break;
- }
- break;
-
- case T_CompositeTypeStmt: /* CREATE TYPE (composite) */
- case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
- case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
- evt->command = E_CreateType;
- break;
-
- case T_AlterEnumStmt: /* ALTER TYPE (enum) */
- evt->command = E_AlterType;
- break;
-
- case T_ViewStmt: /* CREATE VIEW */
- evt->command = E_CreateView;
- break;
-
- case T_CreateFunctionStmt: /* CREATE FUNCTION */
- evt->command = E_CreateFunction;
- break;
-
- case T_AlterFunctionStmt: /* ALTER FUNCTION */
- evt->command = E_AlterFunction;
- break;
-
- case T_IndexStmt: /* CREATE INDEX */
- evt->command = E_CreateIndex;
- break;
-
- case T_CreateSeqStmt:
- evt->command = E_CreateSequence;
- break;
-
- case T_AlterSeqStmt:
- evt->command = E_AlterSequence;
- break;
-
- case T_LoadStmt:
- evt->command = E_Load;
- break;
-
- case T_ClusterStmt:
- evt->command = E_Cluster;
- break;
-
- case T_VacuumStmt:
- evt->command = E_Vacuum;
- break;
-
- case T_CreateTableAsStmt:
- evt->command = E_CreateTableAs;
- break;
-
- case T_CreateTrigStmt:
- evt->command = E_CreateTrigger;
- break;
-
- case T_CreateDomainStmt:
- evt->command = E_CreateDomain;
- break;
-
- case T_ReindexStmt:
- evt->command = E_Reindex;
- break;
-
- case T_CreateConversionStmt:
- evt->command = E_CreateConversion;
- break;
-
- case T_CreateCastStmt:
- evt->command = E_CreateCast;
- break;
-
- case T_CreateOpClassStmt:
- evt->command = E_CreateOperatorClass;
- break;
-
- case T_CreateOpFamilyStmt:
- evt->command = E_CreateOperatorFamily;
- break;
-
- case T_AlterOpFamilyStmt:
- evt->command = E_AlterOperatorFamily;
- break;
-
- case T_AlterTSDictionaryStmt:
- evt->command = E_AlterTextSearchDictionary;
- break;
-
- case T_AlterTSConfigurationStmt:
- evt->command = E_AlterTextSearchConfiguration;
- break;
-
- default:
- /* reaching that part of the code only means that we are not
- * supporting command triggers for the given command, which still
- * needs to execute.
- */
- break;
- }
+ /* guess the ongoing operation from the command tag */
+ if (strncmp(evt->tag, "CREATE ", 7) == 0)
+ evt->operation = pstrdup("CREATE");
+ else if (strncmp(evt->tag, "DROP ", 5) == 0)
+ evt->operation = pstrdup("DROP");
+ else if (strncmp(evt->tag, "ALTER ", 6) == 0)
+ evt->operation = pstrdup("ALTER");
}
/*
- * InitEventContext() must have been called first. When
- * CommandFiresTriggersForEvent() returns false, the EventContext structure
- * needs not be initialized further.
+ * InitEventContext() must have been called first, then the event context field
+ * 'objectype' must have been "manually" for command tags supporting several
+ * kinds of object, such as T_DropStmt, T_RenameStmt, T_AlterObjectSchemaStmt,
+ * T_AlterOwnerStmt or T_DefineStmt.
+ *
+ * When CommandFiresTriggersForEvent() returns false, the EventContext
+ * structure needs not be initialized further.
*/
bool
CommandFiresTriggersForEvent(EventContext ev_ctx, TrigEvent tev)
{
EventCommandTriggers *triggers;
- if (ev_ctx == NULL || ev_ctx->command == E_UNKNOWN)
+ if (ev_ctx == NULL)
+ return false;
+
+ if (ev_ctx->command == ETC_UNSET)
+ ev_ctx->command = get_command_from_nodetag(nodeTag(ev_ctx->parsetree),
+ ev_ctx->objecttype, true);
+
+ if (ev_ctx->command == ETC_UNKNOWN)
return false;
triggers = get_event_triggers(tev, ev_ctx->command);
@@ -1037,7 +507,7 @@ CommandFiresTriggersForEvent(EventContext ev_ctx, TrigEvent tev)
}
/*
- * Actually run command triggers of a specific command. We first run ANY
+ * Actually run event triggers for a specific command. We first run ANY
* command triggers.
*/
void
@@ -1046,7 +516,14 @@ ExecEventTriggers(EventContext ev_ctx, TrigEvent tev)
EventCommandTriggers *triggers;
ListCell *lc;
- if (ev_ctx == NULL || ev_ctx->command == E_UNKNOWN)
+ if (ev_ctx == NULL)
+ return;
+
+ if (ev_ctx->command == ETC_UNSET)
+ ev_ctx->command = get_command_from_nodetag(nodeTag(ev_ctx->parsetree),
+ ev_ctx->objecttype, true);
+
+ if (ev_ctx->command == ETC_UNKNOWN)
return;
triggers = get_event_triggers(tev, ev_ctx->command);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ec5c8f8..f3ab8e9 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -214,7 +214,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
CreateUserStmt CreateUserMappingStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
- DropAssertStmt DropTrigStmt DropEventTrigStmt DropRuleStmt DropCastStmt
+ DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt
DropRoleStmt DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
@@ -755,7 +755,6 @@ stmt :
| DropStmt
| DropTableSpaceStmt
| DropTrigStmt
- | DropEventTrigStmt
| DropRoleStmt
| DropUserStmt
| DropUserMappingStmt
@@ -4368,7 +4367,7 @@ trigger_command:
SCONST
{
TrigEventCommand cmdtag = parse_event_tag($1, true);
- if (cmdtag == E_UNKNOWN)
+ if (cmdtag == ETC_UNKNOWN)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized command \"%s\"", $1),
@@ -4378,27 +4377,6 @@ trigger_command:
;
-DropEventTrigStmt:
- DROP EVENT TRIGGER name opt_drop_behavior
- {
- DropStmt *n = makeNode(DropStmt);
- n->removeType = OBJECT_EVENT_TRIGGER;
- n->objects = list_make1(list_make1(makeString($4)));
- n->behavior = $5;
- n->missing_ok = false;
- $$ = (Node *) n;
- }
- | DROP EVENT TRIGGER IF_P EXISTS name opt_drop_behavior
- {
- DropStmt *n = makeNode(DropStmt);
- n->removeType = OBJECT_EVENT_TRIGGER;
- n->objects = list_make1(list_make1(makeString($6)));
- n->behavior = $7;
- n->missing_ok = true;
- $$ = (Node *) n;
- }
- ;
-
AlterEventTrigStmt:
ALTER EVENT TRIGGER name enable_trigger
{
@@ -5002,6 +4980,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; }
| VIEW { $$ = OBJECT_VIEW; }
| INDEX { $$ = OBJECT_INDEX; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
+ | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| TYPE_P { $$ = OBJECT_TYPE; }
| DOMAIN_P { $$ = OBJECT_DOMAIN; }
| COLLATION { $$ = OBJECT_COLLATION; }
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 29eec11..4e1a8c0 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -63,6 +63,7 @@
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+
/* Hook for plugins to get control in ProcessUtility() */
ProcessUtility_hook_type ProcessUtility_hook = NULL;
@@ -355,12 +356,7 @@ standard_ProcessUtility(Node *parsetree,
completionTag[0] = '\0';
/* Event Trigger support for command_start */
- InitEventContext(&evt, (Node *)parsetree);
-
- if (CommandFiresTriggersForEvent(&evt, E_CommandStart))
- {
- ExecEventTriggers(&evt, E_CommandStart);
- }
+ InitEventContext(&evt, parsetree);
switch (nodeTag(parsetree))
{
@@ -513,6 +509,7 @@ standard_ProcessUtility(Node *parsetree,
* relation and attribute manipulation
*/
case T_CreateSchemaStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateSchemaCommand((CreateSchemaStmt *) parsetree,
queryString);
break;
@@ -525,6 +522,9 @@ standard_ProcessUtility(Node *parsetree,
Oid relOid = InvalidOid;
CreateStmt *stmt = (CreateStmt *) parsetree;
+ /* possibly run event triggers */
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
/* Run parse analysis ... */
stmts = transformCreateStmt(stmt, queryString);
@@ -589,59 +589,75 @@ standard_ProcessUtility(Node *parsetree,
case T_CreateTableSpaceStmt:
PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateTableSpace((CreateTableSpaceStmt *) parsetree);
break;
case T_DropTableSpaceStmt:
PreventTransactionChain(isTopLevel, "DROP TABLESPACE");
+ ExecEventTriggers(&evt, EVT_CommandStart);
DropTableSpace((DropTableSpaceStmt *) parsetree);
break;
case T_AlterTableSpaceOptionsStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree);
break;
case T_CreateExtensionStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateExtension((CreateExtensionStmt *) parsetree);
break;
case T_AlterExtensionStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
break;
case T_AlterExtensionContentsStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
break;
case T_CreateFdwStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
break;
case T_AlterFdwStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
break;
case T_CreateForeignServerStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateForeignServer((CreateForeignServerStmt *) parsetree);
break;
case T_AlterForeignServerStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterForeignServer((AlterForeignServerStmt *) parsetree);
break;
case T_CreateUserMappingStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateUserMapping((CreateUserMappingStmt *) parsetree);
break;
case T_AlterUserMappingStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterUserMapping((AlterUserMappingStmt *) parsetree);
break;
case T_DropUserMappingStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
RemoveUserMapping((DropUserMappingStmt *) parsetree);
break;
case T_DropStmt:
+ evt.objecttype = ((DropStmt *) parsetree)->removeType;
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
switch (((DropStmt *) parsetree)->removeType)
{
case OBJECT_INDEX:
@@ -705,14 +721,20 @@ standard_ProcessUtility(Node *parsetree,
* schema
*/
case T_RenameStmt:
+ evt.objecttype = ((RenameStmt *) parsetree)->renameType;
+ ExecEventTriggers(&evt, EVT_CommandStart);
ExecRenameStmt((RenameStmt *) parsetree);
break;
case T_AlterObjectSchemaStmt:
+ evt.objecttype = ((AlterObjectSchemaStmt *) parsetree)->objectType;
+ ExecEventTriggers(&evt, EVT_CommandStart);
ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
break;
case T_AlterOwnerStmt:
+ evt.objecttype = ((AlterOwnerStmt *) parsetree)->objectType;
+ ExecEventTriggers(&evt, EVT_CommandStart);
ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
@@ -724,6 +746,9 @@ standard_ProcessUtility(Node *parsetree,
ListCell *l;
LOCKMODE lockmode;
+ /* run command_start event triggers, if any */
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
/*
* Figure out lock mode, and acquire lock. This also does
* basic permissions checks, so that we won't wait for a lock
@@ -775,6 +800,9 @@ standard_ProcessUtility(Node *parsetree,
{
AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
+ /* run command_start event triggers, if any */
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
/*
* Some or all of these functions are recursive to cover
* inherited things, so permission checks are done there.
@@ -839,6 +867,9 @@ standard_ProcessUtility(Node *parsetree,
{
DefineStmt *stmt = (DefineStmt *) parsetree;
+ evt.objecttype = stmt->kind;
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
switch (stmt->kind)
{
case OBJECT_AGGREGATE:
@@ -885,15 +916,18 @@ standard_ProcessUtility(Node *parsetree,
{
CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineCompositeType(stmt->typevar, stmt->coldeflist);
}
break;
case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineEnum((CreateEnumStmt *) parsetree);
break;
case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineRange((CreateRangeStmt *) parsetree);
break;
@@ -905,18 +939,22 @@ standard_ProcessUtility(Node *parsetree,
* defining pg_enum entries go away.
*/
PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterEnum((AlterEnumStmt *) parsetree);
break;
case T_ViewStmt: /* CREATE VIEW */
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineView((ViewStmt *) parsetree, queryString);
break;
case T_CreateFunctionStmt: /* CREATE FUNCTION */
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateFunction((CreateFunctionStmt *) parsetree, queryString);
break;
case T_AlterFunctionStmt: /* ALTER FUNCTION */
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterFunction((AlterFunctionStmt *) parsetree);
break;
@@ -924,6 +962,8 @@ standard_ProcessUtility(Node *parsetree,
{
IndexStmt *stmt = (IndexStmt *) parsetree;
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
if (stmt->concurrent)
PreventTransactionChain(isTopLevel,
"CREATE INDEX CONCURRENTLY");
@@ -958,14 +998,17 @@ standard_ProcessUtility(Node *parsetree,
break;
case T_RuleStmt: /* CREATE RULE */
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineRule((RuleStmt *) parsetree, queryString);
break;
case T_CreateSeqStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineSequence((CreateSeqStmt *) parsetree);
break;
case T_AlterSeqStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterSequence((AlterSeqStmt *) parsetree);
break;
@@ -1032,6 +1075,8 @@ standard_ProcessUtility(Node *parsetree,
{
LoadStmt *stmt = (LoadStmt *) parsetree;
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
closeAllVfds(); /* probably not necessary... */
/* Allowed names are restricted if you're not superuser */
load_file(stmt->filename, !superuser());
@@ -1040,12 +1085,14 @@ standard_ProcessUtility(Node *parsetree,
case T_ClusterStmt:
/* we choose to allow this during "read only" transactions */
+ ExecEventTriggers(&evt, EVT_CommandStart);
PreventCommandDuringRecovery("CLUSTER");
cluster((ClusterStmt *) parsetree, isTopLevel);
break;
case T_VacuumStmt:
/* we choose to allow this during "read only" transactions */
+ ExecEventTriggers(&evt, EVT_CommandStart);
PreventCommandDuringRecovery("VACUUM");
vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false,
isTopLevel);
@@ -1056,6 +1103,7 @@ standard_ProcessUtility(Node *parsetree,
break;
case T_CreateTableAsStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
ExecCreateTableAs((CreateTableAsStmt *) parsetree,
queryString, params, completionTag);
break;
@@ -1079,6 +1127,7 @@ standard_ProcessUtility(Node *parsetree,
break;
case T_CreateTrigStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
(void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
InvalidOid, InvalidOid, false);
break;
@@ -1092,6 +1141,7 @@ standard_ProcessUtility(Node *parsetree,
break;
case T_CreatePLangStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break;
@@ -1099,6 +1149,7 @@ standard_ProcessUtility(Node *parsetree,
* ******************************** DOMAIN statements ****
*/
case T_CreateDomainStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineDomain((CreateDomainStmt *) parsetree);
break;
@@ -1164,6 +1215,8 @@ standard_ProcessUtility(Node *parsetree,
{
ReindexStmt *stmt = (ReindexStmt *) parsetree;
+ ExecEventTriggers(&evt, EVT_CommandStart);
+
/* we choose to allow this during "read only" transactions */
PreventCommandDuringRecovery("REINDEX");
switch (stmt->kind)
@@ -1197,30 +1250,37 @@ standard_ProcessUtility(Node *parsetree,
break;
case T_CreateConversionStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateConversionCommand((CreateConversionStmt *) parsetree);
break;
case T_CreateCastStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
CreateCast((CreateCastStmt *) parsetree);
break;
case T_CreateOpClassStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineOpClass((CreateOpClassStmt *) parsetree);
break;
case T_CreateOpFamilyStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
DefineOpFamily((CreateOpFamilyStmt *) parsetree);
break;
case T_AlterOpFamilyStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterOpFamily((AlterOpFamilyStmt *) parsetree);
break;
case T_AlterTSDictionaryStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
break;
case T_AlterTSConfigurationStmt:
+ ExecEventTriggers(&evt, EVT_CommandStart);
AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
break;
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index d7770b8..8590f3c 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -293,6 +293,33 @@ trigger_out(PG_FUNCTION_ARGS)
/*
+ * event_trigger_in - input routine for pseudo-type event_trigger.
+ */
+Datum
+event_trigger_in(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot accept a value of type event_trigger")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+/*
+ * event_trigger_out - output routine for pseudo-type event_trigger.
+ */
+Datum
+event_trigger_out(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot display a value of type event_trigger")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+
+/*
* language_handler_in - input routine for pseudo-type LANGUAGE_HANDLER.
*/
Datum
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 17b62b6..ec93149 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -39,11 +39,9 @@
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
-#include "parser/analyze.h"
#include "parser/keywords.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
-#include "parser/parse_type.h"
#include "parser/parser.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
@@ -261,6 +259,7 @@ static char *flatten_reloptions(Oid relid);
#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
+
/* ----------
* get_ruledef - Do it all and return a text
* that could be used as a statement
diff --git a/src/backend/utils/cache/evtcache.c b/src/backend/utils/cache/evtcache.c
index 65bc6be..bced1e0 100644
--- a/src/backend/utils/cache/evtcache.c
+++ b/src/backend/utils/cache/evtcache.c
@@ -18,6 +18,7 @@
#include "access/heapam.h"
#include "catalog/catalog.h"
+#include "catalog/pg_collation.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
@@ -28,9 +29,11 @@
#include "catalog/pg_type.h"
#include "commands/event_trigger.h"
#include "commands/trigger.h"
+#include "nodes/parsenodes.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/evtcache.h"
+#include "utils/formatting.h"
#include "utils/hsearch.h"
#include "utils/inval.h"
#include "utils/memutils.h"
@@ -39,6 +42,962 @@
#include "utils/syscache.h"
/*
+ * EventTriggerCommandTags
+ *
+ * This array provides meta data allowing to parse and rewrite command tags
+ * from the command and catalogs to the internal integers we use to have fast
+ * lookups.
+ *
+ * Lookups have to be fast because they are done for each and every DDL as soon
+ * as some Event Triggers are defined.
+ */
+typedef struct
+{
+ TrigEventCommand command; /* internal command value */
+ char *tag; /* command tag */
+ NodeTag node; /* internal parser node tag */
+ ObjectType type; /* internal object type */
+} EventTriggerCommandTagsType;
+
+/*
+ * Hash table to cache the content of EventTriggerCommandTags, which is
+ * searched by command tag when building the EventTriggerProcsCache, and by
+ * NodeTag and ObjectType from ProcessUtility.
+ *
+ * In both cases we want to avoid to have to scan the whole array each time, so
+ * we cache a dedicated hash table in the session's memory.
+ */
+static HTAB *EventTriggerCommandTagsCache = NULL;
+static HTAB *EventTriggerCommandNodeCache = NULL;
+
+/* entry for the Tags cache (key is NameData of NAMEDATALEN) */
+typedef struct
+{
+ NameData tag;
+ TrigEventCommand command;
+} EventTriggerCommandTagsEntry;
+
+/* key and entry for the Node cache */
+typedef struct
+{
+ NodeTag node; /* internal parser node tag */
+ ObjectType type; /* internal object type */
+} EventTriggerCommandNodeKey;
+
+typedef struct
+{
+ EventTriggerCommandNodeKey key; /* lookup key, must be first */
+ TrigEventCommand command; /* internal command value */
+} EventTriggerCommandNodeEntry;
+
+static EventTriggerCommandTagsType EventTriggerCommandTags[] =
+{
+ {
+ ETC_CreateAggregate,
+ "CREATE AGGREGATE",
+ T_DefineStmt,
+ OBJECT_AGGREGATE
+ },
+ {
+ ETC_CreateCast,
+ "CREATE CAST",
+ T_CreateCastStmt,
+ -1
+ },
+ {
+ ETC_CreateCollation,
+ "CREATE COLLATION",
+ T_DefineStmt,
+ OBJECT_COLLATION
+ },
+ {
+ ETC_CreateConversion,
+ "CREATE CONVERSION",
+ T_CreateConversionStmt,
+ -1
+ },
+ {
+ ETC_CreateDomain,
+ "CREATE DOMAIN",
+ T_CreateDomainStmt,
+ -1
+ },
+ {
+ ETC_CreateExtension,
+ "CREATE EXTENSION",
+ T_CreateExtensionStmt,
+ -1
+ },
+ {
+ ETC_CreateForeignDataWrapper,
+ "CREATE FOREIGN DATA WRAPPER",
+ T_CreateFdwStmt,
+ -1
+ },
+ {
+ ETC_CreateForeignTable,
+ "CREATE FOREIGN TABLE",
+ T_CreateForeignTableStmt,
+ -1
+ },
+ {
+ ETC_CreateFunction,
+ "CREATE FUNCTION",
+ T_CreateFunctionStmt,
+ -1
+ },
+ {
+ ETC_CreateIndex,
+ "CREATE INDEX",
+ T_IndexStmt,
+ -1
+ },
+ {
+ ETC_CreateLanguage,
+ "CREATE LANGUAGE",
+ T_CreatePLangStmt,
+ -1
+ },
+ {
+ ETC_CreateOperator,
+ "CREATE OPERATOR",
+ T_DefineStmt,
+ OBJECT_OPERATOR
+ },
+ {
+ ETC_CreateOperatorClass,
+ "CREATE OPERATOR CLASS",
+ T_CreateOpClassStmt,
+ -1
+ },
+ {
+ ETC_CreateOperatorFamily,
+ "CREATE OPERATOR FAMILY",
+ T_CreateOpFamilyStmt,
+ -1
+ },
+ {
+ ETC_CreateRule,
+ "CREATE RULE",
+ T_RuleStmt,
+ -1
+ },
+ {
+ ETC_CreateSchema,
+ "CREATE SCHEMA",
+ T_CreateSchemaStmt,
+ -1
+ },
+ {
+ ETC_CreateSequence,
+ "CREATE SEQUENCE",
+ T_CreateSeqStmt,
+ -1
+ },
+ {
+ ETC_CreateServer,
+ "CREATE SERVER",
+ T_CreateForeignServerStmt,
+ -1
+ },
+ {
+ ETC_CreateTable,
+ "CREATE TABLE",
+ T_CreateStmt,
+ -1
+ },
+ {
+ ETC_CreateTableAs,
+ "CREATE TABLE AS",
+ T_CreateTableAsStmt,
+ -1
+ },
+ {
+ ETC_SelectInto,
+ "SELECT INTO",
+ T_CreateTableAsStmt,
+ -1
+ },
+ {
+ ETC_CreateTextSearchParser,
+ "CREATE TEXT SEARCH PARSER",
+ T_DefineStmt,
+ OBJECT_TSPARSER
+ },
+ {
+ ETC_CreateTextSearchConfiguration,
+ "CREATE TEXT SEARCH CONFIGURATION",
+ T_DefineStmt,
+ OBJECT_TSCONFIGURATION
+ },
+ {
+ ETC_CreateTextSearchDictionary,
+ "CREATE TEXT SEARCH DICTIONARY",
+ T_DefineStmt,
+ OBJECT_TSDICTIONARY
+ },
+ {
+ ETC_CreateTextSearchTemplate,
+ "CREATE TEXT SEARCH TEMPLATE",
+ T_DefineStmt,
+ OBJECT_TSTEMPLATE
+ },
+ {
+ ETC_CreateTrigger,
+ "CREATE TRIGGER",
+ T_CreateTrigStmt,
+ -1
+ },
+ {
+ ETC_CreateType,
+ "CREATE TYPE",
+ T_DefineStmt,
+ OBJECT_TYPE
+ },
+ {
+ ETC_CreateType,
+ "CREATE TYPE",
+ T_CompositeTypeStmt,
+ -1
+ },
+ {
+ ETC_CreateType,
+ "CREATE TYPE",
+ T_CreateEnumStmt,
+ -1
+ },
+ {
+ ETC_CreateType,
+ "CREATE TYPE",
+ T_CreateRangeStmt,
+ -1
+ },
+ {
+ ETC_CreateUserMapping,
+ "CREATE USER MAPPING",
+ T_CreateUserMappingStmt,
+ -1
+ },
+ {
+ ETC_CreateView,
+ "CREATE VIEW",
+ T_ViewStmt,
+ -1
+ },
+ {
+ ETC_AlterTable,
+ "ALTER TABLE",
+ T_AlterTableStmt,
+ -1
+ },
+ {
+ ETC_DropAggregate,
+ "DROP AGGREGATE",
+ T_DropStmt,
+ OBJECT_AGGREGATE
+ },
+ {
+ ETC_DropCast,
+ "DROP CAST",
+ T_DropStmt,
+ OBJECT_CAST
+ },
+ {
+ ETC_DropCollation,
+ "DROP COLLATION",
+ T_DropStmt,
+ OBJECT_COLLATION
+ },
+ {
+ ETC_DropConversion,
+ "DROP CONVERSION",
+ T_DropStmt,
+ OBJECT_CONVERSION
+ },
+ {
+ ETC_DropDomain,
+ "DROP DOMAIN",
+ T_DropStmt,
+ OBJECT_DOMAIN
+ },
+ {
+ ETC_DropExtension,
+ "DROP EXTENSION",
+ T_DropStmt,
+ OBJECT_EXTENSION
+ },
+ {
+ ETC_DropForeignDataWrapper,
+ "DROP FOREIGN DATA WRAPPER",
+ T_DropStmt,
+ OBJECT_FDW
+ },
+ {
+ ETC_DropForeignTable,
+ "DROP FOREIGN TABLE",
+ T_DropStmt,
+ OBJECT_FOREIGN_TABLE
+ },
+ {
+ ETC_DropFunction,
+ "DROP FUNCTION",
+ T_DropStmt,
+ OBJECT_FUNCTION
+ },
+ {
+ ETC_DropIndex,
+ "DROP INDEX",
+ T_DropStmt,
+ OBJECT_INDEX
+ },
+ {
+ ETC_DropLanguage,
+ "DROP LANGUAGE",
+ T_DropStmt,
+ OBJECT_LANGUAGE
+ },
+ {
+ ETC_DropOperator,
+ "DROP OPERATOR",
+ T_DropStmt,
+ OBJECT_OPERATOR
+ },
+ {
+ ETC_DropOperatorClass,
+ "DROP OPERATOR CLASS",
+ T_DropStmt,
+ OBJECT_OPCLASS
+ },
+ {
+ ETC_DropOperatorFamily,
+ "DROP OPERATOR FAMILY",
+ T_DropStmt,
+ OBJECT_OPFAMILY
+ },
+ {
+ ETC_DropRule,
+ "DROP RULE",
+ T_DropStmt,
+ OBJECT_RULE
+ },
+ {
+ ETC_DropSchema,
+ "DROP SCHEMA",
+ T_DropStmt,
+ OBJECT_SCHEMA
+ },
+ {
+ ETC_DropSequence,
+ "DROP SEQUENCE",
+ T_DropStmt,
+ OBJECT_SEQUENCE
+ },
+ {
+ ETC_DropServer,
+ "DROP SERVER",
+ T_DropStmt,
+ OBJECT_FOREIGN_SERVER
+ },
+ {
+ ETC_DropTable,
+ "DROP TABLE",
+ T_DropStmt,
+ OBJECT_TABLE
+ },
+ {
+ ETC_DropTextSearchParser,
+ "DROP TEXT SEARCH PARSER",
+ T_DropStmt,
+ OBJECT_TSPARSER
+ },
+ {
+ ETC_DropTextSearchConfiguration,
+ "DROP TEXT SEARCH CONFIGURATION",
+ T_DropStmt,
+ OBJECT_TSCONFIGURATION
+ },
+ {
+ ETC_DropTextSearchDictionary,
+ "DROP TEXT SEARCH DICTIONARY",
+ T_DropStmt,
+ OBJECT_TSDICTIONARY
+ },
+ {
+ ETC_DropTextSearchTemplate,
+ "DROP TEXT SEARCH TEMPLATE",
+ T_DropStmt,
+ OBJECT_TSTEMPLATE
+ },
+ {
+ ETC_DropTrigger,
+ "DROP TRIGGER",
+ T_DropStmt,
+ OBJECT_TRIGGER
+ },
+ {
+ ETC_DropType,
+ "DROP TYPE",
+ T_DropStmt,
+ OBJECT_TYPE
+ },
+ {
+ ETC_DropUserMapping,
+ "DROP USER MAPPING",
+ T_DropUserMappingStmt,
+ -1
+ },
+ {
+ ETC_DropView,
+ "DROP VIEW",
+ T_DropStmt,
+ OBJECT_VIEW
+ },
+ {
+ ETC_Vacuum,
+ "VACUUM",
+ T_VacuumStmt,
+ -1
+ },
+ {
+ ETC_Cluster,
+ "CLUSTER",
+ T_ClusterStmt,
+ -1
+ },
+ {
+ ETC_Load,
+ "LOAD",
+ T_LoadStmt,
+ -1
+ },
+ {
+ ETC_Reindex,
+ "REINDEX",
+ T_ReindexStmt,
+ -1
+ },
+ {
+ ETC_AlterSequence,
+ "ALTER SEQUENCE",
+ T_AlterSeqStmt,
+ -1
+ },
+ {
+ ETC_AlterUserMapping,
+ "ALTER USER MAPPING",
+ T_CreateUserMappingStmt,
+ -1
+ },
+ {
+ ETC_AlterFunction,
+ "ALTER FUNCTION",
+ T_AlterFunctionStmt,
+ -1
+ },
+ {
+ ETC_AlterDomain,
+ "ALTER DOMAIN",
+ T_AlterDomainStmt,
+ -1
+ },
+ /* ALTER <OBJECT> name RENAME TO */
+ {
+ ETC_AlterAggregate,
+ "ALTER AGGREGATE",
+ T_RenameStmt,
+ OBJECT_AGGREGATE
+ },
+ {
+ ETC_AlterType,
+ "ALTER TYPE",
+ T_RenameStmt,
+ OBJECT_ATTRIBUTE
+ },
+ {
+ ETC_AlterCast,
+ "ALTER CAST",
+ T_RenameStmt,
+ OBJECT_CAST
+ },
+ {
+ ETC_AlterCollation,
+ "ALTER COLLATION",
+ T_RenameStmt,
+ OBJECT_COLLATION
+ },
+ {
+ ETC_AlterTable,
+ "ALTER TABLE",
+ T_RenameStmt,
+ OBJECT_COLUMN
+ },
+ {
+ ETC_AlterTable,
+ "ALTER TABLE",
+ T_RenameStmt,
+ OBJECT_CONSTRAINT
+ },
+ {
+ ETC_AlterConversion,
+ "ALTER CONVERSION",
+ T_RenameStmt,
+ OBJECT_CONVERSION
+ },
+ {
+ ETC_AlterDomain,
+ "ALTER DOMAIN",
+ OBJECT_DOMAIN,
+ T_RenameStmt
+ },
+ {
+ ETC_AlterExtension,
+ "ALTER EXTENSION",
+ T_RenameStmt,
+ OBJECT_EXTENSION
+ },
+ {
+ ETC_AlterForeignDataWrapper,
+ "ALTER FOREIGN DATA WRAPPER",
+ OBJECT_FDW,
+ T_RenameStmt
+ },
+ {
+ ETC_AlterServer,
+ "ALTER SERVER",
+ T_RenameStmt,
+ OBJECT_FOREIGN_SERVER
+ },
+ {
+ ETC_AlterForeignTable,
+ "ALTER FOREIGN TABLE",
+ T_RenameStmt,
+ OBJECT_FOREIGN_TABLE
+ },
+ {
+ ETC_AlterFunction,
+ "ALTER FUNCTION",
+ T_RenameStmt,
+ OBJECT_FUNCTION
+ },
+ {
+ ETC_AlterIndex,
+ "ALTER INDEX",
+ T_RenameStmt,
+ OBJECT_INDEX
+ },
+ {
+ ETC_AlterLanguage,
+ "ALTER LANGUAGE",
+ T_RenameStmt,
+ OBJECT_LANGUAGE
+ },
+ {
+ ETC_AlterOperator,
+ "ALTER OPERATOR",
+ T_RenameStmt,
+ OBJECT_OPERATOR
+ },
+ {
+ ETC_AlterOperatorClass,
+ "ALTER OPERATOR CLASS",
+ T_RenameStmt,
+ OBJECT_OPCLASS
+ },
+ {
+ ETC_AlterOperatorFamily,
+ "ALTER OPERATOR FAMILY",
+ T_RenameStmt,
+ OBJECT_OPFAMILY
+ },
+ {
+ ETC_AlterRule,
+ "ALTER RULE",
+ T_RenameStmt,
+ OBJECT_RULE
+ },
+ {
+ ETC_AlterSchema,
+ "ALTER SCHEMA",
+ T_RenameStmt,
+ OBJECT_SCHEMA
+ },
+ {
+ ETC_AlterSequence,
+ "ALTER SEQUENCE",
+ T_RenameStmt,
+ OBJECT_SEQUENCE
+ },
+ {
+ ETC_AlterTable,
+ "ALTER TABLE",
+ T_RenameStmt,
+ OBJECT_TABLE
+ },
+ {
+ ETC_AlterTrigger,
+ "ALTER TRIGGER",
+ T_RenameStmt,
+ OBJECT_TRIGGER
+ },
+ {
+ ETC_AlterTextSearchParser,
+ "ALTER TEXT SEARCH PARSER",
+ T_RenameStmt,
+ OBJECT_TSPARSER
+ },
+ {
+ ETC_AlterTextSearchConfiguration,
+ "ALTER TEXT SEARCH CONFIGURATION",
+ T_RenameStmt,
+ OBJECT_TSCONFIGURATION
+ },
+ {
+ ETC_AlterTextSearchDictionary,
+ "ALTER TEXT SEARCH DICTIONARY",
+ T_RenameStmt,
+ OBJECT_TSDICTIONARY
+ },
+ {
+ ETC_AlterTextSearchTemplate,
+ "ALTER TEXT SEARCH TEMPLATE",
+ T_RenameStmt,
+ OBJECT_TSTEMPLATE
+ },
+ {
+ ETC_AlterType,
+ "ALTER TYPE",
+ T_RenameStmt,
+ OBJECT_TYPE
+ },
+ {
+ ETC_AlterView,
+ "ALTER VIEW",
+ T_RenameStmt,
+ OBJECT_VIEW
+ },
+ /* ALTER <OBJECT> name SET SCHEMA */
+ {
+ ETC_AlterAggregate,
+ "ALTER AGGREGATE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_AGGREGATE
+ },
+ {
+ ETC_AlterCast,
+ "ALTER CAST",
+ T_AlterObjectSchemaStmt,
+ OBJECT_CAST
+ },
+ {
+ ETC_AlterCollation,
+ "ALTER COLLATION",
+ T_AlterObjectSchemaStmt,
+ OBJECT_COLLATION
+ },
+ {
+ ETC_AlterConversion,
+ "ALTER CONVERSION",
+ T_AlterObjectSchemaStmt,
+ OBJECT_CONVERSION
+ },
+ {
+ ETC_AlterDomain,
+ "ALTER DOMAIN",
+ T_AlterObjectSchemaStmt,
+ OBJECT_DOMAIN
+ },
+ {
+ ETC_AlterExtension,
+ "ALTER EXTENSION",
+ T_AlterObjectSchemaStmt,
+ OBJECT_EXTENSION
+ },
+ {
+ ETC_AlterForeignDataWrapper,
+ "ALTER FOREIGN DATA WRAPPER",
+ T_AlterObjectSchemaStmt,
+ OBJECT_FDW
+ },
+ {
+ ETC_AlterForeignTable,
+ "ALTER FOREIGN TABLE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_FOREIGN_TABLE
+ },
+ {
+ ETC_AlterFunction,
+ "ALTER FUNCTION",
+ T_AlterObjectSchemaStmt,
+ OBJECT_FUNCTION
+ },
+ {
+ ETC_AlterIndex,
+ "ALTER CAST",
+ T_AlterObjectSchemaStmt,
+ OBJECT_INDEX
+ },
+ {
+ ETC_AlterLanguage,
+ "ALTER LANGUAGE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_LANGUAGE
+ },
+ {
+ ETC_AlterOperator,
+ "ALTER OPERATOR",
+ T_AlterObjectSchemaStmt,
+ OBJECT_OPERATOR
+ },
+ {
+ ETC_AlterOperatorClass,
+ "ALTER OPERATOR CLASS",
+ T_AlterObjectSchemaStmt,
+ OBJECT_OPCLASS
+ },
+ {
+ ETC_AlterOperatorFamily,
+ "ALTER OPERATOR FAMILY",
+ T_AlterObjectSchemaStmt,
+ OBJECT_OPFAMILY
+ },
+ {
+ ETC_AlterSchema,
+ "ALTER SCHEMA",
+ T_AlterObjectSchemaStmt,
+ OBJECT_SCHEMA
+ },
+ {
+ ETC_AlterSequence,
+ "ALTER SEQUENCE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_SEQUENCE
+ },
+ {
+ ETC_AlterServer,
+ "ALTER SERVER",
+ T_AlterObjectSchemaStmt,
+ OBJECT_FOREIGN_SERVER
+ },
+ {
+ ETC_AlterTable,
+ "ALTER TABLE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_TABLE
+ },
+ {
+ ETC_AlterTextSearchParser,
+ "ALTER TEXT SEARCH PARSER",
+ T_AlterObjectSchemaStmt,
+ OBJECT_TSPARSER
+ },
+ {
+ ETC_AlterTextSearchConfiguration,
+ "ALTER TEXT SEARCH CONFIGURATION",
+ T_AlterObjectSchemaStmt,
+ OBJECT_TSCONFIGURATION
+ },
+ {
+ ETC_AlterTextSearchDictionary,
+ "ALTER TEXT SEARCH DICTIONARY",
+ T_AlterObjectSchemaStmt,
+ OBJECT_TSDICTIONARY
+ },
+ {
+ ETC_AlterTextSearchTemplate,
+ "ALTER TEXT SEARCH TEMPLATE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_TSTEMPLATE
+ },
+ {
+ ETC_AlterTrigger,
+ "ALTER TRIGGER",
+ T_AlterObjectSchemaStmt,
+ OBJECT_TRIGGER
+ },
+ {
+ ETC_AlterType,
+ "ALTER TYPE",
+ T_AlterEnumStmt,
+ -1
+ },
+ {
+ ETC_AlterType,
+ "ALTER TYPE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_ATTRIBUTE
+ },
+ {
+ ETC_AlterType,
+ "ALTER TYPE",
+ T_AlterObjectSchemaStmt,
+ OBJECT_TYPE
+ },
+ {
+ ETC_AlterView,
+ "ALTER VIEW",
+ T_AlterObjectSchemaStmt,
+ OBJECT_VIEW
+ },
+ {
+ ETC_AlterTextSearchDictionary,
+ "ALTER TEXT SEARCH DICTIONARY",
+ T_AlterTSDictionaryStmt,
+ -1
+ },
+ /* ALTER <OBJECT> name OWNER TO */
+ {
+ ETC_AlterAggregate,
+ "ALTER AGGREGATE",
+ T_AlterOwnerStmt,
+ OBJECT_AGGREGATE
+ },
+ {
+ ETC_AlterCast,
+ "ALTER CAST",
+ T_AlterOwnerStmt,
+ OBJECT_CAST
+ },
+ {
+ ETC_AlterCollation,
+ "ALTER COLLATION",
+ T_AlterOwnerStmt,
+ OBJECT_COLLATION
+ },
+ {
+ ETC_AlterConversion,
+ "ALTER CONVERSION",
+ T_AlterOwnerStmt,
+ OBJECT_CONVERSION
+ },
+ {
+ ETC_AlterDomain,
+ "ALTER DOMAIN",
+ T_AlterOwnerStmt,
+ OBJECT_DOMAIN
+ },
+ {
+ ETC_AlterExtension,
+ "ALTER EXTENSION",
+ T_AlterOwnerStmt,
+ OBJECT_EXTENSION
+ },
+ {
+ ETC_AlterForeignDataWrapper,
+ "ALTER FOREIGN DATA WRAPPER",
+ T_AlterOwnerStmt,
+ OBJECT_FDW
+ },
+ {
+ ETC_AlterForeignTable,
+ "ALTER FOREIGN TABLE",
+ T_AlterOwnerStmt,
+ OBJECT_FOREIGN_TABLE
+ },
+ {
+ ETC_AlterFunction,
+ "ALTER FUNCTION",
+ T_AlterOwnerStmt,
+ OBJECT_FUNCTION
+ },
+ {
+ ETC_AlterIndex,
+ "ALTER CAST",
+ T_AlterOwnerStmt,
+ OBJECT_INDEX
+ },
+ {
+ ETC_AlterLanguage,
+ "command_start",
+ T_AlterOwnerStmt,
+ OBJECT_LANGUAGE
+ },
+ {
+ ETC_AlterOperator,
+ "ALTER OPERATOR",
+ T_AlterOwnerStmt,
+ OBJECT_OPERATOR
+ },
+ {
+ ETC_AlterOperatorClass,
+ "ALTER OPERATOR CLASS",
+ T_AlterOwnerStmt,
+ OBJECT_OPCLASS
+ },
+ {
+ ETC_AlterOperatorFamily,
+ "ALTER OPERATOR FAMILY",
+ T_AlterOwnerStmt,
+ OBJECT_OPFAMILY
+ },
+ {
+ ETC_AlterSchema,
+ "ALTER SCHEMA",
+ T_AlterOwnerStmt,
+ OBJECT_SCHEMA
+ },
+ {
+ ETC_AlterSequence,
+ "ALTER SEQUENCE",
+ T_AlterOwnerStmt,
+ OBJECT_SEQUENCE
+ },
+ {
+ ETC_AlterServer,
+ "ALTER SERVER",
+ T_AlterOwnerStmt,
+ OBJECT_FOREIGN_SERVER
+ },
+ {
+ ETC_AlterTextSearchParser,
+ "ALTER TEXT SEARCH PARSER",
+ T_AlterOwnerStmt,
+ OBJECT_TSPARSER
+ },
+ {
+ ETC_AlterTextSearchConfiguration,
+ "ALTER TEXT SEARCH CONFIGURATION",
+ T_AlterOwnerStmt,
+ OBJECT_TSCONFIGURATION
+ },
+ {
+ ETC_AlterTextSearchDictionary,
+ "ALTER TEXT SEARCH DICTIONARY",
+ T_AlterOwnerStmt,
+ OBJECT_TSDICTIONARY
+ },
+ {
+ ETC_AlterTextSearchTemplate,
+ "ALTER TEXT SEARCH TEMPLATE",
+ T_AlterOwnerStmt,
+ OBJECT_TSTEMPLATE
+ },
+ {
+ ETC_AlterTrigger,
+ "ALTER TRIGGER",
+ T_AlterOwnerStmt,
+ OBJECT_TRIGGER
+ },
+ {
+ ETC_AlterType,
+ "ALTER TYPE",
+ T_AlterOwnerStmt,
+ OBJECT_ATTRIBUTE
+ },
+ {
+ ETC_AlterType,
+ "ALTER TYPE",
+ T_AlterOwnerStmt,
+ OBJECT_TYPE
+ },
+ {
+ ETC_AlterView,
+ "ALTER VIEW",
+ T_AlterOwnerStmt,
+ OBJECT_VIEW
+ }
+};
+
+/*
* Cache the event triggers in a format that's suitable to finding which
* function to call at "hook" points in the code. The catalogs are not helpful
* at search time, because we can't both edit a single catalog entry per each
@@ -48,47 +1007,47 @@
* This cache is indexed by Event id then Event Command id (see
* pg_event_trigger.h). It's containing a list of function oid.
*/
-static HTAB *EventCommandTriggerCache = NULL;
+static HTAB *EventTriggerProcsCache = NULL;
/* event and command form the lookup key, and must appear first */
typedef struct
{
TrigEvent event;
TrigEventCommand command;
-} EventCommandTriggerCacheKey;
+} EventTriggerProcsCacheKey;
/* entry for command event trigger lookup hashtable */
typedef struct
{
- EventCommandTriggerCacheKey key; /* lookup key, must be first */
+ EventTriggerProcsCacheKey key; /* lookup key, must be first */
List *names; /* list of names of the triggers to call */
List *procs; /* list of triggers to call */
-} EventCommandTriggerCacheEntry;
+} EventTriggerProcsCacheEntry;
/*
- * Add a new function to EventCommandTriggerCache for given command and event,
+ * Add a new function to EventTriggerProcsCache for given command and event,
* creating a new hash table entry when necessary.
*
* Returns the new hash entry value.
*/
-static EventCommandTriggerCacheEntry *
+static EventTriggerProcsCacheEntry *
add_funcall_to_command_event(TrigEvent event,
TrigEventCommand command,
NameData evtname,
Oid proc)
{
bool found;
- EventCommandTriggerCacheKey key;
- EventCommandTriggerCacheEntry *hresult;
+ EventTriggerProcsCacheKey key;
+ EventTriggerProcsCacheEntry *hresult;
MemoryContext old = MemoryContextSwitchTo(CacheMemoryContext);
memset(&key, 0, sizeof(key));
key.event = event;
key.command = command;
- hresult = (EventCommandTriggerCacheEntry *)
- hash_search(EventCommandTriggerCache, (void *)&key, HASH_ENTER, &found);
+ hresult = (EventTriggerProcsCacheEntry *)
+ hash_search(EventTriggerProcsCache, (void *)&key, HASH_ENTER, &found);
if (found)
{
@@ -113,10 +1072,10 @@ add_funcall_to_command_event(TrigEvent event,
* The idea is that the code to fetch the list of functions to process gets as
* simple as the following:
*
- * foreach(cell, EventCommandTriggerCache[TrigEventCommand][TrigEvent])
+ * foreach(cell, EventTriggerProcsCache[TrigEventCommand][TrigEvent])
*/
static void
-BuildEventTriggerCache()
+BuildEventTriggerCache(void)
{
HASHCTL info;
Relation rel, irel;
@@ -125,13 +1084,13 @@ BuildEventTriggerCache()
/* build the new hash table */
MemSet(&info, 0, sizeof(info));
- info.keysize = sizeof(EventCommandTriggerCacheKey);
- info.entrysize = sizeof(EventCommandTriggerCacheEntry);
+ info.keysize = sizeof(EventTriggerProcsCacheKey);
+ info.entrysize = sizeof(EventTriggerProcsCacheEntry);
info.hash = tag_hash;
info.hcxt = CacheMemoryContext;
/* Create the hash table holding our cache */
- EventCommandTriggerCache =
+ EventTriggerProcsCache =
hash_create("Event Trigger Command Cache",
1024,
&info,
@@ -144,8 +1103,9 @@ BuildEventTriggerCache()
indexScan = index_beginscan(rel, irel, SnapshotNow, 0, 0);
index_rescan(indexScan, NULL, 0, NULL, 0);
- /* we use a full indexscan to guarantee that we see event triggers ordered
- * by name, this way we only even have to append the trigger's function Oid
+ /*
+ * We use a full indexscan to guarantee that we see event triggers ordered
+ * by name. This way, we only even have to append the trigger's function Oid
* to the target cache Oid list.
*/
while (HeapTupleIsValid(tuple = index_getnext(indexScan, ForwardScanDirection)))
@@ -190,7 +1150,7 @@ BuildEventTriggerCache()
/* event triggers created without WHEN clause are targetting all
* commands (ANY command trigger)
*/
- add_funcall_to_command_event(event, E_ANY, name, proc);
+ add_funcall_to_command_event(event, ETC_ANY, name, proc);
}
else
{
@@ -232,8 +1192,8 @@ static void
InvalidateEvtTriggerCommandCacheCallback(Datum arg,
int cacheid, uint32 hashvalue)
{
- hash_destroy(EventCommandTriggerCache);
- EventCommandTriggerCache = NULL;
+ hash_destroy(EventTriggerProcsCache);
+ EventTriggerProcsCache = NULL;
}
/*
@@ -249,7 +1209,7 @@ InitEventTriggerCache(void)
if (!CacheMemoryContext)
CreateCacheMemoryContext();
- EventCommandTriggerCache = NULL;
+ EventTriggerProcsCache = NULL;
/* Watch for invalidation events. */
CacheRegisterSyscacheCallback(EVENTTRIGGERNAME,
@@ -265,30 +1225,30 @@ get_event_triggers(TrigEvent event, TrigEventCommand command)
{
EventCommandTriggers *triggers =
(EventCommandTriggers *) palloc(sizeof(EventCommandTriggers));
- EventCommandTriggerCacheKey anykey, cmdkey;
- EventCommandTriggerCacheEntry *any, *cmd;
+ EventTriggerProcsCacheKey anykey, cmdkey;
+ EventTriggerProcsCacheEntry *any, *cmd;
triggers->event = event;
triggers->command = command;
triggers->procs = NIL;
/* Find existing cache entry, if any. */
- if (!EventCommandTriggerCache)
+ if (!EventTriggerProcsCache)
BuildEventTriggerCache();
/* ANY command triggers */
memset(&anykey, 0, sizeof(anykey));
anykey.event = event;
- anykey.command = E_ANY;
- any = (EventCommandTriggerCacheEntry *)
- hash_search(EventCommandTriggerCache, (void *)&anykey, HASH_FIND, NULL);
+ anykey.command = ETC_ANY;
+ any = (EventTriggerProcsCacheEntry *)
+ hash_search(EventTriggerProcsCache, (void *)&anykey, HASH_FIND, NULL);
/* Specific command triggers */
memset(&cmdkey, 0, sizeof(cmdkey));
cmdkey.event = event;
cmdkey.command = command;
- cmd = (EventCommandTriggerCacheEntry *)
- hash_search(EventCommandTriggerCache, (void *)&cmdkey, HASH_FIND, NULL);
+ cmd = (EventTriggerProcsCacheEntry *)
+ hash_search(EventTriggerProcsCache, (void *)&cmdkey, HASH_FIND, NULL);
if (any == NULL && cmd == NULL)
return triggers;
@@ -327,7 +1287,8 @@ get_event_triggers(TrigEvent event, TrigEventCommand command)
lc_any_procs = lnext(lc_any_procs);
}
- /* now append as many elements from CMD list named before next ANY
+ /*
+ * now append as many elements from CMD list named before next ANY
* entry
*/
do
@@ -352,3 +1313,253 @@ get_event_triggers(TrigEvent event, TrigEventCommand command)
}
return triggers;
}
+
+char *
+event_to_string(TrigEvent event)
+{
+ switch (event)
+ {
+ case EVT_CommandStart:
+ return "command_start";
+ }
+ return NULL;
+}
+
+TrigEvent
+parse_event_name(char *event)
+{
+ if (pg_strcasecmp(event, "command_start") == 0)
+ return EVT_CommandStart;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized event \"%s\"", event)));
+
+ /* make compiler happy */
+ return -1;
+}
+
+TrigEventCommand
+parse_event_tag(char *cmdtag, bool noerror)
+{
+ char *uctag;
+ NameData key;
+ EventTriggerCommandTagsEntry *entry;
+
+ if (EventTriggerCommandTagsCache == NULL)
+ {
+ int index;
+ HASHCTL info;
+ MemoryContext old = MemoryContextSwitchTo(CacheMemoryContext);
+
+ /* build the new hash table */
+ MemSet(&info, 0, sizeof(info));
+ info.keysize = NAMEDATALEN;
+ info.entrysize = sizeof(EventTriggerCommandTagsEntry);
+ info.hash = tag_hash;
+ info.hcxt = CacheMemoryContext;
+
+ /* Create the hash table holding our cache */
+ EventTriggerCommandTagsCache =
+ hash_create("Event Trigger Command Tags Cache",
+ 1024,
+ &info,
+ HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+
+ for (index = 0; index < lengthof(EventTriggerCommandTags); index++)
+ {
+ bool found;
+ char *tag = EventTriggerCommandTags[index].tag;
+ NameData key;
+ EventTriggerCommandTagsEntry *hresult;
+
+ memset(&key, 0, NAMEDATALEN);
+ key = *(DatumGetName(DirectFunctionCall1(namein,
+ CStringGetDatum(tag))));
+
+ hresult = (EventTriggerCommandTagsEntry *)
+ hash_search(EventTriggerCommandTagsCache,
+ (void *)&key, HASH_ENTER, &found);
+
+ hresult->command = EventTriggerCommandTags[index].command;
+ }
+ MemoryContextSwitchTo(old);
+ }
+
+ memset(&key, 0, NAMEDATALEN);
+ uctag = str_toupper(cmdtag, strlen(cmdtag), DEFAULT_COLLATION_OID);
+ key = *(DatumGetName(
+ DirectFunctionCall1(namein, CStringGetDatum(uctag))));
+
+ entry = (EventTriggerCommandTagsEntry *)
+ hash_search(EventTriggerCommandTagsCache,
+ (void *)&key, HASH_FIND, NULL);
+
+ if (entry == NULL)
+ {
+ if (!noerror)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized command \"%s\"", cmdtag)));
+ return ETC_UNKNOWN;
+ }
+ return entry->command;
+}
+
+char *
+command_to_string(TrigEventCommand command)
+{
+ int index;
+ for (index = 0; index < lengthof(EventTriggerCommandTags); index++)
+ {
+ if (command == EventTriggerCommandTags[index].command)
+ return EventTriggerCommandTags[index].tag;
+ }
+ return NULL;
+}
+
+/*
+ * Cache lookup support for ProcessUtility
+ */
+TrigEventCommand
+get_command_from_nodetag(NodeTag node, ObjectType type, bool noerror)
+{
+ EventTriggerCommandNodeKey key;
+ EventTriggerCommandNodeEntry *entry;
+
+ if (EventTriggerCommandNodeCache == NULL)
+ {
+ int index;
+ HASHCTL info;
+ MemoryContext old = MemoryContextSwitchTo(CacheMemoryContext);
+
+ /* build the new hash table */
+ MemSet(&info, 0, sizeof(info));
+ info.keysize = sizeof(EventTriggerCommandNodeKey);
+ info.entrysize = sizeof(EventTriggerCommandNodeEntry);
+ info.hash = tag_hash;
+ info.hcxt = CacheMemoryContext;
+
+ /* Create the hash table holding our cache */
+ EventTriggerCommandNodeCache =
+ hash_create("Event Trigger Command Node Cache",
+ 1024,
+ &info,
+ HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+
+ for (index = 0; index < lengthof(EventTriggerCommandTags); index++)
+ {
+ bool found;
+ EventTriggerCommandNodeKey key;
+ EventTriggerCommandNodeEntry *hresult;
+
+ memset(&key, 0, sizeof(key));
+ key.node = EventTriggerCommandTags[index].node;
+ key.type = EventTriggerCommandTags[index].type;
+
+ hresult = (EventTriggerCommandNodeEntry *)
+ hash_search(EventTriggerCommandNodeCache,
+ (void *)&key, HASH_ENTER, &found);
+
+ hresult->command = EventTriggerCommandTags[index].command;
+ }
+ MemoryContextSwitchTo(old);
+ }
+
+ memset(&key, 0, sizeof(key));
+ key.node = node;
+ key.type = type;
+
+ entry = (EventTriggerCommandNodeEntry *)
+ hash_search(EventTriggerCommandNodeCache,
+ (void *)&key, HASH_FIND, NULL);
+
+ if (entry == NULL)
+ {
+ if (!noerror)
+ /* fixme: should not happen, use elog? */
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized node %d and object %d", node, type)));
+ return ETC_UNKNOWN;
+ }
+ return entry->command;
+}
+
+char *
+objecttype_to_string(ObjectType type)
+{
+ switch(type)
+ {
+ case OBJECT_AGGREGATE:
+ return "AGGREGATE";
+ case OBJECT_ATTRIBUTE:
+ return "ATTRIBUTE";
+ case OBJECT_CAST:
+ return "CAST";
+ case OBJECT_COLUMN:
+ return "COLUMN";
+ case OBJECT_CONSTRAINT:
+ return "CONSTRAINT";
+ case OBJECT_COLLATION:
+ return "COLLATION";
+ case OBJECT_CONVERSION:
+ return "CONVERSION";
+ case OBJECT_DATABASE:
+ return "DATABASE";
+ case OBJECT_DOMAIN:
+ return "DOMAIN";
+ case OBJECT_EVENT_TRIGGER:
+ return "EVENT TRIGGER";
+ case OBJECT_EXTENSION:
+ return "EXTENSION";
+ case OBJECT_FDW:
+ return "FDW";
+ case OBJECT_FOREIGN_SERVER:
+ return "FOREIGN SERVER";
+ case OBJECT_FOREIGN_TABLE:
+ return "FOREIGN TABLE";
+ case OBJECT_FUNCTION:
+ return "FUNCTION";
+ case OBJECT_INDEX:
+ return "INDEX";
+ case OBJECT_LANGUAGE:
+ return "LANGUAGE";
+ case OBJECT_LARGEOBJECT:
+ return "LARGE OBJECT";
+ case OBJECT_OPCLASS:
+ return "OPERATOR CLASS";
+ case OBJECT_OPERATOR:
+ return "OPERATOR";
+ case OBJECT_OPFAMILY:
+ return "OPERATOR FAMILY";
+ case OBJECT_ROLE:
+ return "ROLE";
+ case OBJECT_RULE:
+ return "RULE";
+ case OBJECT_SCHEMA:
+ return "SCHEMA";
+ case OBJECT_SEQUENCE:
+ return "SEQUENCE";
+ case OBJECT_TABLE:
+ return "TABLE";
+ case OBJECT_TABLESPACE:
+ return "TABLESPACE";
+ case OBJECT_TRIGGER:
+ return "TRIGGER";
+ case OBJECT_TSCONFIGURATION:
+ return "TEXT SEARCH CONFIGURATION";
+ case OBJECT_TSDICTIONARY:
+ return "TEXT SEARCH DICTIONARY";
+ case OBJECT_TSPARSER:
+ return "TEXT SEARCH PARSER";
+ case OBJECT_TSTEMPLATE:
+ return "TEXT SEARCH TEMPLATE";
+ case OBJECT_TYPE:
+ return "TYPE";
+ case OBJECT_VIEW:
+ return "VIEW";
+ }
+ /* silence compiler */
+ return NULL;
+}
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 993053c..611c8e3 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -100,7 +100,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
int numForeignDataWrappers;
int numForeignServers;
int numDefaultACLs;
- int numEvtTriggers;
+ int numEventTriggers;
if (g_verbose)
write_msg(NULL, "reading schemas\n");
@@ -242,8 +242,8 @@ getSchemaData(Archive *fout, int *numTablesPtr)
getTriggers(fout, tblinfo, numTables);
if (g_verbose)
- write_msg(NULL, "reading command triggers\n");
- getEvtTriggers(fout, &numEvtTriggers);
+ write_msg(NULL, "reading event triggers\n");
+ getEventTriggers(fout, &numEventTriggers);
*numTablesPtr = numTables;
return tblinfo;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 75b7ff0..09ca6dd 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -187,7 +187,7 @@ static void dumpConversion(Archive *fout, ConvInfo *convinfo);
static void dumpRule(Archive *fout, RuleInfo *rinfo);
static void dumpAgg(Archive *fout, AggInfo *agginfo);
static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
-static void dumpEvtTrigger(Archive *fout, EvtTriggerInfo *evtinfo);
+static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
static void dumpTable(Archive *fout, TableInfo *tbinfo);
static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
@@ -5299,52 +5299,54 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
}
/*
- * getEvtTriggers
- * get information about every command trigger on a dumpable table
+ * getEventTriggers
+ * get information about event triggers
*/
-EvtTriggerInfo *
-getEvtTriggers(Archive *fout, int *numEvtTriggers)
+EventTriggerInfo *
+getEventTriggers(Archive *fout, int *numEventTriggers)
{
int i;
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
- EvtTriggerInfo *evtinfo;
+ EventTriggerInfo *evtinfo;
int i_tableoid,
i_oid,
i_evtname,
i_evtevent,
- i_evtowner,
+ i_evtowner,
i_evttags,
i_evtfname,
i_evtenabled;
int ntups;
+ /* Before 9.3, there are no event triggers */
+ if (fout->remoteVersion < 90300)
+ {
+ *numEventTriggers = 0;
+ return NULL;
+ }
+
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- if (fout->remoteVersion >= 90200)
- {
- appendPQExpBuffer(query,
- "SELECT e.tableoid, e.oid, evtname, evtenabled, "
- "evtevent, (%s evtowner) AS evtowner, "
- "array_to_string(array("
- "select '''' || x || '''' "
- " from unnest(evttags) as t(x)), ', ') as evttags, "
- "n.nspname || '.' || p.proname as evtfname "
- "FROM pg_event_trigger e "
- "JOIN pg_proc p on e.evtfoid = p.oid "
- "JOIN pg_namespace n ON p.pronamespace = n.oid "
- "ORDER BY e.oid",
- username_subquery);
- }
+ appendPQExpBuffer(query,
+ "SELECT e.tableoid, e.oid, evtname, evtenabled, "
+ "evtevent, (%s evtowner) AS evtowner, "
+ "array_to_string(array("
+ "select quote_literal(x) "
+ " from unnest(evttags) as t(x)), ', ') as evttags, "
+ "e.evtfoid::regproc as evtfname "
+ "FROM pg_event_trigger e "
+ "ORDER BY e.oid",
+ username_subquery);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
- *numEvtTriggers = ntups;
+ *numEventTriggers = ntups;
- evtinfo = (EvtTriggerInfo *) pg_malloc(ntups * sizeof(EvtTriggerInfo));
+ evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
@@ -7248,7 +7250,7 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
dumpTrigger(fout, (TriggerInfo *) dobj);
break;
case DO_EVENT_TRIGGER:
- dumpEvtTrigger(fout, (EvtTriggerInfo *) dobj);
+ dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
break;
case DO_CONSTRAINT:
dumpConstraint(fout, (ConstraintInfo *) dobj);
@@ -13743,7 +13745,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
}
static void
-dumpEvtTrigger(Archive *fout, EvtTriggerInfo *evtinfo)
+dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
{
PQExpBuffer query;
PQExpBuffer labelq;
@@ -13754,19 +13756,19 @@ dumpEvtTrigger(Archive *fout, EvtTriggerInfo *evtinfo)
appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
appendPQExpBuffer(query, " ON ");
- appendPQExpBufferStr(query, evtinfo->evtevent);
+ appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
appendPQExpBufferStr(query, " ");
if (strcmp("", evtinfo->evttags) != 0)
{
- appendPQExpBufferStr(query, "when tag in (");
+ appendPQExpBufferStr(query, "\n WHEN TAG IN (");
appendPQExpBufferStr(query, evtinfo->evttags);
appendPQExpBufferStr(query, ") ");
}
- appendPQExpBuffer(query, "EXECUTE PROCEDURE ");
+ appendPQExpBuffer(query, "\n EXECUTE PROCEDURE ");
appendPQExpBufferStr(query, evtinfo->evtfname);
- appendPQExpBuffer(query, " ();\n");
+ appendPQExpBuffer(query, "();\n");
if (evtinfo->evtenabled != 'O')
{
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 758a1df..5793bca 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -363,7 +363,7 @@ typedef struct _evttriggerInfo
char *evtfname;
char evttype;
char evtenabled;
-} EvtTriggerInfo;
+} EventTriggerInfo;
/*
* struct ConstraintInfo is used for all constraint types. However we
@@ -575,6 +575,6 @@ extern ForeignServerInfo *getForeignServers(Archive *fout,
extern DefaultACLInfo *getDefaultACLs(Archive *fout, int *numDefaultACLs);
extern void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
int numExtensions);
-extern EvtTriggerInfo *getEvtTriggers(Archive *fout, int *numEvtTriggers);
+extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers);
#endif /* PG_DUMP_H */
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 6d4c2ba..5318e7a 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -24,8 +24,9 @@ static const char *modulename = gettext_noop("sorter");
* Objects are sorted by priority levels, and within an equal priority level
* by OID. (This is a relatively crude hack to provide semi-reasonable
* behavior for old databases without full dependency info.) Note: collations,
- * extensions, text search, foreign-data, and default ACL objects can't really
- * happen here, so the rather bogus priorities for them don't matter.
+ * extensions, text search, foreign-data, event trigger, and default ACL
+ * objects can't really happen here, so the rather bogus priorities for them
+ * don't matter.
*
* NOTE: object-type priorities must match the section assignments made in
* pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
@@ -114,7 +115,7 @@ static const int newObjectTypePriority[] =
24, /* DO_BLOB_DATA */
22, /* DO_PRE_DATA_BOUNDARY */
25, /* DO_POST_DATA_BOUNDARY */
- 30 /* DO_EVENT_TRIGGER */
+ 32 /* DO_EVENT_TRIGGER */
};
static DumpId preDataBoundId;
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 7ae8049..939e88f 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -491,7 +491,7 @@ exec_command(const char *cmd,
success = listExtensions(pattern);
break;
case 'y': /* Event Triggers */
- success = listEvtTriggers(pattern, show_verbose);
+ success = listEventTriggers(pattern, show_verbose);
break;
default:
status = PSQL_CMD_UNKNOWN;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 7e8c996..14c6fe3 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -2958,7 +2958,7 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
* Describes Event Triggers.
*/
bool
-listEvtTriggers(const char *pattern, bool verbose)
+listEventTriggers(const char *pattern, bool verbose)
{
PQExpBufferData buf;
PGresult *res;
@@ -2971,15 +2971,14 @@ listEvtTriggers(const char *pattern, bool verbose)
"select evtname as \"%s\", "
"evtevent as \"%s\", "
"pg_catalog.pg_get_userbyid(e.evtowner) AS \"%s\", "
- " case evtenabled when 'O' then 'enabled' "
+ "case evtenabled when 'O' then 'enabled' "
" when 'R' then 'replica' "
" when 'A' then 'always' "
" when 'D' then 'disabled' end as \"%s\", "
- "n.nspname || '.' || p.proname || '()' as \"%s\", "
- " array_to_string(array(select x "
+ "e.evtfoid::regproc as \"%s\", "
+ "array_to_string(array(select x "
" from unnest(evttags) as t(x)), ', ') as \"%s\" "
- "FROM pg_event_trigger e JOIN pg_proc p on e.evtfoid = p.oid "
- "JOIN pg_namespace n ON p.pronamespace = n.oid ",
+ "FROM pg_event_trigger e ",
gettext_noop("Name"),
gettext_noop("Event"),
gettext_noop("Owner"),
diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h
index f2bc794..eef7733 100644
--- a/src/bin/psql/describe.h
+++ b/src/bin/psql/describe.h
@@ -97,6 +97,6 @@ extern bool listExtensions(const char *pattern);
extern bool listExtensionContents(const char *pattern);
/* \dy */
-extern bool listEvtTriggers(const char *pattern, bool verbose);
+extern bool listEventTriggers(const char *pattern, bool verbose);
#endif /* DESCRIBE_H */
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 5807265..0843b65 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -229,7 +229,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n"));
fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n"));
- fprintf(output, _(" \\dy [PATTERN] list command triggers\n"));
+ fprintf(output, _(" \\dy [PATTERN] list event triggers\n"));
fprintf(output, _(" \\l[+] list all databases\n"));
fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n"));
fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));
diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h
index 153d48a..a6caaee 100644
--- a/src/include/catalog/pg_event_trigger.h
+++ b/src/include/catalog/pg_event_trigger.h
@@ -60,122 +60,4 @@ typedef FormData_pg_event_trigger *Form_pg_event_trigger;
#define Anum_pg_event_trigger_evtenabled 5
#define Anum_pg_event_trigger_evttags 6
-/*
- * Times at which an event trigger can be fired. These are the
- * possible values for pg_event_trigger.evtevent.
- *
- * As of now we only implement the command_start firing point, we intend on
- * adding more firing points later.
- */
-typedef enum TrigEvent
-{
- E_CommandStart = 1,
-} TrigEvent;
-
-/*
- * Supported commands
- */
-typedef enum TrigEventCommand
-{
- E_UNKNOWN = 0,
- E_ANY = 1,
-
- E_AlterAggregate = 100,
- E_AlterCast,
- E_AlterCollation,
- E_AlterConversion,
- E_AlterDomain,
- E_AlterExtension,
- E_AlterForeignDataWrapper,
- E_AlterForeignTable,
- E_AlterFunction,
- E_AlterIndex,
- E_AlterLanguage,
- E_AlterOperator,
- E_AlterOperatorClass,
- E_AlterOperatorFamily,
- E_AlterSchema,
- E_AlterSequence,
- E_AlterServer,
- E_AlterTable,
- E_AlterTextSearchParser,
- E_AlterTextSearchConfiguration,
- E_AlterTextSearchDictionary,
- E_AlterTextSearchTemplate,
- E_AlterTrigger,
- E_AlterType,
- E_AlterUserMapping,
- E_AlterView,
-
- E_Cluster = 300,
- E_Load,
- E_Reindex,
- E_SelectInto,
- E_Vacuum,
-
- E_CreateAggregate = 400,
- E_CreateCast,
- E_CreateCollation,
- E_CreateConversion,
- E_CreateDomain,
- E_CreateExtension,
- E_CreateForeignDataWrapper,
- E_CreateForeignTable,
- E_CreateFunction,
- E_CreateIndex,
- E_CreateLanguage,
- E_CreateOperator,
- E_CreateOperatorClass,
- E_CreateOperatorFamily,
- E_CreateRule,
- E_CreateSchema,
- E_CreateSequence,
- E_CreateServer,
- E_CreateTable,
- E_CreateTableAs,
- E_CreateTextSearchParser,
- E_CreateTextSearchConfiguration,
- E_CreateTextSearchDictionary,
- E_CreateTextSearchTemplate,
- E_CreateTrigger,
- E_CreateType,
- E_CreateUserMapping,
- E_CreateView,
-
- E_DropAggregate = 600,
- E_DropCast,
- E_DropCollation,
- E_DropConversion,
- E_DropDomain,
- E_DropExtension,
- E_DropForeignDataWrapper,
- E_DropForeignTable,
- E_DropFunction,
- E_DropIndex,
- E_DropLanguage,
- E_DropOperator,
- E_DropOperatorClass,
- E_DropOperatorFamily,
- E_DropRule,
- E_DropSchema,
- E_DropSequence,
- E_DropServer,
- E_DropTable,
- E_DropTextSearchParser,
- E_DropTextSearchConfiguration,
- E_DropTextSearchDictionary,
- E_DropTextSearchTemplate,
- E_DropTrigger,
- E_DropType,
- E_DropUserMapping,
- E_DropView
-} TrigEventCommand;
-
-/* implemented in src/backend/catalog/pg_event_trigger.c */
-char * event_to_string(TrigEvent event);
-TrigEvent parse_event_name(char *event);
-
-char * command_to_string(TrigEventCommand command);
-TrigEventCommand parse_event_tag(char *command, bool noerror);
-
#endif /* PG_EVENT_TRIGGER_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 340de88..743f890 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3456,6 +3456,10 @@ DATA(insert OID = 2300 ( trigger_in PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2
DESCR("I/O");
DATA(insert OID = 2301 ( trigger_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "2279" _null_ _null_ _null_ _null_ trigger_out _null_ _null_ _null_ ));
DESCR("I/O");
+DATA(insert OID = 3594 ( event_trigger_in PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 3838 "2275" _null_ _null_ _null_ _null_ event_trigger_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3595 ( event_trigger_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "3838" _null_ _null_ _null_ _null_ event_trigger_out _null_ _null_ _null_ ));
+DESCR("I/O");
DATA(insert OID = 2302 ( language_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2280 "2275" _null_ _null_ _null_ _null_ language_handler_in _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 2303 ( language_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "2280" _null_ _null_ _null_ _null_ language_handler_out _null_ _null_ _null_ ));
@@ -4645,6 +4649,7 @@ DESCR("SP-GiST support for suffix tree over text");
DATA(insert OID = 4031 ( spg_text_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ spg_text_leaf_consistent _null_ _null_ _null_ ));
DESCR("SP-GiST support for suffix tree over text");
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 98c7dd5..86be998 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -650,7 +650,7 @@ DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void
#define VOIDOID 2278
DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
#define TRIGGEROID 2279
-DATA(insert OID = 3838 ( event_trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3838 ( event_trigger PGNSP PGUID 4 t p P f t \054 0 0 0 event_trigger_in event_trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
#define EVTTRIGGEROID 3838
DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
#define LANGUAGE_HANDLEROID 2280
diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h
index 5c4db5c..13be6bc 100644
--- a/src/include/commands/event_trigger.h
+++ b/src/include/commands/event_trigger.h
@@ -15,6 +15,7 @@
#include "catalog/pg_event_trigger.h"
#include "nodes/parsenodes.h"
+#include "utils/evtcache.h"
/*
* To be able to call user defined function on event triggers, the places in
@@ -30,6 +31,8 @@ typedef struct EventContextData
TrigEventCommand command; /* For command triggers */
char *toplevel; /* TopLevel Command Tag */
char *tag; /* Command Tag */
+ char *operation; /* CREATE / ALTER / DROP, or NULL */
+ ObjectType objecttype; /* TABLE, FUNCTION, CAST, etc, or NULL */
Oid objectId; /* oid of the existing object, if any */
char *schemaname; /* schemaname or NULL if not relevant */
char *objectname; /* objectname */
@@ -48,9 +51,11 @@ typedef struct EventContextData *EventContext;
typedef struct EventTriggerData
{
NodeTag type;
- char *when; /* Either BEFORE or AFTER */
+ char *event; /* command_start, etc */
char *toplevel; /* TopLevel Command Tag */
char *tag; /* Command Tag */
+ char *operation; /* CREATE / ALTER / DROP, or NULL */
+ char *objecttype; /* TABLE, FUNCTION, CAST, etc, or NULL */
Oid objectId; /* oid of the existing object, if any */
char *schemaname; /* schemaname or NULL if not relevant */
char *objectname; /* objectname */
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 2d1cccb..5700e54 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -195,6 +195,7 @@ typedef enum AclObjectKind
ACL_KIND_TSCONFIGURATION, /* pg_ts_config */
ACL_KIND_FDW, /* pg_foreign_data_wrapper */
ACL_KIND_FOREIGN_SERVER, /* pg_foreign_server */
+ ACL_KIND_EVENT_TRIGGER, /* pg_event_trigger */
ACL_KIND_EXTENSION, /* pg_extension */
MAX_ACL_KIND /* MUST BE LAST */
} AclObjectKind;
@@ -322,6 +323,7 @@ extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid);
extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid);
extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid);
extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid);
+extern bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid);
extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
extern bool has_createrole_privilege(Oid roleid);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 71563ad..8b9291c 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -532,6 +532,8 @@ extern Datum void_recv(PG_FUNCTION_ARGS);
extern Datum void_send(PG_FUNCTION_ARGS);
extern Datum trigger_in(PG_FUNCTION_ARGS);
extern Datum trigger_out(PG_FUNCTION_ARGS);
+extern Datum event_trigger_in(PG_FUNCTION_ARGS);
+extern Datum event_trigger_out(PG_FUNCTION_ARGS);
extern Datum language_handler_in(PG_FUNCTION_ARGS);
extern Datum language_handler_out(PG_FUNCTION_ARGS);
extern Datum fdw_handler_in(PG_FUNCTION_ARGS);
@@ -1013,7 +1015,6 @@ extern Datum pg_encoding_max_length_sql(PG_FUNCTION_ARGS);
/* format_type.c */
extern Datum format_type(PG_FUNCTION_ARGS);
extern char *format_type_be(Oid type_oid);
-extern char *format_type_be_without_namespace(Oid type_oid);
extern char *format_type_with_typemod(Oid type_oid, int32 typemod);
extern Datum oidvectortypes(PG_FUNCTION_ARGS);
extern int32 type_maximum_size(Oid type_oid, int32 typemod);
diff --git a/src/include/utils/evtcache.h b/src/include/utils/evtcache.h
index 51f6bec..ef84b90 100644
--- a/src/include/utils/evtcache.h
+++ b/src/include/utils/evtcache.h
@@ -15,6 +15,125 @@
#include "catalog/pg_event_trigger.h"
+
+/*
+ * Times at which an event trigger can be fired. These are the
+ * possible values for pg_event_trigger.evtevent.
+ *
+ * As of now we only implement the command_start firing point, we intend on
+ * adding more firing points later.
+ */
+typedef enum TrigEvent
+{
+ EVT_CommandStart = 1,
+} TrigEvent;
+
+/*
+ * Supported commands
+ *
+ * Those values are not going to disk, so can be shuffled around at will. We
+ * keep the number organized so that it's easier to debug, should it be needed.
+ *
+ * See also EventTriggerCommandTags in src/backend/utils/cache/evtcache.c
+ */
+typedef enum TrigEventCommand
+{
+ ETC_UNSET = -1,
+ ETC_UNKNOWN = 0,
+ ETC_ANY = 1,
+
+ ETC_AlterAggregate = 100,
+ ETC_AlterCast,
+ ETC_AlterCollation,
+ ETC_AlterConversion,
+ ETC_AlterDomain,
+ ETC_AlterExtension,
+ ETC_AlterForeignDataWrapper,
+ ETC_AlterForeignTable,
+ ETC_AlterFunction,
+ ETC_AlterIndex,
+ ETC_AlterLanguage,
+ ETC_AlterOperator,
+ ETC_AlterOperatorClass,
+ ETC_AlterOperatorFamily,
+ ETC_AlterRule,
+ ETC_AlterSchema,
+ ETC_AlterSequence,
+ ETC_AlterServer,
+ ETC_AlterTable,
+ ETC_AlterTextSearchParser,
+ ETC_AlterTextSearchConfiguration,
+ ETC_AlterTextSearchDictionary,
+ ETC_AlterTextSearchTemplate,
+ ETC_AlterTrigger,
+ ETC_AlterType,
+ ETC_AlterUserMapping,
+ ETC_AlterView,
+
+ ETC_Cluster = 300,
+ ETC_Load,
+ ETC_Reindex,
+ ETC_SelectInto,
+ ETC_Vacuum,
+
+ ETC_CreateAggregate = 400,
+ ETC_CreateCast,
+ ETC_CreateCollation,
+ ETC_CreateConversion,
+ ETC_CreateDomain,
+ ETC_CreateExtension,
+ ETC_CreateForeignDataWrapper,
+ ETC_CreateForeignTable,
+ ETC_CreateFunction,
+ ETC_CreateIndex,
+ ETC_CreateLanguage,
+ ETC_CreateOperator,
+ ETC_CreateOperatorClass,
+ ETC_CreateOperatorFamily,
+ ETC_CreateRule,
+ ETC_CreateSchema,
+ ETC_CreateSequence,
+ ETC_CreateServer,
+ ETC_CreateTable,
+ ETC_CreateTableAs,
+ ETC_CreateTextSearchParser,
+ ETC_CreateTextSearchConfiguration,
+ ETC_CreateTextSearchDictionary,
+ ETC_CreateTextSearchTemplate,
+ ETC_CreateTrigger,
+ ETC_CreateType,
+ ETC_CreateUserMapping,
+ ETC_CreateView,
+
+ ETC_DropAggregate = 600,
+ ETC_DropCast,
+ ETC_DropCollation,
+ ETC_DropConversion,
+ ETC_DropDomain,
+ ETC_DropExtension,
+ ETC_DropForeignDataWrapper,
+ ETC_DropForeignTable,
+ ETC_DropFunction,
+ ETC_DropIndex,
+ ETC_DropLanguage,
+ ETC_DropOperator,
+ ETC_DropOperatorClass,
+ ETC_DropOperatorFamily,
+ ETC_DropRule,
+ ETC_DropSchema,
+ ETC_DropSequence,
+ ETC_DropServer,
+ ETC_DropTable,
+ ETC_DropTextSearchParser,
+ ETC_DropTextSearchConfiguration,
+ ETC_DropTextSearchDictionary,
+ ETC_DropTextSearchTemplate,
+ ETC_DropTrigger,
+ ETC_DropType,
+ ETC_DropUserMapping,
+ ETC_DropView
+} TrigEventCommand;
+
/*
* Event Triggers to fire for a given event and command, including ANY command
* triggers.
@@ -30,5 +149,16 @@ void InitEventTriggerCache(void);
EventCommandTriggers *get_event_triggers(TrigEvent event,
TrigEventCommand command);
+char * event_to_string(TrigEvent event);
+TrigEvent parse_event_name(char *event);
+
+char * command_to_string(TrigEventCommand command);
+TrigEventCommand parse_event_tag(char *cmdtag, bool noerror);
+
+TrigEventCommand get_command_from_nodetag(NodeTag node,
+ ObjectType type,
+ bool noerror);
+
+char * objecttype_to_string(ObjectType type);
#endif /* EVTCACHE_H */
diff --git a/src/pl/plperl/expected/plperl_trigger.out b/src/pl/plperl/expected/plperl_trigger.out
index b61d47c..2d1ed56 100644
--- a/src/pl/plperl/expected/plperl_trigger.out
+++ b/src/pl/plperl/expected/plperl_trigger.out
@@ -309,10 +309,10 @@ $$ LANGUAGE plperl;
SELECT direct_trigger();
ERROR: trigger functions can only be called as triggers
CONTEXT: compilation of PL/Perl function "direct_trigger"
--- test plperl command triggers
+-- test plperl event triggers
create or replace function perlsnitch() returns event_trigger language plperl as $$
elog(NOTICE, "perlsnitch: "
- . $_TD->{when} . " "
+ . $_TD->{event} . " "
. $_TD->{tag} . " "
. $_TD->{schemaname} . " "
. $_TD->{objectname});
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 5b456aa..374a81e 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1571,7 +1571,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo)
}
-/* Set up the arguments for a command trigger call. */
+/* Set up the arguments for an event trigger call. */
static SV *
plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
{
@@ -1584,7 +1584,7 @@ plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
tdata = (EventTriggerData *) fcinfo->context;
- hv_store_string(hv, "when", cstr2sv(tdata->when));
+ hv_store_string(hv, "event", cstr2sv(tdata->event));
hv_store_string(hv, "tag", cstr2sv(tdata->tag));
if (tdata->objectId == InvalidOid)
@@ -1594,8 +1594,14 @@ plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
DirectFunctionCall1(oidout, ObjectIdGetDatum(tdata->objectId)));
hv_store_string(hv, "objectid", cstr2sv(objectid));
- hv_store_string(hv, "objectname", cstr2sv(tdata->objectname == NULL ? "NULL" : tdata->objectname));
- hv_store_string(hv, "schemaname", cstr2sv(tdata->schemaname == NULL ? "NULL" : tdata->schemaname));
+ hv_store_string(hv, "operation",
+ cstr2sv(tdata->operation == NULL ? "NULL" : tdata->operation));
+ hv_store_string(hv, "objecttype",
+ cstr2sv(tdata->objecttype == NULL ? "NULL" : tdata->objecttype));
+ hv_store_string(hv, "objectname",
+ cstr2sv(tdata->objectname == NULL ? "NULL" : tdata->objectname));
+ hv_store_string(hv, "schemaname",
+ cstr2sv(tdata->schemaname == NULL ? "NULL" : tdata->schemaname));
return newRV_noinc((SV *) hv);
}
diff --git a/src/pl/plperl/sql/plperl_trigger.sql b/src/pl/plperl/sql/plperl_trigger.sql
index 9cc2408..75a9f11 100644
--- a/src/pl/plperl/sql/plperl_trigger.sql
+++ b/src/pl/plperl/sql/plperl_trigger.sql
@@ -170,10 +170,10 @@ $$ LANGUAGE plperl;
SELECT direct_trigger();
--- test plperl command triggers
+-- test plperl event triggers
create or replace function perlsnitch() returns event_trigger language plperl as $$
elog(NOTICE, "perlsnitch: "
- . $_TD->{when} . " "
+ . $_TD->{event} . " "
. $_TD->{tag} . " "
. $_TD->{schemaname} . " "
. $_TD->{objectname});
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 77c5ed9..4fb1443 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -536,7 +536,7 @@ do_compile(FunctionCallInfo fcinfo,
if (rettypeid == VOIDOID ||
rettypeid == RECORDOID)
/* okay */ ;
- else if (rettypeid == TRIGGEROID)
+ else if (rettypeid == TRIGGEROID || rettypeid == EVTTRIGGEROID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("trigger functions can only be called as triggers")));
@@ -689,15 +689,15 @@ do_compile(FunctionCallInfo fcinfo,
if (procStruct->pronargs != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
- errmsg("command trigger functions cannot have declared arguments")));
+ errmsg("event trigger functions cannot have declared arguments")));
/* Add the variable tg_when */
- var = plpgsql_build_variable("tg_when", 0,
+ var = plpgsql_build_variable("tg_event", 0,
plpgsql_build_datatype(TEXTOID,
-1,
function->fn_input_collation),
true);
- function->tg_when_varno = var->dno;
+ function->tg_event_varno = var->dno;
/* Add the variable tg_tag */
var = plpgsql_build_variable("tg_tag", 0,
@@ -707,6 +707,22 @@ do_compile(FunctionCallInfo fcinfo,
true);
function->tg_tag_varno = var->dno;
+ /* Add the variable tg_operation */
+ var = plpgsql_build_variable("tg_operation", 0,
+ plpgsql_build_datatype(TEXTOID,
+ -1,
+ function->fn_input_collation),
+ true);
+ function->tg_operation_varno = var->dno;
+
+ /* Add the variable tg_objecttype */
+ var = plpgsql_build_variable("tg_objecttype", 0,
+ plpgsql_build_datatype(TEXTOID,
+ -1,
+ function->fn_input_collation),
+ true);
+ function->tg_objecttype_varno = var->dno;
+
/* Add the variable tg_objectid */
var = plpgsql_build_variable("tg_objectid", 0,
plpgsql_build_datatype(OIDOID,
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index fd59d75..a2cf506 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -773,8 +773,8 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
return rettup;
}
-void plpgsql_exec_event_trigger(PLpgSQL_function *func,
- EventTriggerData *trigdata)
+void
+plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
{
PLpgSQL_execstate estate;
ErrorContextCallback plerrcontext;
@@ -805,8 +805,8 @@ void plpgsql_exec_event_trigger(PLpgSQL_function *func,
/*
* Assign the special tg_ variables
*/
- var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]);
- var->value = CStringGetTextDatum(trigdata->when);
+ var = (PLpgSQL_var *) (estate.datums[func->tg_event_varno]);
+ var->value = CStringGetTextDatum(trigdata->event);
var->isnull = false;
var->freeval = true;
@@ -815,6 +815,30 @@ void plpgsql_exec_event_trigger(PLpgSQL_function *func,
var->isnull = false;
var->freeval = true;
+ var = (PLpgSQL_var *) (estate.datums[func->tg_operation_varno]);
+ if (trigdata->operation == NULL)
+ {
+ var->isnull = true;
+ }
+ else
+ {
+ var->value = CStringGetTextDatum(trigdata->operation);
+ var->isnull = false;
+ }
+ var->freeval = false;
+
+ var = (PLpgSQL_var *) (estate.datums[func->tg_objecttype_varno]);
+ if (trigdata->objecttype == NULL)
+ {
+ var->isnull = true;
+ }
+ else
+ {
+ var->value = CStringGetTextDatum(trigdata->objecttype);
+ var->isnull = false;
+ }
+ var->freeval = false;
+
var = (PLpgSQL_var *) (estate.datums[func->tg_objectid_varno]);
if (trigdata->objectId == InvalidOid)
{
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 57f556f..4e15ad8 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -721,6 +721,9 @@ typedef struct PLpgSQL_function
int tg_argv_varno;
int tg_tag_varno;
+ int tg_event_varno;
+ int tg_operation_varno;
+ int tg_objecttype_varno;
int tg_objectid_varno;
int tg_schemaname_varno;
int tg_objectname_varno;
diff --git a/src/pl/plpython/expected/plpython_trigger.out b/src/pl/plpython/expected/plpython_trigger.out
index f756462..5294dc7 100644
--- a/src/pl/plpython/expected/plpython_trigger.out
+++ b/src/pl/plpython/expected/plpython_trigger.out
@@ -610,10 +610,10 @@ SELECT * FROM composite_trigger_nested_test;
("(,t)","(1,f)",)
(3 rows)
--- test plpython command triggers
+-- test plpython event triggers
create or replace function pysnitch() returns event_trigger language plpythonu as $$
plpy.notice(" pysnitch: %s %s %s.%s" %
- (TD["when"], TD["tag"], TD["schemaname"], TD["objectname"]));
+ (TD["event"], TD["tag"], TD["schemaname"], TD["objectname"]));
$$;
create event trigger py_snitch on command_start execute procedure pysnitch();
create or replace function foobar() returns int language sql as $$select 1;$$;
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index 63682bf..7405893 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -348,8 +348,10 @@ PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
PG_TRY();
{
/* build command trigger args */
- PyObject *pltwhen,
+ PyObject *pltevent,
*plttag,
+ *pltoperation,
+ *pltobjecttype,
*pltschemaname,
*pltobjectname;
char *stroid;
@@ -358,14 +360,32 @@ PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
if (!pltdata)
PLy_elog(ERROR, "could not create new dictionary while building command trigger arguments");
- pltwhen = PyString_FromString(tdata->when);
- PyDict_SetItemString(pltdata, "when", pltwhen);
- Py_DECREF(pltwhen);
+ pltevent = PyString_FromString(tdata->event);
+ PyDict_SetItemString(pltdata, "event", pltevent);
+ Py_DECREF(pltevent);
plttag = PyString_FromString(tdata->tag);
PyDict_SetItemString(pltdata, "tag", plttag);
Py_DECREF(plttag);
+ if (tdata->operation == NULL)
+ PyDict_SetItemString(pltdata, "operation", Py_None);
+ else
+ {
+ pltoperation = PyString_FromString(tdata->operation);
+ PyDict_SetItemString(pltdata, "operation", pltoperation);
+ Py_DECREF(pltoperation);
+ }
+
+ if (tdata->objecttype == NULL)
+ PyDict_SetItemString(pltdata, "objecttype", Py_None);
+ else
+ {
+ pltobjecttype = PyString_FromString(tdata->objecttype);
+ PyDict_SetItemString(pltdata, "objecttype", pltobjecttype);
+ Py_DECREF(pltobjecttype);
+ }
+
if (tdata->objectId == InvalidOid)
PyDict_SetItemString(pltdata, "objectId", Py_None);
else
diff --git a/src/pl/plpython/sql/plpython_trigger.sql b/src/pl/plpython/sql/plpython_trigger.sql
index 7ec6e0b..aaa1731 100644
--- a/src/pl/plpython/sql/plpython_trigger.sql
+++ b/src/pl/plpython/sql/plpython_trigger.sql
@@ -388,10 +388,10 @@ INSERT INTO composite_trigger_nested_test VALUES (ROW(ROW(1, 'f'), NULL, 3));
INSERT INTO composite_trigger_nested_test VALUES (ROW(ROW(NULL, 't'), ROW(1, 'f'), NULL));
SELECT * FROM composite_trigger_nested_test;
--- test plpython command triggers
+-- test plpython event triggers
create or replace function pysnitch() returns event_trigger language plpythonu as $$
plpy.notice(" pysnitch: %s %s %s.%s" %
- (TD["when"], TD["tag"], TD["schemaname"], TD["objectname"]));
+ (TD["event"], TD["tag"], TD["schemaname"], TD["objectname"]));
$$;
create event trigger py_snitch on command_start execute procedure pysnitch();
diff --git a/src/pl/tcl/expected/pltcl_setup.out b/src/pl/tcl/expected/pltcl_setup.out
index 9b9c157..cfe124c 100644
--- a/src/pl/tcl/expected/pltcl_setup.out
+++ b/src/pl/tcl/expected/pltcl_setup.out
@@ -519,9 +519,9 @@ select tcl_date_week(2001,10,24);
42
(1 row)
--- test pltcl command triggers
+-- test pltcl event triggers
create or replace function tclsnitch() returns event_trigger language pltcl as $$
- elog NOTICE " tclsnitch: $TG_when $TG_tag $TG_schemaname $TG_objectname"
+ elog NOTICE " tclsnitch: $TG_event $TG_tag $TG_schemaname $TG_objectname"
$$;
create event trigger tcl_snitch on command_start execute procedure tclsnitch();
create or replace function foobar() returns int language sql as $$select 1;$$;
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 7df6467..3ee32f7 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1166,7 +1166,7 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
Tcl_DStringAppendElement(&tcl_cmd, prodesc->internal_proname);
PG_TRY();
{
- Tcl_DStringAppendElement(&tcl_cmd, tdata->when);
+ Tcl_DStringAppendElement(&tcl_cmd, tdata->event);
Tcl_DStringAppendElement(&tcl_cmd, tdata->tag);
if (tdata->objectId == InvalidOid)
@@ -1177,6 +1177,8 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
Tcl_DStringAppendElement(&tcl_cmd, stroid);
pfree(stroid);
+ Tcl_DStringAppendElement(&tcl_cmd, tdata->operation);
+ Tcl_DStringAppendElement(&tcl_cmd, tdata->objecttype);
Tcl_DStringAppendElement(&tcl_cmd, tdata->schemaname);
Tcl_DStringAppendElement(&tcl_cmd, tdata->objectname);
}
@@ -1488,7 +1490,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid,
{
/* event trigger procedure has fixed args */
strcpy(proc_internal_args,
- "TG_when TG_tag TG_objectid TG_schemaname TG_objectname");
+ "TG_event TG_tag TG_objectid TG_operation TG_objecttype TG_schemaname TG_objectname");
}
/************************************************************
diff --git a/src/pl/tcl/sql/pltcl_setup.sql b/src/pl/tcl/sql/pltcl_setup.sql
index 864e23b..2cb4839 100644
--- a/src/pl/tcl/sql/pltcl_setup.sql
+++ b/src/pl/tcl/sql/pltcl_setup.sql
@@ -560,9 +560,9 @@ $$ language pltcl immutable;
select tcl_date_week(2010,1,24);
select tcl_date_week(2001,10,24);
--- test pltcl command triggers
+-- test pltcl event triggers
create or replace function tclsnitch() returns event_trigger language pltcl as $$
- elog NOTICE " tclsnitch: $TG_when $TG_tag $TG_schemaname $TG_objectname"
+ elog NOTICE " tclsnitch: $TG_event $TG_tag $TG_schemaname $TG_objectname"
$$;
create event trigger tcl_snitch on command_start execute procedure tclsnitch();
diff --git a/src/test/regress/expected/event_triggers.out b/src/test/regress/expected/event_triggers.out
index 415605b..687d1c2 100644
--- a/src/test/regress/expected/event_triggers.out
+++ b/src/test/regress/expected/event_triggers.out
@@ -7,12 +7,9 @@ create or replace function snitch()
as $$
begin
-- can't output tg_objectid here that would break pg_regress
- raise notice 'snitch: % % %.%', tg_when, tg_tag, tg_schemaname, tg_objectname;
+ raise notice 'snitch: % % [% - %]', tg_event, tg_tag, tg_operation, tg_objecttype;
end;
$$;
---
--- TODO: REASSIGN OWNED and DROP OWNED
---
create event trigger any_t on command_start
execute procedure snitch();
create event trigger foo_t on command_start
@@ -62,212 +59,216 @@ alter event trigger foo_t disable;
alter event trigger foo_t enable;
alter event trigger foo_t rename to snitch;
create schema cmd;
-NOTICE: snitch: command_start CREATE SCHEMA <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE SCHEMA <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE SCHEMA [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE SCHEMA [CREATE - <NULL>]
create schema cmd2;
-NOTICE: snitch: command_start CREATE SCHEMA <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE SCHEMA <NULL>.<NULL>
-create role regbob;
-alter event trigger snitch owner to regbob;
+NOTICE: snitch: command_start CREATE SCHEMA [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE SCHEMA [CREATE - <NULL>]
+create role regression_bob;
+alter event trigger snitch owner to regression_bob;
+ERROR: permission denied to change owner of event trigger "snitch"
+HINT: The owner of an event trigger must be a superuser.
+alter role regression_bob superuser;
+alter event trigger snitch owner to regression_bob;
create table cmd.foo(id bigserial primary key);
-NOTICE: snitch: command_start CREATE TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE INDEX <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TABLE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TABLE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE SEQUENCE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE SEQUENCE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE INDEX [CREATE - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
create view cmd.v as select * from cmd.foo;
-NOTICE: snitch: command_start CREATE VIEW <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE VIEW <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE VIEW [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE VIEW [CREATE - <NULL>]
alter table cmd.foo add column t text;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
create table cmd.bar as select 1;
-NOTICE: snitch: command_start CREATE TABLE AS <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TABLE AS <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TABLE AS [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TABLE AS [CREATE - <NULL>]
drop table cmd.bar;
-NOTICE: snitch: command_start DROP TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start DROP TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TABLE [DROP - TABLE]
+NOTICE: snitch: command_start DROP TABLE [DROP - TABLE]
select 1 into cmd.bar;
-NOTICE: snitch: command_start SELECT INTO <NULL>.<NULL>
-NOTICE: snitch: command_start SELECT INTO <NULL>.<NULL>
+NOTICE: snitch: command_start SELECT INTO [<NULL> - <NULL>]
+NOTICE: snitch: command_start SELECT INTO [<NULL> - <NULL>]
drop table cmd.bar;
-NOTICE: snitch: command_start DROP TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start DROP TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TABLE [DROP - TABLE]
+NOTICE: snitch: command_start DROP TABLE [DROP - TABLE]
create table test9 (id int, stuff text);
-NOTICE: snitch: command_start CREATE TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TABLE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TABLE [CREATE - <NULL>]
alter table test9 rename to test;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - TABLE]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - TABLE]
alter table test set schema cmd;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - TABLE]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - TABLE]
alter table cmd.test rename column stuff to things;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - COLUMN]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - COLUMN]
alter table cmd.test add column alpha text;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha set data type varchar(300);
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha set default 'test';
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha drop default;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha set statistics 78;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha set storage plain;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha set not null;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha drop not null;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha set (n_distinct = -0.78);
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test alter column alpha reset (n_distinct);
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test drop column alpha;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test add check (id > 2) not valid;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test add check (id < 800000);
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test set without cluster;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test set with oids;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
alter table cmd.test set without oids;
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TABLE [ALTER - <NULL>]
create sequence test_seq_;
-NOTICE: snitch: command_start CREATE SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE SEQUENCE <NULL>.<NULL>
-alter sequence test_seq_ owner to regbob;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE SEQUENCE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE SEQUENCE [CREATE - <NULL>]
+alter sequence test_seq_ owner to regression_bob;
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence test_seq_ rename to test_seq;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - SEQUENCE]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - SEQUENCE]
alter sequence test_seq set schema cmd;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - SEQUENCE]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - SEQUENCE]
alter sequence cmd.test_seq start with 3;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq restart with 4;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq minvalue 3;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq no minvalue;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq maxvalue 900000;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq no maxvalue;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq cache 876;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq cycle;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
alter sequence cmd.test_seq no cycle;
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER SEQUENCE [ALTER - <NULL>]
create view view_test as select id, things from cmd.test;
-NOTICE: snitch: command_start CREATE VIEW <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE VIEW <NULL>.<NULL>
-alter view view_test owner to regbob;
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE VIEW [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE VIEW [CREATE - <NULL>]
+alter view view_test owner to regression_bob;
+NOTICE: snitch: command_start ALTER VIEW [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER VIEW [ALTER - <NULL>]
alter view view_test rename to view_test2;
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER VIEW [ALTER - VIEW]
+NOTICE: snitch: command_start ALTER VIEW [ALTER - VIEW]
alter view view_test2 set schema cmd;
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER VIEW [ALTER - VIEW]
+NOTICE: snitch: command_start ALTER VIEW [ALTER - VIEW]
alter view cmd.view_test2 alter column id set default 9;
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER VIEW [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER VIEW [ALTER - <NULL>]
alter view cmd.view_test2 alter column id drop default;
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER VIEW <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER VIEW [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER VIEW [ALTER - <NULL>]
cluster cmd.foo using foo_pkey;
-NOTICE: snitch: command_start CLUSTER <NULL>.<NULL>
+NOTICE: snitch: command_start CLUSTER [<NULL> - <NULL>]
vacuum cmd.foo;
-NOTICE: snitch: command_start VACUUM <NULL>.<NULL>
-NOTICE: snitch: command_start VACUUM <NULL>.<NULL>
+NOTICE: snitch: command_start VACUUM [<NULL> - <NULL>]
+NOTICE: snitch: command_start VACUUM [<NULL> - <NULL>]
vacuum;
-NOTICE: snitch: command_start VACUUM <NULL>.<NULL>
-NOTICE: snitch: command_start VACUUM <NULL>.<NULL>
+NOTICE: snitch: command_start VACUUM [<NULL> - <NULL>]
+NOTICE: snitch: command_start VACUUM [<NULL> - <NULL>]
reindex table cmd.foo;
-NOTICE: snitch: command_start REINDEX <NULL>.<NULL>
-NOTICE: snitch: command_start REINDEX <NULL>.<NULL>
+NOTICE: snitch: command_start REINDEX [<NULL> - <NULL>]
+NOTICE: snitch: command_start REINDEX [<NULL> - <NULL>]
set session_replication_role to replica;
create table cmd.bar();
-NOTICE: snitch: command_start CREATE TABLE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TABLE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TABLE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TABLE [CREATE - <NULL>]
reset session_replication_role;
create index idx_foo on cmd.foo(t);
-NOTICE: snitch: command_start CREATE INDEX <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE INDEX [CREATE - <NULL>]
reindex index cmd.idx_foo;
-NOTICE: snitch: command_start REINDEX <NULL>.<NULL>
-NOTICE: snitch: command_start REINDEX <NULL>.<NULL>
+NOTICE: snitch: command_start REINDEX [<NULL> - <NULL>]
+NOTICE: snitch: command_start REINDEX [<NULL> - <NULL>]
drop index cmd.idx_foo;
-NOTICE: snitch: command_start DROP INDEX <NULL>.<NULL>
+NOTICE: snitch: command_start DROP INDEX [DROP - INDEX]
create function fun(int) returns text language sql
as $$ select t from cmd.foo where id = $1; $$;
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
alter function fun(int) strict;
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - <NULL>]
alter function fun(int) rename to notfun;
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - FUNCTION]
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - FUNCTION]
alter function notfun(int) set schema cmd;
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
-alter function cmd.notfun(int) owner to regbob;
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - FUNCTION]
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - FUNCTION]
+alter function cmd.notfun(int) owner to regression_bob;
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - FUNCTION]
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - FUNCTION]
alter function cmd.notfun(int) cost 77;
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER FUNCTION [ALTER - <NULL>]
drop function cmd.notfun(int);
-NOTICE: snitch: command_start DROP FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start DROP FUNCTION [DROP - FUNCTION]
create function cmd.plus1(int) returns bigint language sql
as $$ select $1::bigint + 1; $$;
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
create operator cmd.+!(procedure = cmd.plus1, leftarg = int);
-NOTICE: snitch: command_start CREATE OPERATOR <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE OPERATOR <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE OPERATOR [CREATE - OPERATOR]
+NOTICE: snitch: command_start CREATE OPERATOR [CREATE - OPERATOR]
alter operator cmd.+!(int, NONE) set schema public;
-NOTICE: snitch: command_start ALTER OPERATOR <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER OPERATOR <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER OPERATOR [ALTER - OPERATOR]
+NOTICE: snitch: command_start ALTER OPERATOR [ALTER - OPERATOR]
drop operator public.+!(int, NONE);
-NOTICE: snitch: command_start DROP OPERATOR <NULL>.<NULL>
+NOTICE: snitch: command_start DROP OPERATOR [DROP - OPERATOR]
create aggregate cmd.avg (float8)
(
sfunc = float8_accum,
@@ -275,130 +276,130 @@ create aggregate cmd.avg (float8)
finalfunc = float8_avg,
initcond = '{0,0,0}'
);
-NOTICE: snitch: command_start CREATE AGGREGATE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE AGGREGATE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE AGGREGATE [CREATE - AGGREGATE]
+NOTICE: snitch: command_start CREATE AGGREGATE [CREATE - AGGREGATE]
alter aggregate cmd.avg(float8) set schema public;
-NOTICE: snitch: command_start ALTER AGGREGATE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER AGGREGATE [ALTER - AGGREGATE]
drop aggregate public.avg(float8);
-NOTICE: snitch: command_start DROP AGGREGATE <NULL>.<NULL>
-NOTICE: snitch: command_start DROP AGGREGATE <NULL>.<NULL>
+NOTICE: snitch: command_start DROP AGGREGATE [DROP - AGGREGATE]
+NOTICE: snitch: command_start DROP AGGREGATE [DROP - AGGREGATE]
create collation cmd.french (LOCALE = 'fr_FR');
-NOTICE: snitch: command_start CREATE COLLATION <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE COLLATION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE COLLATION [CREATE - COLLATION]
+NOTICE: snitch: command_start CREATE COLLATION [CREATE - COLLATION]
alter collation cmd.french rename to francais;
-NOTICE: snitch: command_start ALTER COLLATION <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER COLLATION <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER COLLATION [ALTER - COLLATION]
+NOTICE: snitch: command_start ALTER COLLATION [ALTER - COLLATION]
create type cmd.compfoo AS (f1 int, f2 text);
-NOTICE: snitch: command_start CREATE TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TYPE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TYPE [CREATE - <NULL>]
alter type cmd.compfoo add attribute f3 text;
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
create type cmd.type_test AS (a integer, b integer, c text);
-NOTICE: snitch: command_start CREATE TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TYPE <NULL>.<NULL>
-alter type cmd.type_test owner to regbob;
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TYPE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TYPE [CREATE - <NULL>]
+alter type cmd.type_test owner to regression_bob;
+NOTICE: snitch: command_start ALTER TYPE [ALTER - TYPE]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - TYPE]
alter type cmd.type_test rename to type_test2;
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - TYPE]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - TYPE]
alter type cmd.type_test2 set schema public;
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - TYPE]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - TYPE]
alter type public.type_test2 rename attribute a to z;
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - ATTRIBUTE]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - ATTRIBUTE]
alter type public.type_test2 add attribute alpha text;
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
alter type public.type_test2 alter attribute alpha set data type char(90);
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
alter type public.type_test2 drop attribute alpha;
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
drop type cmd.compfoo;
-NOTICE: snitch: command_start DROP TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TYPE [DROP - TYPE]
drop type public.type_test2;
-NOTICE: snitch: command_start DROP TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TYPE [DROP - TYPE]
create type cmd.bug_status as enum ('new', 'open', 'closed');
-NOTICE: snitch: command_start CREATE TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TYPE [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TYPE [CREATE - <NULL>]
alter type cmd.bug_status add value 'wontfix';
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TYPE <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER TYPE [ALTER - <NULL>]
create domain cmd.us_postal_code as text check(value ~ '^\d{5}$' or value ~ '^\d{5}-\d{4}$');
-NOTICE: snitch: command_start CREATE DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE DOMAIN [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE DOMAIN [CREATE - <NULL>]
alter domain cmd.us_postal_code set not null;
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
alter domain cmd.us_postal_code set default 90210;
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
alter domain cmd.us_postal_code drop default;
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
alter domain cmd.us_postal_code drop not null;
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
alter domain cmd.us_postal_code add constraint dummy_constraint check (value ~ '^\d{8}$');
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
alter domain cmd.us_postal_code drop constraint dummy_constraint;
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-alter domain cmd.us_postal_code owner to regbob;
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - <NULL>]
+alter domain cmd.us_postal_code owner to regression_bob;
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - DOMAIN]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - DOMAIN]
alter domain cmd.us_postal_code set schema cmd2;
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - DOMAIN]
+NOTICE: snitch: command_start ALTER DOMAIN [ALTER - DOMAIN]
drop domain cmd2.us_postal_code;
-NOTICE: snitch: command_start DROP DOMAIN <NULL>.<NULL>
-NOTICE: snitch: command_start DROP DOMAIN <NULL>.<NULL>
+NOTICE: snitch: command_start DROP DOMAIN [DROP - DOMAIN]
+NOTICE: snitch: command_start DROP DOMAIN [DROP - DOMAIN]
create function cmd.trigfunc() returns trigger language plpgsql as
$$ begin raise notice 'trigfunc'; end;$$;
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
create trigger footg before update on cmd.foo for each row execute procedure cmd.trigfunc();
-NOTICE: snitch: command_start CREATE TRIGGER <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TRIGGER <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TRIGGER [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE TRIGGER [CREATE - <NULL>]
alter trigger footg on cmd.foo rename to foo_trigger;
-NOTICE: snitch: command_start ALTER TRIGGER <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER TRIGGER <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TRIGGER [ALTER - TRIGGER]
+NOTICE: snitch: command_start ALTER TRIGGER [ALTER - TRIGGER]
drop trigger foo_trigger on cmd.foo;
-NOTICE: snitch: command_start DROP TRIGGER <NULL>.<NULL>
-NOTICE: snitch: command_start DROP TRIGGER <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TRIGGER [DROP - TRIGGER]
+NOTICE: snitch: command_start DROP TRIGGER [DROP - TRIGGER]
create conversion test for 'utf8' to 'sjis' from utf8_to_sjis;
-NOTICE: snitch: command_start CREATE CONVERSION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE CONVERSION [CREATE - <NULL>]
create default conversion test2 for 'utf8' to 'sjis' from utf8_to_sjis;
-NOTICE: snitch: command_start CREATE CONVERSION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE CONVERSION [CREATE - <NULL>]
alter conversion test2 rename to test3;
-NOTICE: snitch: command_start ALTER CONVERSION <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER CONVERSION <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER CONVERSION [ALTER - CONVERSION]
+NOTICE: snitch: command_start ALTER CONVERSION [ALTER - CONVERSION]
drop conversion test3;
-NOTICE: snitch: command_start DROP CONVERSION <NULL>.<NULL>
+NOTICE: snitch: command_start DROP CONVERSION [DROP - CONVERSION]
drop conversion test;
-NOTICE: snitch: command_start DROP CONVERSION <NULL>.<NULL>
+NOTICE: snitch: command_start DROP CONVERSION [DROP - CONVERSION]
create operator class test_op_class
for type anyenum using hash as
operator 1 =,
function 1 hashenum(anyenum);
-NOTICE: snitch: command_start CREATE OPERATOR CLASS <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE OPERATOR CLASS <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE OPERATOR CLASS [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE OPERATOR CLASS [CREATE - <NULL>]
create text search configuration test (parser = "default");
-NOTICE: snitch: command_start CREATE TEXT SEARCH CONFIGURATION <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TEXT SEARCH CONFIGURATION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TEXT SEARCH CONFIGURATION [CREATE - TEXT SEARCH CONFIGURATION]
+NOTICE: snitch: command_start CREATE TEXT SEARCH CONFIGURATION [CREATE - TEXT SEARCH CONFIGURATION]
create text search dictionary test_stem (
template = snowball,
language = 'english', stopwords = 'english'
);
-NOTICE: snitch: command_start CREATE TEXT SEARCH DICTIONARY <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TEXT SEARCH DICTIONARY <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TEXT SEARCH DICTIONARY [CREATE - TEXT SEARCH DICTIONARY]
+NOTICE: snitch: command_start CREATE TEXT SEARCH DICTIONARY [CREATE - TEXT SEARCH DICTIONARY]
alter text search dictionary test_stem (StopWords = dutch );
-NOTICE: snitch: command_start ALTER TEXT SEARCH DICTIONARY <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER TEXT SEARCH DICTIONARY [ALTER - <NULL>]
create text search parser test_parser (
start = prsd_start,
gettoken = prsd_nexttoken,
@@ -406,38 +407,38 @@ create text search parser test_parser (
lextypes = prsd_lextype,
headline = prsd_headline
);
-NOTICE: snitch: command_start CREATE TEXT SEARCH PARSER <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TEXT SEARCH PARSER <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TEXT SEARCH PARSER [CREATE - TEXT SEARCH PARSER]
+NOTICE: snitch: command_start CREATE TEXT SEARCH PARSER [CREATE - TEXT SEARCH PARSER]
create text search template test_template (
init = dsimple_init,
lexize = dsimple_lexize
);
-NOTICE: snitch: command_start CREATE TEXT SEARCH TEMPLATE <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE TEXT SEARCH TEMPLATE <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE TEXT SEARCH TEMPLATE [CREATE - TEXT SEARCH TEMPLATE]
+NOTICE: snitch: command_start CREATE TEXT SEARCH TEMPLATE [CREATE - TEXT SEARCH TEMPLATE]
drop text search configuration test;
-NOTICE: snitch: command_start DROP TEXT SEARCH CONFIGURATION <NULL>.<NULL>
-NOTICE: snitch: command_start DROP TEXT SEARCH CONFIGURATION <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TEXT SEARCH CONFIGURATION [DROP - TEXT SEARCH CONFIGURATION]
+NOTICE: snitch: command_start DROP TEXT SEARCH CONFIGURATION [DROP - TEXT SEARCH CONFIGURATION]
drop text search dictionary test_stem;
-NOTICE: snitch: command_start DROP TEXT SEARCH DICTIONARY <NULL>.<NULL>
-NOTICE: snitch: command_start DROP TEXT SEARCH DICTIONARY <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TEXT SEARCH DICTIONARY [DROP - TEXT SEARCH DICTIONARY]
+NOTICE: snitch: command_start DROP TEXT SEARCH DICTIONARY [DROP - TEXT SEARCH DICTIONARY]
drop text search parser test_parser;
-NOTICE: snitch: command_start DROP TEXT SEARCH PARSER <NULL>.<NULL>
-NOTICE: snitch: command_start DROP TEXT SEARCH PARSER <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TEXT SEARCH PARSER [DROP - TEXT SEARCH PARSER]
+NOTICE: snitch: command_start DROP TEXT SEARCH PARSER [DROP - TEXT SEARCH PARSER]
drop text search template test_template;
-NOTICE: snitch: command_start DROP TEXT SEARCH TEMPLATE <NULL>.<NULL>
-NOTICE: snitch: command_start DROP TEXT SEARCH TEMPLATE <NULL>.<NULL>
+NOTICE: snitch: command_start DROP TEXT SEARCH TEMPLATE [DROP - TEXT SEARCH TEMPLATE]
+NOTICE: snitch: command_start DROP TEXT SEARCH TEMPLATE [DROP - TEXT SEARCH TEMPLATE]
create function cmd.testcast(text) returns int4 language plpgsql as $$begin return 4::int4;end;$$;
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE FUNCTION <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE FUNCTION [CREATE - <NULL>]
create cast (text as int4) with function cmd.testcast(text) as assignment;
-NOTICE: snitch: command_start CREATE CAST <NULL>.<NULL>
-NOTICE: snitch: command_start CREATE CAST <NULL>.<NULL>
+NOTICE: snitch: command_start CREATE CAST [CREATE - <NULL>]
+NOTICE: snitch: command_start CREATE CAST [CREATE - <NULL>]
alter schema cmd rename to cmd1;
-NOTICE: snitch: command_start ALTER SCHEMA <NULL>.<NULL>
-NOTICE: snitch: command_start ALTER SCHEMA <NULL>.<NULL>
+NOTICE: snitch: command_start ALTER SCHEMA [ALTER - SCHEMA]
+NOTICE: snitch: command_start ALTER SCHEMA [ALTER - SCHEMA]
drop schema cmd1 cascade;
-NOTICE: snitch: command_start DROP SCHEMA <NULL>.<NULL>
-NOTICE: snitch: command_start DROP SCHEMA <NULL>.<NULL>
+NOTICE: snitch: command_start DROP SCHEMA [DROP - SCHEMA]
+NOTICE: snitch: command_start DROP SCHEMA [DROP - SCHEMA]
NOTICE: drop cascades to 12 other objects
DETAIL: drop cascades to table cmd1.foo
drop cascades to view cmd1.v
@@ -452,15 +453,17 @@ drop cascades to function cmd1.trigfunc()
drop cascades to function cmd1.testcast(text)
drop cascades to cast from text to integer
drop schema cmd2 cascade;
-NOTICE: snitch: command_start DROP SCHEMA <NULL>.<NULL>
-NOTICE: snitch: command_start DROP SCHEMA <NULL>.<NULL>
+NOTICE: snitch: command_start DROP SCHEMA [DROP - SCHEMA]
+NOTICE: snitch: command_start DROP SCHEMA [DROP - SCHEMA]
-- fail because owning event trigger snitch
-drop role regbob;
-ERROR: role "regbob" cannot be dropped because some objects depend on it
+drop role regression_bob;
+ERROR: role "regression_bob" cannot be dropped because some objects depend on it
DETAIL: owner of event trigger snitch
drop event trigger any_t;
-drop event trigger snitch;
-drop role regbob;
+drop event trigger if exists snitch;
+drop event trigger if exists snitch;
+NOTICE: event trigger "snitch" does not exist, skipping
+drop role regression_bob;
create table onerow(id integer);
create or replace function insert_one_row()
returns event_trigger
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 0dac40f..70eab92 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -134,11 +134,10 @@ WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
(p2.prorettype = p1.oid AND NOT p2.proretset)
ORDER BY 1;
- oid | typname | oid | proname
-------+---------------+------+------------
- 1790 | refcursor | 46 | textin
- 3838 | event_trigger | 2300 | trigger_in
-(2 rows)
+ oid | typname | oid | proname
+------+-----------+-----+---------
+ 1790 | refcursor | 46 | textin
+(1 row)
-- Varlena array types will point to array_in
-- Exception as of 8.1: int2vector and oidvector have their own I/O routines
@@ -178,11 +177,10 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
(p2.oid = 'array_out'::regproc AND
p1.typelem != 0 AND p1.typlen = -1)))
ORDER BY 1;
- oid | typname | oid | proname
-------+---------------+------+-------------
- 1790 | refcursor | 47 | textout
- 3838 | event_trigger | 2301 | trigger_out
-(2 rows)
+ oid | typname | oid | proname
+------+-----------+-----+---------
+ 1790 | refcursor | 47 | textout
+(1 row)
SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
diff --git a/src/test/regress/sql/event_triggers.sql b/src/test/regress/sql/event_triggers.sql
index cf25ee7..9ca1a28 100644
--- a/src/test/regress/sql/event_triggers.sql
+++ b/src/test/regress/sql/event_triggers.sql
@@ -7,14 +7,10 @@ create or replace function snitch()
as $$
begin
-- can't output tg_objectid here that would break pg_regress
- raise notice 'snitch: % % %.%', tg_when, tg_tag, tg_schemaname, tg_objectname;
+ raise notice 'snitch: % % [% - %]', tg_event, tg_tag, tg_operation, tg_objecttype;
end;
$$;
---
--- TODO: REASSIGN OWNED and DROP OWNED
---
-
create event trigger any_t on command_start
execute procedure snitch();
@@ -68,9 +64,11 @@ alter event trigger foo_t rename to snitch;
create schema cmd;
create schema cmd2;
-create role regbob;
-alter event trigger snitch owner to regbob;
+create role regression_bob;
+alter event trigger snitch owner to regression_bob;
+alter role regression_bob superuser;
+alter event trigger snitch owner to regression_bob;
create table cmd.foo(id bigserial primary key);
create view cmd.v as select * from cmd.foo;
@@ -103,7 +101,7 @@ alter table cmd.test set with oids;
alter table cmd.test set without oids;
create sequence test_seq_;
-alter sequence test_seq_ owner to regbob;
+alter sequence test_seq_ owner to regression_bob;
alter sequence test_seq_ rename to test_seq;
alter sequence test_seq set schema cmd;
alter sequence cmd.test_seq start with 3;
@@ -117,7 +115,7 @@ alter sequence cmd.test_seq cycle;
alter sequence cmd.test_seq no cycle;
create view view_test as select id, things from cmd.test;
-alter view view_test owner to regbob;
+alter view view_test owner to regression_bob;
alter view view_test rename to view_test2;
alter view view_test2 set schema cmd;
alter view cmd.view_test2 alter column id set default 9;
@@ -142,7 +140,7 @@ as $$ select t from cmd.foo where id = $1; $$;
alter function fun(int) strict;
alter function fun(int) rename to notfun;
alter function notfun(int) set schema cmd;
-alter function cmd.notfun(int) owner to regbob;
+alter function cmd.notfun(int) owner to regression_bob;
alter function cmd.notfun(int) cost 77;
drop function cmd.notfun(int);
@@ -170,7 +168,7 @@ create type cmd.compfoo AS (f1 int, f2 text);
alter type cmd.compfoo add attribute f3 text;
create type cmd.type_test AS (a integer, b integer, c text);
-alter type cmd.type_test owner to regbob;
+alter type cmd.type_test owner to regression_bob;
alter type cmd.type_test rename to type_test2;
alter type cmd.type_test2 set schema public;
alter type public.type_test2 rename attribute a to z;
@@ -191,7 +189,7 @@ alter domain cmd.us_postal_code drop default;
alter domain cmd.us_postal_code drop not null;
alter domain cmd.us_postal_code add constraint dummy_constraint check (value ~ '^\d{8}$');
alter domain cmd.us_postal_code drop constraint dummy_constraint;
-alter domain cmd.us_postal_code owner to regbob;
+alter domain cmd.us_postal_code owner to regression_bob;
alter domain cmd.us_postal_code set schema cmd2;
drop domain cmd2.us_postal_code;
@@ -248,11 +246,12 @@ drop schema cmd1 cascade;
drop schema cmd2 cascade;
-- fail because owning event trigger snitch
-drop role regbob;
+drop role regression_bob;
drop event trigger any_t;
-drop event trigger snitch;
-drop role regbob;
+drop event trigger if exists snitch;
+drop event trigger if exists snitch;
+drop role regression_bob;
create table onerow(id integer);