The following documentation comment has been logged on the website:

Page: https://www.postgresql.org/docs/11/sql-createtrigger.html
Description:

The AFTER Statement-level Trigger runs into infinite execution when another
set of rows are affected for the same table through this trigger. Consider
this use case where a table storage_locations that manages a hierarchy of
storage_locations in stores, and thus having following columns (for
simplicity):
storage_location_id                 SERIAL               NOT NULL    
PRIMARY KEY,
store_id                                   INTEGER            NOT NULL,   
-- REFERENCES stores
storage_location_nm               VARCHAR (25)   NOT NULL,
parent_storage_location_id     INTEGER                    NULL      
REFERENCES   storage_locations,    ---- NULL for root storage locations
storage_location_path             TEXT                  NOT NULL
I have a BEFORE ROW trigger, which updates the storage_location_path with
parent's storage_location_path, if any, concatenated with its
storage_location_name. This works fine - no issues.

I have another AFTER UPDATE STATEMENT-level Trigger and function definitions
as below (which updates the storage_path of the children):
CREATE FUNCTION TRG_storage_locations_b_u_AS_DML ()
        RETURNS TRIGGER
AS      $$
DECLARE
        v_separator     VARCHAR (1)             =       '/';
        v_cnt           INT;
BEGIN
                                       -- [ -- Required to prevent infinite
recursion
        SELECT  COUNT (*)
                INTO    v_cnt
        FROM    new_table;

        IF (v_cnt > 0) THEN
                                       -- ] -- Required to prevent infinite
recursion
                UPDATE  storage_locations
                        SET     storage_location_path   =       COALESCE 
(i.storage_location_path ||
v_separator, '') || storage_locations.storage_location_nm
                FROM    inserted        i
                        JOIN    deleted d
                                ON      (       i.storage_location_id   =       
d.storage_location_id
                                        AND     i.storage_location_path !=      
d.storage_location_path
                                        )
                WHERE   storage_locations.parent_storage_location_id    =       
i.storage_location_id;
        END IF;
        RETURN NULL;
END
$$ LANGUAGE plpgsql;

CREATE TRIGGER storage_locations_b_u_AS_DML
        AFTER   UPDATE
                ON      storage_locations
                        REFERENCING     NEW     TABLE   AS      inserted
                                                OLD     TABLE   AS      deleted
                FOR     EACH STATEMENT  EXECUTE FUNCTION        
TRG_storage_locations_b_u_AS_DML ();

Notice that the Trigger is getting called endlessly (if the number of rows
in the NEW TABLE are NOT checked). I reckon if there are not any rows, what
is the need to call the trigger. Or, may be, I am missing something, which I
need to learn.

Reply via email to