Search code examples
postgresqltriggersdatabase-partitioning

PostgreSQL ON BEFORE DELETE trigger not firing on a parent table in an inheritance scenario


I have a parent table and multiple inherited child tables that I'm using as partitions. I'm not using the new method in PG 10 because I manually calculate the routing and require processing on each INSERT, UPDATE and DELETE operation.

I have this trigger:

CREATE TRIGGER tg_collections_all
  BEFORE UPDATE OR INSERT OR DELETE
  ON cms.collections
  FOR EACH ROW
  EXECUTE PROCEDURE cms.collections_process();

It fires and works correctly on INSERT and UPDATE, but not on DELETE.

I added the following line as line #1 in cms.collections_process() to prove DELETE isn't firing:

  raise exception '(%)', TG_OP;

The row deleted.

The docs state:

In contrast, row-level triggers are fired for all affected partitions or child tables.

Any ideas?


Solution

  • UPDATEs and DELETEs on the parent table will affect rows in the child tables (if you don't specify ONLY), but triggers will only be fired by data modifications directed directly against the table with the trigger on it:

    CREATE TABLE parent(id integer, val text);
    CREATE TABLE child() INHERITS (parent);
    
    CREATE OR REPLACE FUNCTION inh_trigger() RETURNS trigger
       LANGUAGE plpgsql AS
    $$BEGIN
       RAISE NOTICE 'Called by %', TG_OP;
       RETURN CASE WHEN TG_OP = 'DELETE' THEN OLD ELSE NEW END;
    END;$$;
    
    CREATE TRIGGER inh_trigger BEFORE INSERT OR UPDATE OR DELETE ON parent
       FOR EACH ROW EXECUTE PROCEDURE inh_trigger();
    

    Only INSERTs directly on parent file the trigger:

    test=> INSERT INTO parent VALUES (1, 'one');
    NOTICE:  Called by INSERT
    INSERT 0 1
    test=> INSERT INTO child VALUES (2, 'two');
    INSERT 0 1
    

    The same holds for UPDATE and DELETE:

    test=> UPDATE parent SET val = 'changed' WHERE id = 1;
    NOTICE:  Called by UPDATE
    UPDATE 1
    test=> UPDATE parent SET val = 'changed' WHERE id = 2;
    UPDATE 1
    test=> DELETE FROM parent WHERE id = 1;
    NOTICE:  Called by DELETE
    DELETE 1
    test=> DELETE FROM parent WHERE id = 2;
    DELETE 1
    

    This seems to be in direct contrast to the sentence in the documentation you quote, or at least the sentence is highly misleading.

    I'd say that this is a documentation bug, and you should complain about it.