Je suis confronté à l'erreur suivante:
ERROR: functions in index expression must be marked IMMUTABLE
Lorsque vous essayez de créer un index comme celui-ci:
CREATE INDEX full_phone_number ON orders_clientphone (concat(area_code, phone));
D'autre part, lors de l'utilisation de la syntaxe alternative pour la concaténation:
CREATE INDEX full_phone_number ON orders_clientphone ((area_code || phone));
Postgres est presque ok avec ça.
[.____] Les deux colonnes sont définies comme character varying(256)
.
Le facteur décisif pour postgrees est que la fonction concat()
est définie Stable et non immuable Dans le catalogue système pg_proc
:
SELECT proname, provolatile, proargtypes, proargtypes[0]::regtype AS argtype, prosrc
FROM pg_proc
WHERE proname = 'concat';
proname | provolatile | proargtypes| argtype | prosrc
--------+-------------+------------+---------+-----------
concat | s | 2276 | "any" | text_concat
le manuel sur pg_proc.provolatile
:
provolatile
indique si le résultat de la fonction dépend uniquement de ses arguments d'entrée ou est affecté par des facteurs extérieurs. C'esti
pour les fonctions "immuables", qui fournissent toujours le même résultat pour les mêmes entrées. C'ests
pour les fonctions "stables", dont les résultats (pour les intrants fixes) ne changent pas dans une analyse.
J'ai également ajouté les types d'arguments de la fonction ("any"
) pour vous connecter aux réponses de @Dezso et @jjanes, qui fournissent la justification de la décision de rendre cette fonction uniquement stable. Et le nom de la fonction interne (text_concat
).
Voici une question connexe pour illustrer pourquoi l'immuabilité des expressions d'index est une condition sinon non condition:
En ce qui concerne l'utilisation de l'opérateur ||
:
SELECT o.oprname, o.oprleft::regtype, o.oprright::regtype, o.oprcode, p.provolatile
FROM pg_operator o
JOIN pg_proc p ON p.oid = o.oprcode
WHERE oprname = '||';
oprname | oprleft | oprright | oprcode | provolatile
---------+-------------+-------------+-----------------+-------------
|| | anyarray | anyelement | array_append | i
|| | anyelement | anyarray | array_prepend | i
|| | anyarray | anyarray | array_cat | i
|| | text | text | textcat | i
|| | bit varying | bit varying | bitcat | i
|| | bytea | bytea | byteacat | i
|| | text | anynonarray | textanycat | s
|| | anynonarray | text | anytextcat | s
|| | tsvector | tsvector | tsvector_concat | i
|| | tsquery | tsquery | tsquery_or | i
|| | jsonb | jsonb | jsonb_concat | i
La fonction à utiliser en interne dépend de la fonction de données réelle des opérandes. La définition d'un opérateur inclut les types de données des opérandes dans Postgres. Toutes les fonctions sont différentes et différentes de text_concat
ci-dessus. ||
est également stable, lorsque l'un des opérateurs est anynonarray
. Les choses ne sont pas si triviales derrière les rideaux.
character varying(256)
(comme n'importe quel varchar
variante) est Binary-coercable à text
SO résolution de type fonction par défaut à text
.
Je crois que Concat, défini dans la documentation comme suit:
FUNCTION RETURN TYPE DESCRIPTION
-----------------------------------------------------------------------------------
concat(str "any" [, str "any" [, ...] ]) text Concatenate the text repre-
sentations of all the arguments.
NULL arguments are ignored.
n'est pas immuable car la représentation de texte peut dépendre des paramètres de la base de données, comme celle d'une date ou d'un horodatage .
Pour remplir la réponse de DEZSO, voici un exemple de la même entrée produisant différentes sorties en fonction de l'état de la base de données:
select concat(1.0000000000003::float8,56);
1.000000000000356
set extra_float_digits TO 3;
select concat(1.0000000000003::float8,56);
1.0000000000002999856