Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions doc/src/sgml/func/func-info.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -3797,4 +3797,48 @@ acl | {postgres=arwdDxtm/postgres,foo=r/postgres}

</sect2>

<sect2 id="functions-info-retail">
<title>DDL Retail Functions</title>

<para>
<xref linkend="functions-info-retail-table"/> lists functions that
extract information about ....
</para>

<table id="functions-info-retail-table">
<title>DDL Retail Functions</title>
<tgroup cols="1">
<thead>
<row>
<entry role="func_table_entry"><para role="func_signature">
Function
</para>
<para>
Description
</para></entry>
</row>
</thead>

<tbody>
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
<primary>pg_get_event_trigger_ddl</primary>
</indexterm>
<function>pg_get_event_trigger_ddl</function>
( <parameter>event_trigger_name</parameter> <type>name</type> )
<returnvalue>text</returnvalue>
</para>
<para>
Reconstructs the underlying DDL statement for a specified event trigger.
It returns the complete <command>CREATE EVENT TRIGGER</command> statement. If
the event trigger does not exist, an error is raised.
</para></entry>
</row>
</tbody>
</tgroup>
</table>

</sect2>

</sect1>
119 changes: 119 additions & 0 deletions src/backend/utils/adt/ruleutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_language.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
Expand Down Expand Up @@ -1162,6 +1163,124 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
return buf.data;
}

/* ----------
* pg_get_event_trigger_ddl - Get the DDL statement for an event trigger
* ----------
*/
Datum
pg_get_event_trigger_ddl(PG_FUNCTION_ARGS)
{
Name evtName;
HeapTuple evtTup;
HeapTuple procTup;
Form_pg_event_trigger evtForm;
char *evtevent;
Oid evtfoid;
Datum evttagsDatum;
bool evttagsIsNull;
Form_pg_proc proc;
char *proname;
char prokind;
StringInfoData buf;

evtName = PG_GETARG_NAME(0);

/*
* Check provided event trigger name exists
*/
evtTup = SearchSysCache1(EVENTTRIGGERNAME, NameGetDatum(evtName));

if (!HeapTupleIsValid(evtTup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("event trigger \"%s\" does not exist", NameStr(*evtName))));

evtForm = (Form_pg_event_trigger) GETSTRUCT(evtTup);
evtevent = NameStr(evtForm->evtevent);
evtfoid = evtForm->evtfoid;

/*
* Look up event trigger function.
*/
procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(evtfoid));

if (!HeapTupleIsValid(procTup))
elog(ERROR,
"cache lookup failed for function %u", evtfoid);

proc = (Form_pg_proc) GETSTRUCT(procTup);
proname = NameStr(proc->proname);
prokind = proc->prokind;

Assert(prokind == PROKIND_FUNCTION || prokind == PROKIND_PROCEDURE);

/*
* Assemble output.
*/
initStringInfo(&buf);

appendStringInfo(&buf, "CREATE EVENT TRIGGER %s ON %s",
quote_identifier(NameStr(*evtName)),
quote_identifier(evtevent));

/*
* Generate WHEN clause, if any filter events were specified.
*
* Note that as of PostgreSQL 19, the only filter_variable supported
* is "TAG", which is not stored in pg_event_trigger, so is hard-coded
* in the generated output. This also means that by definition, the AND
* clause supported by the CREATE EVENT TRIGGER grammar cannot be actually
* be used in a valid statement, and thus will never be part of the
* generated output.
*/
evttagsDatum = SysCacheGetAttr(EVENTTRIGGEROID, evtTup,
Anum_pg_event_trigger_evttags,
&evttagsIsNull);

