Replace function used in index

IMMUTABLE means "does not change" or "unchangeable". What you must do to strictly avoid violating that rule is drop the function and everything that depends on it then re-create it and the indexes that use it.

If you replace the function in-place you're taking responsibility for the consequences. Personally I think PostgreSQL should disallow OR REPLACE for IMMUTABLE functions for this reason, forcing you to jump through an extra hoop like setting ignore_immutable_checks_even_though_it_might_cause_incorrect_queries configuration option.

If you change an immutable function's behaviour then indexes based on the function are invalid. The server can't tell if the function's behaviour has changed or not; you might just have replaced it with an optimized version that has identical behaviour in every respect. So it won't invalidate the indexes for you, though perhaps it should, since if your function's behaviour does differ you can get incorrect query results for queries based on the function.


If you change the function you will have to rebuild the index.

create table t (i integer);
insert into t (i)
select generate_series(1, 100000);
analyze t;

A simple function to return the opposite integer:

create or replace function f(i integer)
returns integer as $$
select i * -1;
$$ immutable language sql;

And the index on it:

create index t_i_index on t(f(i));

The index is used:

explain select * from t order by f(i);
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Index Scan using t_i_index on t  (cost=0.00..3300.26 rows=100000 width=4)

Now the function is changed to return the integer itself:

create or replace function f(i integer)
returns integer as $$
select i;
$$ immutable language sql;

And the index is not used anymore:

explain select * from t order by f(i);
                          QUERY PLAN                           
---------------------------------------------------------------
 Sort  (cost=11116.32..11366.32 rows=100000 width=4)
   Sort Key: i
   ->  Seq Scan on t  (cost=0.00..1443.00 rows=100000 width=4)

If the index is rebuilt

reindex index t_i_index;

It is used again:

explain select * from t order by f(i);
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Index Scan using t_i_index on t  (cost=0.00..4376.26 rows=100000 width=4)