PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 15.6 » Internes » Conventions de codage pour PostgreSQL » Reporter les erreurs dans le serveur

56.2. Reporter les erreurs dans le serveur

Les messages d'erreurs, d'alertes et de traces produites dans le code du serveur doivent être créés avec ereport ou son ancien cousin elog. L'utilisation de cette fonction est suffisamment complexe pour nécessiter quelques explications.

Il y a deux éléments requis pour chaque message : un niveau de sévérité (allant de DEBUG à PANIC) et un message texte primaire. De plus, il y a des éléments optionnels, le plus commun d'entre eux est le code identifiant de l'erreur qui suit les conventions SQLSTATE des spécifications SQL. ereport en elle-même n'est qu'une macro shell qui existe principalement pour des convenances syntaxiques faisant ressembler la génération de messages à un seul appel d'une fonction dans un code source C. Le seul paramètre directement accepté par ereport est le niveau de sévérité. Le message texte primaire et les autres éléments de messages optionnels sont produits par appel de fonctions auxiliaires, comme errmsg, dans l'appel à ereport.

Un appel typique à ereport peut ressembler à :

ereport(ERROR,
        errcode(ERRCODE_DIVISION_BY_ZERO),
        errmsg("division by zero"));
   

Le niveau de sévérité de l'erreur est ainsi positionné à ERROR (une erreur banale). L'appel à errcode précise l'erreur SQLSTATE en utilisant une macro définie dans src/include/utils/errcodes.h. L'appel à errmsg fournit le message texte primaire.

Vous verrez aussi fréquemment cet ancien style, avec un ensemble supplémentaire de parenthèses entourant les appels de fonction auxiliaire :

ereport(ERROR,
        (errcode(ERRCODE_DIVISION_BY_ZERO),
         errmsg("division by zero")));
   

Les parenthèses supplémentaires sont nécessaires pour les versions de PostgreSQL antérieures à la version 12, et sont depuis optionnelles.

Exemple plus complexe :

ereport(ERROR,
        errcode(ERRCODE_AMBIGUOUS_FUNCTION),
        errmsg("function %s is not unique",
               func_signature_string(funcname, nargs,
                                     NIL, actual_arg_types)),
        errhint("Unable to choose a best candidate function. "
                "You might need to add explicit typecasts."));
   

Cela illustre l'utilisation des codes de formatage pour intégrer des valeurs d'exécution dans un message texte. Un message « conseil », optionnel, est également fourni. Les appels de fonction auxiliaire peuvent être écrits dans tout ordre, bien que la convention est de fait apparaître errcode et errmsg en premier.

Si le niveau de sévérité est ERROR ou plus, ereport annule l'exécution de la requête en cours et ne rend pas la main à l'appelant. Si le niveau de sévérité est moins qu'ERROR, ereport rend la main normalement.

