Convierta inmutablemente enum en cadena

Oct 04 2020

La forma normal de convertir un valor de enumeración en una cadena en PostgreSQL es convertirlo (con ::text) o simplemente confiar en la conversión implícita cuando, por ejemplo, concatenarlo a otra cadena:

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)

Sin embargo, hay un problema: Postgres no considera que tales conversiones sean inmutables . Como consecuencia, obtiene un error si intenta usarlos en un lugar donde se espera una expresión inmutable, como en la definición de una GENERATEDcolumna :

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

Esto parece poco intuitivo y es inconveniente, ya que me gustaría poder concatenar valores de enumeración en cadenas en una columna calculada.

Por tanto, tengo dos preguntas:

  1. ¿Por qué Postgres considera que convertir una enumeración en una cadena no es inmutable? ¿Es este comportamiento un error?
  2. ¿Hay alguna solución que me permita persuadir a Postgres de que dicha conversión es inmutable (y hay algún riesgo de los que deba tener cuidado)?

Respuestas

2 LaurenzAlbe Oct 05 2020 at 12:46
  1. Es posible cambiar el nombre de una entrada de enumeración, por lo que la conversión no lo es IMMUTABLE.

  2. Si está seguro de que nunca cambiará el nombre de los valores de enumeración, escriba su propia función de conversión que use una conversión internamente y etiquete la función IMMUTABLE. Entonces PostgreSQL confiará en esa etiqueta, y depende de usted cumplir la promesa.