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 @@
<entry>enum label and value definitions</entry>
</row>
<row>
<entry><link linkend="catalog-pg-event-trigger"><structname>pg_event_trigger</structname></link></entry>
<entry>event triggers</entry>
</row>
<row>
<entry><link linkend="catalog-pg-extension"><structname>pg_extension</structname></link></entry>
<entry>installed extensions</entry>
......@@ -1857,6 +1862,88 @@
</para>
</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">
<title><structname>pg_constraint</structname></title>
......
This diff is collapsed.
......@@ -61,6 +61,7 @@
<!ENTITY rules SYSTEM "rules.sgml">
<!ENTITY spi SYSTEM "spi.sgml">
<!ENTITY trigger SYSTEM "trigger.sgml">
<!ENTITY event-trigger SYSTEM "event-trigger.sgml">
<!ENTITY xaggr SYSTEM "xaggr.sgml">
<!ENTITY xfunc SYSTEM "xfunc.sgml">
<!ENTITY xindex SYSTEM "xindex.sgml">
......
......@@ -208,6 +208,7 @@
&extend;
&trigger;
&event-trigger;
&rules;
&xplang;
......
......@@ -12,6 +12,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY alterDatabase SYSTEM "alter_database.sgml">
<!ENTITY alterDefaultPrivileges SYSTEM "alter_default_privileges.sgml">
<!ENTITY alterDomain SYSTEM "alter_domain.sgml">
<!ENTITY alterEventTrigger SYSTEM "alter_event_trigger.sgml">
<!ENTITY alterExtension SYSTEM "alter_extension.sgml">
<!ENTITY alterForeignDataWrapper SYSTEM "alter_foreign_data_wrapper.sgml">
<!ENTITY alterForeignTable SYSTEM "alter_foreign_table.sgml">
......@@ -53,6 +54,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY createConversion SYSTEM "create_conversion.sgml">
<!ENTITY createDatabase SYSTEM "create_database.sgml">
<!ENTITY createDomain SYSTEM "create_domain.sgml">
<!ENTITY createEventTrigger SYSTEM "create_event_trigger.sgml">
<!ENTITY createExtension SYSTEM "create_extension.sgml">
<!ENTITY createForeignDataWrapper SYSTEM "create_foreign_data_wrapper.sgml">
<!ENTITY createForeignTable SYSTEM "create_foreign_table.sgml">
......@@ -91,6 +93,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY dropConversion SYSTEM "drop_conversion.sgml">
<!ENTITY dropDatabase SYSTEM "drop_database.sgml">
<!ENTITY dropDomain SYSTEM "drop_domain.sgml">
<!ENTITY dropEventTrigger SYSTEM "drop_event_trigger.sgml">
<!ENTITY dropExtension SYSTEM "drop_extension.sgml">
<!ENTITY dropForeignDataWrapper SYSTEM "drop_foreign_data_wrapper.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
COLLATION <replaceable class="PARAMETER">object_name</replaceable> |
CONVERSION <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 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> [, ...] ] ) |
......
......@@ -32,6 +32,7 @@ COMMENT ON
DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
DOMAIN <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 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> [, ...] ] ) |
......
<!--
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;
</listitem>
</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>
<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
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable> [, ...] ) |
DATABASE <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>
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> |
......
......@@ -41,6 +41,7 @@
&alterDefaultPrivileges;
&alterDomain;
&alterExtension;
&alterEventTrigger;
&alterForeignDataWrapper;
&alterForeignTable;
&alterFunction;
......@@ -82,6 +83,7 @@
&createDatabase;
&createDomain;
&createExtension;
&createEventTrigger;
&createForeignDataWrapper;
&createForeignTable;
&createFunction;
......@@ -120,6 +122,7 @@
&dropDatabase;
&dropDomain;
&dropExtension;
&dropEventTrigger;
&dropForeignDataWrapper;
&dropForeignTable;
&dropFunction;
......
......@@ -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_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_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_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 \
......
......@@ -29,6 +29,7 @@
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
......@@ -277,6 +278,10 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
case ACL_KIND_FOREIGN_SERVER:
whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
break;
case ACL_KIND_EVENT_TRIGGER:
elog(ERROR, "grantable rights not supported for event triggers");
/* not reached, but keep compiler quiet */
return ACL_NO_RIGHTS;
case ACL_KIND_TYPE:
whole_mask = ACL_ALL_RIGHTS_TYPE;
break;
......@@ -3286,6 +3291,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
gettext_noop("permission denied for foreign-data wrapper %s"),
/* ACL_KIND_FOREIGN_SERVER */
gettext_noop("permission denied for foreign server %s"),
/* ACL_KIND_EVENT_TRIGGER */
gettext_noop("permission denied for event trigger %s"),
/* ACL_KIND_EXTENSION */
gettext_noop("permission denied for extension %s"),
};
......@@ -3330,6 +3337,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
gettext_noop("must be owner of foreign-data wrapper %s"),
/* ACL_KIND_FOREIGN_SERVER */
gettext_noop("must be owner of foreign server %s"),
/* ACL_KIND_EVENT_TRIGGER */
gettext_noop("must be owner of event trigger %s"),
/* ACL_KIND_EXTENSION */
gettext_noop("must be owner of extension %s"),
};
......@@ -3455,6 +3464,10 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_FOREIGN_SERVER:
return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_EVENT_TRIGGER:
elog(ERROR, "grantable rights not supported for event triggers");
/* not reached, but keep compiler quiet */
return ACL_NO_RIGHTS;
case ACL_KIND_TYPE:
return pg_type_aclmask(table_oid, roleid, mask, how);
default:
......@@ -4875,6 +4888,33 @@ pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
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).
*/
......
......@@ -34,6 +34,7 @@
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
......@@ -56,6 +57,7 @@
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
......@@ -158,7 +160,8 @@ static const Oid object_classes[MAX_OCLASS] = {
ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */
UserMappingRelationId, /* OCLASS_USER_MAPPING */
DefaultAclRelationId, /* OCLASS_DEFACL */
ExtensionRelationId /* OCLASS_EXTENSION */
ExtensionRelationId, /* OCLASS_EXTENSION */
EventTriggerRelationId /* OCLASS_EVENT_TRIGGER */
};
......@@ -1112,6 +1115,10 @@ doDeletion(const ObjectAddress *object, int flags)
break;
}
case OCLASS_EVENT_TRIGGER:
RemoveEventTriggerById(object->objectId);
break;
case OCLASS_PROC:
RemoveFunctionById(object->objectId);
break;
......@@ -2269,6 +2276,9 @@ getObjectClass(const ObjectAddress *object)
case ExtensionRelationId:
return OCLASS_EXTENSION;
case EventTriggerRelationId:
return OCLASS_EVENT_TRIGGER;
}
/* shouldn't get here */
......@@ -2903,6 +2913,21 @@ getObjectDescription(const ObjectAddress *object)
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:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,
......
......@@ -21,6 +21,7 @@
#include "catalog/objectaddress.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
......@@ -46,6 +47,7 @@
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/tablespace.h"
......@@ -203,6 +205,12 @@ static ObjectPropertyType ObjectProperty[] =
-1,
InvalidAttrNumber
},
{
EventTriggerRelationId,
EventTriggerOidIndexId,
-1,
InvalidAttrNumber
},
{
TSConfigRelationId,
TSConfigOidIndexId,
......@@ -325,6 +333,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
case OBJECT_LANGUAGE:
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
case OBJECT_EVENT_TRIGGER:
address = get_object_address_unqualified(objtype,
objname, missing_ok);
break;
......@@ -546,6 +555,9 @@ get_object_address_unqualified(ObjectType objtype,
case OBJECT_FOREIGN_SERVER:
msg = gettext_noop("server name cannot be qualified");
break;
case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("event trigger name cannot be qualified");
break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
msg = NULL; /* placate compiler */
......@@ -601,6 +613,11 @@ get_object_address_unqualified(ObjectType objtype,
address.objectId = get_foreign_server_oid(name, missing_ok);
address.objectSubId = 0;
break;
case OBJECT_EVENT_TRIGGER:
address.classId = EventTriggerRelationId;
address.objectId = get_event_trigger_oid(name, missing_ok);
address.objectSubId = 0;
break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
/* placate compiler, which doesn't know elog won't return */
......@@ -980,6 +997,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
NameListToString(objname));
break;
case OBJECT_EVENT_TRIGGER:
if (!pg_event_trigger_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
NameListToString(objname));
break;
case OBJECT_LANGUAGE:
if (!pg_language_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
......
......@@ -25,6 +25,7 @@
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
......@@ -42,6 +43,7 @@
#include "commands/collationcmds.h"
#include "commands/conversioncmds.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
......@@ -1398,6 +1400,10 @@ shdepReassignOwned(List *roleids, Oid newrole)
AlterExtensionOwner_oid(sdepForm->objid, newrole);
break;
case EventTriggerRelationId:
AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
break;
default:
elog(ERROR, "unexpected classid %u", sdepForm->classid);
break;
......
......@@ -310,6 +310,19 @@ FROM
WHERE
l.objsubid = 0
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
l.objoid, l.classoid, 0::int4 AS objsubid,
'database'::text AS objtype,
......
......@@ -14,8 +14,8 @@ include $(top_builddir)/src/Makefile.global
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
collationcmds.o constraint.o conversioncmds.o copy.o createas.o \
dbcommands.o define.o discard.o dropcmds.o explain.o extension.o \
foreigncmds.o functioncmds.o \
dbcommands.o define.o discard.o dropcmds.o \
event_trigger.o explain.o extension.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
......
......@@ -24,6 +24,7 @@
#include "commands/conversioncmds.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
......@@ -77,6 +78,10 @@ ExecRenameStmt(RenameStmt *stmt)
RenameForeignServer(stmt->subname, stmt->newname);
break;
case OBJECT_EVENT_TRIGGER:
RenameEventTrigger(stmt->subname, stmt->newname);
break;
case OBJECT_FUNCTION:
RenameFunction(stmt->object, stmt->objarg, stmt->newname);
break;
......@@ -534,6 +539,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
break;
case OBJECT_EVENT_TRIGGER:
AlterEventTriggerOwner(strVal(linitial(stmt->object)), newowner);
break;
default:
elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
(int) stmt->objectType);
......
......@@ -206,6 +206,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
args = NameListToString(list_truncate(objname,
list_length(objname) - 1));
break;
case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
name = NameListToString(objname);
break;
case OBJECT_RULE:
msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
name = strVal(llast(objname));
......
This diff is collapsed.
......@@ -3466,6 +3466,30 @@ _copyCreateTrigStmt(const CreateTrigStmt *from)
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 *
_copyCreatePLangStmt(const CreatePLangStmt *from)
{
......@@ -4317,6 +4341,12 @@ copyObject(const void *from)
case T_CreateTrigStmt:
retval = _copyCreateTrigStmt(from);
break;
case T_CreateEventTrigStmt:
retval = _copyCreateEventTrigStmt(from);
break;
case T_AlterEventTrigStmt:
retval = _copyAlterEventTrigStmt(from);
break;
case T_CreatePLangStmt:
retval = _copyCreatePLangStmt(from);
break;
......
......@@ -1792,6 +1792,26 @@ _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b)
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
_equalCreatePLangStmt(const CreatePLangStmt *a, const CreatePLangStmt *b)
{
......@@ -2872,6 +2892,12 @@ equal(const void *a, const void *b)
case T_CreateTrigStmt:
retval = _equalCreateTrigStmt(a, b);
break;
case T_CreateEventTrigStmt:
retval = _equalCreateEventTrigStmt(a, b);
break;
case T_AlterEventTrigStmt:
retval = _equalAlterEventTrigStmt(a, b);
break;
case T_CreatePLangStmt:
retval = _equalCreatePLangStmt(a, b);
break;
......
......@@ -55,6 +55,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_trigger.h"
#include "commands/defrem.h"
#include "commands/trigger.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/gramparse.h"
......@@ -194,6 +195,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
}
%type <node> stmt schema_stmt
AlterEventTrigStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
......@@ -207,7 +209,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
CreateAssertStmt CreateTrigStmt
CreateAssertStmt CreateTrigStmt CreateEventTrigStmt
CreateUserStmt CreateUserMappingStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
......@@ -268,6 +270,10 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
%type <value> TriggerFuncArg
%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
database_name access_method_clause access_method attr_name
name cursor_name file_name
......@@ -505,7 +511,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
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
EXTENSION EXTERNAL EXTRACT
......@@ -674,7 +680,8 @@ stmtmulti: stmtmulti ';' stmt
;
stmt :
AlterDatabaseStmt
AlterEventTrigStmt
| AlterDatabaseStmt
| AlterDatabaseSetStmt
| AlterDefaultPrivilegesStmt
| AlterDomainStmt
......@@ -725,6 +732,7 @@ stmt :
| CreateStmt
| CreateTableSpaceStmt
| CreateTrigStmt
| CreateEventTrigStmt
| CreateRoleStmt
| CreateUserStmt
| CreateUserMappingStmt
......@@ -3554,6 +3562,15 @@ AlterExtensionContentsStmt:
n->objname = list_make1(makeString($6));
$$ = (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
{
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
......@@ -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 :
......@@ -4868,6 +4954,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; }
| VIEW { $$ = OBJECT_VIEW; }
| INDEX { $$ = OBJECT_INDEX; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| TYPE_P { $$ = OBJECT_TYPE; }
| DOMAIN_P { $$ = OBJECT_DOMAIN; }
| COLLATION { $$ = OBJECT_COLLATION; }
......@@ -4931,7 +5018,7 @@ opt_restart_seqs:
* EXTENSION | ROLE | TEXT SEARCH PARSER |
* TEXT SEARCH DICTIONARY | TEXT SEARCH TEMPLATE |
* TEXT SEARCH CONFIGURATION | FOREIGN TABLE |
* FOREIGN DATA WRAPPER | SERVER ] <objname> |
* FOREIGN DATA WRAPPER | SERVER | EVENT TRIGGER ] <objname> |
* AGGREGATE <aggname> (arg1, ...) |
* FUNCTION <funcname> (arg1, arg2, ...) |
* OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
......@@ -5113,6 +5200,7 @@ comment_type:
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| SERVER { $$ = OBJECT_FOREIGN_SERVER; }
| FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; }
| EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
;
comment_text:
......@@ -5195,6 +5283,7 @@ opt_provider: FOR ColId_or_Sconst { $$ = $2; }
security_label_type:
COLUMN { $$ = OBJECT_COLUMN; }
| DATABASE { $$ = OBJECT_DATABASE; }
| EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
......@@ -6850,6 +6939,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->missing_ok = false;
$$ = (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
{
RenameStmt *n = makeNode(RenameStmt);
......@@ -7329,6 +7426,14 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (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 @@
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/discard.h"
#include "commands/event_trigger.h"
#include "commands/explain.h"
#include "commands/extension.h"
#include "commands/lockcmds.h"
......@@ -183,6 +184,8 @@ check_xact_readonly(Node *parsetree)
case T_CommentStmt:
case T_DefineStmt:
case T_CreateCastStmt:
case T_CreateEventTrigStmt:
case T_AlterEventTrigStmt:
case T_CreateConversionStmt:
case T_CreatedbStmt:
case T_CreateDomainStmt:
......@@ -1056,6 +1059,14 @@ standard_ProcessUtility(Node *parsetree,
InvalidOid, InvalidOid, false);
break;
case T_CreateEventTrigStmt:
CreateEventTrigger((CreateEventTrigStmt *) parsetree);
break;
case T_AlterEventTrigStmt:
AlterEventTrigger((AlterEventTrigStmt *) parsetree);
break;
case T_CreatePLangStmt:
CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break;
......@@ -1472,6 +1483,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
case OBJECT_TRIGGER:
tag = "ALTER TRIGGER";
break;
case OBJECT_EVENT_TRIGGER:
tag = "ALTER EVENT TRIGGER";
break;
case OBJECT_TSCONFIGURATION:
tag = "ALTER TEXT SEARCH CONFIGURATION";
break;
......@@ -1741,6 +1755,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_TRIGGER:
tag = "DROP TRIGGER";
break;
case OBJECT_EVENT_TRIGGER:
tag = "DROP EVENT TRIGGER";
break;
case OBJECT_RULE:
tag = "DROP RULE";
break;
......@@ -1994,6 +2011,14 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE TRIGGER";
break;
case T_CreateEventTrigStmt:
tag = "CREATE EVENT TRIGGER";
break;
case T_AlterEventTrigStmt:
tag = "ALTER EVENT TRIGGER";
break;
case T_CreatePLangStmt:
tag = "CREATE LANGUAGE";
break;
......@@ -2489,6 +2514,14 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
case T_CreateEventTrigStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterEventTrigStmt:
lev = LOGSTMT_DDL;
break;
case T_CreatePLangStmt:
lev = LOGSTMT_DDL;
break;
......
......@@ -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.
*/
......
......@@ -34,6 +34,7 @@
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
......@@ -379,6 +380,28 @@ static const struct cachedesc cacheinfo[] = {
},
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 */
ForeignDataWrapperNameIndexId,
1,
......
......@@ -100,6 +100,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
int numForeignDataWrappers;
int numForeignServers;
int numDefaultACLs;
int numEventTriggers;
if (g_verbose)
write_msg(NULL, "reading schemas\n");
......@@ -240,6 +241,10 @@ getSchemaData(Archive *fout, int *numTablesPtr)
write_msg(NULL, "reading triggers\n");
getTriggers(fout, tblinfo, numTables);
if (g_verbose)
write_msg(NULL, "reading event triggers\n");
getEventTriggers(fout, &numEventTriggers);
*numTablesPtr = numTables;
return tblinfo;
}
......
......@@ -49,6 +49,7 @@
#include "catalog/pg_cast.h"
#include "catalog/pg_class.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h"
#include "catalog/pg_proc.h"
......@@ -186,6 +187,7 @@ static void dumpConversion(Archive *fout, ConvInfo *convinfo);
static void dumpRule(Archive *fout, RuleInfo *rinfo);
static void dumpAgg(Archive *fout, AggInfo *agginfo);
static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
static void dumpTable(Archive *fout, TableInfo *tbinfo);
static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
......@@ -5296,6 +5298,87 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
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
* get basic information about every procedural language in the system
......@@ -7166,6 +7249,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_TRIGGER:
dumpTrigger(fout, (TriggerInfo *) dobj);
break;
case DO_EVENT_TRIGGER:
dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
break;
case DO_CONSTRAINT:
dumpConstraint(fout, (ConstraintInfo *) dobj);
break;
......@@ -13658,6 +13744,69 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
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
* Dump a rule
......@@ -14153,6 +14302,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
break;
case DO_INDEX:
case DO_TRIGGER:
case DO_EVENT_TRIGGER:
case DO_DEFAULT_ACL:
/* Post-data objects: must come after the post-data boundary */
addObjectDependency(dobj, postDataBound->dumpId);
......
......@@ -120,7 +120,8 @@ typedef enum
DO_BLOB,
DO_BLOB_DATA,
DO_PRE_DATA_BOUNDARY,
DO_POST_DATA_BOUNDARY
DO_POST_DATA_BOUNDARY,
DO_EVENT_TRIGGER
} DumpableObjectType;
typedef struct _dumpableObject
......@@ -352,6 +353,18 @@ typedef struct _triggerInfo
char *tgdef;
} 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
* use a different objType for foreign key constraints, to make it easier
......@@ -562,5 +575,6 @@ extern ForeignServerInfo *getForeignServers(Archive *fout,
extern DefaultACLInfo *getDefaultACLs(Archive *fout, int *numDefaultACLs);
extern void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
int numExtensions);
extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers);
#endif /* PG_DUMP_H */
......@@ -24,8 +24,9 @@ static const char *modulename = gettext_noop("sorter");
* Objects are sorted by priority levels, and within an equal priority level
* by OID. (This is a relatively crude hack to provide semi-reasonable
* behavior for old databases without full dependency info.) Note: collations,
* extensions, text search, foreign-data, and default ACL objects can't really
* happen here, so the rather bogus priorities for them don't matter.
* extensions, text search, foreign-data, event trigger, and default ACL
* objects can't really happen here, so the rather bogus priorities for them
* don't matter.
*
* NOTE: object-type priorities must match the section assignments made in
* pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
......@@ -66,7 +67,8 @@ static const int oldObjectTypePriority[] =
9, /* DO_BLOB */
12, /* DO_BLOB_DATA */
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[] =
21, /* DO_BLOB */
24, /* DO_BLOB_DATA */
22, /* DO_PRE_DATA_BOUNDARY */
25 /* DO_POST_DATA_BOUNDARY */
25, /* DO_POST_DATA_BOUNDARY */
32 /* DO_EVENT_TRIGGER */
};
static DumpId preDataBoundId;
......@@ -1147,6 +1150,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
"TRIGGER %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid);
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:
snprintf(buf, bufsize,
"CONSTRAINT %s (ID %d OID %u)",
......
......@@ -490,6 +490,9 @@ exec_command(const char *cmd,
else
success = listExtensions(pattern);
break;
case 'y': /* Event Triggers */
success = listEventTriggers(pattern, show_verbose);
break;
default:
status = PSQL_CMD_UNKNOWN;
}
......
......@@ -2952,6 +2952,67 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
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
*
......
......@@ -96,4 +96,7 @@ extern bool listExtensions(const char *pattern);
/* \dx+ */
extern bool listExtensionContents(const char *pattern);
/* \dy */
extern bool listEventTriggers(const char *pattern, bool verbose);
#endif /* DESCRIBE_H */
......@@ -229,6 +229,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n"));
fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n"));
fprintf(output, _(" \\dy [PATTERN] list event triggers\n"));
fprintf(output, _(" \\l[+] list all databases\n"));
fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n"));
fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));
......
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201207111
#define CATALOG_VERSION_NO 201207181
#endif
......@@ -146,6 +146,7 @@ typedef enum ObjectClass
OCLASS_USER_MAPPING, /* pg_user_mapping */
OCLASS_DEFACL, /* pg_default_acl */
OCLASS_EXTENSION, /* pg_extension */
OCLASS_EVENT_TRIGGER, /* pg_event_trigger */
MAX_OCLASS /* MUST BE LAST */
} ObjectClass;
......
......@@ -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));
#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));
#define TSConfigNameNspIndexId 3608
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
DESCR("I/O");
DATA(insert OID = 2301 ( trigger_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "2279" _null_ _null_ _null_ _null_ trigger_out _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 3594 ( event_trigger_in PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 3838 "2275" _null_ _null_ _null_ _null_ event_trigger_in _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 3595 ( event_trigger_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "3838" _null_ _null_ _null_ _null_ event_trigger_out _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 2302 ( language_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2280 "2275" _null_ _null_ _null_ _null_ language_handler_in _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 2303 ( language_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "2280" _null_ _null_ _null_ _null_ language_handler_out _null_ _null_ _null_ ));
......
......@@ -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
DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
#define TRIGGEROID 2279
DATA(insert OID = 3838 ( event_trigger PGNSP PGUID 4 t p P f t \054 0 0 0 event_trigger_in event_trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
#define EVTTRIGGEROID 3838
DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
#define LANGUAGE_HANDLEROID 2280
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
T_CreateExtensionStmt,
T_AlterExtensionStmt,
T_AlterExtensionContentsStmt,
T_CreateEventTrigStmt,
T_AlterEventTrigStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
......
......@@ -1113,6 +1113,7 @@ typedef enum ObjectType
OBJECT_CONVERSION,
OBJECT_DATABASE,
OBJECT_DOMAIN,
OBJECT_EVENT_TRIGGER,
OBJECT_EXTENSION,
OBJECT_FDW,
OBJECT_FOREIGN_SERVER,
......@@ -1731,6 +1732,32 @@ typedef struct 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
* ----------------------
*/
......
......@@ -141,6 +141,7 @@ PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
......
......@@ -195,6 +195,7 @@ typedef enum AclObjectKind
ACL_KIND_TSCONFIGURATION, /* pg_ts_config */
ACL_KIND_FDW, /* pg_foreign_data_wrapper */
ACL_KIND_FOREIGN_SERVER, /* pg_foreign_server */
ACL_KIND_EVENT_TRIGGER, /* pg_event_trigger */
ACL_KIND_EXTENSION, /* pg_extension */
MAX_ACL_KIND /* MUST BE LAST */
} AclObjectKind;
......@@ -322,6 +323,7 @@ extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid);
extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid);
extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid);
extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid);
extern bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid);
extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
extern bool has_createrole_privilege(Oid roleid);
......
......@@ -532,6 +532,8 @@ extern Datum void_recv(PG_FUNCTION_ARGS);
extern Datum void_send(PG_FUNCTION_ARGS);
extern Datum trigger_in(PG_FUNCTION_ARGS);
extern Datum trigger_out(PG_FUNCTION_ARGS);
extern Datum event_trigger_in(PG_FUNCTION_ARGS);
extern Datum event_trigger_out(PG_FUNCTION_ARGS);
extern Datum language_handler_in(PG_FUNCTION_ARGS);
extern Datum language_handler_out(PG_FUNCTION_ARGS);
extern Datum fdw_handler_in(PG_FUNCTION_ARGS);
......
......@@ -54,6 +54,8 @@ enum SysCacheIdentifier
DEFACLROLENSPOBJ,
ENUMOID,
ENUMTYPOIDNAME,
EVENTTRIGGERNAME,
EVENTTRIGGEROID,
FOREIGNDATAWRAPPERNAME,
FOREIGNDATAWRAPPEROID,
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
pg_depend | t
pg_description | t
pg_enum | t
pg_event_trigger | t
pg_extension | t
pg_foreign_data_wrapper | t
pg_foreign_server | t
......@@ -164,7 +165,7 @@ SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
(153 rows)
(154 rows)
--
-- another sanity check: every system catalog that has OIDs should have
......
......@@ -88,6 +88,8 @@ test: privileges security_label collate
test: misc
# rules cannot run concurrently with any test that creates a view
test: rules
# event triggers cannot run concurrently with any test that runs DDL
test: event_trigger
# ----------
# Another group of parallel tests
......
......@@ -96,6 +96,7 @@ test: security_label
test: collate
test: misc
test: rules
test: event_trigger
test: select_views
test: portals_p2
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