Dimitri Fontaine <[email protected]> writes:
> I added some in the attached patch.
>
> doc/src/sgml/event-trigger.sgml | 10 ++
> src/backend/commands/event_trigger.c | 6 +-
> src/test/regress/expected/event_trigger.out | 106 +++++++++++++++++++
> src/test/regress/sql/event_trigger.sql | 47 ++++++++
> 4 files changed, 167 insertions(+), 2 deletions(-)
And I did drop a comment line I didn't mean to when trying things out,
so here's the update copy. There's a bug fix in there too, in both the
versions of the patch, that the new regression tests exercise.
Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support
*** a/doc/src/sgml/event-trigger.sgml
--- b/doc/src/sgml/event-trigger.sgml
***************
*** 52,57 ****
--- 52,67 ----
</para>
<para>
+ Event Triggers themselves are not run in
+ a <xref linkend="sql-savepoint">. That means that you can stop the
+ execution of the current command by issuing a <command>RAISE
+ EXCEPTION</command> command from anywhere in your trigger function, and
+ that if an error occurs in the command itself (e.g.
+ when <command>DROP</command> targets an object that does not exists),
+ the <literal>ddl_command_end</> triggers will not get run.
+ </para>
+
+ <para>
For a complete list of commands supported by the event trigger mechanism,
see <xref linkend="event-trigger-matrix">.
</para>
*** a/src/backend/commands/event_trigger.c
--- b/src/backend/commands/event_trigger.c
***************
*** 551,557 **** filter_event_trigger(const char **tag, EventTriggerCacheItem *item)
}
/* Filter by tags, if any were specified. */
! if (item->ntags != 0 && bsearch(&tag, item->tag,
item->ntags, sizeof(char *),
pg_qsort_strcmp) == NULL)
return false;
--- 551,557 ----
}
/* Filter by tags, if any were specified. */
! if (item->ntags != 0 && bsearch(tag, item->tag,
item->ntags, sizeof(char *),
pg_qsort_strcmp) == NULL)
return false;
***************
*** 752,757 **** EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
--- 752,760 ----
ListCell *lc;
bool first = true;
+ /* Guard against stack overflow due to recursive event trigger */
+ check_stack_depth();
+
/*
* Let's evaluate event triggers in their own memory context, so
* that any leaks get cleaned up promptly.
*** a/src/test/regress/expected/event_trigger.out
--- b/src/test/regress/expected/event_trigger.out
***************
*** 67,72 **** alter event trigger regress_event_trigger enable;
--- 67,73 ----
alter event trigger regress_event_trigger disable;
-- regress_event_trigger2 should fire, but not regress_event_trigger
create table event_trigger_fire1 (a int);
+ NOTICE: test_event_trigger: ddl_command_start CREATE TABLE
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE
-- but nothing should fire here
drop table event_trigger_fire1;
***************
*** 90,95 **** ERROR: event trigger "regress_event_trigger" does not exist
--- 91,201 ----
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
+ -- now try something crazy to ensure we don't crash the backend
+ create function test_event_trigger_drop_function()
+ returns event_trigger
+ set max_stack_depth to '100' -- limit the size of the stack trace we output
+ as $$
+ BEGIN
+ drop function test_event_trigger2() cascade;
+ END
+ $$ language plpgsql;
+ NOTICE: test_event_trigger: ddl_command_start CREATE FUNCTION
+ NOTICE: test_event_trigger: ddl_command_end CREATE FUNCTION
+ create function test_event_trigger2() returns event_trigger as $$
+ BEGIN
+ RAISE NOTICE 'test_event_trigger2: % %', tg_event, tg_tag;
+ END
+ $$ language plpgsql;
+ NOTICE: test_event_trigger: ddl_command_start CREATE FUNCTION
+ NOTICE: test_event_trigger: ddl_command_end CREATE FUNCTION
+ create event trigger drop_test_a on "ddl_command_start"
+ execute procedure test_event_trigger_drop_function();
+ create event trigger drop_test_b on "ddl_command_start"
+ execute procedure test_event_trigger2();
+ -- now watch the fun
+ create table event_trigger_fire1 (a int);
+ ERROR: stack depth limit exceeded
+ HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate.
+ CONTEXT: SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ SQL statement "drop function test_event_trigger2() cascade"
+ PL/pgSQL function test_event_trigger_drop_function() line 3 at SQL statement
+ -- now limit the event trigger to avoid infinite recursion
+ drop event trigger drop_test_a;
+ create event trigger drop_test_a on "ddl_command_start"
+ when tag in ('create table')
+ execute procedure test_event_trigger_drop_function();
+ -- and try again, see if we crash
+ --
+ -- we want to avoid seeing the following in the regression tests:
+ -- ERROR: cache lookup failed for function 30201
+ -- because the OID of course changes each time
+ --
+ set client_min_messages to fatal;
+ create table event_trigger_fire1 (a int);
+ reset client_min_messages;
+ -- then cleanup the crazy test
+ drop event trigger drop_test_a;
+ drop event trigger drop_test_b;
+ drop function test_event_trigger_drop_function();
+ NOTICE: test_event_trigger: ddl_command_end DROP FUNCTION
-- 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;
*** a/src/test/regress/sql/event_trigger.sql
--- b/src/test/regress/sql/event_trigger.sql
***************
*** 95,100 **** drop event trigger regress_event_trigger;
--- 95,147 ----
-- should fail, regression_bob owns regress_event_trigger2/3
drop role regression_bob;
+ -- now try something crazy to ensure we don't crash the backend
+ create function test_event_trigger_drop_function()
+ returns event_trigger
+ set max_stack_depth to '100' -- limit the size of the stack trace we output
+ as $$
+ BEGIN
+ drop function test_event_trigger2() cascade;
+ END
+ $$ language plpgsql;
+
+ create function test_event_trigger2() returns event_trigger as $$
+ BEGIN
+ RAISE NOTICE 'test_event_trigger2: % %', tg_event, tg_tag;
+ END
+ $$ language plpgsql;
+
+ create event trigger drop_test_a on "ddl_command_start"
+ execute procedure test_event_trigger_drop_function();
+
+ create event trigger drop_test_b on "ddl_command_start"
+ execute procedure test_event_trigger2();
+
+ -- now watch the fun
+ create table event_trigger_fire1 (a int);
+
+ -- now limit the event trigger to avoid infinite recursion
+ drop event trigger drop_test_a;
+
+ create event trigger drop_test_a on "ddl_command_start"
+ when tag in ('create table')
+ execute procedure test_event_trigger_drop_function();
+
+ -- and try again, see if we crash
+ --
+ -- we want to avoid seeing the following in the regression tests:
+ -- ERROR: cache lookup failed for function 30201
+ -- because the OID of course changes each time
+ --
+ set client_min_messages to fatal;
+ create table event_trigger_fire1 (a int);
+ reset client_min_messages;
+
+ -- then cleanup the crazy test
+ drop event trigger drop_test_a;
+ drop event trigger drop_test_b;
+ drop function test_event_trigger_drop_function();
+
-- 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;
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers