| 16 | | nouveaux types de données. Cette section décrit comment définir de nouveaux |
|---|
| 17 | | types de base, qui sont des types de données définis en-dessous du niveau du |
|---|
| 18 | | langage <acronym>SQL</>. Créer un nouveau type de base requiert |
|---|
| 19 | | l'implémentation de fonctions pour opérer sur le type dans un langage de base |
|---|
| 20 | | du niveau du C. |
|---|
| | 16 | nouveaux types de données. Cette section décrit la définition de nouveaux |
|---|
| | 17 | types basiques. Ces types de données sont définis en-dessous du |
|---|
| | 18 | <acronym>SQL</>. Créer un nouveau type requiert d'mplanter des |
|---|
| | 19 | fonctions dans un langage de bas niveau, généralement |
|---|
| | 20 | le C. |
|---|
| 38 | | Un type défini par l'utilisateur doit toujours avoir des fonctions d'entrée |
|---|
| 39 | | et de sortie. <indexterm><primary>fonction d'entrée</primary><secondary>d'un |
|---|
| 40 | | type de données</secondary></indexterm><indexterm><primary>fonction de sortie |
|---|
| 41 | | </primary><secondary>d'un type de données</secondary></indexterm>Ces |
|---|
| 42 | | fonctions déterminent comment le type apparaît dans les chaînes de caractères |
|---|
| 43 | | (pour l'entrée par l'utilisateur et le renvoi à l'utilisateur) et comment ce |
|---|
| 44 | | type est organisé en mémoire. La fonction d'entrée prend comme argument une |
|---|
| 45 | | chaîne de caractères terminée par NULL et renvoie la représentation interne |
|---|
| 46 | | (en mémoire) du type. La fonction de sortie prend comme argument la |
|---|
| 47 | | représentation interne du type et renvoie une chaîne de caractères terminée |
|---|
| 48 | | par NULL. Si vous voulez faire plus avec le type que simplement l'enregistrer, |
|---|
| 49 | | vous devez apporter des fonctions supplémentaires pour implémenter toutes |
|---|
| 50 | | opérations que vous souhaitez avoir pour ce type. |
|---|
| 51 | | </para> |
|---|
| 52 | | |
|---|
| 53 | | <para> |
|---|
| 54 | | Supposons que nous voulions définir un type <type>complex</> représentant les |
|---|
| 55 | | nombres complexes. Une façon naturelle de représenter un nombre complexe en |
|---|
| 56 | | mémoire serait la structure C suivante : |
|---|
| | 38 | Un type utilisateur doit toujours avoir des fonctions d'entrée et de sortie. |
|---|
| | 39 | <indexterm> |
|---|
| | 40 | <primary>fonction d'entrée</primary> |
|---|
| | 41 | <secondary>d'un type de données</secondary> |
|---|
| | 42 | </indexterm> |
|---|
| | 43 | <indexterm> |
|---|
| | 44 | <primary>fonction de sortie</primary> |
|---|
| | 45 | <secondary>d'un type de données</secondary> |
|---|
| | 46 | </indexterm> |
|---|
| | 47 | Ces fonctions déterminent la présentation du type en chaînes de caractères |
|---|
| | 48 | (pour l'entrée par l'utilisateur et le renvoi à l'utilisateur) et son |
|---|
| | 49 | organisation en mémoire. La fonction d'entrée prend comme argument une |
|---|
| | 50 | chaîne de caractères terminée par NULL et retourne la représentation interne |
|---|
| | 51 | (en mémoire) du type. La fonction de sortie prend en argument la |
|---|
| | 52 | représentation interne du type et retourne une chaîne de caractères terminée |
|---|
| | 53 | par NULL. |
|---|
| | 54 | </para> |
|---|
| | 55 | <para> |
|---|
| | 56 | Il est possible de faire plus que stocker un type, mais il faut pour cela |
|---|
| | 57 | implanter des fonctions supplémentaires gérant les opérations souhaitées. |
|---|
| | 58 | </para> |
|---|
| | 59 | |
|---|
| | 60 | <para> |
|---|
| | 61 | Soit le cas d'un type <type>complex</> représentant les nombres complexes. Une |
|---|
| | 62 | façon naturelle de représenter un nombre complexe en mémoire passe par la |
|---|
| | 63 | structure C suivante : |
|---|
| 65 | | Nous aurons besoin d'utiliser ce type par référence car il est trop important |
|---|
| 66 | | pour tenir sur une seule valeur <type>Datum</>. |
|---|
| 67 | | </para> |
|---|
| 68 | | |
|---|
| 69 | | <para> |
|---|
| 70 | | Comme représentation externe du type sous forme de chaîne, nous choisissons |
|---|
| 71 | | une chaîne de la forme <literal>(x,y)</literal>. |
|---|
| 72 | | </para> |
|---|
| 73 | | |
|---|
| 74 | | <para> |
|---|
| 75 | | Habituellement, les fonctions d'entrée et de sortie ne sont pas compliquées à |
|---|
| 76 | | écrire, surtout la fonction de sortie. Mais en définissant la représentation |
|---|
| 77 | | externe du type par une chaîne, souvenez-vous que vous devez éventuellement |
|---|
| 78 | | écrire un analyseur complet et robuste pour cette représentation en tant que |
|---|
| 79 | | fonction d'entrée. Par exemple : |
|---|
| | 72 | Ce type ne pouvant tenir sur une simple valeur <type>Datum</>, il sera passé |
|---|
| | 73 | par référence. |
|---|
| | 74 | </para> |
|---|
| | 75 | |
|---|
| | 76 | <para> |
|---|
| | 77 | La représentation externe du type se fera sous la forme du chaîne |
|---|
| | 78 | <literal>(x,y)</literal>. |
|---|
| | 79 | </para> |
|---|
| | 80 | |
|---|
| | 81 | <para> |
|---|
| | 82 | Les fonctions d'entrée et de sortie ne sont, en général, pas compliquées à |
|---|
| | 83 | écrire, particulièrement la fonction de sortie. |
|---|
| | 84 | Mais lors de la définition de la représentation externe du type par une chaîne de caractères, il faudra peut-être écrire un analyseur complet et robuste, comme fonction d'entrée, pour cette représentation. Par exemple : |
|---|
| 124 | | Vous devriez faire attention en écrivant des fonctions d'entrée et de sortie |
|---|
| 125 | | inverses l'une de l'autre. Sinon, vous aurez de graves problèmes quand vous |
|---|
| 126 | | aurez besoin de sauvegarder votre base de données dans un fichier et ensuite |
|---|
| 127 | | de le relire. Ceci est un problème particulièrement fréquent quand des nombres |
|---|
| 128 | | à virgule flottante sont concernés. |
|---|
| | 129 | Il est particulièrement important de veiller à ce que les fonctions d'entrée |
|---|
| | 130 | et de sortie soient bien inverses l'une de l'autre. Dans le cas contraire, |
|---|
| | 131 | de grosses difficultés pourraient apparaître lors de la sauvegarde |
|---|
| | 132 | de la base dans un fichier en vue d'une future relecture de ce fichier. |
|---|
| | 133 | Ceci est un problème particulièrement fréquent lorsque des nombres |
|---|
| | 134 | à virgule flottante entrent en jeu. |
|---|
| 135 | | textuelles. Avec les entrées/sorties textuelles, c'est à vous de définir |
|---|
| 136 | | exactement la représentation binaire externe. La plupart des types de données |
|---|
| 137 | | intégrés essaient d'apporter une représentation binaire indépendante de la |
|---|
| 138 | | machine. Pour <type>complex</type>, nous allons revenir aux convertisseurs |
|---|
| 139 | | d'entrées/sorties binaires pour le type <type>float8</> : |
|---|
| | 141 | textuelles. Comme avec les entrées/sorties textuelles, c'est l'utilisateur |
|---|
| | 142 | qui définit précisément la représentation binaire externe. La plupart des |
|---|
| | 143 | types de données intégrés tentent de fournir une représentation binaire |
|---|
| | 144 | indépendante de la machine. Dans le cas du type <type>complex</type>, |
|---|
| | 145 | des convertisseurs d'entrées/sorties binaires pour le type <type>float8</> sont utilisés : |
|---|
| 223 | | des tableaux de ce type. <indexterm><primary>tableau</primary><secondary>types |
|---|
| 224 | | définis par l'utilisateur</secondary></indexterm> Pour des raisons |
|---|
| 225 | | historiques, le type tableau a le même nom que le type de base avec un |
|---|
| 226 | | caractère souligné (<literal>_</>) en préfixe. |
|---|
| 227 | | </para> |
|---|
| 228 | | |
|---|
| 229 | | <para> |
|---|
| 230 | | Une fois que le type de données existe, nous pouvons déclarer les fonctions |
|---|
| 231 | | supplémentaires pour apporter des opérations utiles pour ce type de données. |
|---|
| 232 | | Les opérateurs peuvent alors être définis au-dessus de ces fonctions et, si |
|---|
| 233 | | nécessaire, les classes d'opérateurs peuvent aussi être créées pour apporter |
|---|
| | 226 | des tableaux de ce type. |
|---|
| | 227 | <indexterm> |
|---|
| | 228 | <primary>tableau</primary> |
|---|
| | 229 | <secondary>types utilisateur</secondary> |
|---|
| | 230 | </indexterm> |
|---|
| | 231 | Pour des raisons historiques, le type tableau a le nom du type de base, |
|---|
| | 232 | préfixé par avec un caractère souligné (<literal>_</>). |
|---|
| | 233 | </para> |
|---|
| | 234 | |
|---|
| | 235 | <para> |
|---|
| | 236 | Lorsque le type de données existe, il est possible de déclarer les fonctions |
|---|
| | 237 | supplémentaires de définition des opérations utiles pour ce type. |
|---|
| | 238 | Les opérateurs peuvent alors être définis par dessus ces fonctions et, si |
|---|
| | 239 | nécessaire, des classes d'opérateurs peuvent être créées pour |
|---|
| 239 | | Si les valeurs de votre type de donnée peuvent excéder une taille de quelques |
|---|
| 240 | | centaines d'octets (sous la forme interne), vous devriez marquer le type de |
|---|
| 241 | | données comme TOAST-able. <indexterm><primary>TOAST</primary><secondary>types |
|---|
| 242 | | définis par l'utilisateur</secondary></indexterm> Pour cela, la |
|---|
| 243 | | représentation interne doit suivre le cadre standard des données à longueur |
|---|
| 244 | | variable : les quatre premiers octets doivent être un <type>int32</type> |
|---|
| 245 | | contenant la longueur totale en octets de la donnée (lui-même inclus). Les |
|---|
| 246 | | fonctions C opérant sur le type de données doivent faire bien attention à |
|---|
| 247 | | déballer toutes les valeurs toast des données (ce détail peut normalement être |
|---|
| 248 | | cachée dans les macros <function>GETARG</function>). Puis, quand on exécute |
|---|
| 249 | | la commande <command>CREATE TYPE</command>, spécifiez la longueur interne |
|---|
| 250 | | comme <literal>variable</> et choisissez l'option de stockage en mémoire |
|---|
| 251 | | appropriée. |
|---|
| | 245 | Si les valeurs du type de données peuvent excéder une taille de quelques |
|---|
| | 246 | centaines d'octets (sous la forme interne), le type de |
|---|
| | 247 | données devrait être marqué comme TOAST-able. |
|---|
| | 248 | <indexterm> |
|---|
| | 249 | <primary>TOAST</primary> |
|---|
| | 250 | <secondary>types utilisateur</secondary> |
|---|
| | 251 | </indexterm> |
|---|
| | 252 | Pour cela, la représentation interne doit suivre le cadre standard des données |
|---|
| | 253 | à longueur variable : les quatre premiers octets sont un |
|---|
| | 254 | <type>int32</type> contenant la longueur totale en octets de la donnée |
|---|
| | 255 | (incluant les quatre premiers octets). Les |
|---|
| | 256 | fonctions C opérant sur le type de données doivent être attentives à |
|---|
| | 257 | dépaqueter toutes les valeurs toastées des données. |
|---|
| | 258 | (Ce détail est généralement masqué par la définition de macros <function>GETARG</function> spécifiques). |
|---|
| | 259 | Puis, lors de l'exécution de la commande <command>CREATE TYPE</command>, |
|---|
| | 260 | la longueur interne sera spécifiée |
|---|
| | 261 | comme <literal>variable</> et l'option de stockage en mémoire appropriée |
|---|
| | 262 | sera choisie. |
|---|