CREATE CAST — Définir un transtypage
CREATE CAST (type_source
AStype_cible
) WITH FUNCTIONnom_fonction
[ (type_argument
[, ...]) ] [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (type_source
AStype_cible
) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (type_source
AStype_cible
) WITH INOUT [ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST
définit un transtypage. Un transtypage
spécifie l'opération de conversion entre deux types de
données. Par exemple :
SELECT CAST(42 AS float8);
convertit la constante entière 42 en float8
en appelant
une fonction précédemment définie, float8(int4)
dans le cas
présent (si aucun transtypage convenable n'a été défini, la conversion échoue).
Deux types peuvent être coercibles binairement,
ce qui signifie que le transtypage peut être fait « gratuitement »
sans invoquer aucune fonction. Ceci impose que les valeurs correspondantes
aient la même représentation interne. Par exemple, les types text
et
varchar
sont coercibles binairement dans les deux sens. La coercibilité
binaire n'est pas forcément une relation symétrique. Par exemple, le transtypage
du type xml
au type text
peut être fait gratuitement dans
l'implémentation actuelle, mais l'opération inverse nécessite une fonction qui fasse
au moins une validation syntaxique. (Deux types qui sont coercibles binairement dans
les deux sens sont aussi appelés binairement compatibles.)
Vous pouvez définir un transtypage comme transtypage I/O
en utilisant la syntaxe WITH INOUT
. Un transtype I/O est
effectué en appelant la fonction de sortie du type de données source, et en
passant la chaîne résultante à la fonction d'entrée du type de données
cible. Dans la plupart des cas, cette fonctionnalité évite d'avoir à écrire
une fonction de transtypage séparée pour la conversion. Un transtypage I/O
agit de la même façon qu'un transtypage standard basé sur une fonction. Seule
l'implémentation diffère.
Un transtypage peut être appelé explicitement.
Par exemple : CAST(
ou
x
AS
nomtype
)x
::
nomtype
.
Si le transtypage est marqué AS ASSIGNMENT
(NDT : à l'affectation),
alors son appel peut être
implicite lors de l'affectation d'une valeur à une colonne du
type de donnée cible. Par exemple, en supposant que
foo.f1
soit une colonne de type text
:
INSERT INTO foo (f1) VALUES (42);
est autorisé si la conversion du type integer
vers le type
text
est indiquée AS ASSIGNMENT
. Dans le cas contraire,
c'est interdit. Le terme de transtypage d'affectation
est utilisé pour décrire ce type de conversion.
Si la conversion est marquée AS IMPLICIT
, alors elle
peut être appelée implicitement dans tout contexte, soit par une affectation
soit en interne dans une expression (nous utilisons généralement le terme
conversion implicite pour décrire ce type de
conversion.)
Par exemple, voici une requête :
SELECT 2 + 4.0;
L'analyseur marque au début les constantes comme étant de type
integer
et numeric
respectivement. Il n'existe pas
d'opérateur integer
+
numeric
dans les catalogues systèmes mais il existe un opérateur
numeric
+
numeric
. La requête
sera un succès si une conversion de integer
vers
numeric
est disponible et marquée AS IMPLICIT
-- ce qui est le cas. L'analyseur appliquera la conversion implicite
et résoudra la requête comme si elle avait été écrite de cette façon :
SELECT CAST ( 2 AS numeric ) + 4.0;
Maintenant, les catalogues fournissent aussi une conversion de
numeric
vers integer
. Si cette conversion était
marquée AS IMPLICIT
-- mais ce n'est pas le cas
-- alors l'analyseur devra choisir entre l'interprétation ci-dessus et
son alternative (la conversion de la constante numeric
en un
integer
) et appliquer l'opérateur integer
+
integer
. Comme il n'a aucune information
qui lui permettrait de choisir le meilleur moyen, il abandonne et déclare la
requête comme étant ambigüe. Le fait qu'une seule des conversions est
indiquée comme implicite est le moyen par lequel nous apprenons à l'analyseur
de préférer la première solution (c'est-à-dire de transformer une expression
numeric
-and-integer
en
numeric
) ; il n'y a pas d'autre moyen.
Il est conseillé d'être conservateur sur le marquage du caractère implicite
des transtypages. Une surabondance de transtypages implicites peut conduire
PostgreSQL à interpréter étrangement des commandes,
voire à se retrouver dans l'incapacité totale de les résoudre parce que plusieurs
interprétations s'avèrent envisageables. Une bonne règle est de ne réaliser
des transtypages implicites que pour les transformations entre types de la
même catégorie générale et qui préservent l'information. Par exemple,
la conversion entre int2
et int4
peut être
raisonnablement implicite mais celle entre float8
et
int4
est probablement réservée à l'affectation. Les
transtypages inter-catégories, tels que de text
vers int4
,
sont préférablement exécutés dans le seul mode explicite.
Il est parfois nécessaire, pour des raisons de convivialité ou de respect des standards, de fournir plusieurs transtypages implicites sur un ensemble de types de données. Ceux-ci peuvent alors entraîner des ambiguités qui ne peuvent être évitées, comme ci-dessus. L'analyseur possède pour ces cas une heuristique de secours s'appuyant sur les catégories de types et les types préférés, qui peut aider à fournir le comportement attendu dans ce genre de cas. Voir CREATE TYPE pour plus de détails.
Pour créer un transtypage, il faut être propriétaire
du type source ou destination et avoir le droit USAGE
sur l'autre type. Seul le super-utilisateur peut créer
un transtypage binairement compatible (une erreur sur un tel transtypage
peut aisément engendrer un arrêt brutal du serveur).
typesource
Le nom du type de donnée source du transtypage.
typecible
Le nom du type de donnée cible du transtypage.
nom_fonction
[(type_argument
[, ...])]
La fonction utilisée pour effectuer la conversion. Le nom de la fonction peut être qualifié du nom du schéma. Si ce n'est pas le cas, la fonction est recherchée dans le chemin des schémas. Le type de données résultant de la fonction doit correspondre au type cible du transtypage. Ses arguments sont explicités ci-dessous. Si aucune liste d'arguments n'est spécifiée, le nom de la fonction doit être unique dans son schéma.
WITHOUT FUNCTION
Indication d'une compatibilité binaire entre le type source et le type cible pour qu'aucune fonction ne soit requise pour effectuer la conversion.
WITH INOUT
Inique que le transtypage est un transtypage I/O, effectué en appelant la fonction de sortie du type de données source, et en passant la chaîne résultante à la fonction d'entrée du type de données cible.
AS ASSIGNMENT
Lors d'une affectation, l'invocation du transtypage peut être implicite.
AS IMPLICIT
L'invocation du transtypage peut être implicite dans tout contexte.
Les fonctions de transtypage ont un à trois arguments. Le
premier argument est du même type que le type source ou doit être compatible
avec ce type. Le deuxième argument, si fourni,
doit être de type integer
. Il stocke le modificateur de type associé au type de
destination, ou -1
en l'absence de modificateur. Le troisième
argument, si fourni, doit être de type boolean
. Il vaut
true
si la conversion est explicite, false
dans le
cas contraire. Bizarrement, le standard SQL appelle des comportements
différents pour les transtypages explicites et implicites dans certains
cas. Ce paramètre est fourni pour les fonctions qui implémentent
de tel transtypages. Il n'est pas recommandé de concevoir des types de
données utilisateur entrant dans ce cas de figure.
Le type de retour d'une fonction de transtypage doit être identique ou coercible binairement avec le type cible du transtypage.
En général, un transtypage correspond à des type source et destination différents. Cependant, il est permis de déclarer un transtypage entre types source et destination identiques si la fonction de transtypage a plus d'un argument. Cette possibilité est utilisée pour représenter dans le catalogue système des fonctions de transtypage agissant sur la longueur d'un type. La fonction nommée est utilisée pour convertir la valeur d'un type à la valeur du modificateur de type fournie par le second argument.
Quand un transtypage concerne des types source et destination différents et que la fonction a plus d'un argument, le transtypage et la conversion de longueur du type destination sont faites en une seule étape. Quand une telle entrée n'est pas disponible, le transtypage vers un type qui utilise un modificateur de type implique deux étapes, une pour convertir les types de données et la seconde pour appliquer le modificateur.
Le transtypage du ou vers le type d'un domaine n'a actuellement pas d'effet. Transtyper d'un ou vers un domaine utilise le transtypage associé avec son type sous-jacent.
DROP CAST
est utilisé
pour supprimer les transtypages utilisateur.
Pour convertir les types dans les deux sens, il est obligatoire de déclarer explicitement les deux sens.
Il est n'est pas nécessaire habituellement de créer des conversions entre des types
définis par l'utilisateur et des types de chaîne standards (text
,
varchar
etchar(
, pas plus
que pour des types définis par l'utilisateur définis comme entrant dans la catégorie
des chaînes).
PostgreSQL fournit un transtypage I/O automatique pour cela.
Ce transtypage automatique vers des types chaînes est traité comme des transtypages
d'affectation, alors que les transtypages automatiques à partir de types chaîne sont
de type explicite seulement.
Vous pouvez changer ce comportement en déclarant votre propre conversion
pour remplacer une conversion automatique. La seule raison usuelle
de le faire est de vouloir rendre l'appel de la conversion plus simple que le paramétrage
standard (affectation seulement ou explicite seulement).
Une autre raison envisageable
est de vouloir que la conversion se comporte différement de la fonction
I/O du type ; mais c'est suffisamment déroutant pour que vous y pensiez
à deux fois avant de le faire. (Un petit nombre de types internes ont
en fait des comportements différents pour les conversions, principalement
à cause des besoins du standard SQL.)
n
)
Bien que cela ne soit pas requis, il est recommandé de
suivre l'ancienne convention de nommage des fonctions de transtypage
en fonction du type de données de destination. Beaucoup d'utilisateurs sont
habitués à convertir des types de données à l'aide d'une notation
de style fonction, c'est-à-dire
nom_type
(x
). En fait, cette
notation n'est ni plus ni moins qu'un appel à la fonction d'implantation du transtypage ;
sa gestion n'est pas spécifique à un transtypage. Le non-respect de cette convention peut
surprendre certains utilisateurs. Puisque
PostgreSQL permet de surcharger un même nom de fonction avec
différents types d'argument, il n'y a aucune difficulté à avoir plusieurs
fonctions de conversion vers des types différents qui utilisent toutes le même
nom de type destination.
En fait, le paragraphe précédent est une sursimplification : il existe
deux cas pour lesquels une construction d'appel de fonction sera traitée
comme une demande de conversion sans qu'il y ait correspondance avec une
fonction réelle. Si un appel de fonction
nom
(x
) ne correspond
pas exactement à une fonction existante, mais que
nom
est le nom d'un type de données et que
pg_cast
fournit une conversion compatible
binairement vers ce type à partir du type x
,
alors l'appel sera construit à partir de la conversion compatible
binairement. Cette exception est faite pour que les conversions compatibles
binairement puissent être appelées en utilisant la syntaxe fonctionnelle,
même si la fonction manque. De ce fait, s'il n'y pas d'entrée dans
pg_cast
mais que la conversion serait à partir de
ou vers un type chaîne, l'appel sera réalisé avec une conversion I/O.
Cette exception autorise l'appel de conversion I/O en utilisant la syntaxe
fonctionnelle.
Il existe aussi une exception à l'exception : le transtypage I/O
convertissant des types composites en types chaîne de caractères ne peut
pas être appelé en utilisant la syntaxe fonctionnelle, mais doit être
écrite avec la syntaxe de transtypage explicite (soit
CAST
soit ::
). Cette exception a été
ajoutée car, après l'introduction du transtypage I/O automatique, il était
trop facile de provoquer par erreur une telle conversion alors que l'intention
était de référencer une fonction ou une colonne.
Création d'un transtypage d'affectation du type bigint
vers le type
int4
à l'aide de la fonction
int4(bigint)
:
CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;
(Ce transtypage est déjà prédéfini dans le système.)
La commande CREATE CAST
est conforme à SQL
à ceci près que SQL ne mentionne pas les types binairement compatibles et les arguments
supplémentaires pour les fonctions d'implantation. AS IMPLICIT
est aussi une extension PostgreSQL.