Skip to content

Instantly share code, notes, and snippets.

@teles
Created October 3, 2025 13:19
Show Gist options
  • Save teles/17e89137d9ccb7d96bb23f613ec9d447 to your computer and use it in GitHub Desktop.
Save teles/17e89137d9ccb7d96bb23f613ec9d447 to your computer and use it in GitHub Desktop.

Erro PostgreSQL: cached plan must not change result type (SQLSTATE 0A000)

Esse erro vem do PostgreSQL e significa o seguinte:

“cached plan must not change result type (SQLSTATE 0A000)”

Contexto

  • O PostgreSQL cria planos de execução em cache para consultas parametrizadas (principalmente em prepared statements ou queries vindas de drivers de ORM).
  • Esses planos em cache assumem que a consulta sempre retornará o mesmo conjunto de colunas e tipos.
  • Se, por algum motivo, a mesma query (ou o mesmo statement preparado) puder retornar tipos diferentes em execuções diferentes, o Postgres acusa erro.

Situações comuns que causam isso

  1. Funções que retornam tipo polimórfico ou anyelement – se em uma execução retornam int e em outra text, quebra.
  2. Uso de UNION ou CASE sem coerção explícita – se em uma execução o otimizador inferir um tipo diferente.
  3. Views ou funções com RETURN RECORD – se a estrutura muda entre chamadas.
  4. Consultas que dependem de parâmetros para definir o tipo de saída – ex.:
    PREPARE my_stmt AS SELECT $1; -- Tipo do parâmetro influencia o tipo de saída
    EXECUTE my_stmt(1);     -- inteiro
    EXECUTE my_stmt('abc'); -- texto → erro
  5. ORMs (tipo Hibernate, Sequelize, etc.) – que reaproveitam o mesmo statement com parâmetros diferentes, causando mudança de tipo inferido.

Como resolver

  • Forçar casting explícito em colunas/valores para que o tipo não varie:
    SELECT CASE WHEN cond THEN 'A' ELSE 'B' END::text;
  • Evitar funções polimórficas sem cast; se usar, force o retorno:
    SELECT myfunc($1)::int;
  • Revisar prepared statements no app/ORM: talvez precise invalidar o plano ao mudar o tipo do parâmetro.
  • EXECUTE com tipos consistentes: sempre usar parâmetros coerentes.
  • Em casos específicos, desativar plan caching no ORM (ou usar query nativa).

Exemplos práticos

Exemplo 1: CASE sem cast

-- Isso pode gerar erro em planos em cache:
SELECT CASE WHEN true THEN 1 ELSE 'texto' END;

-- Correto (com cast explícito):
SELECT CASE WHEN true THEN 1::text ELSE 'texto' END;

Exemplo 2: UNION com tipos diferentes

-- Pode falhar se o Postgres tentar cachear o plano:
SELECT 1
UNION ALL
SELECT 'abc';

-- Correto (forçando coerção):
SELECT 1::text
UNION ALL
SELECT 'abc';

Exemplo 3: Função polimórfica

-- Suponha uma função que retorna anyelement
PREPARE stmt AS SELECT myfunc($1);

EXECUTE stmt(1);      -- retorna inteiro
EXECUTE stmt('texto'); -- quebra, pois o tipo mudou

Correção:

PREPARE stmt AS SELECT myfunc($1)::text;

👉 Resumo:
Esse erro acontece porque o PostgreSQL detectou que um statement em cache que deveria ter sempre o mesmo tipo de saída mudou entre execuções.
A solução é garantir consistência de tipos (com casts) ou ajustar o uso de prepared statements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment