Обсуждение: BUG #16177: pg_event_trigger_ddl_commands() returns empty set for ddl_command_start and "drop table"

Поиск
Список
Период
Сортировка

BUG #16177: pg_event_trigger_ddl_commands() returns empty set for ddl_command_start and "drop table"

От
PG Bug reporting form
Дата:
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();
        ---


Re: BUG #16177: pg_event_trigger_ddl_commands() returns empty setfor ddl_command_start and "drop table"

От
Alvaro Herrera
Дата:
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



Re: BUG #16177: pg_event_trigger_ddl_commands() returns empty set forddl_command_start and "drop table"

От
Andrei Pozolotin
Дата:
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.

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.



Re: BUG #16177: pg_event_trigger_ddl_commands() returns empty setfor ddl_command_start and "drop table"

От
Alvaro Herrera
Дата:
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



Re: BUG #16177: pg_event_trigger_ddl_commands() returns empty set forddl_command_start and "drop table"

От
Andrei Pozolotin
Дата:
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:

> 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.