IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

33.8. Gestion des Erreurs

Cett section explique comment vous pouvez traiter des conditions d'exception et des avertissements dans un programme SQL embarqué. Il y a deux fonctionnalités non-exclusives pour cela.

  • Des fonctions de rappel (callbacks) peuvent être configurées pour traiter les conditions d'avertissement et d'erreur en utilisant la commande WHENEVER.
  • Des informations détaillées à propos de l'erreur ou de l'avertissement peuvent être obtenues de la variable sqlca.

33.8.1. Mettre en Place des Callbacks

Une méthode simple pour intercepter des erreurs et des avertissements est de paramétrer des actions spécifiques à exécuter dès qu'une condition particulière se produit. En général:

EXEC SQL WHENEVER condition action;

condition peut être un des éléments suivants:

SQLERROR

L'action spécifiée est appelée dès qu'une erreur se produit durant l'exécution d'un ordre SQL.

SQLWARNING

L'action spécifiée est appelée dès qu'un avertissement se produit durant l'exécution d'un ordre SQL.

NOT FOUND

L'action spécifiée est appelée dès qu'un ordre SQL récupère ou affecte zéro enregistrement. (Cette condition n'est pas une erreur, mais vous pourriez être intéressé par un traitement spécial dans ce cas).

action peut être un des éléments suivants:

CONTINUE

Cela signifie en fait que la condition est ignorée. C'est le comportement par défaut.

GOTO label, GO TO label

Sauter au label spécifié (en utilisant un ordre goto C).

SQLPRINT

Affiche un message vers la sortie standard. C'est utile pour des programmes simples ou durant le prototypage. Le détail du message ne peut pas être configuré.

STOP

Appelle exit(1), ce qui mettra fin au programme.

DO BREAK

Exécuter l'ordre C break. Cela ne devrait être utilisé que dans des boucles ou des ordres switch.

CALL name (args), DO name (args)

Appelle la fonction C spécifiée avec les arguments spécifiés.

Le standard SQL ne fournit que les actions CONTINUE et GOTO (and GO TO).

Voici un exemple de ce que pourriez vouloir utiliser dans un programme simple. Il affichera un message quand un avertissement se produit et tuera le programme quand une erreur se produit:

EXEC SQL WHENEVER SQLWARNING SQLPRINT;
EXEC SQL WHENEVER SQLERROR STOP;

L'ordre EXEC SQL WHENEVER est une directive du préprocesseur SQL, pas un ordre SQL. L'action sur erreur ou avertissement qu'il met en place s'applique à tous les ordres SQL embarqués qui apparaissent après le point où le gestionnaire est mis en place, sauf si une autre action a été mise en place pour la même condition entre le premier EXEC SQL WHENEVER et l'ordre SQL entrainant la condition, quel que soit le déroulement du programme C. Par conséquent, aucun des extraits des deux programmes C suivants n'aura l'effet escompté:

/*
 * WRONG
 */
int main(int argc, char *argv[])
{
    ...
    if (verbose) {
        EXEC SQL WHENEVER SQLWARNING SQLPRINT;
    }
    ...
    EXEC SQL SELECT ...;
    ...
}
/*
 * WRONG
 */
int main(int argc, char *argv[])
{
    ...
    set_error_handler();
    ...
    EXEC SQL SELECT ...;
    ...
}

static void set_error_handler(void)
{
    EXEC SQL WHENEVER SQLERROR STOP;
}

33.8.2. sqlca

Pour une gestion plus approfondie des erreurs, l'interface SQL embarquée fournit une variable globale appelée sqlca (SQL communication area, ou zone de communication SQL) qui a la structure suivante:

struct
{
    char sqlcaid[8];
    long sqlabc;
    long sqlcode;
    struct
    {
        int sqlerrml;
        char sqlerrmc[SQLERRMC_LEN];
    } sqlerrm;
    char sqlerrp[8];
    long sqlerrd[6];
    char sqlwarn[8];
    char sqlstate[5];
} sqlca;

(Dans un programme multi-threadé, chaque thread récupère automatiquement sa propre copie de sqlca. Ce fonctionnement est similaire à celui de la variable C globale errno.) errno.)

sqlca couvre à la fois les avertissements et les erreurs. Si plusieurs avertissements ou erreurs se produisent durant l'exécution d'un ordre, alors sqlca ne contiendra d'informations que sur le dernier.

