

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.
WHENEVER.
     sqlca.
     
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 WHENEVERconditionaction;
    condition peut être un des éléments suivants:
    
SQLERRORL'action spécifiée est appelée dès qu'une erreur se produit durant l'exécution d'un ordre SQL.
SQLWARNINGL'action spécifiée est appelée dès qu'un avertissement se produit durant l'exécution d'un ordre SQL.
NOT FOUNDL'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:
    
CONTINUECela signifie en fait que la condition est ignorée. C'est le comportement par défaut.
GOTO labelGO TO label
        Sauter au label spécifié (en utilisant un ordre goto
        C).
       
SQLPRINTAffiche 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.
       
DO CONTINUE
        Exécute l'instruction C continue. Ceci doit
        seulement être utilisé dans les instructions de boucle. Son exécution
        fait que le flot de contrôle est renvoyé au sommet de la boucle.
       
CALL name (args)DO name (args)
        Appelle la fonction C spécifiée avec les arguments spécifiés. (Son
        utilisation est différente des instructions CALL et
        DO dans la grammaire habituelle de PostgreSQL.)
       
    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;
}
    
    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,
    sqlabc,
    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
===============
    
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.
   
    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
    au cas par cas.
   
    Voici les valeurs de SQLCODE assignées:
    
ECPG_NO_ERROR)Indique pas d'erreur. (SQLSTATE 00000)
ECPG_NOT_FOUND)C'est un état sans danger indiquant 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.
       
ECPG_OUT_OF_MEMORY)
        Indique que votre mémoire virtuelle est épuisée. La valeur
        numérique est définie comme -ENOMEM.
        (SQLSTATE YE001)
       
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)
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)
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)
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)
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).
       
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).
       
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).
       
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).
       
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).
       
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).
       
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).
       
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)
       
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)
ECPG_MISSING_INDICATOR)Une valeur null a été retournée et aucune variable d'indicateur null n'a été fournie. (SQLSTATE 22002)
ECPG_NO_ARRAY)Une variable ordinaire a été utilisée à un endroit qui nécessite un tableau. (SQLSTATE 42804)
ECPG_DATA_NOT_ARRAY)La base a retourné une variable ordinaire à un endroir qui nécessite une variable de tableau. (SQLSTATE 42804)
ECPG_ARRAY_INSERT)La valeur n'a pas pu être insérée dans le tableau. (SQLSTATE 42804)
ECPG_NO_CONN)Le programme a essayé d'utiliser une connexion qui n'existe pas. (SQLSTATE 08003)
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)
ECPG_INVALID_STMT)L'ordre que vous essayez d'exécuter n'a pas été préparé. (SQLSTATE 26000)
ECPG_INFORMIX_DUPLICATE_KEY)Erreur de clé en doublon, violation de contrainte unique (mode de compatibilité Informix). (SQLSTATE 23505)
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)
ECPG_INVALID_DESCRIPTOR_INDEX)L'index de descripteur spécifié était hors de portée. (SQLSTATE 07009)
ECPG_UNKNOWN_DESCRIPTOR_ITEM)Un objet de descripteur invalide a été demandé. (C'est une erreur interne.) (SQLSTATE YE002)
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)
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)
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)
ECPG_PGSQL)Une erreur causée par le serveur PostgreSQL. Le message contient le message d'erreur du serveur PostgreSQL.
ECPG_TRANS)Le serveur PostgreSQL a signalé que nous ne pouvons pas démarrer, valider ou annuler la transaction. (SQLSTATE 08007)
ECPG_CONNECT)La tentative de connexion à la base n'a pas réussi. (SQLSTATE 08001)
ECPG_DUPLICATE_KEY)Erreur de clé dupliquée, violation d'une contrainte unique. (SQLSTATE 23505)
ECPG_SUBSELECT_NOT_ONE)Un résultat de la sous-requête n'est pas un enregistrement unique. (SQLSTATE 21000)
ECPG_WARNING_UNKNOWN_PORTAL)Un nom de curseur invalide a été spécifié. (SQLSTATE 34000)
ECPG_WARNING_IN_TRANSACTION)Transaction en cours. (SQLSTATE 25001)
ECPG_WARNING_NO_TRANSACTION)Il n'y a pas de transaction active (en cours). (SQLSTATE 25P01)
ECPG_WARNING_PORTAL_EXISTS)Un nom de curseur existant a été spécifié. (SQLSTATE 42P03)