Documentation PostgreSQL 15.15 » Internes » Déclaration du catalogue système et contenu initial » Données initiales du catalogue système

Précédent | Niveau supérieur | Suivant
74.1. Règles de déclaration de catalogue système | Sommaire | 74.3. Format des fichiers BKI

## 74.2. Données initiales du catalogue système

Chaque catalogue qui a des données initiales créées manuellement (certains n'en ont pas) a un fichier `.dat` correspondant qui contient ses données initiales dans un format éditable.

### 74.2.1. Format de fichier de données

Chaque fichier `.dat` contient des structures de données Perl littérales qui sont simplement évaluées pour produire une structure de données en mémoire qui consiste en un tableau de références de hash, un par ligne de catalogue. Un extrait de `pg_database.dat` légèrement modifié va vous décrire les fonctionnalités principales :

    [

    # A comment could appear here.
    { oid => '1', oid_symbol => 'Template1DbOid',
      descr => 'database\'s default template',
      datname => 'template1', encoding => 'ENCODING',
      datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't',
      datallowconn => 't', datconnlimit => '-1', datfrozenxid => '0',
      datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE',
      datctype => 'LC_CTYPE', daticulocale => 'ICU_LOCALE', datacl => '_null_' },

    ]

Les points à noter :

- La structure générale du fichier est : crochet ouvrant, un ensemble ou plus d'accolades qui chacune représentent une ligne de catalogue, crochet fermant. Il faut mettre une virgule après chaque accolade fermante.

- Au sein de chaque ligne de catalogue, écrivez des paires de `clé` `=>` `valeur` séparées par des virgules. Les `clé`s autorisées sont les noms des colonnes du catalogue, ainsi que les clés de métadonnées `oid`, `oid_symbol`, `array_type_oid` et `descr`. (L'utilisation de `oid` et `oid_symbol` est décrite dans Section 74.2.2 ci-dessous, alors que `array_type_oid` est décrite dans Section 74.2.4. `descr` fournit une chaîne de texte de description pour l'objet, qui sera insérée dans `pg_description` ou `pg_shdescription` selon le cas.) Bien que les clés de métadonnées soient facultatives, les colonnes définies pour le catalogue doivent toutes être fournies, sauf pour le cas où le fichier `.h` du catalogue définit une valeur par défaut pour la colonne. (Dans l'exemple ci-dessus, le champ `datdba` a été volontairement omis car `pg_database.h` en fournit une valeur appropriée par défaut.)

- Toutes les valeurs doivent être entourées de guillemets simples. Il faut échapper les guillemets simples utilisés au sein d'une valeur avec un antislash. Les antislash qui doivent être utilisés comme une donnée peuvent être doublés, mais cela n'est pas nécessaire ; cela correspond aux règles Perl pour les littéraux entourés d'un guillemet simple. Veuillez noter que les antislash apparaissant comme données seront traités comme des échappements par le scanner du « bootstrap », d'après les mêmes règles que pour les échappements de chaînes de texte constantes (voir Section 4.1.2.2) ; par exemple `\t` est converti en un caractère tabulation. Si vous voulez un antislash dans la valeur finale, il vous faudra en écrire quatre : Perl en retire deux, laissant `\\` pour le scanner « bootstrap ».

- Les valeurs NULL sont représentées par `_null_`. (Veuillez noter qu'il n'y a aucun moyen de créer une valeur qui est simplement cette chaîne de texte.)

- Les commentaires sont précédés d'un `#`, et doivent être sur leur propre ligne.

- Les valeurs de champs référençant des OID d'autres entrées de catalogue devraient être représentées par des macros plutôt que par de vrais nombres OID. (Dans l'exemple ci-dessus, `dattablespace` contient une telle référence.) Cela est décrit dans Section 74.2.3 ci-dessous.

- Puisque les hash sont des structures de données non triées, l'ordre des champs et des lignes ne sont pas sémantiquement significatifs. Cependant, pour maintenir un aspect cohérent, nous définissions quelques règles qui sont appliquées par le script de formatage `reformat_dat_file.pl` :

  - Au sein de chaque paire d'accolades, les champs de métadonnées `oid`, `oid_symbol`, `array_type_oid` et `descr` (si présent) apparaissent en premier, dans cet ordre, puis les champs propres au catalogue apparaissent dans leur ordre défini.

  - Des retours à la ligne sont insérés entre les champs selon le besoin pour limiter la longueur de ligne à 80 caractères, si cela est possible. Un retour à la ligne est également inséré entre les champs de métadonnées et les champs normaux.

  - Si le fichier de catalogue `.h` spécifie une valeur par défaut pour la colonne, et qu'une entrée de donnée a la même valeur, `reformat_dat_file.pl` omettra cette valeur du fichier de données. Cela conserve la représentation de données compacte.

  - `reformat_dat_file.pl` conserve les lignes vides et les commentaires en l'état.

  Il est recommandé d'exécuter `reformat_dat_file.pl` avant de soumettre des patchs pour les données de catalogue. Par commodité, vous pouvez simplement effectuer des changements dans `src/include/catalog/` et exécuter `make reformat-dat-files`.

- Si vous voulez ajouter une nouvelle méthode pour diminuer la taille de de la représentation des données, vous devez l'implémenter dans `reformat_dat_file.pl` et également apprendre à `Catalog::ParseData()` comment remettre les données dans leur représentation complète.

### 74.2.2. Affectation d'OID

Il est possible de donner un OID manuellement assigné à une ligne de catalogue apparaissant dans les données initiales en écrivant un champ de métadonnées `oid => `nnnn``. De plus, si un OID est assigné, une macro C pour cet OID peut être créée en écrivant un champ de métadonnée `oid_symbol => `nom``.

Les lignes de catalogues préchargées doivent avoir des OID pré-assignés s'il y a des références d'OID pointant vers elles dans d'autres lignes pré-chargées. Un OID pré-assigné est également nécessaire si l'OID de la ligne doit être référencé depuis le code C. Si aucun de ces cas ne s'applique, le champ de métadonnée `oid` peut être omis, auquel cas le code de « bootstrap » assignera un OID automatiquement. En pratique, nous pré-assignons généralement des OID pour soit toutes soit aucune des lignes d'un catalogue donné, même si seulement une partie des lignes sont vraiment référencées dans d'autres catalogues.

Écrire la vraie valeur numérique d'un OID dans le code C est considéré comme une très mauvaise pratique ; il faut toujours utiliser une macro à la place. Des références directes à des OID de `pg_proc` sont suffisamment communes pour qu'il y ait un mécanisme spécial afin de créer les macros nécessaires automatiquement ; voir `src/backend/utils/Gen_fmgrtab.pl`. De même -- mais, pour raisons historiques, fait d'une autre manière -- il y a une méthode automatique pour créer les macros pour les OID de `pg_type`. Les entrées de `oid_symbol` ne sont donc pas forcément dans ces deux catalogues. De la même manière, les macros pour les OID de catalogue système et index `pg_class` sont positionnés automatiquement. Pour tous les autres catalogues systèmes, vous devez spécifier manuellement toute macro dont vous avez besoin avec les entrées `oid_symbol`.

Pour trouver un OID disponible pour une nouvelle ligne préchargée, exécutez le script `src/include/catalog/unused_oids`. Il affiche l'intervalle inclusif d'OID inutilisés (par exemple, la ligne en sortie `45-900` signifie que les OID 45 jusqu'à 900 n'ont pas encore été alloués). Pour le moment, les OID 1–9999 sont réservés pour des allocations manuelles ; le script `unused_oids` regarde simplement dans les en-têtes de catalogue et les fichiers `.dat` pour voir lesquels n'apparaissent pas. Vous pouvez également utiliser le script `duplicate_oids` pour trouver des erreurs. (`genbki.pl` va allouer des OID à toutes les lignes qui n'en auraient pas reçu manuellement, et va aussi détecter les OID dupliqués au moment de la compilation.)

