Commit 3855968f authored by Robert Haas's avatar Robert Haas

Syntax support and documentation for event triggers.

They don't actually do anything yet; that will get fixed in a
follow-on commit.  But this gets the basic infrastructure in place,
including CREATE/ALTER/DROP EVENT TRIGGER; support for COMMENT,
SECURITY LABEL, and ALTER EXTENSION .. ADD/DROP EVENT TRIGGER;
pg_dump and psql support; and documentation for the anticipated
initial feature set.

Dimitri Fontaine, with review and a bunch of additional hacking by me.
Thom Brown extensively reviewed earlier versions of this patch set,
but there's not a whole lot of that code left in this commit, as it
turns out.
parent faf26bf1
...@@ -143,6 +143,11 @@ ...@@ -143,6 +143,11 @@
<entry>enum label and value definitions</entry> <entry>enum label and value definitions</entry>
</row> </row>
<row>
<entry><link linkend="catalog-pg-event-trigger"><structname>pg_event_trigger</structname></link></entry>
<entry>event triggers</entry>
</row>
<row> <row>
<entry><link linkend="catalog-pg-extension"><structname>pg_extension</structname></link></entry> <entry><link linkend="catalog-pg-extension"><structname>pg_extension</structname></link></entry>
<entry>installed extensions</entry> <entry>installed extensions</entry>
...@@ -1857,6 +1862,88 @@ ...@@ -1857,6 +1862,88 @@
</para> </para>
</sect1> </sect1>
<sect1 id="catalog-pg-event-trigger">
<title><structname>pg_event_trigger</structname></title>
<indexterm zone="catalog-pg-event-trigger">
<primary>pg_event_trigger</primary>
</indexterm>
<para>
The catalog <structname>pg_event_trigger</structname> stores event triggers.
See <xref linkend="event-triggers"> for more information.
</para>
<table>
<title><structname>pg_event_trigger</> Columns</title>
<tgroup cols="4">
<thead>
<row>
<entry>Name</entry>
<entry>Type</entry>
<entry>References</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>evtname</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
<entry>Trigger name (must be unique)</entry>
</row>
<row>
<entry><structfield>evtevent</structfield></entry>
<entry><type>name</type></entry>
<entry></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 function to be called</entry>
</row>
<row>
<entry><structfield>evtenabled</structfield></entry>
<entry><type>char</type></entry>
<entry></entry>
<entry>
Controls in which <xref linkend="guc-session-replication-role"> modes
the event trigger fires.
<literal>O</> = trigger fires in <quote>origin</> and <quote>local</> modes,
<literal>D</> = trigger is disabled,
<literal>R</> = trigger fires in <quote>replica</> mode,
<literal>A</> = trigger fires always.
</entry>
</row>
<row>
<entry><structfield>evttags</structfield></entry>
<entry><type>text[]</type></entry>
<entry></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>
</table>
</sect1>
<sect1 id="catalog-pg-constraint"> <sect1 id="catalog-pg-constraint">
<title><structname>pg_constraint</structname></title> <title><structname>pg_constraint</structname></title>
......
This diff is collapsed.
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
<!ENTITY rules SYSTEM "rules.sgml"> <!ENTITY rules SYSTEM "rules.sgml">
<!ENTITY spi SYSTEM "spi.sgml"> <!ENTITY spi SYSTEM "spi.sgml">
<!ENTITY trigger SYSTEM "trigger.sgml"> <!ENTITY trigger SYSTEM "trigger.sgml">
<!ENTITY event-trigger SYSTEM "event-trigger.sgml">
<!ENTITY xaggr SYSTEM "xaggr.sgml"> <!ENTITY xaggr SYSTEM "xaggr.sgml">
<!ENTITY xfunc SYSTEM "xfunc.sgml"> <!ENTITY xfunc SYSTEM "xfunc.sgml">
<!ENTITY xindex SYSTEM "xindex.sgml"> <!ENTITY xindex SYSTEM "xindex.sgml">
......
...@@ -208,6 +208,7 @@ ...@@ -208,6 +208,7 @@
&extend; &extend;
&trigger; &trigger;
&event-trigger;
&rules; &rules;
&xplang; &xplang;
......
...@@ -12,6 +12,7 @@ Complete list of usable sgml source files in this directory. ...@@ -12,6 +12,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY alterDatabase SYSTEM "alter_database.sgml"> <!ENTITY alterDatabase SYSTEM "alter_database.sgml">
<!ENTITY alterDefaultPrivileges SYSTEM "alter_default_privileges.sgml"> <!ENTITY alterDefaultPrivileges SYSTEM "alter_default_privileges.sgml">
<!ENTITY alterDomain SYSTEM "alter_domain.sgml"> <!ENTITY alterDomain SYSTEM "alter_domain.sgml">
<!ENTITY alterEventTrigger SYSTEM "alter_event_trigger.sgml">
<!ENTITY alterExtension SYSTEM "alter_extension.sgml"> <!ENTITY alterExtension SYSTEM "alter_extension.sgml">
<!ENTITY alterForeignDataWrapper SYSTEM "alter_foreign_data_wrapper.sgml"> <!ENTITY alterForeignDataWrapper SYSTEM "alter_foreign_data_wrapper.sgml">
<!ENTITY alterForeignTable SYSTEM "alter_foreign_table.sgml"> <!ENTITY alterForeignTable SYSTEM "alter_foreign_table.sgml">
...@@ -53,6 +54,7 @@ Complete list of usable sgml source files in this directory. ...@@ -53,6 +54,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY createConversion SYSTEM "create_conversion.sgml"> <!ENTITY createConversion SYSTEM "create_conversion.sgml">
<!ENTITY createDatabase SYSTEM "create_database.sgml"> <!ENTITY createDatabase SYSTEM "create_database.sgml">
<!ENTITY createDomain SYSTEM "create_domain.sgml"> <!ENTITY createDomain SYSTEM "create_domain.sgml">
<!ENTITY createEventTrigger SYSTEM "create_event_trigger.sgml">
<!ENTITY createExtension SYSTEM "create_extension.sgml"> <!ENTITY createExtension SYSTEM "create_extension.sgml">
<!ENTITY createForeignDataWrapper SYSTEM "create_foreign_data_wrapper.sgml"> <!ENTITY createForeignDataWrapper SYSTEM "create_foreign_data_wrapper.sgml">
<!ENTITY createForeignTable SYSTEM "create_foreign_table.sgml"> <!ENTITY createForeignTable SYSTEM "create_foreign_table.sgml">
...@@ -91,6 +93,7 @@ Complete list of usable sgml source files in this directory. ...@@ -91,6 +93,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY dropConversion SYSTEM "drop_conversion.sgml"> <!ENTITY dropConversion SYSTEM "drop_conversion.sgml">
<!ENTITY dropDatabase SYSTEM "drop_database.sgml"> <!ENTITY dropDatabase SYSTEM "drop_database.sgml">
<!ENTITY dropDomain SYSTEM "drop_domain.sgml"> <!ENTITY dropDomain SYSTEM "drop_domain.sgml">
<!ENTITY dropEventTrigger SYSTEM "drop_event_trigger.sgml">
<!ENTITY dropExtension SYSTEM "drop_extension.sgml"> <!ENTITY dropExtension SYSTEM "drop_extension.sgml">
<!ENTITY dropForeignDataWrapper SYSTEM "drop_foreign_data_wrapper.sgml"> <!ENTITY dropForeignDataWrapper SYSTEM "drop_foreign_data_wrapper.sgml">
<!ENTITY dropForeignTable SYSTEM "drop_foreign_table.sgml"> <!ENTITY dropForeignTable SYSTEM "drop_foreign_table.sgml">
......
<!--
doc/src/sgml/ref/alter_event_trigger.sgml
PostgreSQL documentation
-->
<refentry id="SQL-ALTEREVENTTRIGGER">
<refmeta>
<refentrytitle>ALTER EVENT TRIGGER</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>ALTER EVENT TRIGGER</refname>
<refpurpose>change the definition of an event trigger</refpurpose>
</refnamediv>
<indexterm zone="sql-altereventtrigger">
<primary>ALTER EVENT TRIGGER</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
ALTER EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable> DISABLE
ALTER EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable> ENABLE [ REPLICA | ALWAYS ]
ALTER EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
ALTER EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>ALTER EVENT TRIGGER</command> changes properties of an
existing event trigger.
</para>
<para>
You must be superuser to alter an event trigger.
</para>
</refsect1>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><replaceable class="PARAMETER">name</replaceable></term>
<listitem>
<para>
The name of an existing trigger to alter.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">new_owner</replaceable></term>
<listitem>
<para>
The user name of the new owner of the event trigger.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">new_name</replaceable></term>
<listitem>
<para>
The new name of the event trigger.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DISABLE</literal>/<literal>ENABLE [ REPLICA | ALWAYS ] TRIGGER</literal></term>
<listitem>
<para>
These forms configure the firing of event triggers. A disabled trigger
is still known to the system, but is not executed when its triggering
event occurs. See also <xref linkend="guc-session-replication-role">.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="sql-alterventtrigger-compatibility">
<title>Compatibility</title>
<para>
There is no <command>ALTER EVENT TRIGGER</command> statement in the
SQL standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createeventtrigger"></member>
<member><xref linkend="sql-dropeventtrigger"></member>
</simplelist>
</refsect1>
</refentry>
...@@ -35,6 +35,7 @@ ALTER EXTENSION <replaceable class="PARAMETER">name</replaceable> DROP <replacea ...@@ -35,6 +35,7 @@ ALTER EXTENSION <replaceable class="PARAMETER">name</replaceable> DROP <replacea
COLLATION <replaceable class="PARAMETER">object_name</replaceable> | COLLATION <replaceable class="PARAMETER">object_name</replaceable> |
CONVERSION <replaceable class="PARAMETER">object_name</replaceable> | CONVERSION <replaceable class="PARAMETER">object_name</replaceable> |
DOMAIN <replaceable class="PARAMETER">object_name</replaceable> | DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
EVENT TRIGGER <replaceable class="PARAMETER">object_name</replaceable> |
FOREIGN DATA WRAPPER <replaceable class="PARAMETER">object_name</replaceable> | FOREIGN DATA WRAPPER <replaceable class="PARAMETER">object_name</replaceable> |
FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable> | FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable> |
FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) | FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) |
......
...@@ -32,6 +32,7 @@ COMMENT ON ...@@ -32,6 +32,7 @@ COMMENT ON
DATABASE <replaceable class="PARAMETER">object_name</replaceable> | DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
DOMAIN <replaceable class="PARAMETER">object_name</replaceable> | DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
EXTENSION <replaceable class="PARAMETER">object_name</replaceable> | EXTENSION <replaceable class="PARAMETER">object_name</replaceable> |
EVENT TRIGGER <replaceable class="PARAMETER">object_name</replaceable> |
FOREIGN DATA WRAPPER <replaceable class="PARAMETER">object_name</replaceable> | FOREIGN DATA WRAPPER <replaceable class="PARAMETER">object_name</replaceable> |
FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable> | FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable> |
FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) | FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) |
......
<!--
doc/src/sgml/ref/create_event_trigger.sgml
PostgreSQL documentation
-->
<refentry id="SQL-CREATEEVENTTRIGGER">
<refmeta>
<refentrytitle>CREATE EVENT TRIGGER</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>CREATE EVENT TRIGGER</refname>
<refpurpose>define a new event trigger</refpurpose>
</refnamediv>
<indexterm zone="sql-createeventtrigger">
<primary>CREATE EVENT TRIGGER</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
ON <replaceable class="PARAMETER">event</replaceable>
[ WHEN <replaceable class="PARAMETER">filter_variable</replaceable> IN (filter_value [ AND ... ] ) ]
EXECUTE PROCEDURE <replaceable class="PARAMETER">function_name</replaceable>()
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>CREATE EVENT TRIGGER</command> creates a new event trigger.
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>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The name to give the new trigger. This name must be unique within
the database.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">event</replaceable></term>
<listitem>
<para>
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>
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 supported
<replaceable class="parameter">filter_variable</replaceable>
is <literal>TAG</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">filter_value</replaceable></term>
<listitem>
<para>
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>
<varlistentry>
<term><replaceable class="parameter">function_name</replaceable></term>
<listitem>
<para>
A user-supplied function that is declared as taking no argument and
returning type <literal>event_trigger</literal>.
</para>
<para>
If your event trigger is implemented in <literal>C</literal> then it
will be called with an argument, of
type <literal>internal</literal>, which is a pointer to
the <literal>Node *</literal> parse tree.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="sql-createeventtrigger-notes">
<title>Notes</title>
<para>
To create a trigger on a event, the user must be superuser.
</para>
</refsect1>
<refsect1 id="sql-createeventtrigger-examples">
<title>Examples</title>
<para>
Forbid the execution of any <link linkend="ddl">ddl</link> command:
<programlisting>
CREATE OR REPLACE FUNCTION abort_any_command()
RETURNS event_trigger
LANGUAGE plpgsql
AS $$
BEGIN
RAISE EXCEPTION 'command % is disabled', tg_tag;
END;
$$;
CREATE EVENT TRIGGER abort_ddl ON ddl_command_start
EXECUTE PROCEDURE abort_any_command();
</programlisting>
</para>
</refsect1>
<refsect1 id="sql-createeventtrigger-compatibility">
<title>Compatibility</title>
<para>
There is no <command>CREATE EVENT TRIGGER</command> statement in the
SQL standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createfunction"></member>
<member><xref linkend="sql-altereventtrigger"></member>
<member><xref linkend="sql-dropeventtrigger"></member>
</simplelist>
</refsect1>
</refentry>
<!--
doc/src/sgml/ref/drop_event_trigger.sgml
PostgreSQL documentation
-->
<refentry id="SQL-DROPEVENTTRIGGER">
<refmeta>
<refentrytitle>DROP EVENT TRIGGER</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DROP EVENT TRIGGER</refname>
<refpurpose>remove an event trigger</refpurpose>
</refnamediv>
<indexterm zone="sql-dropeventtrigger">
<primary>DROP EVENT TRIGGER</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
DROP EVENT TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<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>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><literal>IF EXISTS</literal></term>
<listitem>
<para>
Do not throw an error if the event trigger does not exist. A notice
is issued in this case.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">name</replaceable></term>
<listitem>
<para>
The name of the event trigger to remove.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CASCADE</literal></term>
<listitem>
<para>
Automatically drop objects that depend on the trigger.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>RESTRICT</literal></term>
<listitem>
<para>
Refuse to drop the trigger if any objects depend on it. This is
the default.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="sql-dropeventtrigger-examples">
<title>Examples</title>
<para>
Destroy the trigger <literal>snitch</literal>:
<programlisting>
DROP EVENT TRIGGER snitch;
</programlisting></para>
</refsect1>
<refsect1 id="sql-dropeventtrigger-compatibility">
<title>Compatibility</title>
<para>
There is no <command>DROP EVENT TRIGGER</command> statement in the
SQL standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createeventtrigger"></member>
<member><xref linkend="sql-altereventtrigger"></member>
</simplelist>
</refsect1>
</refentry>
...@@ -1455,6 +1455,20 @@ testdb=&gt; ...@@ -1455,6 +1455,20 @@ testdb=&gt;
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>\dy[+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
<listitem>
<para>
Lists event triggers.
If <replaceable class="parameter">pattern</replaceable>
is specified, only those event triggers whose names match the pattern
are listed.
If <literal>+</literal> is appended to the command name, each object
is listed with its associated description.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><literal>\e</literal> or <literal>\edit</> <literal> <optional> <replaceable class="parameter">filename</> </optional> <optional> <replaceable class="parameter">line_number</> </optional> </literal></term> <term><literal>\e</literal> or <literal>\edit</> <literal> <optional> <replaceable class="parameter">filename</> </optional> <optional> <replaceable class="parameter">line_number</> </optional> </literal></term>
......
...@@ -28,6 +28,7 @@ SECURITY LABEL [ FOR <replaceable class="PARAMETER">provider</replaceable> ] ON ...@@ -28,6 +28,7 @@ SECURITY LABEL [ FOR <replaceable class="PARAMETER">provider</replaceable> ] ON
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable> [, ...] ) | AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable> [, ...] ) |
DATABASE <replaceable class="PARAMETER">object_name</replaceable> | DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
DOMAIN <replaceable class="PARAMETER">object_name</replaceable> | DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
EVENT TRIGGER <replaceable class="PARAMETER">object_name</replaceable> |
FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable> FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable>
FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) | FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) |
LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable> | LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable> |
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
&alterDefaultPrivileges; &alterDefaultPrivileges;
&alterDomain; &alterDomain;
&alterExtension; &alterExtension;
&alterEventTrigger;
&alterForeignDataWrapper; &alterForeignDataWrapper;
&alterForeignTable; &alterForeignTable;
&alterFunction; &alterFunction;
...@@ -82,6 +83,7 @@ ...@@ -82,6 +83,7 @@
&createDatabase; &createDatabase;
&createDomain; &createDomain;
&createExtension; &createExtension;
&createEventTrigger;
&createForeignDataWrapper; &createForeignDataWrapper;
&createForeignTable; &createForeignTable;
&createFunction; &createFunction;
...@@ -120,6 +122,7 @@ ...@@ -120,6 +122,7 @@
&dropDatabase; &dropDatabase;
&dropDomain; &dropDomain;
&dropExtension; &dropExtension;
&dropEventTrigger;
&dropForeignDataWrapper; &dropForeignDataWrapper;
&dropForeignTable; &dropForeignTable;
&dropFunction; &dropFunction;
......
...@@ -31,7 +31,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ ...@@ -31,7 +31,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \ pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \ pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \
pg_statistic.h pg_rewrite.h pg_trigger.h pg_description.h \ pg_statistic.h pg_rewrite.h pg_trigger.h pg_event_trigger.h pg_description.h \
pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \ pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "catalog/pg_conversion.h" #include "catalog/pg_conversion.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h" #include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h" #include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h" #include "catalog/pg_foreign_server.h"
...@@ -277,6 +278,10 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, ...@@ -277,6 +278,10 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
case ACL_KIND_FOREIGN_SERVER: case ACL_KIND_FOREIGN_SERVER:
whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER; whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
break; 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: case ACL_KIND_TYPE:
whole_mask = ACL_ALL_RIGHTS_TYPE; whole_mask = ACL_ALL_RIGHTS_TYPE;
break; break;
...@@ -3286,6 +3291,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] = ...@@ -3286,6 +3291,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
gettext_noop("permission denied for foreign-data wrapper %s"), gettext_noop("permission denied for foreign-data wrapper %s"),
/* ACL_KIND_FOREIGN_SERVER */ /* ACL_KIND_FOREIGN_SERVER */
gettext_noop("permission denied for foreign server %s"), gettext_noop("permission denied for foreign server %s"),
/* ACL_KIND_EVENT_TRIGGER */
gettext_noop("permission denied for event trigger %s"),
/* ACL_KIND_EXTENSION */ /* ACL_KIND_EXTENSION */
gettext_noop("permission denied for extension %s"), gettext_noop("permission denied for extension %s"),
}; };
...@@ -3330,6 +3337,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] = ...@@ -3330,6 +3337,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
gettext_noop("must be owner of foreign-data wrapper %s"), gettext_noop("must be owner of foreign-data wrapper %s"),
/* ACL_KIND_FOREIGN_SERVER */ /* ACL_KIND_FOREIGN_SERVER */
gettext_noop("must be owner of foreign server %s"), 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 */ /* ACL_KIND_EXTENSION */
gettext_noop("must be owner of extension %s"), gettext_noop("must be owner of extension %s"),
}; };
...@@ -3455,6 +3464,10 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid, ...@@ -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); return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_FOREIGN_SERVER: case ACL_KIND_FOREIGN_SERVER:
return pg_foreign_server_aclmask(table_oid, roleid, mask, how); 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: case ACL_KIND_TYPE:
return pg_type_aclmask(table_oid, roleid, mask, how); return pg_type_aclmask(table_oid, roleid, mask, how);
default: default:
...@@ -4875,6 +4888,33 @@ pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid) ...@@ -4875,6 +4888,33 @@ pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
return has_privs_of_role(roleid, ownerId); return has_privs_of_role(roleid, ownerId);
} }
/*
* 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). * Ownership check for a database (specified by OID).
*/ */
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h" #include "catalog/pg_default_acl.h"
#include "catalog/pg_depend.h" #include "catalog/pg_depend.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h" #include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h" #include "catalog/pg_foreign_server.h"
...@@ -56,6 +57,7 @@ ...@@ -56,6 +57,7 @@
#include "commands/comment.h" #include "commands/comment.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h" #include "commands/extension.h"
#include "commands/proclang.h" #include "commands/proclang.h"
#include "commands/schemacmds.h" #include "commands/schemacmds.h"
...@@ -158,7 +160,8 @@ static const Oid object_classes[MAX_OCLASS] = { ...@@ -158,7 +160,8 @@ static const Oid object_classes[MAX_OCLASS] = {
ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */ ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */
UserMappingRelationId, /* OCLASS_USER_MAPPING */ UserMappingRelationId, /* OCLASS_USER_MAPPING */
DefaultAclRelationId, /* OCLASS_DEFACL */ DefaultAclRelationId, /* OCLASS_DEFACL */
ExtensionRelationId /* OCLASS_EXTENSION */ ExtensionRelationId, /* OCLASS_EXTENSION */
EventTriggerRelationId /* OCLASS_EVENT_TRIGGER */
}; };
...@@ -1112,6 +1115,10 @@ doDeletion(const ObjectAddress *object, int flags) ...@@ -1112,6 +1115,10 @@ doDeletion(const ObjectAddress *object, int flags)
break; break;
} }
case OCLASS_EVENT_TRIGGER:
RemoveEventTriggerById(object->objectId);
break;
case OCLASS_PROC: case OCLASS_PROC:
RemoveFunctionById(object->objectId); RemoveFunctionById(object->objectId);
break; break;
...@@ -2269,6 +2276,9 @@ getObjectClass(const ObjectAddress *object) ...@@ -2269,6 +2276,9 @@ getObjectClass(const ObjectAddress *object)
case ExtensionRelationId: case ExtensionRelationId:
return OCLASS_EXTENSION; return OCLASS_EXTENSION;
case EventTriggerRelationId:
return OCLASS_EVENT_TRIGGER;
} }
/* shouldn't get here */ /* shouldn't get here */
...@@ -2903,6 +2913,21 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2903,6 +2913,21 @@ getObjectDescription(const ObjectAddress *object)
break; break;
} }
case OCLASS_EVENT_TRIGGER:
{
HeapTuple tup;
tup = SearchSysCache1(EVENTTRIGGEROID,
ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for event trigger %u",
object->objectId);
appendStringInfo(&buffer, _("event trigger %s"),
NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
ReleaseSysCache(tup);
break;
}
default: default:
appendStringInfo(&buffer, "unrecognized object %u %u %d", appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId, object->classId,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "catalog/objectaddress.h" #include "catalog/objectaddress.h"
#include "catalog/pg_authid.h" #include "catalog/pg_authid.h"
#include "catalog/pg_cast.h" #include "catalog/pg_cast.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_collation.h" #include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h" #include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h" #include "catalog/pg_conversion.h"
...@@ -46,6 +47,7 @@ ...@@ -46,6 +47,7 @@
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h" #include "commands/extension.h"
#include "commands/proclang.h" #include "commands/proclang.h"
#include "commands/tablespace.h" #include "commands/tablespace.h"
...@@ -203,6 +205,12 @@ static ObjectPropertyType ObjectProperty[] = ...@@ -203,6 +205,12 @@ static ObjectPropertyType ObjectProperty[] =
-1, -1,
InvalidAttrNumber InvalidAttrNumber
}, },
{
EventTriggerRelationId,
EventTriggerOidIndexId,
-1,
InvalidAttrNumber
},
{ {
TSConfigRelationId, TSConfigRelationId,
TSConfigOidIndexId, TSConfigOidIndexId,
...@@ -325,6 +333,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, ...@@ -325,6 +333,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
case OBJECT_LANGUAGE: case OBJECT_LANGUAGE:
case OBJECT_FDW: case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER: case OBJECT_FOREIGN_SERVER:
case OBJECT_EVENT_TRIGGER:
address = get_object_address_unqualified(objtype, address = get_object_address_unqualified(objtype,
objname, missing_ok); objname, missing_ok);
break; break;
...@@ -546,6 +555,9 @@ get_object_address_unqualified(ObjectType objtype, ...@@ -546,6 +555,9 @@ get_object_address_unqualified(ObjectType objtype,
case OBJECT_FOREIGN_SERVER: case OBJECT_FOREIGN_SERVER:
msg = gettext_noop("server name cannot be qualified"); msg = gettext_noop("server name cannot be qualified");
break; break;
case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("event trigger name cannot be qualified");
break;
default: default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype); elog(ERROR, "unrecognized objtype: %d", (int) objtype);
msg = NULL; /* placate compiler */ msg = NULL; /* placate compiler */
...@@ -601,6 +613,11 @@ get_object_address_unqualified(ObjectType objtype, ...@@ -601,6 +613,11 @@ get_object_address_unqualified(ObjectType objtype,
address.objectId = get_foreign_server_oid(name, missing_ok); address.objectId = get_foreign_server_oid(name, missing_ok);
address.objectSubId = 0; address.objectSubId = 0;
break; break;
case OBJECT_EVENT_TRIGGER:
address.classId = EventTriggerRelationId;
address.objectId = get_event_trigger_oid(name, missing_ok);
address.objectSubId = 0;
break;
default: default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype); elog(ERROR, "unrecognized objtype: %d", (int) objtype);
/* placate compiler, which doesn't know elog won't return */ /* placate compiler, which doesn't know elog won't return */
...@@ -980,6 +997,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, ...@@ -980,6 +997,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
NameListToString(objname)); NameListToString(objname));
break; 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: case OBJECT_LANGUAGE:
if (!pg_language_ownercheck(address.objectId, roleid)) if (!pg_language_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE, aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "catalog/pg_conversion.h" #include "catalog/pg_conversion.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h" #include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h" #include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h" #include "catalog/pg_foreign_server.h"
...@@ -42,6 +43,7 @@ ...@@ -42,6 +43,7 @@
#include "commands/collationcmds.h" #include "commands/collationcmds.h"
#include "commands/conversioncmds.h" #include "commands/conversioncmds.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h" #include "commands/extension.h"
#include "commands/proclang.h" #include "commands/proclang.h"
#include "commands/schemacmds.h" #include "commands/schemacmds.h"
...@@ -1398,6 +1400,10 @@ shdepReassignOwned(List *roleids, Oid newrole) ...@@ -1398,6 +1400,10 @@ shdepReassignOwned(List *roleids, Oid newrole)
AlterExtensionOwner_oid(sdepForm->objid, newrole); AlterExtensionOwner_oid(sdepForm->objid, newrole);
break; break;
case EventTriggerRelationId:
AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
break;
default: default:
elog(ERROR, "unexpected classid %u", sdepForm->classid); elog(ERROR, "unexpected classid %u", sdepForm->classid);
break; break;
......
...@@ -310,6 +310,19 @@ FROM ...@@ -310,6 +310,19 @@ FROM
WHERE WHERE
l.objsubid = 0 l.objsubid = 0
UNION ALL UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
'event trigger'::text AS objtype,
NULL::oid AS objnamespace,
quote_ident(evt.evtname) AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_event_trigger evt ON l.classoid = evt.tableoid
AND l.objoid = evt.oid
WHERE
l.objsubid = 0
UNION ALL
SELECT SELECT
l.objoid, l.classoid, 0::int4 AS objsubid, l.objoid, l.classoid, 0::int4 AS objsubid,
'database'::text AS objtype, 'database'::text AS objtype,
......
...@@ -14,8 +14,8 @@ include $(top_builddir)/src/Makefile.global ...@@ -14,8 +14,8 @@ include $(top_builddir)/src/Makefile.global
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \ OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
collationcmds.o constraint.o conversioncmds.o copy.o createas.o \ collationcmds.o constraint.o conversioncmds.o copy.o createas.o \
dbcommands.o define.o discard.o dropcmds.o explain.o extension.o \ dbcommands.o define.o discard.o dropcmds.o \
foreigncmds.o functioncmds.o \ event_trigger.o explain.o extension.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \ indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \ portalcmds.o prepare.o proclang.o \
schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \ schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "commands/conversioncmds.h" #include "commands/conversioncmds.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h" #include "commands/extension.h"
#include "commands/proclang.h" #include "commands/proclang.h"
#include "commands/schemacmds.h" #include "commands/schemacmds.h"
...@@ -77,6 +78,10 @@ ExecRenameStmt(RenameStmt *stmt) ...@@ -77,6 +78,10 @@ ExecRenameStmt(RenameStmt *stmt)
RenameForeignServer(stmt->subname, stmt->newname); RenameForeignServer(stmt->subname, stmt->newname);
break; break;
case OBJECT_EVENT_TRIGGER:
RenameEventTrigger(stmt->subname, stmt->newname);
break;
case OBJECT_FUNCTION: case OBJECT_FUNCTION:
RenameFunction(stmt->object, stmt->objarg, stmt->newname); RenameFunction(stmt->object, stmt->objarg, stmt->newname);
break; break;
...@@ -534,6 +539,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) ...@@ -534,6 +539,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner); AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
break; break;
case OBJECT_EVENT_TRIGGER:
AlterEventTriggerOwner(strVal(linitial(stmt->object)), newowner);
break;
default: default:
elog(ERROR, "unrecognized AlterOwnerStmt type: %d", elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
(int) stmt->objectType); (int) stmt->objectType);
......
...@@ -206,6 +206,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs) ...@@ -206,6 +206,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
args = NameListToString(list_truncate(objname, args = NameListToString(list_truncate(objname,
list_length(objname) - 1)); list_length(objname) - 1));
break; break;
case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
name = NameListToString(objname);
break;
case OBJECT_RULE: case OBJECT_RULE:
msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping"); msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
name = strVal(llast(objname)); name = strVal(llast(objname));
......
This diff is collapsed.
...@@ -3466,6 +3466,30 @@ _copyCreateTrigStmt(const CreateTrigStmt *from) ...@@ -3466,6 +3466,30 @@ _copyCreateTrigStmt(const CreateTrigStmt *from)
return newnode; return newnode;
} }
static CreateEventTrigStmt *
_copyCreateEventTrigStmt(const CreateEventTrigStmt *from)
{
CreateEventTrigStmt *newnode = makeNode(CreateEventTrigStmt);
COPY_STRING_FIELD(trigname);
COPY_SCALAR_FIELD(eventname);
COPY_NODE_FIELD(whenclause);
COPY_NODE_FIELD(funcname);
return newnode;
}
static AlterEventTrigStmt *
_copyAlterEventTrigStmt(const AlterEventTrigStmt *from)
{
AlterEventTrigStmt *newnode = makeNode(AlterEventTrigStmt);
COPY_STRING_FIELD(trigname);
COPY_SCALAR_FIELD(tgenabled);
return newnode;
}
static CreatePLangStmt * static CreatePLangStmt *
_copyCreatePLangStmt(const CreatePLangStmt *from) _copyCreatePLangStmt(const CreatePLangStmt *from)
{ {
...@@ -4317,6 +4341,12 @@ copyObject(const void *from) ...@@ -4317,6 +4341,12 @@ copyObject(const void *from)
case T_CreateTrigStmt: case T_CreateTrigStmt:
retval = _copyCreateTrigStmt(from); retval = _copyCreateTrigStmt(from);
break; break;
case T_CreateEventTrigStmt:
retval = _copyCreateEventTrigStmt(from);
break;
case T_AlterEventTrigStmt:
retval = _copyAlterEventTrigStmt(from);
break;
case T_CreatePLangStmt: case T_CreatePLangStmt:
retval = _copyCreatePLangStmt(from); retval = _copyCreatePLangStmt(from);
break; break;
......
...@@ -1792,6 +1792,26 @@ _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b) ...@@ -1792,6 +1792,26 @@ _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b)
return true; return true;
} }
static bool
_equalCreateEventTrigStmt(const CreateEventTrigStmt *a, const CreateEventTrigStmt *b)
{
COMPARE_STRING_FIELD(trigname);
COMPARE_SCALAR_FIELD(eventname);
COMPARE_NODE_FIELD(funcname);
COMPARE_NODE_FIELD(whenclause);
return true;
}
static bool
_equalAlterEventTrigStmt(const AlterEventTrigStmt *a, const AlterEventTrigStmt *b)
{
COMPARE_STRING_FIELD(trigname);
COMPARE_SCALAR_FIELD(tgenabled);
return true;
}
static bool static bool
_equalCreatePLangStmt(const CreatePLangStmt *a, const CreatePLangStmt *b) _equalCreatePLangStmt(const CreatePLangStmt *a, const CreatePLangStmt *b)
{ {
...@@ -2872,6 +2892,12 @@ equal(const void *a, const void *b) ...@@ -2872,6 +2892,12 @@ equal(const void *a, const void *b)
case T_CreateTrigStmt: case T_CreateTrigStmt:
retval = _equalCreateTrigStmt(a, b); retval = _equalCreateTrigStmt(a, b);
break; break;
case T_CreateEventTrigStmt:
retval = _equalCreateEventTrigStmt(a, b);
break;
case T_AlterEventTrigStmt:
retval = _equalAlterEventTrigStmt(a, b);
break;
case T_CreatePLangStmt: case T_CreatePLangStmt:
retval = _equalCreatePLangStmt(a, b); retval = _equalCreatePLangStmt(a, b);
break; break;
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/trigger.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "parser/gramparse.h" #include "parser/gramparse.h"
...@@ -194,6 +195,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, ...@@ -194,6 +195,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
} }
%type <node> stmt schema_stmt %type <node> stmt schema_stmt
AlterEventTrigStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
...@@ -207,7 +209,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, ...@@ -207,7 +209,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
CreateAssertStmt CreateTrigStmt CreateAssertStmt CreateTrigStmt CreateEventTrigStmt
CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreateUserStmt CreateUserMappingStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
...@@ -268,6 +270,10 @@ static void processCASbits(int cas_bits, int location, const char *constrType, ...@@ -268,6 +270,10 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
%type <value> TriggerFuncArg %type <value> TriggerFuncArg
%type <node> TriggerWhen %type <node> TriggerWhen
%type <list> event_trigger_when_list event_trigger_value_list
%type <defelt> event_trigger_when_item
%type <chr> enable_trigger
%type <str> copy_file_name %type <str> copy_file_name
database_name access_method_clause access_method attr_name database_name access_method_clause access_method attr_name
name cursor_name file_name name cursor_name file_name
...@@ -505,7 +511,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, ...@@ -505,7 +511,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT
EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN
EXTENSION EXTERNAL EXTRACT EXTENSION EXTERNAL EXTRACT
...@@ -674,7 +680,8 @@ stmtmulti: stmtmulti ';' stmt ...@@ -674,7 +680,8 @@ stmtmulti: stmtmulti ';' stmt
; ;
stmt : stmt :
AlterDatabaseStmt AlterEventTrigStmt
| AlterDatabaseStmt
| AlterDatabaseSetStmt | AlterDatabaseSetStmt
| AlterDefaultPrivilegesStmt | AlterDefaultPrivilegesStmt
| AlterDomainStmt | AlterDomainStmt
...@@ -725,6 +732,7 @@ stmt : ...@@ -725,6 +732,7 @@ stmt :
| CreateStmt | CreateStmt
| CreateTableSpaceStmt | CreateTableSpaceStmt
| CreateTrigStmt | CreateTrigStmt
| CreateEventTrigStmt
| CreateRoleStmt | CreateRoleStmt
| CreateUserStmt | CreateUserStmt
| CreateUserMappingStmt | CreateUserMappingStmt
...@@ -3554,6 +3562,15 @@ AlterExtensionContentsStmt: ...@@ -3554,6 +3562,15 @@ AlterExtensionContentsStmt:
n->objname = list_make1(makeString($6)); n->objname = list_make1(makeString($6));
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER EXTENSION name add_drop EVENT TRIGGER name
{
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_EVENT_TRIGGER;
n->objname = list_make1(makeString($7));
$$ = (Node *)n;
}
| ALTER EXTENSION name add_drop TABLE any_name | ALTER EXTENSION name add_drop TABLE any_name
{ {
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
...@@ -4282,6 +4299,75 @@ DropTrigStmt: ...@@ -4282,6 +4299,75 @@ DropTrigStmt:
; ;
/*****************************************************************************
*
* QUERIES :
* CREATE EVENT TRIGGER ...
* DROP EVENT TRIGGER ...
* ALTER EVENT TRIGGER ...
*
*****************************************************************************/
CreateEventTrigStmt:
CREATE EVENT TRIGGER name ON ColLabel
EXECUTE PROCEDURE func_name '(' ')'
{
CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
n->trigname = $4;
n->eventname = $6;
n->whenclause = NULL;
n->funcname = $9;
$$ = (Node *)n;
}
| CREATE EVENT TRIGGER name ON ColLabel
WHEN event_trigger_when_list
EXECUTE PROCEDURE func_name '(' ')'
{
CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
n->trigname = $4;
n->eventname = $6;
n->whenclause = $8;
n->funcname = $11;
$$ = (Node *)n;
}
;
event_trigger_when_list:
event_trigger_when_item
{ $$ = list_make1($1); }
| event_trigger_when_list AND event_trigger_when_item
{ $$ = lappend($1, $3); }
;
event_trigger_when_item:
ColId IN_P '(' event_trigger_value_list ')'
{ $$ = makeDefElem($1, (Node *) $4); }
;
event_trigger_value_list:
SCONST
{ $$ = list_make1(makeString($1)); }
| event_trigger_value_list ',' SCONST
{ $$ = lappend($1, makeString($3)); }
;
AlterEventTrigStmt:
ALTER EVENT TRIGGER name enable_trigger
{
AlterEventTrigStmt *n = makeNode(AlterEventTrigStmt);
n->trigname = $4;
n->tgenabled = $5;
$$ = (Node *) n;
}
;
enable_trigger:
ENABLE_P { $$ = TRIGGER_FIRES_ON_ORIGIN; }
| ENABLE_P REPLICA { $$ = TRIGGER_FIRES_ON_REPLICA; }
| ENABLE_P ALWAYS { $$ = TRIGGER_FIRES_ALWAYS; }
| DISABLE_P { $$ = TRIGGER_DISABLED; }
;
/***************************************************************************** /*****************************************************************************
* *
* QUERIES : * QUERIES :
...@@ -4868,6 +4954,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; } ...@@ -4868,6 +4954,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; }
| VIEW { $$ = OBJECT_VIEW; } | VIEW { $$ = OBJECT_VIEW; }
| INDEX { $$ = OBJECT_INDEX; } | INDEX { $$ = OBJECT_INDEX; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| TYPE_P { $$ = OBJECT_TYPE; } | TYPE_P { $$ = OBJECT_TYPE; }
| DOMAIN_P { $$ = OBJECT_DOMAIN; } | DOMAIN_P { $$ = OBJECT_DOMAIN; }
| COLLATION { $$ = OBJECT_COLLATION; } | COLLATION { $$ = OBJECT_COLLATION; }
...@@ -4931,7 +5018,7 @@ opt_restart_seqs: ...@@ -4931,7 +5018,7 @@ opt_restart_seqs:
* EXTENSION | ROLE | TEXT SEARCH PARSER | * EXTENSION | ROLE | TEXT SEARCH PARSER |
* TEXT SEARCH DICTIONARY | TEXT SEARCH TEMPLATE | * TEXT SEARCH DICTIONARY | TEXT SEARCH TEMPLATE |
* TEXT SEARCH CONFIGURATION | FOREIGN TABLE | * TEXT SEARCH CONFIGURATION | FOREIGN TABLE |
* FOREIGN DATA WRAPPER | SERVER ] <objname> | * FOREIGN DATA WRAPPER | SERVER | EVENT TRIGGER ] <objname> |
* AGGREGATE <aggname> (arg1, ...) | * AGGREGATE <aggname> (arg1, ...) |
* FUNCTION <funcname> (arg1, arg2, ...) | * FUNCTION <funcname> (arg1, arg2, ...) |
* OPERATOR <op> (leftoperand_typ, rightoperand_typ) | * OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
...@@ -5113,6 +5200,7 @@ comment_type: ...@@ -5113,6 +5200,7 @@ comment_type:
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| SERVER { $$ = OBJECT_FOREIGN_SERVER; } | SERVER { $$ = OBJECT_FOREIGN_SERVER; }
| FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; } | FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; }
| EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
; ;
comment_text: comment_text:
...@@ -5195,6 +5283,7 @@ opt_provider: FOR ColId_or_Sconst { $$ = $2; } ...@@ -5195,6 +5283,7 @@ opt_provider: FOR ColId_or_Sconst { $$ = $2; }
security_label_type: security_label_type:
COLUMN { $$ = OBJECT_COLUMN; } COLUMN { $$ = OBJECT_COLUMN; }
| DATABASE { $$ = OBJECT_DATABASE; } | DATABASE { $$ = OBJECT_DATABASE; }
| EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| SCHEMA { $$ = OBJECT_SCHEMA; } | SCHEMA { $$ = OBJECT_SCHEMA; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; } | SEQUENCE { $$ = OBJECT_SEQUENCE; }
...@@ -6850,6 +6939,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name ...@@ -6850,6 +6939,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->missing_ok = false; n->missing_ok = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER EVENT TRIGGER name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_EVENT_TRIGGER;
n->subname = $4;
n->newname = $7;
$$ = (Node *)n;
}
| ALTER ROLE RoleId RENAME TO RoleId | ALTER ROLE RoleId RENAME TO RoleId
{ {
RenameStmt *n = makeNode(RenameStmt); RenameStmt *n = makeNode(RenameStmt);
...@@ -7329,6 +7426,14 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId ...@@ -7329,6 +7426,14 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6; n->newowner = $6;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER EVENT TRIGGER name OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
n->object = list_make1(makeString($4));
n->newowner = $7;
$$ = (Node *)n;
}
; ;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/discard.h" #include "commands/discard.h"
#include "commands/event_trigger.h"
#include "commands/explain.h" #include "commands/explain.h"
#include "commands/extension.h" #include "commands/extension.h"
#include "commands/lockcmds.h" #include "commands/lockcmds.h"
...@@ -183,6 +184,8 @@ check_xact_readonly(Node *parsetree) ...@@ -183,6 +184,8 @@ check_xact_readonly(Node *parsetree)
case T_CommentStmt: case T_CommentStmt:
case T_DefineStmt: case T_DefineStmt:
case T_CreateCastStmt: case T_CreateCastStmt:
case T_CreateEventTrigStmt:
case T_AlterEventTrigStmt:
case T_CreateConversionStmt: case T_CreateConversionStmt:
case T_CreatedbStmt: case T_CreatedbStmt:
case T_CreateDomainStmt: case T_CreateDomainStmt:
...@@ -1056,6 +1059,14 @@ standard_ProcessUtility(Node *parsetree, ...@@ -1056,6 +1059,14 @@ standard_ProcessUtility(Node *parsetree,
InvalidOid, InvalidOid, false); InvalidOid, InvalidOid, false);
break; break;
case T_CreateEventTrigStmt:
CreateEventTrigger((CreateEventTrigStmt *) parsetree);
break;
case T_AlterEventTrigStmt:
AlterEventTrigger((AlterEventTrigStmt *) parsetree);
break;
case T_CreatePLangStmt: case T_CreatePLangStmt:
CreateProceduralLanguage((CreatePLangStmt *) parsetree); CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break; break;
...@@ -1472,6 +1483,9 @@ AlterObjectTypeCommandTag(ObjectType objtype) ...@@ -1472,6 +1483,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
case OBJECT_TRIGGER: case OBJECT_TRIGGER:
tag = "ALTER TRIGGER"; tag = "ALTER TRIGGER";
break; break;
case OBJECT_EVENT_TRIGGER:
tag = "ALTER EVENT TRIGGER";
break;
case OBJECT_TSCONFIGURATION: case OBJECT_TSCONFIGURATION:
tag = "ALTER TEXT SEARCH CONFIGURATION"; tag = "ALTER TEXT SEARCH CONFIGURATION";
break; break;
...@@ -1741,6 +1755,9 @@ CreateCommandTag(Node *parsetree) ...@@ -1741,6 +1755,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_TRIGGER: case OBJECT_TRIGGER:
tag = "DROP TRIGGER"; tag = "DROP TRIGGER";
break; break;
case OBJECT_EVENT_TRIGGER:
tag = "DROP EVENT TRIGGER";
break;
case OBJECT_RULE: case OBJECT_RULE:
tag = "DROP RULE"; tag = "DROP RULE";
break; break;
...@@ -1994,6 +2011,14 @@ CreateCommandTag(Node *parsetree) ...@@ -1994,6 +2011,14 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE TRIGGER"; tag = "CREATE TRIGGER";
break; break;
case T_CreateEventTrigStmt:
tag = "CREATE EVENT TRIGGER";
break;
case T_AlterEventTrigStmt:
tag = "ALTER EVENT TRIGGER";
break;
case T_CreatePLangStmt: case T_CreatePLangStmt:
tag = "CREATE LANGUAGE"; tag = "CREATE LANGUAGE";
break; break;
...@@ -2489,6 +2514,14 @@ GetCommandLogLevel(Node *parsetree) ...@@ -2489,6 +2514,14 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL; lev = LOGSTMT_DDL;
break; break;
case T_CreateEventTrigStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterEventTrigStmt:
lev = LOGSTMT_DDL;
break;
case T_CreatePLangStmt: case T_CreatePLangStmt:
lev = LOGSTMT_DDL; lev = LOGSTMT_DDL;
break; break;
......
...@@ -292,6 +292,33 @@ trigger_out(PG_FUNCTION_ARGS) ...@@ -292,6 +292,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. * language_handler_in - input routine for pseudo-type LANGUAGE_HANDLER.
*/ */
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h" #include "catalog/pg_default_acl.h"
#include "catalog/pg_enum.h" #include "catalog/pg_enum.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h" #include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h" #include "catalog/pg_foreign_table.h"
...@@ -379,6 +380,28 @@ static const struct cachedesc cacheinfo[] = { ...@@ -379,6 +380,28 @@ static const struct cachedesc cacheinfo[] = {
}, },
256 256
}, },
{EventTriggerRelationId, /* EVENTTRIGGERNAME */
EventTriggerNameIndexId,
1,
{
Anum_pg_event_trigger_evtname,
0,
0,
0
},
8
},
{EventTriggerRelationId, /* EVENTTRIGGEROID */
EventTriggerOidIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
},
8
},
{ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */ {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */
ForeignDataWrapperNameIndexId, ForeignDataWrapperNameIndexId,
1, 1,
......
...@@ -100,6 +100,7 @@ getSchemaData(Archive *fout, int *numTablesPtr) ...@@ -100,6 +100,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
int numForeignDataWrappers; int numForeignDataWrappers;
int numForeignServers; int numForeignServers;
int numDefaultACLs; int numDefaultACLs;
int numEventTriggers;
if (g_verbose) if (g_verbose)
write_msg(NULL, "reading schemas\n"); write_msg(NULL, "reading schemas\n");
...@@ -240,6 +241,10 @@ getSchemaData(Archive *fout, int *numTablesPtr) ...@@ -240,6 +241,10 @@ getSchemaData(Archive *fout, int *numTablesPtr)
write_msg(NULL, "reading triggers\n"); write_msg(NULL, "reading triggers\n");
getTriggers(fout, tblinfo, numTables); getTriggers(fout, tblinfo, numTables);
if (g_verbose)
write_msg(NULL, "reading event triggers\n");
getEventTriggers(fout, &numEventTriggers);
*numTablesPtr = numTables; *numTablesPtr = numTables;
return tblinfo; return tblinfo;
} }
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "catalog/pg_cast.h" #include "catalog/pg_cast.h"
#include "catalog/pg_class.h" #include "catalog/pg_class.h"
#include "catalog/pg_default_acl.h" #include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_largeobject.h" #include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h" #include "catalog/pg_largeobject_metadata.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
...@@ -186,6 +187,7 @@ static void dumpConversion(Archive *fout, ConvInfo *convinfo); ...@@ -186,6 +187,7 @@ static void dumpConversion(Archive *fout, ConvInfo *convinfo);
static void dumpRule(Archive *fout, RuleInfo *rinfo); static void dumpRule(Archive *fout, RuleInfo *rinfo);
static void dumpAgg(Archive *fout, AggInfo *agginfo); static void dumpAgg(Archive *fout, AggInfo *agginfo);
static void dumpTrigger(Archive *fout, TriggerInfo *tginfo); static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
static void dumpTable(Archive *fout, TableInfo *tbinfo); static void dumpTable(Archive *fout, TableInfo *tbinfo);
static void dumpTableSchema(Archive *fout, TableInfo *tbinfo); static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo); static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
...@@ -5296,6 +5298,87 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables) ...@@ -5296,6 +5298,87 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
destroyPQExpBuffer(query); destroyPQExpBuffer(query);
} }
/*
* getEventTriggers
* get information about event triggers
*/
EventTriggerInfo *
getEventTriggers(Archive *fout, int *numEventTriggers)
{
int i;
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
EventTriggerInfo *evtinfo;
int i_tableoid,
i_oid,
i_evtname,
i_evtevent,
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");
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);
*numEventTriggers = ntups;
evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
i_evtname = PQfnumber(res, "evtname");
i_evtevent = PQfnumber(res, "evtevent");
i_evtowner = PQfnumber(res, "evtowner");
i_evttags = PQfnumber(res, "evttags");
i_evtfname = PQfnumber(res, "evtfname");
i_evtenabled = PQfnumber(res, "evtenabled");
for (i = 0; i < ntups; i++)
{
evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&evtinfo[i].dobj);
evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
}
PQclear(res);
destroyPQExpBuffer(query);
return evtinfo;
}
/* /*
* getProcLangs * getProcLangs
* get basic information about every procedural language in the system * get basic information about every procedural language in the system
...@@ -7166,6 +7249,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) ...@@ -7166,6 +7249,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_TRIGGER: case DO_TRIGGER:
dumpTrigger(fout, (TriggerInfo *) dobj); dumpTrigger(fout, (TriggerInfo *) dobj);
break; break;
case DO_EVENT_TRIGGER:
dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
break;
case DO_CONSTRAINT: case DO_CONSTRAINT:
dumpConstraint(fout, (ConstraintInfo *) dobj); dumpConstraint(fout, (ConstraintInfo *) dobj);
break; break;
...@@ -13658,6 +13744,69 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) ...@@ -13658,6 +13744,69 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
destroyPQExpBuffer(labelq); destroyPQExpBuffer(labelq);
} }
static void
dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
{
PQExpBuffer query;
PQExpBuffer labelq;
query = createPQExpBuffer();
labelq = createPQExpBuffer();
appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
appendPQExpBuffer(query, " ON ");
appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
appendPQExpBufferStr(query, " ");
if (strcmp("", evtinfo->evttags) != 0)
{
appendPQExpBufferStr(query, "\n WHEN TAG IN (");
appendPQExpBufferStr(query, evtinfo->evttags);
appendPQExpBufferStr(query, ") ");
}
appendPQExpBuffer(query, "\n EXECUTE PROCEDURE ");
appendPQExpBufferStr(query, evtinfo->evtfname);
appendPQExpBuffer(query, "();\n");
if (evtinfo->evtenabled != 'O')
{
appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
fmtId(evtinfo->dobj.name));
switch (evtinfo->evtenabled)
{
case 'D':
appendPQExpBuffer(query, "DISABLE");
break;
case 'A':
appendPQExpBuffer(query, "ENABLE ALWAYS");
break;
case 'R':
appendPQExpBuffer(query, "ENABLE REPLICA");
break;
default:
appendPQExpBuffer(query, "ENABLE");
break;
}
appendPQExpBuffer(query, ";\n");
}
appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
fmtId(evtinfo->dobj.name));
ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
"EVENT TRIGGER", SECTION_POST_DATA,
query->data, "", NULL, NULL, 0, NULL, NULL);
dumpComment(fout, labelq->data,
NULL, NULL,
evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
destroyPQExpBuffer(query);
destroyPQExpBuffer(labelq);
}
/* /*
* dumpRule * dumpRule
* Dump a rule * Dump a rule
...@@ -14153,6 +14302,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, ...@@ -14153,6 +14302,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
break; break;
case DO_INDEX: case DO_INDEX:
case DO_TRIGGER: case DO_TRIGGER:
case DO_EVENT_TRIGGER:
case DO_DEFAULT_ACL: case DO_DEFAULT_ACL:
/* Post-data objects: must come after the post-data boundary */ /* Post-data objects: must come after the post-data boundary */
addObjectDependency(dobj, postDataBound->dumpId); addObjectDependency(dobj, postDataBound->dumpId);
......
...@@ -120,7 +120,8 @@ typedef enum ...@@ -120,7 +120,8 @@ typedef enum
DO_BLOB, DO_BLOB,
DO_BLOB_DATA, DO_BLOB_DATA,
DO_PRE_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY,
DO_POST_DATA_BOUNDARY DO_POST_DATA_BOUNDARY,
DO_EVENT_TRIGGER
} DumpableObjectType; } DumpableObjectType;
typedef struct _dumpableObject typedef struct _dumpableObject
...@@ -352,6 +353,18 @@ typedef struct _triggerInfo ...@@ -352,6 +353,18 @@ typedef struct _triggerInfo
char *tgdef; char *tgdef;
} TriggerInfo; } TriggerInfo;
typedef struct _evttriggerInfo
{
DumpableObject dobj;
char *evtname;
char *evtevent;
char *evtowner;
char *evttags;
char *evtfname;
char evttype;
char evtenabled;
} EventTriggerInfo;
/* /*
* struct ConstraintInfo is used for all constraint types. However we * struct ConstraintInfo is used for all constraint types. However we
* use a different objType for foreign key constraints, to make it easier * use a different objType for foreign key constraints, to make it easier
...@@ -562,5 +575,6 @@ extern ForeignServerInfo *getForeignServers(Archive *fout, ...@@ -562,5 +575,6 @@ extern ForeignServerInfo *getForeignServers(Archive *fout,
extern DefaultACLInfo *getDefaultACLs(Archive *fout, int *numDefaultACLs); extern DefaultACLInfo *getDefaultACLs(Archive *fout, int *numDefaultACLs);
extern void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], extern void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
int numExtensions); int numExtensions);
extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers);
#endif /* PG_DUMP_H */ #endif /* PG_DUMP_H */
...@@ -24,8 +24,9 @@ static const char *modulename = gettext_noop("sorter"); ...@@ -24,8 +24,9 @@ static const char *modulename = gettext_noop("sorter");
* Objects are sorted by priority levels, and within an equal priority level * Objects are sorted by priority levels, and within an equal priority level
* by OID. (This is a relatively crude hack to provide semi-reasonable * by OID. (This is a relatively crude hack to provide semi-reasonable
* behavior for old databases without full dependency info.) Note: collations, * behavior for old databases without full dependency info.) Note: collations,
* extensions, text search, foreign-data, and default ACL objects can't really * extensions, text search, foreign-data, event trigger, and default ACL
* happen here, so the rather bogus priorities for them don't matter. * 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 * 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, * pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
...@@ -66,7 +67,8 @@ static const int oldObjectTypePriority[] = ...@@ -66,7 +67,8 @@ static const int oldObjectTypePriority[] =
9, /* DO_BLOB */ 9, /* DO_BLOB */
12, /* DO_BLOB_DATA */ 12, /* DO_BLOB_DATA */
10, /* DO_PRE_DATA_BOUNDARY */ 10, /* DO_PRE_DATA_BOUNDARY */
13 /* DO_POST_DATA_BOUNDARY */ 13, /* DO_POST_DATA_BOUNDARY */
20 /* DO_EVENT_TRIGGER */
}; };
/* /*
...@@ -112,7 +114,8 @@ static const int newObjectTypePriority[] = ...@@ -112,7 +114,8 @@ static const int newObjectTypePriority[] =
21, /* DO_BLOB */ 21, /* DO_BLOB */
24, /* DO_BLOB_DATA */ 24, /* DO_BLOB_DATA */
22, /* DO_PRE_DATA_BOUNDARY */ 22, /* DO_PRE_DATA_BOUNDARY */
25 /* DO_POST_DATA_BOUNDARY */ 25, /* DO_POST_DATA_BOUNDARY */
32 /* DO_EVENT_TRIGGER */
}; };
static DumpId preDataBoundId; static DumpId preDataBoundId;
...@@ -1147,6 +1150,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize) ...@@ -1147,6 +1150,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
"TRIGGER %s (ID %d OID %u)", "TRIGGER %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid); obj->name, obj->dumpId, obj->catId.oid);
return; return;
case DO_EVENT_TRIGGER:
snprintf(buf, bufsize,
"EVENT TRIGGER %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid);
return;
case DO_CONSTRAINT: case DO_CONSTRAINT:
snprintf(buf, bufsize, snprintf(buf, bufsize,
"CONSTRAINT %s (ID %d OID %u)", "CONSTRAINT %s (ID %d OID %u)",
......
...@@ -490,6 +490,9 @@ exec_command(const char *cmd, ...@@ -490,6 +490,9 @@ exec_command(const char *cmd,
else else
success = listExtensions(pattern); success = listExtensions(pattern);
break; break;
case 'y': /* Event Triggers */
success = listEventTriggers(pattern, show_verbose);
break;
default: default:
status = PSQL_CMD_UNKNOWN; status = PSQL_CMD_UNKNOWN;
} }
......
...@@ -2952,6 +2952,67 @@ listConversions(const char *pattern, bool verbose, bool showSystem) ...@@ -2952,6 +2952,67 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
return true; return true;
} }
/*
* \dy
*
* Describes Event Triggers.
*/
bool
listEventTriggers(const char *pattern, bool verbose)
{
PQExpBufferData buf;
PGresult *res;
printQueryOpt myopt = pset.popt;
static const bool translate_columns[] =
{false, false, false, true, false, false, false};
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf,
"select evtname as \"%s\", "
"evtevent as \"%s\", "
"pg_catalog.pg_get_userbyid(e.evtowner) AS \"%s\", "
"case evtenabled when 'O' then 'enabled' "
" when 'R' then 'replica' "
" when 'A' then 'always' "
" when 'D' then 'disabled' end as \"%s\", "
"e.evtfoid::regproc as \"%s\", "
"array_to_string(array(select x "
" from unnest(evttags) as t(x)), ', ') as \"%s\" ",
gettext_noop("Name"),
gettext_noop("Event"),
gettext_noop("Owner"),
gettext_noop("Enabled"),
gettext_noop("Procedure"),
gettext_noop("Tags"));
if (verbose)
appendPQExpBuffer(&buf,
",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
gettext_noop("Description"));
appendPQExpBuffer(&buf,
"\nFROM pg_event_trigger e ");
processSQLNamePattern(pset.db, &buf, pattern, false, false,
NULL, "evtname", NULL, NULL);
appendPQExpBuffer(&buf, "ORDER BY 1");
res = PSQLexec(buf.data, false);
termPQExpBuffer(&buf);
if (!res)
return false;
myopt.nullPrint = NULL;
myopt.title = _("List of event triggers");
myopt.translate_header = true;
myopt.translate_columns = translate_columns;
printQuery(res, &myopt, pset.queryFout, pset.logfile);
PQclear(res);
return true;
}
/* /*
* \dC * \dC
* *
......
...@@ -96,4 +96,7 @@ extern bool listExtensions(const char *pattern); ...@@ -96,4 +96,7 @@ extern bool listExtensions(const char *pattern);
/* \dx+ */ /* \dx+ */
extern bool listExtensionContents(const char *pattern); extern bool listExtensionContents(const char *pattern);
/* \dy */
extern bool listEventTriggers(const char *pattern, bool verbose);
#endif /* DESCRIBE_H */ #endif /* DESCRIBE_H */
...@@ -229,6 +229,7 @@ slashUsage(unsigned short int pager) ...@@ -229,6 +229,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n")); fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n")); fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n"));
fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n")); fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n"));
fprintf(output, _(" \\dy [PATTERN] list event triggers\n"));
fprintf(output, _(" \\l[+] list all databases\n")); fprintf(output, _(" \\l[+] list all databases\n"));
fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n")); fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n"));
fprintf(output, _(" \\z [PATTERN] same as \\dp\n")); fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));
......
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201207111 #define CATALOG_VERSION_NO 201207181
#endif #endif
...@@ -146,6 +146,7 @@ typedef enum ObjectClass ...@@ -146,6 +146,7 @@ typedef enum ObjectClass
OCLASS_USER_MAPPING, /* pg_user_mapping */ OCLASS_USER_MAPPING, /* pg_user_mapping */
OCLASS_DEFACL, /* pg_default_acl */ OCLASS_DEFACL, /* pg_default_acl */
OCLASS_EXTENSION, /* pg_extension */ OCLASS_EXTENSION, /* pg_extension */
OCLASS_EVENT_TRIGGER, /* pg_event_trigger */
MAX_OCLASS /* MUST BE LAST */ MAX_OCLASS /* MUST BE LAST */
} ObjectClass; } ObjectClass;
......
...@@ -234,6 +234,11 @@ DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, on pg_trigger using ...@@ -234,6 +234,11 @@ DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, on pg_trigger using
DECLARE_UNIQUE_INDEX(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops)); DECLARE_UNIQUE_INDEX(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops));
#define TriggerOidIndexId 2702 #define TriggerOidIndexId 2702
DECLARE_UNIQUE_INDEX(pg_event_trigger_evtname_index, 3467, on pg_event_trigger using btree(evtname name_ops));
#define EventTriggerNameIndexId 3467
DECLARE_UNIQUE_INDEX(pg_event_trigger_oid_index, 3468, on pg_event_trigger using btree(oid oid_ops));
#define EventTriggerOidIndexId 3468
DECLARE_UNIQUE_INDEX(pg_ts_config_cfgname_index, 3608, on pg_ts_config using btree(cfgname name_ops, cfgnamespace oid_ops)); DECLARE_UNIQUE_INDEX(pg_ts_config_cfgname_index, 3608, on pg_ts_config using btree(cfgname name_ops, cfgnamespace oid_ops));
#define TSConfigNameNspIndexId 3608 #define TSConfigNameNspIndexId 3608
DECLARE_UNIQUE_INDEX(pg_ts_config_oid_index, 3712, on pg_ts_config using btree(oid oid_ops)); DECLARE_UNIQUE_INDEX(pg_ts_config_oid_index, 3712, on pg_ts_config using btree(oid oid_ops));
......
/*-------------------------------------------------------------------------
*
* pg_event_trigger.h
* definition of the system "event trigger" relation (pg_event_trigger)
* along with the relation's initial contents.
*
*
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/catalog/pg_event_trigger.h
*
* NOTES
* the genbki.pl script reads this file and generates .bki
* information from the DATA() statements.
*
*-------------------------------------------------------------------------
*/
#ifndef PG_EVENT_TRIGGER_H
#define PG_EVENT_TRIGGER_H
#include "catalog/genbki.h"
/* ----------------
* pg_event_trigger definition. cpp turns this into
* typedef struct FormData_pg_event_trigger
* ----------------
*/
#define EventTriggerRelationId 3466
CATALOG(pg_event_trigger,3466)
{
NameData evtname; /* trigger's name */
NameData evtevent; /* trigger's event */
Oid evtowner; /* trigger's owner */
Oid evtfoid; /* OID of function to be called */
char evtenabled; /* trigger's firing configuration WRT
* session_replication_role */
#ifdef CATALOG_VARLEN
text evttags[1]; /* command TAGs this event trigger targets */
#endif
} FormData_pg_event_trigger;
/* ----------------
* Form_pg_event_trigger corresponds to a pointer to a tuple with
* the format of pg_event_trigger relation.
* ----------------
*/
typedef FormData_pg_event_trigger *Form_pg_event_trigger;
/* ----------------
* compiler constants for pg_event_trigger
* ----------------
*/
#define Natts_pg_event_trigger 6
#define Anum_pg_event_trigger_evtname 1
#define Anum_pg_event_trigger_evtevent 2
#define Anum_pg_event_trigger_evtowner 3
#define Anum_pg_event_trigger_evtfoid 4
#define Anum_pg_event_trigger_evtenabled 5
#define Anum_pg_event_trigger_evttags 6
#endif /* PG_EVENT_TRIGGER_H */
...@@ -3460,6 +3460,10 @@ DATA(insert OID = 2300 ( trigger_in PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2 ...@@ -3460,6 +3460,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"); 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_ )); 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"); 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_ )); 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"); 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_ )); 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_ ));
......
...@@ -650,6 +650,8 @@ DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void ...@@ -650,6 +650,8 @@ DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void
#define VOIDOID 2278 #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_ )); 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 #define TRIGGEROID 2279
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_ )); 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 #define LANGUAGE_HANDLEROID 2280
DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f 0 -1 0 0 _null_ _null_ _null_ )); DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f 0 -1 0 0 _null_ _null_ _null_ ));
......
/*-------------------------------------------------------------------------
*
* event_trigger.h
* Declarations for command trigger handling.
*
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/commands/event_trigger.h
*
*-------------------------------------------------------------------------
*/
#ifndef EVENT_TRIGGER_H
#define EVENT_TRIGGER_H
#include "catalog/pg_event_trigger.h"
#include "nodes/parsenodes.h"
extern void CreateEventTrigger(CreateEventTrigStmt *stmt);
extern void RemoveEventTriggerById(Oid ctrigOid);
extern Oid get_event_trigger_oid(const char *trigname, bool missing_ok);
extern void AlterEventTrigger(AlterEventTrigStmt *stmt);
extern void RenameEventTrigger(const char* trigname, const char *newname);
extern void AlterEventTriggerOwner(const char *name, Oid newOwnerId);
extern void AlterEventTriggerOwner_oid(Oid, Oid newOwnerId);
#endif /* EVENT_TRIGGER_H */
...@@ -357,6 +357,8 @@ typedef enum NodeTag ...@@ -357,6 +357,8 @@ typedef enum NodeTag
T_CreateExtensionStmt, T_CreateExtensionStmt,
T_AlterExtensionStmt, T_AlterExtensionStmt,
T_AlterExtensionContentsStmt, T_AlterExtensionContentsStmt,
T_CreateEventTrigStmt,
T_AlterEventTrigStmt,
/* /*
* TAGS FOR PARSE TREE NODES (parsenodes.h) * TAGS FOR PARSE TREE NODES (parsenodes.h)
......
...@@ -1113,6 +1113,7 @@ typedef enum ObjectType ...@@ -1113,6 +1113,7 @@ typedef enum ObjectType
OBJECT_CONVERSION, OBJECT_CONVERSION,
OBJECT_DATABASE, OBJECT_DATABASE,
OBJECT_DOMAIN, OBJECT_DOMAIN,
OBJECT_EVENT_TRIGGER,
OBJECT_EXTENSION, OBJECT_EXTENSION,
OBJECT_FDW, OBJECT_FDW,
OBJECT_FOREIGN_SERVER, OBJECT_FOREIGN_SERVER,
...@@ -1731,6 +1732,32 @@ typedef struct CreateTrigStmt ...@@ -1731,6 +1732,32 @@ typedef struct CreateTrigStmt
} CreateTrigStmt; } CreateTrigStmt;
/* ---------------------- /* ----------------------
* Create EVENT TRIGGER Statement
* ----------------------
*/
typedef struct CreateEventTrigStmt
{
NodeTag type;
char *trigname; /* TRIGGER's name */
char *eventname; /* event's identifier */
List *whenclause; /* list of DefElems indicating filtering */
List *funcname; /* qual. name of function to call */
} CreateEventTrigStmt;
/* ----------------------
* Alter EVENT TRIGGER Statement
* ----------------------
*/
typedef struct AlterEventTrigStmt
{
NodeTag type;
char *trigname; /* TRIGGER's name */
char tgenabled; /* trigger's firing configuration WRT
* session_replication_role */
} AlterEventTrigStmt;
/* ----------------------
* Create/Drop PROCEDURAL LANGUAGE Statements
* Create PROCEDURAL LANGUAGE Statements * Create PROCEDURAL LANGUAGE Statements
* ---------------------- * ----------------------
*/ */
......
...@@ -141,6 +141,7 @@ PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD) ...@@ -141,6 +141,7 @@ PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
PG_KEYWORD("end", END_P, RESERVED_KEYWORD) PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD) PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD) PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD) PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD) PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD) PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
......
...@@ -195,6 +195,7 @@ typedef enum AclObjectKind ...@@ -195,6 +195,7 @@ typedef enum AclObjectKind
ACL_KIND_TSCONFIGURATION, /* pg_ts_config */ ACL_KIND_TSCONFIGURATION, /* pg_ts_config */
ACL_KIND_FDW, /* pg_foreign_data_wrapper */ ACL_KIND_FDW, /* pg_foreign_data_wrapper */
ACL_KIND_FOREIGN_SERVER, /* pg_foreign_server */ ACL_KIND_FOREIGN_SERVER, /* pg_foreign_server */
ACL_KIND_EVENT_TRIGGER, /* pg_event_trigger */
ACL_KIND_EXTENSION, /* pg_extension */ ACL_KIND_EXTENSION, /* pg_extension */
MAX_ACL_KIND /* MUST BE LAST */ MAX_ACL_KIND /* MUST BE LAST */
} AclObjectKind; } AclObjectKind;
...@@ -322,6 +323,7 @@ extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid); ...@@ -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_ts_config_ownercheck(Oid cfg_oid, Oid roleid);
extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_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_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 pg_extension_ownercheck(Oid ext_oid, Oid roleid);
extern bool has_createrole_privilege(Oid roleid); extern bool has_createrole_privilege(Oid roleid);
......
...@@ -532,6 +532,8 @@ extern Datum void_recv(PG_FUNCTION_ARGS); ...@@ -532,6 +532,8 @@ extern Datum void_recv(PG_FUNCTION_ARGS);
extern Datum void_send(PG_FUNCTION_ARGS); extern Datum void_send(PG_FUNCTION_ARGS);
extern Datum trigger_in(PG_FUNCTION_ARGS); extern Datum trigger_in(PG_FUNCTION_ARGS);
extern Datum trigger_out(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_in(PG_FUNCTION_ARGS);
extern Datum language_handler_out(PG_FUNCTION_ARGS); extern Datum language_handler_out(PG_FUNCTION_ARGS);
extern Datum fdw_handler_in(PG_FUNCTION_ARGS); extern Datum fdw_handler_in(PG_FUNCTION_ARGS);
......
...@@ -54,6 +54,8 @@ enum SysCacheIdentifier ...@@ -54,6 +54,8 @@ enum SysCacheIdentifier
DEFACLROLENSPOBJ, DEFACLROLENSPOBJ,
ENUMOID, ENUMOID,
ENUMTYPOIDNAME, ENUMTYPOIDNAME,
EVENTTRIGGERNAME,
EVENTTRIGGEROID,
FOREIGNDATAWRAPPERNAME, FOREIGNDATAWRAPPERNAME,
FOREIGNDATAWRAPPEROID, FOREIGNDATAWRAPPEROID,
FOREIGNSERVERNAME, FOREIGNSERVERNAME,
......
-- should fail, return type mismatch
create event trigger regress_event_trigger
on ddl_command_start
execute procedure pg_backend_pid();
ERROR: function "pg_backend_pid" must return type "event_trigger"
-- cheesy hack for testing purposes
create function fake_event_trigger()
returns event_trigger
language internal
as 'pg_backend_pid';
-- should fail, no elephant_bootstrap entry point
create event trigger regress_event_trigger on elephant_bootstrap
execute procedure fake_event_trigger();
ERROR: unrecognized event name "elephant_bootstrap"
-- OK
create event trigger regress_event_trigger on ddl_command_start
execute procedure fake_event_trigger();
-- should fail, food is not a valid filter variable
create event trigger regress_event_trigger2 on ddl_command_start
when food in ('sandwhich')
execute procedure fake_event_trigger();
ERROR: unrecognized filter variable "food"
-- should fail, sandwhich is not a valid command tag
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('sandwhich')
execute procedure fake_event_trigger();
ERROR: filter value "sandwhich" not recognized for filter variable "tag"
-- should fail, create skunkcabbage is not a valid comand tag
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('create table', 'create skunkcabbage')
execute procedure fake_event_trigger();
ERROR: filter value "create skunkcabbage" not recognized for filter variable "tag"
-- should fail, can't have event triggers on event triggers
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('DROP EVENT TRIGGER')
execute procedure fake_event_trigger();
ERROR: event triggers are not supported for "DROP EVENT TRIGGER"
-- should fail, can't have same filter variable twice
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('create table') and tag in ('CREATE FUNCTION')
execute procedure fake_event_trigger();
ERROR: filter variable "tag" specified more than once
-- OK
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('create table', 'CREATE FUNCTION')
execute procedure fake_event_trigger();
-- OK
comment on event trigger regress_event_trigger is 'test comment';
-- should fail, event triggers are not schema objects
comment on event trigger wrong.regress_event_trigger is 'test comment';
ERROR: event trigger name cannot be qualified
-- drop as non-superuser should fail
create role regression_bob;
set role regression_bob;
create event trigger regress_event_trigger_noperms on ddl_command_start
execute procedure fake_event_trigger();
ERROR: permission denied to create event trigger "regress_event_trigger_noperms"
HINT: Must be superuser to create an event trigger.
reset role;
-- all OK
alter event trigger regress_event_trigger disable;
alter event trigger regress_event_trigger enable replica;
alter event trigger regress_event_trigger enable always;
alter event trigger regress_event_trigger enable;
-- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regression_bob;
ERROR: permission denied to change owner of event trigger "regress_event_trigger"
HINT: The owner of an event trigger must be a superuser.
-- alter owner to superuser should work
alter role regression_bob superuser;
alter event trigger regress_event_trigger owner to regression_bob;
-- should fail, name collision
alter event trigger regress_event_trigger rename to regress_event_trigger2;
ERROR: event trigger "regress_event_trigger2" already exists
-- OK
alter event trigger regress_event_trigger rename to regress_event_trigger3;
-- should fail, doesn't exist any more
drop event trigger regress_event_trigger;
ERROR: event trigger "regress_event_trigger" does not exist
-- should fail, regression_bob owns regress_event_trigger2/3
drop role regression_bob;
ERROR: role "regression_bob" cannot be dropped because some objects depend on it
DETAIL: owner of event trigger regress_event_trigger3
-- these are all OK; the second one should emit a NOTICE
drop event trigger if exists regress_event_trigger2;
drop event trigger if exists regress_event_trigger2;
NOTICE: event trigger "regress_event_trigger2" does not exist, skipping
drop event trigger regress_event_trigger3;
drop function fake_event_trigger();
drop role regression_bob;
This diff is collapsed.
...@@ -102,6 +102,7 @@ SELECT relname, relhasindex ...@@ -102,6 +102,7 @@ SELECT relname, relhasindex
pg_depend | t pg_depend | t
pg_description | t pg_description | t
pg_enum | t pg_enum | t
pg_event_trigger | t
pg_extension | t pg_extension | t
pg_foreign_data_wrapper | t pg_foreign_data_wrapper | t
pg_foreign_server | t pg_foreign_server | t
...@@ -164,7 +165,7 @@ SELECT relname, relhasindex ...@@ -164,7 +165,7 @@ SELECT relname, relhasindex
timetz_tbl | f timetz_tbl | f
tinterval_tbl | f tinterval_tbl | f
varchar_tbl | f varchar_tbl | f
(153 rows) (154 rows)
-- --
-- another sanity check: every system catalog that has OIDs should have -- another sanity check: every system catalog that has OIDs should have
......
...@@ -88,6 +88,8 @@ test: privileges security_label collate ...@@ -88,6 +88,8 @@ test: privileges security_label collate
test: misc test: misc
# rules cannot run concurrently with any test that creates a view # rules cannot run concurrently with any test that creates a view
test: rules test: rules
# event triggers cannot run concurrently with any test that runs DDL
test: event_trigger
# ---------- # ----------
# Another group of parallel tests # Another group of parallel tests
......
...@@ -96,6 +96,7 @@ test: security_label ...@@ -96,6 +96,7 @@ test: security_label
test: collate test: collate
test: misc test: misc
test: rules test: rules
test: event_trigger
test: select_views test: select_views
test: portals_p2 test: portals_p2
test: foreign_key test: foreign_key
......
-- should fail, return type mismatch
create event trigger regress_event_trigger
on ddl_command_start
execute procedure pg_backend_pid();
-- cheesy hack for testing purposes
create function fake_event_trigger()
returns event_trigger
language internal
as 'pg_backend_pid';
-- should fail, no elephant_bootstrap entry point
create event trigger regress_event_trigger on elephant_bootstrap
execute procedure fake_event_trigger();
-- OK
create event trigger regress_event_trigger on ddl_command_start
execute procedure fake_event_trigger();
-- should fail, food is not a valid filter variable
create event trigger regress_event_trigger2 on ddl_command_start
when food in ('sandwhich')
execute procedure fake_event_trigger();
-- should fail, sandwhich is not a valid command tag
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('sandwhich')
execute procedure fake_event_trigger();
-- should fail, create skunkcabbage is not a valid comand tag
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('create table', 'create skunkcabbage')
execute procedure fake_event_trigger();
-- should fail, can't have event triggers on event triggers
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('DROP EVENT TRIGGER')
execute procedure fake_event_trigger();
-- should fail, can't have same filter variable twice
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('create table') and tag in ('CREATE FUNCTION')
execute procedure fake_event_trigger();
-- OK
create event trigger regress_event_trigger2 on ddl_command_start
when tag in ('create table', 'CREATE FUNCTION')
execute procedure fake_event_trigger();
-- OK
comment on event trigger regress_event_trigger is 'test comment';
-- should fail, event triggers are not schema objects
comment on event trigger wrong.regress_event_trigger is 'test comment';
-- drop as non-superuser should fail
create role regression_bob;
set role regression_bob;
create event trigger regress_event_trigger_noperms on ddl_command_start
execute procedure fake_event_trigger();
reset role;
-- all OK
alter event trigger regress_event_trigger disable;
alter event trigger regress_event_trigger enable replica;
alter event trigger regress_event_trigger enable always;
alter event trigger regress_event_trigger enable;
-- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regression_bob;
-- alter owner to superuser should work
alter role regression_bob superuser;
alter event trigger regress_event_trigger owner to regression_bob;
-- should fail, name collision
alter event trigger regress_event_trigger rename to regress_event_trigger2;
-- OK
alter event trigger regress_event_trigger rename to regress_event_trigger3;
-- should fail, doesn't exist any more
drop event trigger regress_event_trigger;
-- should fail, regression_bob owns regress_event_trigger2/3
drop role regression_bob;
-- these are all OK; the second one should emit a NOTICE
drop event trigger if exists regress_event_trigger2;
drop event trigger if exists regress_event_trigger2;
drop event trigger regress_event_trigger3;
drop function fake_event_trigger();
drop role regression_bob;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment