Toda função tem uma classificação de volatilidade,
com as seguintes possibilidades: VOLATILE,
STABLE ou IMMUTABLE.
VOLATILE é o padrão quando o comando
CREATE FUNCTION não especifica a categoria.
A categoria da volatilidade é uma promessa feita ao otimizador
sobre o comportamento da função:
Uma função VOLATILE pode fazer qualquer coisa,
inclusive modificar o banco de dados, e retornar resultados
diferentes em chamadas sucessivas com os mesmos argumentos.
O otimizador não faz suposições sobre o comportamento dessas funções.
Em uma consulta usando uma função volátil, esta função será
reavaliada em cada linha onde seu valor for necessário.
Uma função STABLE não pode modificar o banco
de dados, e garante retornar os mesmos resultados, se for
chamada com os mesmos argumentos, para todas as linhas dentro
da mesma instrução.
Esta categoria permite que o otimizador transforme várias
chamadas à função em uma única chamada.
Em particular, é seguro usar uma expressão contendo uma função
dessa categoria em uma condição de varredura de índice.
(Como a varredura de índice avalia o valor de comparação apenas
uma vez, e não uma vez a cada linha, portanto não é válido usar
uma função VOLATILE em uma condição de
varredura de índice.)
Uma função IMMUTABLE não pode modificar o banco
de dados, e garante retornar os mesmos resultados, se for chamada
com os mesmos argumentos, para sempre.
Esta categoria permite que o otimizador pré-avalie a função quando
a consulta a chama com argumentos constantes.
Por exemplo, uma consulta como
SELECT ... WHERE x = 2 + 2 pode ser simplificada
para SELECT ... WHERE x = 4, porque a função
subjacente ao operador de adição de números inteiros está marcada
como IMMUTABLE.
Para melhores resultados de otimização, as funções devem ser rotuladas com a categoria de volatilidade mais estrita válida para elas.
Qualquer função com efeitos colaterais deve ser
rotulada como VOLATILE, de modo que as chamadas
para ela não possam ser otimizadas.
Mesmo uma função sem efeitos colaterais precisa ser rotulada como
VOLATILE, se o seu valor puder mudar na mesma
consulta; alguns exemplos são random(),
currval() e timeofday().
Outro exemplo importante é a família de funções
current_timestamp poder se qualificar como
STABLE, porque seus valores não mudam dentro
da transação.
Há relativamente pouca diferença entre as categorias
STABLE e IMMUTABLE ao
considerar consultas interativas simples, que são planejadas e
executadas imediatamente: não importa muito se uma função é
executada uma vez durante o planejamento, ou uma vez durante a
inicialização da execução da consulta.
Mas há uma grande diferença se o plano for salvo e reutilizado
posteriormente.
Rotular uma função como IMMUTABLE, quando na
verdade não é, pode permitir que ela seja convertida prematuramente
para uma constante durante o planejamento, fazendo com que um valor
obsoleto seja reutilizado durante os usos subsequentes do plano.
Isto é um perigo ao usar instruções preparadas, ou ao usar linguagens
de função que armazenam planos
(tal como o PL/pgSQL).
Para funções escritas em SQL, ou em qualquer uma
das linguagens procedurais padrão, há uma segunda propriedade
importante determinada pela categoria de volatilidade, ou seja,
a visibilidade de quaisquer alterações nos dados feitas pelo comando
SQL que está chamando a função.
Uma função VOLATILE verá estas mudanças, uma função
STABLE ou IMMUTABLE não verá.
Este comportamento é implementado usando o comportamento de
instantâneo do MVCC (veja Controle de concorrência):
As funções STABLE e IMMUTABLE
usam o instantâneo estabelecido desde o início da consulta chamadora,
enquanto as funções VOLATILE obtêm um novo
instantâneo no início de cada consulta que executam.
As funções escritas em C podem gerenciar instantâneos como quiserem, mas é geralmente uma boa ideia fazer as funções C funcionarem dessa forma também.
Devido a este comportamento de captura de instantâneo, uma função
contendo apenas comandos SELECT pode ser marcada
com segurança como STABLE, mesmo se selecionar
tabelas que possam estar sofrendo modificações por consultas simultâneas.
O PostgreSQL executará todos os comandos
de uma função STABLE usando o instantâneo
estabelecido para a consulta chamadora, portanto, verá uma visão
fixa do banco de dados durante esta consulta.
O mesmo comportamento de instantâneo é usado para comandos
SELECT nas funções IMMUTABLE.
Geralmente não é recomendável selecionar tabelas de banco de dados
numa função IMMUTABLE, porque a
imutabilidade será quebrada se o conteúdo da tabela mudar.
No entanto, o PostgreSQL não impõe que
não se faça isto.
Um erro comum é rotular uma função como IMMUTABLE,
quando seus resultados dependem de um parâmetro de configuração.
Por exemplo, uma função que manipula carimbos de data e hora podem
ter resultados que dependem da configuração de
TimeZone.
Por segurança, estas funções devem ser rotuladas como
STABLE.
O PostgreSQL requer que as funções
STABLE e IMMUTABLE não
contenham nenhum comando SQL além do
SELECT, para prevenir a modificação de dados.
(Este não é um teste inteiramente seguro, já que estas funções ainda
podem chamar funções VOLATILE que modificam o
banco de dados.
Se isto for feito, vai se descobrir que a função
STABLE ou IMMUTABLE não
percebe as alterações no banco de dados aplicadas pela função
chamada, porque elas estão ocultas de seu instantâneo.)