Lors du choix d'OID pour l'écriture d'un patch qui n'est pas supposé être validé immédiatement, la bonne pratique est d'utiliser un groupe d'OID plus-ou-moins consécutifs en commençant par un choix aléatoire dans l'intervalle 8000 -- 9999. Cela minimise le risque de collisions d'OID avec d'autres patchs développés en parallèle. Pour garder l'intervalle 8000 -- 9999 libre pour le développement, après qu'un patch ait été validé sur le dépôt git principal, ces OID doivent être renumérotés dans un intervalle inférieur libre. Typiquement, cela sera fait à l'approche de la fin de chaque cycle de développement, déplaçant tous les OID consommés par des patchs validés lors de ce cycle en même temps. Le script `renumber_oids.pl` peut être utilisé pour faire cela. Si un patch non validé contient des OID en conflit avec un patch récemment validé, `renumber_oids.pl` peut aussi être utile pour rétablir une telle situation.

À cause de cette convention de renumérotation des OID consommés par les patchs, les OID attribués à un patch ne doivent pas être considérés comme stables jusqu'à ce que celui-ci ait été inclus dans une version officielle. Nous ne changeons toutefois pas les OID assignés manuellement une fois la version sortie, car cela pourrait engendrer des problèmes de compatibilité.

Si `genbki.pl` a besoin d'assigner un OID à un enregistrement du catalogue ne pouvant donc être un OID assigné manuellement, il utilisera une valeur de l'intervalle 10000 -- 11999. Le compteur des OID serveur est défini à 10000 au début d'une phase de « bootstrap », pour que tout objet créé à la volée lors du traitement du « bootstrap » reçoive aussi un OID dans cet intervalle. (Le mécanisme habituel d'attribution des OID fait attention à prévenir tout conflit.).

