33.2. Système de typage de PostgreSQL

Les types de données de PostgreSQL sont répartis en types de base, types composé, types de domaine et pseudo-types.

Les types de base sont ceux qui, comme int4, sont implémentés sous le niveau du langage SQL (typiquement dans un langage de bas niveau comme le C). Ils correspondent généralement à ce qui est souvent connu comme des types de données abstraits. PostgreSQL peut opérer sur de tels types seulement au moyen de fonctions fournies par l'utilisateur et n'en comprend le fonctionnement que dans la mesure où l'utilisateur les décrit. Les types de base sont divisés en types scalaires et types tableaux. Pour chaque type scalaire, un type tableau est automatiquement créé. Ce type tableau peut contenir des tableaux à taille variable du type scalaire correspondant.

Les types composés, ou types lignes, sont créés chaque fois qu'un utilisateur crée une table ; il est aussi possible de définir un type composé autonome sans table associée. Un type composé est simplement une liste de types de base avec des noms de champs associés. Une valeur pour un type composé correspond à une ligne ou un enregistrement de valeurs de champ. L'utilisateur peut accéder à ces champs à partir de requêtes SQL.

Un type de domaine est basé sur un type de base particulier et il est interchangeable à de multiples fins avec son type de base. Toutefois, un domaine peut avoir des contraintes qui restreignent ses valeurs valides à un sous-ensemble de ce qui est permis par le type de base sous-jacent. Les domaines peuvent être créés par de simples commandes SQL.

Enfin, il existe quelques << pseudo-types >> pour des besoins particuliers. Les pseudo-types ne peuvent pas apparaître comme des champs de table ou des types composés, mais ils peuvent être utilisés pour déclarer les types des arguments et des résultats de fonctions. Dans le système de typage, ils fournissent un mécanisme pour identifier des classes spéciales de fonctions. La Tableau 8-20 donne la liste des pseudo-types existants.

33.2.1. Types et fonctions polymorphes

Deux pseudo-types particulièrement intéressants sont anyelement et anyarray, collectivement appelés types polymorphes. Toute fonction déclarée utilisant ces types est dite fonction polymorphe. Une fonction polymorphe peut opérer sur de nombreux et différents types de données, les types de données spécifiques étant déterminés par les types des données réellement passés lors d'un appel particulier de la fonction.

Les arguments et les résultats polymorphes sont liés les uns aux autres et sont résolus dans un type de données spécifique quand une requête faisant appel à une fonction polymorphe est analysée. Chaque occurrence déclarée comme anyelement (soit argument, soit valeur renvoyée par la fonction) peut prendre n'importe quel type réel de données mais, lors d'un appel de fonction donné, elles doivent toutes avoir le même type réel. Chaque occurrence déclarée comme anyarray peut prendre n'importe quel type de données tableau mais, de la même façon, elles doivent toutes être du même type. Si des occurrences sont déclarées comme anyarray et d'autres comme anyelement, le type de tableau réel des occurrences anyarray doit être un tableau dont les éléments sont du même type que ceux apparaissant dans les occurrences de type anyelement.

Ainsi, quand plus d'une occurrence d'argument est déclarée avec un type polymorphe, l'effet direct est que seulement certaines combinaisons de types réels d'argument sont autorisées. Par exemple, une fonction déclarée comme foo(anyelement, anyelement) prendra en argument n'importe quelles valeurs en argument à condition qu'elles soient du même type de données.

Quand la valeur renvoyée par une fonction est déclarée de type polymorphe, il doit exister au moins une occurrence d'argument également polymorphe, et le type réel de donnée passé comme argument détermine le type réel de résultat renvoyé lors de cet appel à la fonction. Par exemple, s'il n'existait pas déjà un mécanisme d'extraction d'éléments (indexation) de tableau, on pourrait définir une fonction qui implémente ce mécanisme comme ceci : indice(anyarray, integer) returns anyelement. La déclaration de fonction contraint le premier argument réel à être de type tableau et permet à l'analyseur d'inférer le type correct de résultat à partir du type réel du premier argument.