Les routines auxiliaires disponibles pour ereport sont :

  • errcode(sqlerrcode) précise le code SQLSTATE de l'identifiant erreur pour la condition. Si cette routine n'est pas appelée, l'identifiant l'erreur est, par défaut, ERRCODE_INTERNAL_ERROR quand le niveau de sévérité de l'erreur est ERROR ou plus haut, ERRCODE_WARNING quand le niveau d'erreur est WARNING et ERRCODE_SUCCESSFUL_COMPLETION pour NOTICE et inférieur. Bien que ces valeurs par défaut soient souvent commodes, il faut se demander si elles sont appropriées avant d'omettre l'appel à errcode().

  • errmsg(const char *msg, ...) indique le message texte primaire de l'erreur et les possibles valeurs d'exécutions à y insérer. Les insertions sont précisées par les codes de formatage dans le style sprintf. En plus des codes de formatage standard acceptés par sprintf, le code %m peut être utilisé pour insérer le message d'erreur retourné par strerror pour la valeur courante de errno. [16] %m ne nécessite aucune entrée correspondante dans la liste de paramètres pour errmsg. Notez que la chaîne de caractères du message sera passée à travers gettext pour une possible adaptation linguistique avant que les codes de formatage ne soient exécutés.

  • errmsg_internal(const char *msg, ...) fait la même chose que errmsg à l'exception que la chaîne de caractères du message ne sera ni traduite ni incluse dans le dictionnaire de messages d'internationalisation. Cela devrait être utilisé pour les cas qui « ne peuvent pas arriver » et pour lesquels il n'est probablement pas intéressant de déployer un effort de traduction.

  • errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...) est identique à errmsg mais avec le support pour plusieurs formes de pluriel du message. fmt_singular est le format singulier de l'anglais, fmt_plural est le format pluriel en anglais, n est la valeur entière qui détermine la forme utilisée. Les arguments restants sont formatés suivant le chaîne de format sélectionnée. Pour plus d'informations, voir Section 57.2.2.

  • errdetail(const char *msg, ...) fournit un message « détail » optionnel ; cela est utilisé quand il y a des informations supplémentaires qu'il semble inadéquat de mettre dans le message primaire. La chaîne de caractères du message est traitée de la même manière que celle de errmsg.

  • errdetail_internal(const char *msg, ...) est identique à errdetail, sauf que le message ne sera ni traduit ni inclut dans le dictionnaire des messages à traduire. Elle doit être utilisée pour les messages de niveau détail pour lequel un effort de traduction est inutile, par exemple parce qu'ils sont trop techniques pour que cela soit utile à la majorité des utilisateurs.

  • errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...) est identique à errdetail mais avec le support de plusieurs formes de pluriel pour le message. Pour plus d'information, voir Section 57.2.2.

  • errdetail_log(const char *msg, ...) est identique à errdetail sauf que cette chaîne ne va que dans les traces du serveur. Elle n'est jamais envoyée au client. Si errdetail (ou un de ses équivalents ci-dessus) et errdetail_log sont utilisées ensemble, alors une chaîne est envoyés au client et l'autre dans les traces du serveur. C'est utile pour les détails d'erreur qui concernent la sécurité ou qui sont trop techniques pour être inclus dans le rapport envoyé au client.

  • errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...) est identique à errdetail_log, mais avec le support de plusieurs formes de pluriel pour le message. Pour plus d'informations, voir Section 57.2.2.

  • errhint(const char *msg, ...) fournit un message « conseil » optionnel ; cela est utilisé pour offrir des suggestions sur la façon de régler un problème, par opposition aux détails effectifs au sujet de ce qui a mal tourné. La chaîne de caractères du message est traitée de la même manière que celle de errmsg.

  • errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...) est identique à errhint, mais avec le support de plusieurs formes plurielles du message. Pour plus d'informations, voir Section 57.2.2.

  • errcontext(const char *msg, ...) n'est normalement pas appelée directement depuis un site de message de ereport mais plutôt elle est utilisée dans les fonctions de rappels error_context_stack pour fournir des informations à propos du contexte dans lequel une erreur s'est produite, comme les endroits courants dans la fonction PL. La chaîne de caractères du message est traitée de la même manière que celle de errmsg. À l'inverse des autres fonctions auxiliaires, celle-ci peut être appelée plus d'une fois dans un appel de ereport ; les chaînes successives ainsi fournies sont concaténées et séparées pas des caractères d'interlignes (NL).

  • errposition(int cursorpos) spécifie l'endroit textuel d'une erreur dans la chaîne de caractères de la requête. Actuellement, c'est seulement utile pour les erreurs détectées dans les phases d'analyses lexicales et syntaxiques du traitement de la requête.

  • errtable(Relation rel) spécifie une relation dont le nom et le schéma doivent être inclus comme champs auxiliaires du rapport d'erreur.

  • errtablecol(Relation rel, int attnum) indique une colonne dont le nom, le nom de la table et le nom du schéma doivent être inclus comme champs auxiliaires du rapport d'erreur.

  • errtableconstraint(Relation rel, const char *conname) spécifie une contrainte de table dont le nom, le nom de la table et le nom du schéma doivent être inclus comme champs du rapport d'erreur. Les index doivent être considérés comme des contraintes dans ce but, qu'ils soient ou non associés à une entrée dans pg_constraint. Faites attention à fournir la relation principale sous-jacente et non pas l'index lui-même, via rel.

  • errdatatype(Oid datatypeOid) spécifie un type de données dont le nom et le nom du schéma doivent être inclus comme champs auxiliaires dans le rapport d'erreur.

  • errdomainconstraint(Oid datatypeOid, const char *conname) spécifie une contrainte de domaine dont le nom, le nom du domaine et le nom du schéma doivent être inclus comme champs auxiliaires du rapport d'erreur.

  • errcode_for_file_access() est une fonction commode qui sélectionne l'identifiant d'erreur SQLSTATE approprié pour une défaillance dans l'appel système relatif à l'accès d'un fichier. Elle utilise le errno sauvegardé pour déterminer quel code d'erreur générer. Habituellement cela devrait être utilisé en combinaison avec %m dans le texte du message d'erreur primaire.

  • errcode_for_socket_access() est une fonction commode qui sélectionne l'identifiant d'erreur SQLSTATE approprié pour une défaillance dans l'appel système relatif à une socket.

  • errhidestmt(bool hide_stmt) peut être appelé pour indiquer la suppression de la portion STATEMENT: d'un message dans le journal applicatif de postmaster. Habituellement, c'est approprié si le texte du message contient déjà l'instruction en cours.

  • errhidecontext(bool hide_ctx) peut être appelé pour spécifier la suppression de la portion CONTEXT: d'un message dans les traces de postmaster. Ceci devrait seulement être utilisé pour les messages verbeux de débogage où l'inclusion répétée de contexte ferait grossir les journaux trop fortement.