Si aucune erreur ne s'est produite durant le dernier ordre SQL, sqlca.sqlcode vaudra 0 sqlca.sqlstate vaudra "00000". Si un avertissement ou erreur s'est produit, alors sqlca.sqlcode sera négatif sqlca.sqlstate sera différent de "00000". Une valeur positive de sqlca.sqlcode indique une condition sans gravité comme le fait que la dernière requête ait retourné zéro enregistrements. sqlcode et sqlstate sont deux différents schemas de code d'erreur; les détails sont fournis plus bas.

Si le dernier ordre SQL a réussi, alors sqlca.sqlerrd[1] contient l'OID de la ligne traitée, si applicable, et sqlca.sqlerrd[2] contient le nombre d'enregistrements traités ou retournés, si applicable à la commande.

En cas d'erreur ou d'avertissement, sqlca.sqlerrm.sqlerrmc contiendra une chaine qui décrira une erreur. Le champ sqlca.sqlerrm.sqlerrml contiendra la longueur du message d'erreur qui est stocké dans sqlca.sqlerrm.sqlerrmc (le résultat de strlen(), par réellement intéressant pour un programmeur C). Notez que certains messages sont trop longs pour tenir dans le tableau de taille fixe sqlerrmc; ils seront tronqués.

En cas d'avertissement, sqlca.sqlwarn[2] est positionné à W. (Dans tous les autres cas, il est positionné à quelque chose de différent de W.) Si sqlca.sqlwarn[1] est positionné à W, alors une valeur a été tronquée quand elle a été stockée dans une variable hôte. sqlca.sqlwarn[0] est positionné à W si n'importe lequel des autres éléments est positionné pour indiquer un avertissement.

Les champs sqlcaid, sqlcabc, sqlerrp, et les éléments restants de sqlerrd et sqlwarn ne contiennent pour le moment aucune information utile.

La structure sqlca n'est pas définie dans le standard SQL, mais est implémentée dans plusieurs autres systèmes de base de données. Les définitions sont similaires dans leur principe, mais si vous voulez écrire des applications portables, vous devriez étudier les différentes implémentations de façon attentive.

Voici un exemple qui combine l'utilisation de WHENEVER et de sqlca, en affichant le contenu de sqlca quand une erreur se produit. Cela pourrait être utile pour déboguer ou prototyper des applications, avant d'installer un gestionnaire d'erreurs plus « user-friendly ».

EXEC SQL WHENEVER SQLERROR CALL print_sqlca();

void
print_sqlca()
{
    fprintf(stderr, "==== sqlca ====\n");
    fprintf(stderr, "sqlcode: %ld\n", sqlca.sqlcode);
    fprintf(stderr, "sqlerrm.sqlerrml: %d\n", sqlca.sqlerrm.sqlerrml);
    fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
    fprintf(stderr, "sqlerrd: %ld %ld %ld %ld %ld %ld\n", sqlca.sqlerrd[0],sqlca.sqlerrd[1],sqlca.sqlerrd[2],
                                                          sqlca.sqlerrd[3],sqlca.sqlerrd[4],sqlca.sqlerrd[5]);
    fprintf(stderr, "sqlwarn: %d %d %d %d %d %d %d %d\n", sqlca.sqlwarn[0], sqlca.sqlwarn[1], sqlca.sqlwarn[2],
                                                          sqlca.sqlwarn[3], sqlca.sqlwarn[4], sqlca.sqlwarn[5],
                                                          sqlca.sqlwarn[6], sqlca.sqlwarn[7]);
    fprintf(stderr, "sqlstate: %5s\n", sqlca.sqlstate);
    fprintf(stderr, "===============\n");
}

Le résultat pourrait ressembler à ce qui suit (ici une erreur due à un nom de table mal saisi):

==== sqlca ====
sqlcode: -400
sqlerrm.sqlerrml: 49
sqlerrm.sqlerrmc: relation "pg_databasep" does not exist on line 38
sqlerrd: 0 0 0 0 0 0
sqlwarn: 0 0 0 0 0 0 0 0
sqlstate: 42P01
===============

33.8.3. SQLSTATE contre SQLCODE

Les champs sqlca.sqlstate et sqlca.sqlcode sont deux schémas qui fournissent des codes d'erreurs. Les deux sont dérivés du standard SQL, mais SQLCODE a été marqué comme déprécié dans l'édition SQL-92 du standard, et a été supprimé des éditions suivantes. Par conséquent, les nouvelles applications ont fortement intérêt à utiliser SQLSTATE.

