CREATE TYPE

Nom

CREATE TYPE -- définit un nouveau type de donnée

Synopsis

CREATE TYPE nom AS
    ( nom_attribut type_donnée [, ... ] )

CREATE TYPE nom (
    INPUT = fonction_entrée,
    OUTPUT = fonction_sortie
    [ , RECEIVE = fonction_réception ]
    [ , SEND = fonction_envoi ]
    [ , INTERNALLENGTH = { longueurinterne | VARIABLE } ]
    [ , PASSEDBYVALUE ]
    [ , ALIGNMENT = alignement ]
    [ , STORAGE = stockage ]
    [ , DEFAULT = défaut ]
    [ , ELEMENT = élément ]
    [ , DELIMITER = délimiteur ]
)

Description

CREATE TYPE enregistre un nouveau type de données à utiliser dans la base de données actuelle. L'utilisateur qui définit un type devient son propriétaire.

Si un nom de schéma est donné, alors le type est créé dans le schéma spécifié. Sinon, il est créé dans le schéma courant. Le nom du type doit être distinct du nom des types ou domaines existants dans le même schéma. (Comme les tables ont des types de données associés, le nom du type doit aussi être distinct du nom de toute table existante dans le même schéma.)

Types composés

La première forme CREATE TYPE crée un type composite. Le type composé est spécifié par une liste de noms d'attributs et de types de données. Ceci est essentiellement le même que le type row d'une table mais utiliser CREATE TYPE évite le besoin de créer une table réelle quand tout ce qui est souhaité est la définition d'un type. Un type composite autonome est utile comme type de retour d'une fonction.

Types de base

La seconde forme CREATE TYPE crée un nouveau type de base (type scalaire). Les paramètres pourraient apparaître dans n'importe quel ordre, pas seulement celui illustré ci-dessus, et la plupart sont optionnels. Vous devez enregistrer au moins deux fonctions (en utilisant CREATE FUNCTION) avant de définir le type. Les fonctions de support fonction_entrée et fonction_sortie sont requises alors que les fonctions fonction_réception et fonction_envoi sont optionnelles. Généralement, ces fonctions doivent être codées en C ou dans un autre langage de bas niveau.

La fonction_entrée convertit la représentation textuelle externe du type avec la représentation interne utilisée par les opérateurs et fonctions définis pour le type. fonction_sortie réalise la transformation inverse. La fonction en entrée pourrait être déclarée comme prenant un argument de type cstring ou comme prenant trois arguments de types cstring, oid, integer. Le premier argument est le texte en entrée en tant que chaîne C, le second argument est le type d'élément dans le cas où il s'agit d'un type tableau et le troisième est le typmod de la colonne destination, s'il est connu. La fonction en entrée devrait renvoyer une valeur du type de données lui-même. La fonction en sortie pourrait être déclarée comme prenant un argument du nouveau type de données ou comme prenant deux arguments dont le second est de type oid. Le second argument est de nouveau le type d'élément de tableau pour les types tableau. La fonction de sortie devrait renvoyer le type cstring.

La fonction_réception optionnelle convertit la représentation binaire externe du type vers la représentation interne. Si cette fonction n'est pas fournie, le type ne peut pas participer à l'entrée binaire. La représentation binaire devrait être choisie pour être peu coûteuse sur la conversion vers la forme interne tout en étant raisonnablement 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 devrait réaliser des vérifications adéquates pour s'assurer que la valeur est valide. La fonction de réception pourrait être déclarée comme prenant un argument de type internal ou deux arguments de types internal et oid. Elle doit renvoyer une valeur de type de données lui-même. (Le premier argument est un pointeur vers un tampon StringInfo contenant la chaîne d'octets reçus ; le second argument optionnel est le type d'élément dans le cas où il s'agit d'un tableau.) De façon similaire, la fonction_envoi optionnelle convertit à partir de la représentation interne vers la représentation binaire externe. Si cette fonction n'est pas fournie, le type ne peut pas participer dans la sortie binaire. La fonction d'envoi pourrait être déclarée comme prenant un argument du nouveau type de données ou comme prenant deux arguments dont le second est de type oid. Le second argument est encore le type d'élément du tableau pour les types tableau. La fonction d'envoi doit renvoyer le type bytea.

