Postgresql – Postgres 12: declare a function as constant or immutable ignoring parameters

postgresqltrigger

In a trigger function I want to conditionally do pg_notify() calls, depending on an application setup option. In order to do that I created a wrapper notify_conditionally(). If the application is started with the notifications disabled, a second SQL function will create this wrapper that doesn't do anything and is defined as IMMUTABLE:

CREATE OR REPLACE FUNCTION notify_conditionally(channel text, payload text) RETURNS int
LANGUAGE plpgsql IMMUTABLE AS
$inner$
BEGIN
    PERFORM 1 WHERE 1 = 0;
    RETURN 0;
END;
$inner$;

If notifications are enabled, this function is defined as a call to pg_notify() with the parameters of the function:

CREATE OR REPLACE FUNCTION notify_conditionally(channel text, payload text) RETURNS int
LANGUAGE plpgsql STABLE AS
$inner$
BEGIN
    PERFORM pg_notify(channel, payload);
    RETURN 0;
END;
$inner$;

Since the parameters to conditionally_notify() (and hence pg_notify()) change with every call, I suppose the IMMUTABLE keyword doesn't help much in terms of result value caching (in fact, it might even be counter-productive?). Therefore I am wondering is there a way that I can define this function as "constant" and have the planner be clever enough to not call this function or only call it once and reuse the first result for all other calls? This would basically be like an IMMUTABLE that ignores all parameters. This would be useful to avoid calling this function if notifications are disabled. On bigger queries this makes a difference from ~500ms in my case and ideally I could lower this in the case of disabled notifications.

While it is a possibility to also update the code that uses notify_conditionally() function dynamically based on whether notifications are enabled and in case they aren't just not use notify_conditionally(), I would prefer to not do this. The reason is that this happens in a rather large trigger function that currently should only be changed through a full migration.

Best Answer

Declare the no-op version as an SQL function then it will be in-lined as a constant value by the optimiser.

CREATE OR REPLACE FUNCTION notify_conditionally(channel text, payload text) RETURNS int
LANGUAGE sql AS
$inner$
SELECT 0;
$inner$;