Les objets dont l'OID est en-dessous de `FirstUnpinnedObjectId` (12000) sont considérés comme « fixes », les empêchant d'être supprimés. (Il existe un petit nombre d'exceptions, qui sont gérées en dur par la fonction `IsPinnedObject()`.) initdb force le compteur d'OID à `FirstUnpinnedObjectId` dès qu'il est prêt à créer des objets non fixes. De ce fait, les objets créés dans les phases ultérieures de initdb, comme des objets créés lors de l'exécution du script `information_schema.sql`, ne seront pas fixes alors que tous les objets connus de `genbki.pl` le seront.

Les OID assignés durant les opérations normales de la base de données sont contraints entre 16384 et plus. Cela assure que l'intervalle 10000 -- 16383 soit libre pour l'assignation automatique d'OID par `genbki.pl` ou durant l'« initdb ». Ces OID assignés automatiquement ne sont pas considérés comme stables, et peuvent changer d'une installation à l'autre.

### 74.2.3. Recherche de référence d'OID

En principe, la référence d'une ligne de catalogue vers une autre pourrait être écrite juste en se servant de l'OID pré-assigné de la ligne à référencer dans le champ la référençant. Cependant, cela va à l'encontre de la politique du projet, car sujet aux erreurs, difficile à lire et source d'incohérence si un OID nouvellement assigné est renuméroté. C'est pourquoi `genbki.pl` fournit un mécanisme de génération de macros à utiliser à la place. Les règles sont les suivantes :

- L'utilisation de références symboliques est activée pour une colonne en particulier en attachant `BKI_LOOKUP(`lookuprule`)` à la définition de la colonne, où `lookuprule` est le nom du catalogue référencé, par exemple `pg_proc`. `BKI_LOOKUP` peut être attaché aux colonnes de type `Oid`, `regproc`, `oidvector`, ou `Oid[]` ; dans les deux derniers cas, cela implique d'effectuer une recherche pour chaque élément du tableau.

- Dans certaines colonnes du catalogue, des entrées à zéro sont permises à la place d'une référence valide. Si cela est permis, écrivez `BKI_LOOKUP_OPT` au lieu de `BKI_LOOKUP`. Ainsi, vous pouvez écrire `0` dans une entrée. (Si la colonne est déclarée `regproc`, vous pouvez optionnellement écrire `-` au lieu de `0`.) En dehors de ce cas spécial, toutes les entrées dans une colonne `BKI_LOOKUP` doivent être une référence symbolique. `genbki.pl` vous avertira à propos des noms non reconnus.

- Il est également permis d'attacher `BKI_LOOKUP(encoding)` aux colonnes de type entier pour référencer les encodages de caractères, ce qui n'est actuellement pas représenté par des OID de catalogue, mais par un ensemble de valeurs connues de `genbki.pl`.

- La plupart des types d'objets du catalogue sont référencées par leurs noms. Notez que ces noms doivent être strictement identiques aux entrées `typname` de `pg_type`; vous ne pouvez pas utiliser d'alias comme `integer` à la place de `int4`.

- Une fonction peut être représentée par son `proname`, s'il est unique parmi les entrées de `pg_proc.dat` (cela fonctionne comme les entrées regproc). Sinon, écrivez-les sous la forme `proname(argtypename,argtypename,...)`, comme pour `regprocedure`. Les noms de type des arguments doivent être écrits exactement comme ils le sont dans les champs `proargtypes` des entrées de `pg_proc.dat`. N'insérez aucun espace.

- Les opérateurs sont représentés par `oprname(lefttype,righttype)`, en écrivant les noms de type exactement comme ils apparaissent dans les `oprleft` et `oprright` des entrées de `pg_operator.dat`. (Écrivez `0` pour les opérandes omises d'un opérateur unaire.)

- Les noms des classes et familles d'opérateur ne sont uniques qu'au sein d'une méthode d'accès, elles sont donc représentées avec `nom_methode_acces``/``nom_objet`.

- Il n'est prévu de qualification par le schéma pour aucun de ces cas ; tous les objets créés durant le « bootstrap » sont prévus pour être dans le schéma `pg_catalog`.

`genbki.pl` résout toutes les références symboliques pendant son exécution, et inscrit de simples OID numériques dans les fichiers BKI émis. Le processus client de « bootstrap » n'a donc pas besoin de gérer les références symboliques.

Il est recommandé de marquer les colonnes de référence OID avec `BKI_LOOKUP` ou `BKI_LOOKUP_OPT` même si le catalogue n'a pas de données initiales nécessitant une recherche. Ceci permet à `genbki.pl` d'enregistrer les clés étrangères des relations qui existent dans le catalogue système. Cette information est utilisée dans les tests de régression pour vérifier les entrées incorrectes. Voir aussi les macros `DECLARE_FOREIGN_KEY`, `DECLARE_FOREIGN_KEY_OPT`, `DECLARE_ARRAY_FOREIGN_KEY`, et `DECLARE_ARRAY_FOREIGN_KEY_OPT`, qui sont utilisées pour déclarer les clés étrangères des relations qui sont trop complexes pour `BKI_LOOKUP` (typiquement, des clés étrangères multi-colonnes).

### 74.2.4. Création automatique des types de tableau

La plupart des types de données scalaires devraient avoir un type tableau correspondant (en fait, un type de tableau « varlena » standard, dont le type d'élément est un scalaire référencé par le champ `typarray` de l'entrée de type scalaire de `pg_type`). `genbki.pl` est capable de générer l'entrée de `pg_type` pour le type de tableau automatiquement dans la plupart des cas.

Pour se servir de cette fonctionnalité, il suffit d'inscrire un champ de méta-données `array_type_oid=> `nnnn`` dans l'entrée de type scalaire de `pg_type`, spécifiant l'OID à utiliser pour le type de tableau. Vous pouvez ensuite omettre le champ `typarray`, puisque l'OID y sera automatiquement renseigné.

Le nom du type de tableau généré est le nom du type scalaire préfixé du tiret bas. Les autres champs du type de tableau sont remplis par les annotations `BKI_ARRAY_DEFAULT(`value`)` de `pg_type.h`, ou s'il n'y en a pas, copiés du type scalaire. (Il y a aussi un cas particulier pour `typalign`.) Ensuite, les champs `typelem` et `typarray` des deux enregistrements sont positionnés afin de se référencer l'un et l'autre.

### 74.2.5. Recettes pour éditer les fichiers de données

Voici quelques suggestions pour les moyens les plus simples d'effectuer des tâches communes lors de la mise à jour de fichiers de données du catalogue.

Ajouter une nouvelle colonne avec valeur par défaut à un catalogue : Ajoutez la colonne au fichier d'en-tête avec une annotation `BKI_DEFAULT(`valeur`)` Le fichier de données ne doit être ajusté en ajoutant le champ dans les lignes existantes que quand il est nécessaire d'avoir autre chose que la valeur par défaut.

Ajouter une valeur par défaut à une colonne existante qui n'en a pas : Ajoutez une annotation `BKI_DEFAULT` au fichier d'en-tête, puis exécutez `make reformat-dat-files` pour supprimer les entrées de champ qui sont maintenant redondantes.

Ajouter une colonne, qu'elle ait une valeur par défaut ou non : Supprimez la colonne de l'en-tête, puis exécutez `make reformat-dat-files` pour supprimer les entrées du champ maintenant inutiles.

Changer ou supprimer une valeur par défaut existante : Vous ne pouvez pas simplement changer le fichier d'en-tête, puisque cela aurait pour conséquence une mauvaise interprétation des données actuelles. Tout d'abord, exécutez `make expand-dat-files` pour réécrire les fichiers de données avec toutes les valeurs par défaut insérées explicitement, puis modifiez ou supprimez l'annotation `BKI_DEFAULT`, puis exécutez `make reformat-dat-files` pour supprimer à nouveau les champs superflus.

Édition en masse ad hoc : `reformat_dat_file.pl` peut être modifié pour effectuer différents types de changements en masse. Cherchez les commentaires de blocs montrant où du code unique peut être inséré. Dans l'exemple suivant, nous allons consolider deux champs booléens de `pg_proc` en un champ de type char :

1. Ajout de la nouvelle colonne, avec une valeur par défaut, à `pg_proc.h`:

       +    /* see PROKIND_ categories below */
       +    char        prokind BKI_DEFAULT(f);

2. Création d'un nouveau script basé sur `reformat_dat_file.pl` pour insérer les valeurs appropriées à la volée :

       -           # At this point we have the full row in memory as a hash
       -           # and can do any operations we want. As written, it only
       -           # removes default values, but this script can be adapted to
       -           # do one-off bulk-editing.
       +           # One-off change to migrate to prokind
       +           # Default has already been filled in by now, so change to other
       +           # values as appropriate
       +           if ($values{proisagg} eq 't')
       +           {
       +               $values{prokind} = 'a';
       +           }
       +           elsif ($values{proiswindow} eq 't')
       +           {
       +               $values{prokind} = 'w';
       +           }

3. Lancement du nouveau script :

       $ cd src/include/catalog
       $ perl  rewrite_dat_with_prokind.pl  pg_proc.dat

   À cette étape, `pg_proc.dat` a la totalité des trois colonnes, `prokind`, `proisagg` et `proiswindow`, bien qu'elles n'apparaîtront que dans les lignes où elles ont des valeurs qui ne sont pas la valeur par défaut.

4. Suppression de l'ancienne colonne de `pg_proc.h` :

       -    /* is it an aggregate? */
       -    bool        proisagg BKI_DEFAULT(f);
       -
       -    /* is it a window function? */
       -    bool        proiswindow BKI_DEFAULT(f);

5. Finalement, exécution de `make reformat-dat-files` pour supprimer les anciennes entrées inutiles de `pg_proc.dat`.

Pour plus d'exemples de scripts utilisés pour l'édition en masse, voir `convert_oid2name.pl` et `remove_pg_type_oid_symbols.pl` joints au message suivant : https://www.postgresql.org/message-id/CAJVSVGVX8gXnPm+Xa=DxR7kFYprcQ1tNcCT5D0O3ShfnM6jehA@mail.gmail.com