Maintenant, vous devriez vous demander comment les fonctions d'entrée et de sortie peuvent être déclarées pour avoir des résultats ou des arguments du nouveau type avant que le nouveau type soit créé. La réponse est que la fonction en entrée doit être créée en premier, puis la fonction de sortie (et les fonctions d'entrées/sorties binaires si souhaitées) et enfin le type de données. PostgreSQL verra tout d'abord le nom du nouveau type de données comme type de retour de la fonction en entrée. Il créera un type << shell >>, qui est une simple entrée d'emplacement dans le catalogue système et lie la définition de fonction en entrée au type de shell. De façon similaire, les autres fonctions seront liées au (maintenant déjà existant) type de shell. Enfin, CREATE TYPE remplace l'entrée de shell avec une définition complète du type et le nouveau type peut être utilisé.

Alors que les détails de la représentation interne du nouveau type sont seulement connus des fonctions d'entrées/sorties et des autres fonctions que vous créez pour travailler avec le type, il existe plusieurs propriétés de représentation interne devant être déclarées à PostgreSQL. En premier lieu se trouve longueurinterne. Les types de données de base peuvent avoir une longueur fixe auquel cas longueurinterne est un entier positif, ou une longueur variable, indiquée en initialisant longueurinterne à VARIABLE. (En interne, ceci est représenté en initialisant typlen à -1.) La représentation interne de tous les types de longueur variable doit commencer avec un entier de quatre octets donnant la longueur totale de cette valeur du type.

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. Vous pourriez ne pas passer par les types de valeurs dont la représentation interne est plus importante que la taille du type Datum (quatre octets sur la plupart des machines, huit sur quelques-unes).

Le paramètre alignement spécifie l'alignement de stockage requis pour le type de données. Les valeurs permises ont un alignement sur les limites de 1, 2, 4 ou 8 octets. Notez que les types de longueurs variables doivent avoir un alignement d'au moins quatre octets car ils contiennent nécessairement un int4 comme premier composant.

Le paramètre stockage permet la sélection de stratégies de stockage pour des types de données de longueur variable. (Seul plain est autorisé pour les types de longueur fixe.) plain spécifie que les données du type seront toujours stockées en ligne et non compressées. extended spécifie que le système essaiera tout d'abord de compresser une valeur longue de données et déplacera la valeur en dehors de la ligne de la table principale si elle est trop longue. external permet à la valeur d'être déplacée hors de la table principale mais le système ne tentera pas de la compresser. main autorise la compression mais décourage le déplacement de la valeur en dehors de la table principale. (Les éléments de données avec cette stratégie de stockage pourraient toujours être déplacés hors de la table principale s'il n'y a pas d'autres moyens d'y placer une ligne mais ils seront conservés de préférence dans la table principale sur les éléments extended et external.)

Une valeur par défaut pourrait être spécifiée dans le cas où l'utilisateur souhaite que les colonnes du type de données aient pour valeur par défaut une valeur autre que NULL. Spécifiez la valeur par défaut avec le mot clé DEFAULT. (Une telle valeur par défaut peut être surchargée par une clause DEFAULT explicite attachée dans une colonne particulière.)

Pour indiquer qu'un type est un tableau, spécifiez le type des éléments du tableau en utilisant le mot clé ELEMENT. Par exemple, pour définir un tableau d'entiers de quatre octets (int4), spécifiez ELEMENT = int4. Plus de détails sur les types tableau apparaissent ci-dessous.

Pour indiquer le délimiteur à utiliser entre les valeurs dans la représentation externe des tableaux de ce type, délimiteur peut être configuré à un caractère particulier. Le délimiteur par défaut est la virgule (,). Notez que le délimiteur est associé avec le type d'élément de tableau, pas le type tableau lui-même.

Types de tableaux

À chaque fois qu'un type de données de base défini par un utilisateur est créé, PostgreSQL crée automatiquement un type tableau associé dont le nom consiste du nom du type de base précédé d'un tiret base. L'analyseur comprend cette convention de nommage et traduit les requêtes pour les colonnes de type foo[] en requêtes pour le type _foo. Le type tableau créé implicitement est de longueur variable et utilise les fonctions entrée et sortie intégrée array_in et array_out.