Note

Au moins une des fonctions errtable, errtablecol, errtableconstraint, errdatatype ou errdomainconstraint doivent être utilisées dans un appel à ereport. Ces fonctions existent pour permettre aux applications d'extraire le nom de l'objet de la base associé à l'erreur sans avoir à examiner le texte du messahe d'erreur potentiellement traduit. Ces fonctions doivent être utilisées dans les rapports d'erreur pour lesquels il est probable que les applications voudraient une gestion automatique des erreurs. À partir de PostgreSQL 9.3, une couverture complète existe pour les erreurs de la classe SQLSTATE 23 (violation des contraintes d'intégrité), mais il est probable que cette couverture soit étendue dans les prochaines versions.

Il y a une plus ancienne fonction nommée elog, qui est toujours largement utilisée. Un appel à elog :

elog(niveau, "chaine format", ...);

est strictement équivalent à :

ereport(level, errmsg_internal("chaine format", ...));

Le code d'erreur SQLSTATE est toujours celui par défaut, la chaîne de caractères du message n'est pas sujette à traduction. Par conséquent, elog ne devrait être utilisé que pour les erreurs internes et l'enregistrement de trace de débogage de bas niveau. N'importe quel message susceptible d'intéresser les utilisateurs ordinaires devrait passer par ereport. Néanmoins, il y a suffisamment de contrôles des erreurs internes qui « ne peuvent pas arriver » dans le système, pour que elog soit toujours largement utilisée ; elle est préférée pour ces messages du fait de sa simplicité d'écriture.

Des conseils sur l'écriture de bons messages d'erreurs peuvent être trouvés dans la Section 56.3.



[16] C'est-à-dire la valeur qui était courante quand l'appel à ereport a été atteinte ; les changements d'errno dans les routines auxiliaires de rapports ne l'affecteront pas. Cela ne sera pas vrai si vous devez écrire explicitement strerror(errno) dans la liste de paramètres de errmsg ; en conséquence ne faites pas comme ça.