BUG #16177: pg_event_trigger_ddl_commands() returns empty set for ddl_command_start and "drop table"
The following bug has been logged on the website:
Bug reference: 16177
Logged by: Andrei Pozolotin
Email address: andrei.pozolotin@gmail.com
PostgreSQL version: 11.6
Operating system: linux
Description:
1. use case is to delete rows with oid references to the table before "drop
table"
2. one way to do that is with event_trigger, see code snippet below
3. the problem is that:
pg_event_trigger_ddl_commands() returns empty set for ddl_command_start and
"drop table"
4. this issue was already mentioned before:
https://postgrespro.com/list/thread-id/2394772
5. sample code:
CREATE OR REPLACE FUNCTION pglogical_assign_repset()
RETURNS event_trigger AS $$
DECLARE obj record;
BEGIN
RAISE NOTICE 'pglogical assign: % %', tg_event, tg_tag;
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands()
LOOP
IF obj.object_type = 'table' THEN
IF obj.schema_name = 'public' THEN
IF tg_tag IN ('CREATE TABLE') THEN
PERFORM
pglogical.replication_set_add_table('default', obj.objid);
END IF;
IF tg_tag IN ('DROP TABLE') THEN
PERFORM
pglogical.replication_set_remove_table('default', obj.objid);
END IF;
END IF;
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
---
DROP EVENT TRIGGER IF EXISTS
pglogical_assign_repset_create;
CREATE EVENT TRIGGER
pglogical_assign_repset_create
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE')
EXECUTE FUNCTION pglogical_assign_repset();
---
DROP EVENT TRIGGER IF EXISTS
pglogical_assign_repset_delete;
CREATE EVENT TRIGGER
pglogical_assign_repset_delete
ON ddl_command_start
WHEN TAG IN ('DROP TABLE')
EXECUTE FUNCTION pglogical_assign_repset();
---
On 2019-Dec-22, PG Bug reporting form wrote:
1. use case is to delete rows with oid references to the table before "drop
table"
I think you could achieve that with an event trigger on event sql_drop.
IIRC that event trigger is run for the objects before the drops are
actually executed.
ddl_command_start is pretty useless, because it doesn't have much info
abot the command being run; I'm sure that
pg_event_trigger_ddl_commands() would always return empty there.
The function would return non-empty only during ddl_command_end, but
that's no useful to you because the drops will already have run.
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Alvaro, hi:
1. thank you for the idea, I have just tried that
2. I could not make it work, since "sql_drop" event
happens **after** the "drop table" has already being attempted
and failed due to table oid dependencies
3. you may find it curious that I was in fact trying to improve on the
following trigger function:
https://github.com/2ndQuadrant/pglogical#automatic-assignment-of-replication-sets-for-new-tables
to make it work for "drop table" as well
4. my current workaround is to move trigger logic for "create
table"/"drop table"
outside of postgre into the app layer, essentially doing via execute()
intercept:
* replicate_ddl_command("create table; replication_set_add_table();")
* replicate_ddl_command("replication_set_remove_table(); drop table;")
5. nonetheless, can you suggest any other way to make "event_trigger"
work for this scenario:
https://github.com/2ndQuadrant/pglogical#automatic-assignment-of-replication-sets-for-new-tables
?
Thanks,
Andrei.
Show quoted text
On 2019-12-23 08:36, Alvaro Herrera wrote:
On 2019-Dec-22, PG Bug reporting form wrote:
1. use case is to delete rows with oid references to the table before
"drop
table"I think you could achieve that with an event trigger on event sql_drop.
IIRC that event trigger is run for the objects before the drops are
actually executed.ddl_command_start is pretty useless, because it doesn't have much info
abot the command being run; I'm sure that
pg_event_trigger_ddl_commands() would always return empty there.
The function would return non-empty only during ddl_command_end, but
that's no useful to you because the drops will already have run.
Hello,
On 2019-Dec-23, Andrei Pozolotin wrote:
1. thank you for the idea, I have just tried that
2. I could not make it work, since "sql_drop" event
happens **after** the "drop table" has already being attempted
and failed due to table oid dependencies
Well, that's really disappointing, but now that you say it, I remember
that yes we had to save all table info prior to firing the trigger
because it (the trigger) would run after the drop. I think there was a
restriction that forced us to do things that way, but TBH I don't
remember clearly.
3. you may find it curious that I was in fact trying to improve on the
following trigger function:
https://github.com/2ndQuadrant/pglogical#automatic-assignment-of-replication-sets-for-new-tables
to make it work for "drop table" as well
That makes sense.
4. my current workaround is to move trigger logic for "create table"/"drop
table"
outside of postgre into the app layer, essentially doing via execute()
intercept:
* replicate_ddl_command("create table; replication_set_add_table();")
* replicate_ddl_command("replication_set_remove_table(); drop table;")
That seems a decent workaround, if suboptimal.
5. nonetheless, can you suggest any other way to make "event_trigger" work
for this scenario:
https://github.com/2ndQuadrant/pglogical#automatic-assignment-of-replication-sets-for-new-tables
?
I wonder if it's possible for pglogical to register pg_depend entries to
the replication set, so that the repset membership is dropped alongside
the table.
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Alvaro:
great, I posted your idea with pglogical:
https://github.com/2ndQuadrant/pglogical/issues/234
Andrei.
On 2019-12-24 10:18, Alvaro Herrera wrote:
Show quoted text
I wonder if it's possible for pglogical to register pg_depend entries
to
the replication set, so that the repset membership is dropped alongside
the table.