Hello all,

I've run into this issue in several contexts recently, and wonder if folks here 
can help clear up my understanding of function volatility.  I often have 
functions which are not truly immutable (they do something minor, like read in 
configuration information), but the functions themselves are fairly expensive, 
so I want them to run just once per query.  At face value, I feel like STABLE 
should do what I want, but often it does not.  Here is a simple example of what 
I am talking about (tested on 9.1.9):

--------------------------------------------------------------------------
CREATE TABLE t1(id INT PRIMARY KEY, val TEXT);

-- Using numbers as "text" for convenience
INSERT INTO t1 SELECT generate_series(1,1000), random() * 1000;

-- The real function reads configuration from the DB, and so
-- cannot be truthfully IMMUTABLE
--
-- This function returns 'text' to better match my real case,
-- but is otherwise just for demonstration
--
CREATE OR REPLACE FUNCTION passthru(myval text)
 RETURNS text
 LANGUAGE plpgsql
 STABLE STRICT
AS $function$
DECLARE
BEGIN
    RAISE NOTICE 'test';
    RETURN myval;
END;
$function$
;

EXPLAIN ANALYZE select * from t1 where val like passthru('55') || '%';

ALTER FUNCTION passthru(text) IMMUTABLE;

EXPLAIN ANALYZE select * from t1 where val like passthru('55') || '%';
-------------------------------------------------------------------------------------

If you run this, you should see two things:

1) When STABLE, the function still runs many, many times (see notices), despite 
having a fixed input.
2) When switching to IMMUTABLE, the function runs just once (as expected) and 
the query is orders of magnitude faster.

Is STABLE working as it should in this example?  I've searched around, and in 
some threads I see explanations that STABLE only /allows/ the planner to run 
the function once, but the planner is free to run it as many times as it sees 
fit.  If this is the case, is there a way to alter the function to tell the 
planner, "trust me, you only want to run this once per query"?  In effect, it 
seems I want something between IMMUTABLE and the current interpretation of 
STABLE, maybe a SUPERSTABLE designation or something.

I have also seen that wrapping the function in a subselect is a workaround, but 
it seems unusual to require such a workaround for what seems like a common need.

Thanks for any insight you might have!

Sincerely,
Dan


Reply via email to