Si un nom de schéma est précisé, le type est créé dans ce schéma.
Sinon, il est créé dans le schéma courant. Le nom du type doit être
distinct du nom de tout type ou domaine existant dans le même
schéma. Les tables possèdent des types de données associés. Il est
donc nécessaire que le nom du type soit également distinct du nom
de toute table existant dans le même schéma.
Types de base
La seconde forme de
CREATE
TYPE
crée un nouveau type de base (type
scalaire). L'ordre des paramètres, dont la plupart sont
optionnels, n'a aucune d'importance. Avant de définir le type, il
est nécessaire de définir au moins deux fonctions (à l'aide de la
commande
CREATE
FUNCTION
). Les fonctions de support
fonction_entrée
et
fonction_sortie
sont obligatoires.
Les fonctions
fonction_réception
,
fonction_envoi
et
fonction_analyse
sont optionnelles.
Généralement, ces fonctions sont codées en C ou dans un autre
langage de bas niveau.
La
fonction_entrée
convertit la représentation textuelle externe du type en
représentation interne utilisée par les opérateurs et fonctions
définis pour le type. La
fonction_sortie
réalise la
transformation inverse. La fonction entrée peut être déclarée
avec un argument de type cstring ou
trois arguments de types cstring,
oid, integer.
Le premier argument est le texte en entrée sous la forme d'une
chaîne C, le second argument est l'OID du type (sauf dans le cas
des types tableau où il s'agit de l'OID du type de l'élément) et
le troisième est le typmod de la colonne
destination, s'il est connu (-1 sinon). La fonction entrée doit
renvoyer une valeur du nouveau type de données. Habituellement,
une fonction d'entrée devrait être déclarée comme STRICT si ce
n'est pas le cas, elle sera appelée avec un premier paramètre
NULL à la lecture d'une valeur NULL en entrée. La fonction doit
toujours envoyer NULL dans ce cas, sauf si une erreur est
rapportée. (Ce cas a pour but de supporter les fonctions d'entrée
des domaines qui ont besoin de rejeter les entrées NULL.) La
fonction sortie doit prendre un argument du nouveau type de
données, et retourner le type cstring.
Les fonctions sortie ne sont pas appelées pour des valeurs NULL.
La
fonction_réception
,
optionnelle, convertit la représentation binaire externe du type
en représentation interne. Si cette fonction n'est pas fournie,
le type n'accepte pas d'entrée binaire. La représentation binaire
est choisie de telle sorte que sa conversion en forme interne
soit peu coûteuse, tout en restant portable. (Par exemple, les
types de données standard entiers utilisent l'ordre réseau des
octets comme représentation binaire externe alors que la
représentation interne est dans l'ordre natif des octets de la
machine.) La fonction de réception réalise les vérifications
adéquates pour s'assurer que la valeur est valide. Elle peut être
déclarée avec un argument de type internal ou trois arguments de types internal, integer et
oid. Le premier argument est un
pointeur vers un tampon StringInfo qui
contient la chaîne d'octets reçue ; les arguments optionnels sont
les mêmes que pour la fonction entrée de type texte. La fonction
de réception retourne une valeur du type de données.
Habituellement, une fonction de réception devrait être déclarée
comme STRICT si ce n'est pas le cas, elle sera appelée avec un
premier paramètre NULL à la lecture d'une valeur NULL en entrée.
La fonction doit toujours envoyer NULL dans ce cas, sauf si une
erreur est rapportée. (Ce cas a pour but de supporter les
fonctions de réception des domaines qui ont besoin de rejeter les
entrées NULL.) De façon similaire, la
fonction_envoi
, optionnelle,
convertit la représentation interne en représentation binaire
externe. Si cette fonction n'est pas fournie, le type n'accepte
pas de sortie binaire. La fonction d'envoi doit être déclarée
avec un argument du nouveau type de données et retourner le type
bytea. Les fonctions réception ne sont
pas appelées pour des valeurs NULL.
À ce moment-là, vous pouvez vous demander comment les fonctions
d'entrée et de sortie peuvent être déclarées avoir un résultat ou
un argument du nouveau type alors qu'elles sont à créer avant que
le nouveau type ne soit créé. La réponse est que le type sera
tout d'abord défini en tant que type
squelette (
shell type
), une ébauche de type sans
propriété à part un nom et un propriétaire. Ceci se fait en
exécutant la commande CREATE TYPE
nom
sans paramètres
supplémentaires. Ensuite, les fonctions d'entrée/sortie peuvent
être définies en référençant le squelette. Enfin, le
CREATE TYPE
avec une définition
complète remplace le squelette avec une définition complète et
valide du type, après quoi le nouveau type peut être utilisé
normalement.
La
fonction_analyse
,
optionnelle, calcule des statistiques spécifiques au type de
données pour les colonnes de ce type. Par défaut,
ANALYZE
tente de récupérer des
statistiques à l'aide des opérateurs d'« égalité » et d'« infériorité » du type, s'il existe une classe
d'opérateur B-tree par défaut pour le type. Ce comportement est
inadapté aux types non-scalaires ; il peut être surchargé à
l'aide d'une fonction d'analyse personnalisée. La fonction
d'analyse doit être déclarée avec un seul argument de type
internal et un résultat de type
boolean. L'API détaillée des fonctions
d'analyses est présentée dans src/include/commands/vacuum.h.
Alors que les détails de la représentation interne du nouveau
type ne sont connus que des fonctions d'entrées/sorties et des
fonctions utilisateurs d'interaction avec le type, plusieurs
propriétés de la représentation interne doivent être déclarées à
PostgreSQL™. La première
est
longueurinterne
. Les
types de données basiques peuvent être de longueur fixe (dans ce
cas,
longueurinterne
est un
entier positif) ou de longueur variable (indiquée par le
positionnement de
longueurinterne
à VARIABLE ; en interne, cela est représenté en
initialisant typlen à -1). La
représentation interne de tous les types de longueur variable
doit commencer par un entier de quatre octets indiquant la
longueur totale de cette valeur.
Le drapeau optionnel PASSEDBYVALUE
indique que les valeurs de ce type de données sont passées par
valeur plutôt que par référence. Les types dont la représentation
interne est plus grande que la taille du type Datum (quatre octets sur la plupart des machines,
huit sur quelques-unes) ne doivent pas être passés par valeur.
Le paramètre
alignement
spécifie l'alignement de stockage requis pour le type de données.
Les valeurs permises sont des alignements sur 1, 2, 4 ou 8
octets. Les types de longueurs variables ont un alignement d'au
moins quatre octets car leur premier composant est nécessairement
un int4.
Le paramètre
stockage
permet de choisir une stratégie de stockage pour les types de
données de longueur variable. (Seul plain est autorisé pour les types de longueur
fixe.) plain indique des données
stockées en ligne et non compressées. Dans le cas d'extended le système essaie tout d'abord de
compresser une valeur longue et déplace la valeur hors de la
ligne de la table principale si elle est toujours trop longue.
external permet à la valeur d'être
déplacée hors de la table principale mais le système ne tente pas
de la compresser. main autorise la
compression mais ne déplace la valeur hors de la table principale
qu'en dernier recours. (Ils seront déplacés s'il n'est pas
possible de placer la ligne dans la table principale, mais sont
préférentiellement conservés dans la table principale,
contrairement aux éléments extended et
external.)
Une valeur par défaut peut être spécifiée dans le cas où
l'utilisateur souhaite que cette valeur soit différente de NULL
pour les colonnes de ce type. La valeur par défaut est précisée à
l'aide du mot clé DEFAULT. (Une telle
valeur par défaut peut être surchargée par une clause DEFAULT explicite attachée à une colonne
particulière.)
Pour indiquer qu'un type est un tableau, le type des éléments du
tableau est précisé par le mot clé ELEMENT. Par exemple, pour définir un tableau
d'entiers de quatre octets (int4),
ELEMENT = int4 est utilisé. Plus de
détails sur les types tableau apparaissent ci-dessous.
Pour préciser le délimiteur de valeurs utilisé dans la
représentation externe des tableaux de ce type,
délimiteur
peut être positionné à un
caractère particulier. Le délimiteur par défaut est la virgule
(,). Le délimiteur est associé avec le
type élément de tableau, pas avec le type tableau.