SQLSTATE est un tableau de cinq caractères. Les cinq caractères contiennent des chiffres ou des lettres en majuscule qui représentent les codes des différentes conditions d'erreur et d'avertissement. SQLSTATE a un schéma hiérarchique: les deux premiers caractères indiquent la classe générique de la condition, les trois caractères suivants indiquent la sous-classe de la condition générique. Un état de succès est indiqué par le code 00000. Les codes SQLSTATE sont pour la plupart définis dans le standard SQL. Le serveur PostgreSQL™ supporte nativement les codes d'erreur SQLSTATE; par conséquent, un haut niveau de cohérence entre toutes les applications peut être obtenu en utilisant ce schéma de codes d'erreur. Pour plus d'informations voyez Annexe A, Codes d'erreurs de PostgreSQL.

SQLCODE, le schéma d'erreurs déprécié, est un entier simple. Une valeur de 0 indique le succès, une valeur positive indique un succès avec des informations supplémentaires, une valeur négative indique une erreur. Le standard SQL ne définit que la valeur positive +100, qui indique que l'ordre précédent a retourné ou affecté zéro enregistrement, et aucune valeur négative spécifique. par conséquent, ce schéma ne fournit qu'une piètre portabilité et n'a pas de hiérarchie de code d'erreurs. Historiquement, le processeur de SQL embarqué de PostgreSQL™ a assigné des valeurs spécifiques de SQLCODE pour son utilisation propre, qui sont listées ci-dessous avec leur valeur numérique et leur nom symbolique. Rappelez vous qu'ils ne sont pas portables vers d'autres implémentations SQL. Pour simplifier le portage des applications vers le schéma SQLSTATE, les valeurs SQLSTATE sont aussi listées. Il n'y a pas, toutefois, de correspondance un à un ou un à plusieurs entre les deux schémas (c'est en fait du plusieurs à plusieurs), vous devriez donc consulter la liste globale SQLSTATE dans Annexe A, Codes d'erreurs de PostgreSQL au cas par cas.

Voici les valeurs de SQLCODE assignées:

0 (ECPG_NO_ERROR)

Indique pas d'erreur. (SQLSTATE 00000)

100 (ECPG_NOT_FOUND)

C'est un état sans danger indicant que la dernière commande a récupéré ou traité zéro enregistrements, ou que vous êtes au bout du curseur. (SQLSTATE 02000)

Quand vous bouclez sur un curseur, vous pourriez utiliser ce code comme façon de détecter quand arrêter la boucle, comme ceci:

while (1)
{
    EXEC SQL FETCH ... ;
    if (sqlca.sqlcode == ECPG_NOT_FOUND)
        break;
}

Mais WHENEVER NOT FOUND DO BREAK fait en fait cela en interne, il n'y a donc habituellement aucun avantage à écrire ceci de façon explicite.

-12 (ECPG_OUT_OF_MEMORY)

Indique que votre mémoire virtuelle est épuisée. La valeur numérique est définie comme -ENOMEM. (SQLSTATE YE001)

-200 (ECPG_UNSUPPORTED)

Indique que le préprocesseur a généré quelque chose que la librairie ne connait pas. Peut-être êtes vous en train d'utiliser des versions incompatibles du préprocesseur et de la librairie. (SQLSTATE YE002)

-201 (ECPG_TOO_MANY_ARGUMENTS)

Cela signifie que la commande a spécifié plus de variables hôte que la commande n'en attendait. (SQLSTATE 07001 or 07002)

-202 (ECPG_TOO_FEW_ARGUMENTS)

Cela signifie que la commande a spécifié moins de variables hôtes que la commande n'en attendait. (SQLSTATE 07001 or 07002)

-203 (ECPG_TOO_MANY_MATCHES)

Cela signifie que la requête a retourné pluiseurs enregistrements mais que l'ordre n'était capable d'en recevoir qu'un (par exemple parce que les variables spécifiées ne sont pas des tableaux. (SQLSTATE 21000)

-204 (ECPG_INT_FORMAT)

La variable hôte est du type int et la donnée dans la base de données est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un int. La librairie utilise strtol() pour cette conversion. (SQLSTATE 42804).

-205 (ECPG_UINT_FORMAT)

La variable hôte est du type unsigned int et la donnée dans la base de données est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un unsigned int. La librairie utilise strtoul() pour cette conversion. (SQLSTATE 42804).

-206 (ECPG_FLOAT_FORMAT)

La variable hôte est du type float et la donnée dans la base de données est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un float. La librairie utilise strtod() pour cette conversion. (SQLSTATE 42804).

-207 (ECPG_NUMERIC_FORMAT)

La variable hôte est du type numeric et la donnée dans la base de données est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un numeric. (SQLSTATE 42804).

-208 (ECPG_INTERVAL_FORMAT)

La variable hôte est du type interval et la donnée dans la base de données est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un interval. (SQLSTATE 42804).

-209 (ECPG_DATE_FORMAT)

La variable hôte est du type date et la donnée dans la base de données est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un date. (SQLSTATE 42804).

-210 (ECPG_TIMESTAMP_FORMAT)

La variable hôte est du type timestamp et la donnée dans la base de données est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un timestamp. (SQLSTATE 42804).

-211 (ECPG_CONVERT_BOOL)

Cela signifie que la variable hôte est de type bool et que la donnée dans la base n'est ni 't' ni 'f'. (SQLSTATE 42804)

-212 (ECPG_EMPTY)

L'ordre envoyé au serveur PostgreSQL™ était vide. (Cela ne peut normalement pas arriver dans un programme SQL embarqué, cela pourrait donc laisser supposer une erreur interne.) (SQLSTATE YE002)

-213 (ECPG_MISSING_INDICATOR)

Une valeur null a été retournée et aucune variable d'indicateur null n'a été fournie. (SQLSTATE 22002)

-214 (ECPG_NO_ARRAY)

Une variable ordinaire a été utilisée à un endroit qui nécessite un tableau. (SQLSTATE 42804)

-215 (ECPG_DATA_NOT_ARRAY)

La base a retourné une variable ordinaire à un endroir qui nécessite une variable de tableau. (SQLSTATE 42804)

-220 (ECPG_NO_CONN)

Le programme a essayé d'utiliser une connexion qui n'existe pas. (SQLSTATE 08003)

-221 (ECPG_NOT_CONN)

Le programme a essayé d'utiliser une connexion qui existe mais n'est pas ouverte. (C'est une erreur interne.) (SQLSTATE YE002)

-230 (ECPG_INVALID_STMT)

L'ordre que vous essayez d'exécuter n'a pas été préparé. (SQLSTATE 26000)

-239 (ECPG_INFORMIX_DUPLICATE_KEY)

Erreur de clé en doublon, violation de contrainte unique (mode de compatibilité Informix). (SQLSTATE 23505)

-240 (ECPG_UNKNOWN_DESCRIPTOR)

Le descripteur spécifié n'a pas été trouvé. L'ordre que vous essayez d'utiliser n'a pas été préparé. (SQLSTATE 33000)

-241 (ECPG_INVALID_DESCRIPTOR_INDEX)

L'index de descripteur spécifié était hors de portée. (SQLSTATE 07009)

-242 (ECPG_UNKNOWN_DESCRIPTOR_ITEM)

Un objet de descripteur invalide a été demandé. (C'est une erreur interne.) (SQLSTATE YE002)

-243 (ECPG_VAR_NOT_NUMERIC)

Durant l'exécution d'un ordre dynamique, la base a retourné une valeur numeric et la variable hôte n'était pas numeric. (SQLSTATE 07006)

-244 (ECPG_VAR_NOT_CHAR)

Durant l'exécution d'un ordre dynamique, la base a retourné une valeur non numeric et la variable hôte était numeric. (SQLSTATE 07006)

-284 (ECPG_INFORMIX_SUBSELECT_NOT_ONE)

Un résultat de la sous-requête n'était pas un enregistrement seul (mode de compatibilité Informix). (SQLSTATE 21000)

-400 (ECPG_PGSQL)

Une erreur causée par le serveur PostgreSQL™. Le message contient le message d'erreur du serveur PostgreSQL™.

-401 (ECPG_TRANS)

Le serveur PostgreSQL™ a signalé que nous ne pouvons pas démarrer, valider ou annuler la transaction. (SQLSTATE 08007)

-402 (ECPG_CONNECT)

La tentative de connexion à la base n'a pas réussi. (SQLSTATE 08001)

-403 (ECPG_DUPLICATE_KEY)

Erreur de clé dupliquée, violation d'une contrainte unique. (SQLSTATE 23505)

-404 (ECPG_SUBSELECT_NOT_ONE)

Un résultat de la sous-requête n'est pas un enregistrement unique. (SQLSTATE 21000)

-602 (ECPG_WARNING_UNKNOWN_PORTAL)

Un nom de curseur invalide a été spécifié. (SQLSTATE 34000)

-603 (ECPG_WARNING_IN_TRANSACTION)

Transaction en cours. (SQLSTATE 25001)

-604 (ECPG_WARNING_NO_TRANSACTION)

Il n'y a pas de transaction active (en cours). (SQLSTATE 25P01)

-605 (ECPG_WARNING_PORTAL_EXISTS)

Un nom de curseur existant a été spécifié. (SQLSTATE 42P03)