33.2.2. Types de base

Les types de base sont ceux implémentés avant le langage SQL comme int4 (typiquement dans un langage de bas niveau comme le C). Ils correspondent généralement à ce qu'on nomme les types de données abstraits. PostgreSQL peut opérer avec de tels types seulement au travers de fonctions apportées par l'utilisateur et comprend uniquement le comportement de tels types par la description qu'en a fait l'utilisateur. Les types de base sont ensuite sous-divisés en types scalaires et tableaux. Pour chaque type scalaire, un type de tableau correspondant est automatiquement créé, pouvant contenir des tableaux à la taille des variables de ce type scalaire.

33.2.3. Types composites

Les types composites, ou types lignes, sont crées lorsqu'un utilisateur crée une table ; il est aussi possible de définir un type composite se suffisant à lui-même (<< stand-alone >>) sans table associée. Un type composite est simplement une liste de types de base avec les noms des champs associés. Une valeur d'un type composite est une ligne ou un enregistrement de champs. L'utilisateur peut accéder aux champs du composant à partir de requêtes SQL.

33.2.4. Domaines

Un domaine est basé sur un type de base particulier et est interchangeable pour de nombreux buts avec son type de base. Néanmoins, un domaine pourrait avoir des contraintes restreignant ses valeurs valides à un sous-ensemble du type de base de départ.

Les domaines peuvent être créés avec les commandes SQL CREATE DOMAIN. Leur création et utilisation ne sont pas discutées dans ce chapitre.

33.2.5. Pseudo-Types

Il existe quelques << pseudo-types >> pour certains buts très spécifiques. Les pseudo-types ne peuvent pas apparaître comme colonnes de tables ou d'attributs de types composés, mais peuvent être utilisés pour déclarer les types d'argument ou de résultat de fonctions. Cela fournit un mécanisme à l'intérieur du système de types pour identifier les classes spéciales de fonctions. Le Tableau 8-20 liste les pseudos-types existants.

33.2.6. Types polymorphiques

Deux pseudo-types d'un grand intérêt sont anyelement et anyarray, collectivement appelés des types polymorphiques. Toute fonction déclarée utilisant ces types est dite être une fonction polymorphique. Une fonction polymorphique peut opérer sur différents types de données, les types de données spécifiques étant déterminés par les types de données réellement passés lors d'un appel particulier.

Les arguments et résultats polymorphiques sont liés les uns aux autres et sont modifiés en un type spécifique de données lorsqu'une requête appelant une fonction polymorphique est analysée. Chaque position (argument ou valeur de retour) déclarée en tant que anyelement est autorisée à avoir tout type de donnée spécifique mais, sur un seul appel, elles doivent toutes avoir le même type. Chaque position déclarée comme anyarray peut avoir n'importe quel type de données mais, de façon similaire, elles doivent toutes avoir le même type. Si des positions sont déclarées anyarray et d'autres anyelement, le type de tableau réel dans les positions anyarray doit être un tableau dont les éléments sont du même type que ceux des positions anyelement.

Du coup, lorsque plus d'un argument est déclaré polymorphique, l'effet est que seules certaines combinaisons de types d'argument sont autorisées. Par exemple, une fonction déclarée de cette façon foo(anyelement, anyelement) prendra seulement deux valeurs en entrées, à condition qu'elles soient du même type.

Lorsque la valeur de retour d'une fonction est déclarée polymorphique, il doit exister au moins un argument lui-aussi polymorphique et le type de données fourni en argument détermine le type de données du code de retour pour cet appel. Par exemple, s'il n'existait pas déjà un mécanisme d'abonnement d'un tableau, nous pourrions définir une fonction qui implémente cet abonnement avec subscript(anyarray, integer) returns anyelement. Cette déclaration contraint le premier argument à être de type tableau et permet à l'analyseur d'inférer le bon type de retour à partir du type du premier argument.