Vous pourriez raisonnablement vous demander pourquoi il existe une option ELEMENT si le système fabrique automatiquement le bon type tableau. Le seul cas où il est utile d'utiliser ELEMENT est lorsque vous réalisez un type de longueur fixe qui est en interne un tableau d'un nombre identique d'éléments et que vous souhaitez autoriser ces éléments à accéder directement aux indices, en plus de toute autre opération que vous pensiez fournir pour le type dans sa globalité. Par exemple, le type name permet à ses éléments char constituants d'être accessible de cette façon. Un type point en 2-D pourrait autoriser les deux numéros de composant à être accédé ainsi : point[0] et point[1]. Notez que cette fonctionnalité fonctionne uniquement avec les types de longueur fixe dont la forme interne est exactement une séquence de champs de longueur variable. Un type longueur de variable à indice doit avoir la représentation interne généralisée utilisée par array_in et array_out. Pour des raisons historiques (c'est-à-dire qu'il est clairement mauvais parce qu'il est trop tard pour changer) s'abonner à des types de longueur variable commence à partir de zéro plutôt que de un pour les tableaux de longueur variable.

Paramètres

nom

Le nom d'un type à créer (pouvant être qualifié par le nom du schéma).

nom_attribut

Le nom d'un attribut (colonne) pour le type composé.

type_données

Le nom d'un type de données existant qui deviendra une colonne du type composé.

fonction_entrée

Le nom d'une fonction qui convertit les données à partir de la forme textuelle externe du type en sa forme interne.

fonction_sortie

Le nom d'une fonction qui convertit les données à partir de la forme interne du type dans sa forme textuelle externe.

fonction_réception

Le nom d'une fonction qui convertit la forme binaire externe du type dans sa forme interne.

fonction_envoi

Le nom d'une fonction qui convertit les données à partir de la forme interne du type dans sa forme binaire externe.

longueurinterne

Une constante numérique qui spécifie la longueur en octets de la représentation interne du nouveau type. La supposition par défaut est que la longueur est variable.

alignement

Le besoin d'alignement du stockage du type de données. Si spécifié, il doit être parmi char, int2, int4 ou double ; par défaut, il s'agit d'int4.

stockage

La stratégie de stockage pour le type de données. Si spécifiée, elle doit faire partie de plain, external, extended ou main ; la valeur par défaut est plain.

défaut

La valeur par défaut pour le type de données. Si elle est omise, elle est NULL.

élément

Le type en cours de création est un tableau ; ceci spécifie le type des éléments du tableau.

délimiteur

Le caractère délimiteur à utiliser entre les valeurs des tableaux de ce type.

Notes

Les noms de types définis par l'utilisateur ne peuvent pas commencer avec un tiret bas (_) et ont une longueur maximale de 62 caractères (ou en général NAMEDATALEN - 2, plutôt que NAMEDATALEN - 1 caractères autorisés pour les autres noms). Les noms de types commençant avec un tiret bas sont réservés par les noms de type tableau créés en interne.

Dans les versions de PostgreSQL antérieures à la 7.3, il était coutumier d'éviter de créer un type shell en remplaçant les références des fonctions au nom du type avec le pseudotype opaque. Les arguments cstring et les résultats doivent aussi être déclarés comme opaque avant la 7.3. Pour supporter le chargement d'anciens fichiers de sauvegarde, CREATE TYPE acceptera les fonctions déclarées avec opaque mais il affichera un message d'avertissement et modifiera la déclaration de la fonction pour utiliser les bons types.

Exemples

Cet exemple crée un type composite et l'utilise dans la définition d'une fonction :

CREATE TYPE compfoo AS (f1 int, f2 text);
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS
  'SELECT fooid, fooname FROM foo' LANGUAGE SQL;

Cet exemple crée le type de données de base box, puis l'utilise dans une définition de table :

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = ma_fonction_entree_box,
    OUTPUT = ma_fonction_sortie_box
);

CREATE TABLE myboxes (
    id integer,
    description box
);

Si la structure interne de box était un tableau de quatre éléments float4, nous pourrions faire

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = ma_fonction_entree_box,
    OUTPUT = ma_fonction_sortie_box,
    ELEMENT = float4
);

ce qui permettrait un accès aux nombres composant la valeur d'une boîte avec les indices. Sinon, le type se comporte de la même façon qu'avant.

Cet exemple crée un objet large et l'utilise dans une définition de table :

CREATE TYPE bigobj (
    INPUT = lo_filein, OUTPUT = lo_fileout,
    INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
    id integer,
    obj bigobj
);

Vous trouverez plus d'exemples, intégrant des fonctions intéressantes en entrée et en sortie, dans Chapitre 33.

Compatibilité

Cette commande CREATE TYPE est une extension PostgreSQL. Il existe une instruction CREATE TYPE dans SQL99 qui est plutôt différente dans le détail.

Voir aussi

CREATE FUNCTION, DROP TYPE