I had this exact same issue and figured out a clever and clean way to resolve it.
Firstly, you cannot disable a trigger within a trigger if that is the trigger that you are currently executing. That was my scenario - I was inserting into a table as a result of inserts to it - which would otherwise cause an infinite loop of triggers.
The way I resolved it was to add a local parameter variable into the mix that essentially acted as a global variable that would disable the trigger from further invocations when it was already being used.
To do so, add the following code to your trigger function, at the very beginning:
SET LOCAL your.variable_name to 'TRUE';
and then (assuming you're working with pg ≥ 9.6) you can just add the following line to your CREATE TRIGGER
:
WHEN (current_setting('your.variable_name', 't') <> 'TRUE')
I haven't done any bench testing, but from my prior experiences I expect it to be very performant.
UPDATE:
I've been using this approach for several years now in a highly active data warehouse and now have it setup on all my triggers (there are probably 50 of them) by default. I've formalized the code as such:
CREATE OR REPLACE FUNCTION trigger_state(
IN setting_name TEXT
) RETURNS BOOLEAN AS
$$
BEGIN
RETURN coalesce(NOT upper(current_setting(setting_name, TRUE)) = 'DISABLED',TRUE);
END
$$
LANGUAGE plpgsql
STABLE
;
and use it like this:
CREATE TRIGGER some_trigger
BEFORE INSERT
ON some_table
FOR EACH ROW
WHEN (
trigger_state('some_domain_name.trigger_state.some_trigger')
AND OLD.some_column IS DISTINCT FROM NEW.some_column
)
EXECUTE FUNCTION some_trg_funct()
;
To disable the trigger (for any reason) whether in code or command line, just:
SET "some_domain_name.trigger_state.some_trigger" = 'DISABLED';
This works in transactions, sessions, etc. as you'd expect with the SET
syntax. It isn't subject to locks or anything like that and within the current session/scope, takes affect immediately.
NOTE: However, its affect is NOT predictable globally (especially in the short term). If you need to disable a trigger globally, then the best method of doing that is with the cannonical methods mentioned above.
Anyways, its been hugely instrumental for me. I've had nothing but success with it - at least as far as I've been able to tell many guzillion of txns later.
SET session_replication_role = replica;
end up locking the table? – Sarabia