if (!evttagsIsNull)
{
ArrayType *arr = DatumGetArrayTypeP(evttagsDatum);
Datum *elems;
int nelems;
int i;

deconstruct_array_builtin(arr, TEXTOID, &elems, NULL, &nelems);

appendStringInfoString(&buf, " WHEN TAG IN (");

for (i = 0; i < nelems; ++i)
{
char *str = TextDatumGetCString(elems[i]);

if (i)
appendStringInfoChar(&buf, ',');

appendStringInfo(&buf, "'%s'", str);
}

appendStringInfoString(&buf, ")");
}

/*
* Finally, add EXECUTE clause.
*/
appendStringInfo(&buf, " EXECUTE %s %s.%s()",
prokind == PROKIND_FUNCTION ? "FUNCTION" : "PROCEDURE",
quote_identifier(get_namespace_name(proc->pronamespace)),
quote_identifier(proname));

/*
* Terminate query
*/
appendStringInfoChar(&buf, ';');

/* Clean up */
ReleaseSysCache(evtTup);
ReleaseSysCache(procTup);
PG_RETURN_TEXT_P(string_to_text(buf.data));
}


/* ----------
* pg_get_indexdef - Get the definition of an index
*
Expand Down
3 changes: 3 additions & 0 deletions src/include/catalog/pg_proc.dat
Original file line number Diff line number Diff line change
Expand Up @@ -8547,6 +8547,9 @@
{ oid => '2730', descr => 'trigger description with pretty-print option',
proname => 'pg_get_triggerdef', provolatile => 's', prorettype => 'text',
proargtypes => 'oid bool', prosrc => 'pg_get_triggerdef_ext' },
{ oid => '9067', descr => 'get CREATE statement for event trigger',
proname => 'pg_get_event_trigger_ddl', proisstrict => 't',
prorettype => 'text', proargtypes => 'name', prosrc => 'pg_get_event_trigger_ddl' },

# asynchronous notifications
{ oid => '3035',
Expand Down
26 changes: 26 additions & 0 deletions src/test/regress/expected/event_trigger.out
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,32 @@ create event trigger regress_event_trigger2 on ddl_command_start
execute procedure test_event_trigger();
-- OK
comment on event trigger regress_event_trigger is 'test comment';
-- these are all OK - checks the DDL output without a tag filter and with one
SELECT pg_get_event_trigger_ddl('regress_event_trigger');
pg_get_event_trigger_ddl
---------------------------------------------------------------------------------------------------------------
CREATE EVENT TRIGGER regress_event_trigger ON ddl_command_start EXECUTE FUNCTION public.test_event_trigger();
(1 row)

SELECT pg_get_event_trigger_ddl('regress_event_trigger2');
pg_get_event_trigger_ddl
---------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE EVENT TRIGGER regress_event_trigger2 ON ddl_command_start WHEN TAG IN ('CREATE TABLE','CREATE FUNCTION') EXECUTE FUNCTION public.test_event_trigger();
(1 row)

-- will return NULL
SELECT pg_get_event_trigger_ddl(NULL);
pg_get_event_trigger_ddl
--------------------------

(1 row)

-- should fail, no argument
SELECT pg_get_event_trigger_ddl();
ERROR: function pg_get_event_trigger_ddl() does not exist
LINE 1: SELECT pg_get_event_trigger_ddl();
^
DETAIL: No function of that name accepts the given number of arguments.
-- drop as non-superuser should fail
create role regress_evt_user;
set role regress_evt_user;
Expand Down
10 changes: 10 additions & 0 deletions src/test/regress/sql/event_trigger.sql
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ create event trigger regress_event_trigger2 on ddl_command_start
-- OK
comment on event trigger regress_event_trigger is 'test comment';

-- these are all OK - checks the DDL output without a tag filter and with one
SELECT pg_get_event_trigger_ddl('regress_event_trigger');
SELECT pg_get_event_trigger_ddl('regress_event_trigger2');

-- will return NULL
SELECT pg_get_event_trigger_ddl(NULL);

-- should fail, no argument
SELECT pg_get_event_trigger_ddl();

-- drop as non-superuser should fail
create role regress_evt_user;
set role regress_evt_user;
Expand Down