Cette section décrit la gestion des conditions exceptionnelles et des avertissements dans un programme SQL embarqué. Il existe plusieurs fonctions non exclusives pour cela.
Une méthode simple de récupération des erreurs et des avertissements consiste à configurer une action spécifique à exécuter à chaque fois qu'une condition particulière survient. En général :
EXEC SQL WHENEVER condition action;
condition peut prendre une des valeurs suivantes :
l'action indiquée est appelée lorsqu'une erreur survient pendant l'exécution d'une instruction SQL ;
l'action indiquée est appelée lorsqu'un avertissement survient pendant l'exécution d'une instruction SQL ;
l'action indiquée est appelée lorsqu'une instruction ne récupère ou n'affecte aucune ligne (cette condition n'est pas une erreur mais il peut être intéressant de la gérer de façon particulière).
action peut prendre une des valeurs suivantes :
la condition est ignorée. C'est le comportement par défaut ;
saute au label indiqué (à l'iade d'une instruction C goto) ;
affiche un message sur la sortie standard. Cela est utile pour les programmes simples ou lors du prototypage. Les détails du message ne peuvent pas être configurés ;
appelle exit(1), ce qui termine le programme ;
exécute l'instruction C break. Cela ne doit être utilisé que dans les boucles et les instructions switch ;
appelle les fonctions C indiquées avec les arguments indiqués.
Le standard SQL ne définit que les actions CONTINUE et GOTO (et GO TO).
L'exemple suivant est utilisable dans un programme simple. Il affiche un message lorsqu'un avertissement survient et termine le programme quand une erreur se produit :
EXEC SQL WHENEVER SQLWARNING SQLPRINT; EXEC SQL WHENEVER SQLERROR STOP;
L'instruction EXEC SQL WHENEVER est une directive du préprocesseur SQL, pas une instruction C. Les actions sur erreur ou avertissement qu'elle définit s'appliquent à toutes les instructions SQL embarquées qui apparaissent avant l'endroit où le gestionnaire est défini, à moins qu'une action différente n'ait été définie pour la même condition entre le premier EXEC SQL WHENEVER et l'instruction SQL qui engendre la condition, quelque soit le flux de contrôle du programme C. De ce fait, aucun des deux extraits de programme C qui suivent n'a le comportement désiré :
/* * FAUX */ int main(int argc, char *argv[]) { ... if (verbose) { EXEC SQL WHENEVER SQLWARNING SQLPRINT; } ... EXEC SQL SELECT ...; ... }
/* * FAUX */ 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 puissante des erreurs, l'interface du SQL embarqué fournit une variable globale de nom sqlca qui a la structure suivante :
struct { char sqlcaid[8]; long sqlabc; long sqlcode; struct { int sqlerrml; char sqlerrmcSQLERRMC_LEN; } sqlerrm; char sqlerrp[8]; long sqlerrd[6]; char sqlwarn[8]; char sqlstate[5]; } sqlca;
(Dans un programme multithreadé, chaque thread obtient automatiquement sa propre copie de sqlca. Ceci fonctionne de façon similaire à la gestion de la variable globale C standard errno.)
sqlca couvre à la fois les avertissements et les erreurs. Si plusieurs avertissements ou erreurs surviennent lors de l'exécution d'une instruction, alors sqlca ne contient que les informations relatives à la dernière.
Si aucune erreur ne survient dans la dernière instruction SQL, sqlca.sqlcode vaut 0 et sqlca.sqlstate vaut "00000". Si un avertissement ou une erreur survient, alors sqlca.sqlcode est négatif et sqlca.sqlstate est différent de "00000". Une valeur positive de sqlca.sqlcode indique une condition sans dommage, telle que « la dernière requête n'a retourné aucune ligne ». sqlcode et sqlstate sont deux schémas de code d'erreur différents ; les détails apparaissent ci-dessous.
Si la dernière instruction 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 de lignes traitées ou renvoyées, si applicable à la commande.
En cas d'erreur ou d'avertissement, sqlca.sqlerrm.sqlerrmc contient une chaîne décrivant l'erreur. Le champ sqlca.sqlerrm.sqlerrml contient la longueur du message d'erreur stocké dans sqlca.sqlerrm.sqlerrmc (le résultat de strlen(), sans réel intérêt pour un programmeur C). Certains messages sont trop longs pour entrer dans le tableau sqlerrmc de taille fixe ; ils sont alors 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 lors de son stockage dans une variable hôte. sqlca.sqlwarn[0] est positionné à W si tout autre élément est positionné pour indiquer un avertissement.
Les champs sqlcaid, sqlcabc, sqlerrp et les éléments restant de sqlerrd et sqlwarn ne contiennent actuellement aucune information utile.
La structure sqlca n'est pas définie dans le standard SQL mais elle est implantée dans plusieurs autres systèmes de bases de données SQL. Leurs définitions sont similaires dans l'esprit, mais l'écriture d'applications portables nécessite une étude attentive des autres implantations.
Les champs sqlca.sqlstate et sqlca.sqlcode sont deux schémas différents fournissant des codes d'erreur. Les deux sont dérivés du standard SQL mais SQLCODE est indiqué comme obsolète dans l'édition SQL-92 du standard et a été supprimé dans les éditions ultérieures. C'est pourquoi il est fortement recommandé que les nouvelles applications utilisent SQLSTATE dans les nouvelles applications.
SQLSTATE est un tableau de cinq caractères. Ces cinq caractères contiennent des chiffres ou des lettres en majuscules représentant les codes de différentes conditions d'erreur ou d'avertissement. SQLSTATE dispose d'un schéma hiérarchique : les deux premiers caractères indiquent la classe générale de la condition, les trois derniers caractères indiquent une sous-classe de la condition générale. Un 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'erreurs SQLSTATE ; de ce fait, un haut degré de cohérence peut être atteint en utilisant ce schéma de code d'erreur dans toutes les applications. Pour plus d'informations, voir l'Annexe A, Codes d'erreurs de PostgreSQL™.
SQLCODE, schéma obsolète de codes d'erreur, est un simple entier. Une valeur 0 indique un 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 la dernière commande n'a renvoyé ou modifié aucune ligne, et aucune valeur négative spécifique. De ce fait, ce schéma n'est que faiblement portable et ne propose pas d'affectation de code hiérarchique. Historiquement, le processeur de SQL embarqué pour PostgreSQL™ a affecté quelques valeurs à SQLCODE spécifiques pour sa propre utilisation. ces valeurs sont listées ci-dessous avec leurs valeurs numériques et leurs noms symboliques. Elles ne sont pas portables vers d'autres implantations SQL. Pour simplifier le portage d'applications vers la schéma SQLSTATE, le code SQLSTATE correspondant est également affiché. Il n'y a toutefois pas de correspondance une-à-une ou une-à-plusieurs entre les deux schémas (en fait, c'est plutôt plusieurs-à-plusieurs). Il est préférable de consulter le schéma SQLSTATE global dans l'Annexe A, Codes d'erreurs de PostgreSQL™ pour chaque cas.
Valeurs affectées à SQLCODE :
la mémoire virtuelle est épuisée, (SQLSTATE YE001) ;
le préprocesseur a engendré quelque chose que la bibliothèque ne connaît pas. Il peut s'agir de l'exécution de versions incompatibles du préprocesseur et de la bibliothèque, (SQLSTATE YE002). ;
la commande indique plus de variables hôtes que n'en attend la commande (SQLSTATE 07001 ou 07002) ;
la commande indique moins de variables hôtes que n'en attend la commande (SQLSTATE 07001 ou 07002) ;
une requête retourne plusieurs lignes alors que l'instruction est préparée à ne stocker qu'une seule ligne de résultat (par exemple, parce que les variables indiquées ne sont pas des tableaux) (SQLSTATE 21000) ;
la variable hôte est de type int alors que la donnée dans la base est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un int. La bibliothèque utilise strtol() pour cette conversion (SQLSTATE 42804) ;
la variable hôte est de type unsigned int alors que la donnée de la base est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un unsigned int. La bibliothèque utilise strtoul() pour cette conversion (SQLSTATE 42804) ;
la variable hôte est de type float alors que la donnée de la base est d'un type différent et contient une valeur qui ne peut pas être interprétée comme un float. La bibliothèque utilise strtod() pour cette conversion (SQLSTATE 42804) ;
la variable hôte est de type bool alors que la donnée de la base n'est ni 't' ni 'f' (SQLSTATE 42804) ;
l'instruction envoyée au serveur PostgreSQL™ est vide (ceci ne peut normalement pas survenir dans un programme SQL embarqué et peut donc indiquer une erreur interne) (SQLSTATE YE002) ;
une valeur NULL est retournée alors qu'aucune variable indicateur de nullité n'est fournie (SQLSTATE 22002) ;
une variable ordinaire est utilisée à un endroit qui requiert un tableau (SQLSTATE 42804) ;
la base de données a retourné une variable ordinaire à un endroit qui requiert une valeur de tableau (SQLSTATE 42804) ;
le programme tente d'accéder à une connexion qui n'existe pas (SQLSTATE 08003) ;
le programme tente d'accéder à une connexion qui existe mais n'est pas ouverte (ceci est une erreur interne) (SQLSTATE YE002) ;
l'instruction utilisée n'a pas été préparée (SQLSTATE 26000) ;
le descripteur indiqué n'a pas été trouvé. L'instruction utilisée n'a pas été préparée (SQLSTATE 33000) ;
l'index du descripteur indiqué est hors échelle (SQLSTATE 07009) ;
un élément invalide du descripteur est demandé (erreur interne) (SQLSTATE YE002) ;
lors de l'exécution d'une instruction dynamique, la base de données a retourné une valeur numérique alors que la variable hôte n'est pas numérique (SQLSTATE 07006) ;
lors de l'exécution d'une instruction dynamique, la base de données a retourné une valeur non numérique alors que la variable hôte est numérique (SQLSTATE 07006) ;
le serveur PostgreSQL™ a engendré une erreur. Le message contient le message d'erreur du serveur PostgreSQL™ ;
le serveur PostgreSQL™ signale que la transaction ne peut être commencée, validée ou annulée (SQLSTATE 08007) ;
la tentative de connexion à la base de données a échoué (SQLSTATE 08001) ;
il s'agit d'une condition sans gravité qui indique que la dernière commande n'a récupéré ni traité aucune ligne, ou que la fin du curseur est atteinte (SQLSTATE 02000).