Dimitri Fontaine <dimi...@2ndquadrant.fr> 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 (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to