Imutavelmente converte enum em string

Oct 04 2020

A maneira normal de converter um valor enum em uma string no PostgreSQL é convertê-lo (com ::text) ou simplesmente confiar na conversão implícita ao, digamos, concatená-lo com outra string:

testdb=# CREATE TYPE color AS ENUM ('red', 'green', 'blue');
CREATE TYPE
testdb=# CREATE TABLE object (id serial, name text, color color);
CREATE TABLE
testdb=# INSERT INTO object (name, color) VALUES ('table', 'red'), ('chair', 'green');
INSERT 0 2
testdb=# SELECT name || color FROM object;
  ?column?  
------------
 tablered
 chairgreen
(2 rows)

No entanto, há um problema: essas conversões parecem não ser consideradas imutáveis pelo Postgres. Como consequência, você obterá um erro se tentar usá-los em um lugar onde uma expressão imutável é esperada, como na definição de uma GENERATEDcoluna :

testdb=# ALTER TABLE object ADD COLUMN namecolor text GENERATED ALWAYS AS (name || color) STORED;
ERROR:  generation expression is not immutable
testdb=# ALTER TABLE object ADD COLUMN colorastext text GENERATED ALWAYS AS (color::text) STORED;
ERROR:  generation expression is not immutable

Isso parece não intuitivo e é inconveniente, já que gostaria de poder concatenar valores de enum em strings em uma coluna computada.

Portanto, tenho duas perguntas:

  1. Por que o Postgres considera a conversão de um enum em uma string para não ser imutável? Este comportamento é um bug?
  2. Existe uma solução alternativa que me permita persuadir o Postgres de que essa conversão é imutável (e há algum risco com o qual eu deveria ter cuidado)?

Respostas

2 LaurenzAlbe Oct 05 2020 at 12:46
  1. É possível renomear uma entrada enum, portanto, o elenco não é IMMUTABLE.

  2. Se você tiver certeza de que nunca renomeará os valores enum, escreva sua própria função de conversão que usa uma conversão internamente e rotule a função IMMUTABLE. Então o PostgreSQL confiará nesse rótulo e cabe a você cumprir a promessa.