| 1 |
<!-- |
|---|
| 2 |
$Header: /var/lib/cvs/pgsql-fr/sgml/ecpg.sgml,v 1.7.2.5 2005/09/29 06:51:33 guillaume Exp $ |
|---|
| 3 |
--> |
|---|
| 4 |
|
|---|
| 5 |
<chapter id="ecpg"> |
|---|
| 6 |
<title><application>ECPG</application> - <acronym>SQL</acronym> embarqué dans |
|---|
| 7 |
du C</title> |
|---|
| 8 |
|
|---|
| 9 |
<indexterm zone="ecpg"><primary>SQL embarqué</primary><secondary>dans du |
|---|
| 10 |
C</secondary></indexterm> |
|---|
| 11 |
<indexterm zone="ecpg"><primary>C</primary></indexterm> |
|---|
| 12 |
<indexterm zone="ecpg"><primary>ECPG</primary></indexterm> |
|---|
| 13 |
|
|---|
| 14 |
<para> |
|---|
| 15 |
Ce chapitre décrit l'interface <acronym>SQL</acronym> embarqué pour |
|---|
| 16 |
<productname>PostgreSQL</productname>. Il fonctionne avec le |
|---|
| 17 |
<acronym>C</acronym> et le <acronym>C++</acronym>. Il a été écrit par |
|---|
| 18 |
Linus Tolke (<email>linus@epact.se</email>) et Michael Meskes |
|---|
| 19 |
(<email>meskes@postgresql.org</email>). |
|---|
| 20 |
</para> |
|---|
| 21 |
|
|---|
| 22 |
<para> |
|---|
| 23 |
Il ne fait aucun doute que cette documentation est assez incomplète. Mais du |
|---|
| 24 |
fait de la sandardisation de cette interface, des informations complémentaires sont |
|---|
| 25 |
disponibles à travers de nombreuses ressources traitant du SQL. |
|---|
| 26 |
</para> |
|---|
| 27 |
|
|---|
| 28 |
<sect1 id="ecpg-concept"> |
|---|
| 29 |
<title>Concept</title> |
|---|
| 30 |
|
|---|
| 31 |
<para> |
|---|
| 32 |
Un programme <acronym>SQL</acronym> embarqué consiste en du code écrit dans un langage de |
|---|
| 33 |
programmation ordinaire, dans le cas présent, le <acronym>C</acronym>, mélangé à des commandes SQL incluses dans |
|---|
| 34 |
des sections spécialement marquées. Pour construire le programme, le code |
|---|
| 35 |
source est d'abord passé au préprocesseur <acronym>SQL</acronym> embarqué qui le convertit en un |
|---|
| 36 |
programme <acronym>C</acronym> ordinaire. Il peut alors être traité par un outil de compilation |
|---|
| 37 |
<acronym>C</acronym>. |
|---|
| 38 |
</para> |
|---|
| 39 |
|
|---|
| 40 |
<para> |
|---|
| 41 |
Le <acronym>SQL</acronym> embarqué a des avantages par rapport aux autres méthodes |
|---|
| 42 |
de gestion de commandes <acronym>SQL</acronym> dans du code C. Premièrement, |
|---|
| 43 |
il gère le passage laborieux des informations de et vers les variables du |
|---|
| 44 |
programme <acronym>C</acronym>. Deuxièmement, le code SQL du programme est |
|---|
| 45 |
vérifié syntaxiquement au moment de la construction. Troisièmement, le |
|---|
| 46 |
<acronym>SQL</acronym> embarqué en C est spécifié dans le standard |
|---|
| 47 |
<acronym>SQL</acronym> et supporté par de nombreux systèmes de bases de |
|---|
| 48 |
données <acronym>SQL</acronym>. L'implémentation <productname>PostgreSQL</> |
|---|
| 49 |
est conçue pour correspondre au mieux à ce standard. Il est de ce fait |
|---|
| 50 |
assez facile de porter les programmes <acronym>SQL</acronym> |
|---|
| 51 |
embarqués écrits pour d'autres bases de données SQL vers |
|---|
| 52 |
<productname>PostgreSQL</productname>. |
|---|
| 53 |
</para> |
|---|
| 54 |
|
|---|
| 55 |
<para> |
|---|
| 56 |
Comme indiqué précédemment, les programmes écrits pour l'interface <acronym>SQL</acronym> |
|---|
| 57 |
embarqué sont des programmes C normaux contenant un code spécial inséré pour |
|---|
| 58 |
réaliser les actions en relation avec la base de données. Ce code spécial a |
|---|
| 59 |
toujours la forme |
|---|
| 60 |
<programlisting> |
|---|
| 61 |
EXEC SQL ...; |
|---|
| 62 |
</programlisting> |
|---|
| 63 |
Ces instructions prennent syntaxiquement la place d'une instruction C. |
|---|
| 64 |
Suivant l'instruction particulière, elles peuvent apparaître dans le |
|---|
| 65 |
contexte global ou à l'intérieur d'une fonction. Les instructions |
|---|
| 66 |
<acronym>SQL</acronym> embarquées suivent les règles de sensibilité à la |
|---|
| 67 |
casse d'un code <acronym>SQL</acronym> normal, et non pas ceux du C. |
|---|
| 68 |
</para> |
|---|
| 69 |
|
|---|
| 70 |
<para> |
|---|
| 71 |
Les sections suivantes expliquent toutes les instructions SQL embarquées. |
|---|
| 72 |
</para> |
|---|
| 73 |
</sect1> |
|---|
| 74 |
|
|---|
| 75 |
<sect1 id="ecpg-connect"> |
|---|
| 76 |
<title>Se connecter au serveur de bases de données</title> |
|---|
| 77 |
|
|---|
| 78 |
<para> |
|---|
| 79 |
La connexion à une base de données se fait en utilisant l'instruction |
|---|
| 80 |
suivante : |
|---|
| 81 |
<programlisting> |
|---|
| 82 |
EXEC SQL CONNECT TO <replaceable>cible</replaceable> <optional>AS <replaceable>nom-connexion</replaceable></optional> <optional>USER <replaceable>nom-utilisateur</replaceable></optional>; |
|---|
| 83 |
</programlisting> |
|---|
| 84 |
La <replaceable>cible</replaceable> peut être spécifiée d'une des façons |
|---|
| 85 |
suivantes : |
|---|
| 86 |
|
|---|
| 87 |
<itemizedlist> |
|---|
| 88 |
<listitem> |
|---|
| 89 |
<simpara><literal><replaceable>nombase</><optional>@<replaceable>nomhôte</> |
|---|
| 90 |
</optional><optional>:<replaceable>port</></optional></literal> |
|---|
| 91 |
</simpara> |
|---|
| 92 |
</listitem> |
|---|
| 93 |
|
|---|
| 94 |
<listitem> |
|---|
| 95 |
<simpara><literal>tcp:postgresql://<replaceable>nomhôte</> |
|---|
| 96 |
<optional>:<replaceable>port</> </optional> |
|---|
| 97 |
<optional>/<replaceable>nombase</></optional><optional>?<replaceable> |
|---|
| 98 |
options</></optional></literal> |
|---|
| 99 |
</simpara> |
|---|
| 100 |
</listitem> |
|---|
| 101 |
|
|---|
| 102 |
<listitem> |
|---|
| 103 |
<simpara> |
|---|
| 104 |
<literal>unix:postgresql://<replaceable>nomhôte</><optional>: |
|---|
| 105 |
<replaceable>port</></optional><optional>/<replaceable>nombase</> |
|---|
| 106 |
</optional><optional>?<replaceable> options</></optional></literal> |
|---|
| 107 |
</simpara> |
|---|
| 108 |
</listitem> |
|---|
| 109 |
|
|---|
| 110 |
<listitem> |
|---|
| 111 |
<simpara> |
|---|
| 112 |
une chaîne SQL littérale contenant une des formes précédentes |
|---|
| 113 |
</simpara> |
|---|
| 114 |
</listitem> |
|---|
| 115 |
|
|---|
| 116 |
<listitem> |
|---|
| 117 |
<simpara> |
|---|
| 118 |
une référence à une variable contenant une des formes précédentes (voir les |
|---|
| 119 |
exemples) |
|---|
| 120 |
</simpara> |
|---|
| 121 |
</listitem> |
|---|
| 122 |
|
|---|
| 123 |
<listitem> |
|---|
| 124 |
<simpara> |
|---|
| 125 |
<literal>DEFAULT</literal> |
|---|
| 126 |
</simpara> |
|---|
| 127 |
</listitem> |
|---|
| 128 |
</itemizedlist> |
|---|
| 129 |
|
|---|
| 130 |
Si la cible de connexion est spécifiée littéralement (c'est-à-dire non pas via une |
|---|
| 131 |
variable de référence) et la valeur n'est pas mise entre guillemets, |
|---|
| 132 |
les règles d'insensibilité à la casse du SQL standard sont appliquées. |
|---|
| 133 |
Dans ce cas, il est possible, si cela s'avérait nécessaire, d'encadrer |
|---|
| 134 |
séparément les paramètres individuels de guillemets doubles. |
|---|
| 135 |
En pratique, l'utilisation d'une chaîne littérale (entre guillemets |
|---|
| 136 |
simples) ou d'une variable de référence engendre moins d'erreurs. La cible de |
|---|
| 137 |
connexion <literal>DEFAULT</literal> initie une connexion à la base de |
|---|
| 138 |
données standard avec l'utilisateur standard. Aucun nom d'utilisateur ou |
|---|
| 139 |
de connexion ne peut être spécifié isolément dans ce cas. |
|---|
| 140 |
</para> |
|---|
| 141 |
|
|---|
| 142 |
<para> |
|---|
| 143 |
Il existe également différentes façons de préciser le nom de l'utilisateur : |
|---|
| 144 |
|
|---|
| 145 |
<itemizedlist> |
|---|
| 146 |
<listitem> |
|---|
| 147 |
<simpara> |
|---|
| 148 |
<literal><replaceable>nomutilisateur</replaceable></literal> |
|---|
| 149 |
</simpara> |
|---|
| 150 |
</listitem> |
|---|
| 151 |
|
|---|
| 152 |
<listitem> |
|---|
| 153 |
<simpara> |
|---|
| 154 |
<literal><replaceable>nomutilisateur</replaceable>/ |
|---|
| 155 |
<replaceable>motdepasse</replaceable></literal> |
|---|
| 156 |
</simpara> |
|---|
| 157 |
</listitem> |
|---|
| 158 |
|
|---|
| 159 |
<listitem> |
|---|
| 160 |
<simpara> |
|---|
| 161 |
<literal><replaceable>nomutilisateur</replaceable> IDENTIFIED BY |
|---|
| 162 |
<replaceable>motdepasse</replaceable></literal> |
|---|
| 163 |
</simpara> |
|---|
| 164 |
</listitem> |
|---|
| 165 |
|
|---|
| 166 |
<listitem> |
|---|
| 167 |
<simpara> |
|---|
| 168 |
<literal><replaceable>nomutilisateur</replaceable> USING |
|---|
| 169 |
<replaceable>motdepasse</replaceable></literal> |
|---|
| 170 |
</simpara> |
|---|
| 171 |
</listitem> |
|---|
| 172 |
</itemizedlist> |
|---|
| 173 |
|
|---|
| 174 |
Comme indiqué ci-dessus, les paramètres |
|---|
| 175 |
<replaceable>nomutilisateur</replaceable> et |
|---|
| 176 |
<replaceable>motdepasse</replaceable> peuvent être un identificateur SQL, une |
|---|
| 177 |
chaîne SQL littérale ou une référence à une variable de type caractère. |
|---|
| 178 |
</para> |
|---|
| 179 |
|
|---|
| 180 |
<para> |
|---|
| 181 |
<replaceable>nom-connexion</replaceable> est utilisé pour gérer plusieurs |
|---|
| 182 |
connexions dans un même programme. Il peut être omis si un programme n'utilise |
|---|
| 183 |
qu'une seule connexion. La connexion la plus récemment ouverte devient la |
|---|
| 184 |
connexion courante, utilisée par défaut lorsqu'une instruction SQL est à |
|---|
| 185 |
exécuter (voir plus loin dans ce chapitre). |
|---|
| 186 |
</para> |
|---|
| 187 |
|
|---|
| 188 |
<para> |
|---|
| 189 |
Voici quelques exemples d'instructions <command>CONNECT</command> : |
|---|
| 190 |
<programlisting> |
|---|
| 191 |
EXEC SQL CONNECT TO mabase@sql.mondomaine.com; |
|---|
| 192 |
|
|---|
| 193 |
EXEC SQL CONNECT TO 'unix:postgresql://sql.mondomaine.com/mabase' AS |
|---|
| 194 |
maconnexion USER john; |
|---|
| 195 |
|
|---|
| 196 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 197 |
const char *cible = "mabase@sql.mondomaine.com"; |
|---|
| 198 |
const char *utilisateur = "john"; |
|---|
| 199 |
EXEC SQL END DECLARE SECTION; |
|---|
| 200 |
... |
|---|
| 201 |
EXEC SQL CONNECT TO :cible USER :utilisateur; |
|---|
| 202 |
</programlisting> |
|---|
| 203 |
La dernière forme utilise la variante dite de la variable de référence, |
|---|
| 204 |
à laquelle il est fait allusion ci-dessus. Nous verrons dans les prochaines sections comment |
|---|
| 205 |
utiliser des variables C dans des instructions SQL en les |
|---|
| 206 |
préfixant par un caractère deux-points. |
|---|
| 207 |
</para> |
|---|
| 208 |
|
|---|
| 209 |
<para> |
|---|
| 210 |
Il est à noter que le format de la cible de connexion n'est pas spécifié dans |
|---|
| 211 |
le standard SQL. Ainsi, lorsque l'on souhaite développer des applications portables, |
|---|
| 212 |
il est préférable d'utiliser une syntaxe basée sur le dernier exemple ci-dessus |
|---|
| 213 |
pour encapsuler la chaîne de la cible de connexion. |
|---|
| 214 |
</para> |
|---|
| 215 |
</sect1> |
|---|
| 216 |
|
|---|
| 217 |
<sect1 id="ecpg-disconnect"> |
|---|
| 218 |
<title>Fermer une connexion</title> |
|---|
| 219 |
|
|---|
| 220 |
<para> |
|---|
| 221 |
Pour fermer une connexion, l'instruction suivante est utilisée : |
|---|
| 222 |
<programlisting> |
|---|
| 223 |
EXEC SQL DISCONNECT <optional><replaceable>connexion</replaceable></optional>; |
|---|
| 224 |
</programlisting> |
|---|
| 225 |
<replaceable>connexion</replaceable> peut être spécifiée de |
|---|
| 226 |
différentes façons : |
|---|
| 227 |
|
|---|
| 228 |
<itemizedlist> |
|---|
| 229 |
<listitem> |
|---|
| 230 |
<simpara> |
|---|
| 231 |
<literal><replaceable>nom-connexion</replaceable></literal> |
|---|
| 232 |
</simpara> |
|---|
| 233 |
</listitem> |
|---|
| 234 |
|
|---|
| 235 |
<listitem> |
|---|
| 236 |
<simpara> |
|---|
| 237 |
<literal>DEFAULT</literal> |
|---|
| 238 |
</simpara> |
|---|
| 239 |
</listitem> |
|---|
| 240 |
|
|---|
| 241 |
<listitem> |
|---|
| 242 |
<simpara> |
|---|
| 243 |
<literal>CURRENT</literal> |
|---|
| 244 |
</simpara> |
|---|
| 245 |
</listitem> |
|---|
| 246 |
|
|---|
| 247 |
<listitem> |
|---|
| 248 |
<simpara> |
|---|
| 249 |
<literal>ALL</literal> |
|---|
| 250 |
</simpara> |
|---|
| 251 |
</listitem> |
|---|
| 252 |
</itemizedlist> |
|---|
| 253 |
|
|---|
| 254 |
Si aucun nom de connexion n'est spécifié, la connexion en cours est fermée. |
|---|
| 255 |
</para> |
|---|
| 256 |
|
|---|
| 257 |
<para> |
|---|
| 258 |
Il est toujours préférable qu'une application ferme explicitement |
|---|
| 259 |
chaque connexion qu'elle a ouverte. |
|---|
| 260 |
</para> |
|---|
| 261 |
</sect1> |
|---|
| 262 |
|
|---|
| 263 |
<sect1 id="ecpg-commands"> |
|---|
| 264 |
<title>Exécuter des commandes SQL</title> |
|---|
| 265 |
|
|---|
| 266 |
<para> |
|---|
| 267 |
Toute commande SQL peut être exécutée à l'intérieur d'une application SQL |
|---|
| 268 |
embarquée. Ci-dessous se trouvent quelques exemples de façons de procéder. |
|---|
| 269 |
</para> |
|---|
| 270 |
|
|---|
| 271 |
<para> |
|---|
| 272 |
Création d'une table : |
|---|
| 273 |
<programlisting> |
|---|
| 274 |
EXEC SQL CREATE TABLE foo (nombre integer, ascii char(16)); |
|---|
| 275 |
EXEC SQL CREATE UNIQUE INDEX num1 ON foo(nombre); |
|---|
| 276 |
EXEC SQL COMMIT; |
|---|
| 277 |
</programlisting> |
|---|
| 278 |
</para> |
|---|
| 279 |
|
|---|
| 280 |
<para> |
|---|
| 281 |
Insertion de lignes : |
|---|
| 282 |
<programlisting> |
|---|
| 283 |
EXEC SQL INSERT INTO foo (nombre, ascii) VALUES (9999, 'doodad'); |
|---|
| 284 |
EXEC SQL COMMIT; |
|---|
| 285 |
</programlisting> |
|---|
| 286 |
</para> |
|---|
| 287 |
|
|---|
| 288 |
<para> |
|---|
| 289 |
Suppression de lignes : |
|---|
| 290 |
<programlisting> |
|---|
| 291 |
EXEC SQL DELETE FROM foo WHERE nombre = 9999; |
|---|
| 292 |
EXEC SQL COMMIT; |
|---|
| 293 |
</programlisting> |
|---|
| 294 |
</para> |
|---|
| 295 |
|
|---|
| 296 |
<para> |
|---|
| 297 |
Sélection d'une ligne : |
|---|
| 298 |
<programlisting> |
|---|
| 299 |
EXEC SQL SELECT foo INTO :FooBar FROM table1 WHERE ascii = 'doodad'; |
|---|
| 300 |
</programlisting> |
|---|
| 301 |
</para> |
|---|
| 302 |
|
|---|
| 303 |
<para> |
|---|
| 304 |
Sélection utilisant des curseurs : |
|---|
| 305 |
<programlisting> |
|---|
| 306 |
EXEC SQL DECLARE foo_bar CURSOR FOR |
|---|
| 307 |
SELECT nombre, ascii FROM foo |
|---|
| 308 |
ORDER BY ascii; |
|---|
| 309 |
EXEC SQL OPEN foo_bar; |
|---|
| 310 |
EXEC SQL FETCH foo_bar INTO :FooBar, DooDad; |
|---|
| 311 |
... |
|---|
| 312 |
EXEC SQL CLOSE foo_bar; |
|---|
| 313 |
EXEC SQL COMMIT; |
|---|
| 314 |
</programlisting> |
|---|
| 315 |
</para> |
|---|
| 316 |
|
|---|
| 317 |
<para> |
|---|
| 318 |
Mises à jour : |
|---|
| 319 |
<programlisting> |
|---|
| 320 |
EXEC SQL UPDATE foo |
|---|
| 321 |
SET ascii = 'foobar' |
|---|
| 322 |
WHERE nombre = 9999; |
|---|
| 323 |
EXEC SQL COMMIT; |
|---|
| 324 |
</programlisting> |
|---|
| 325 |
</para> |
|---|
| 326 |
|
|---|
| 327 |
<para> |
|---|
| 328 |
Les marques de la forme |
|---|
| 329 |
<quote><literal>:<replaceable>quelquechose</replaceable></literal></quote> |
|---|
| 330 |
sont des <firstterm>variables hôtes</firstterm>, c'est-à-dire qu'elles font |
|---|
| 331 |
référence à des variables dans le programme C. Elles sont expliquées dans |
|---|
| 332 |
la <xref linkend="ecpg-variables">. |
|---|
| 333 |
</para> |
|---|
| 334 |
|
|---|
| 335 |
<para> |
|---|
| 336 |
Dans le mode par défaut, les instructions ne sont validées que lorsque |
|---|
| 337 |
<command>EXEC SQL COMMIT</command> est exécuté. L'interface SQL embarquée |
|---|
| 338 |
supporte aussi la validation automatique des transactions (aussi connue des |
|---|
| 339 |
autres interfaces) via l'option <option>-t</option> en ligne de commande pour |
|---|
| 340 |
<command>ecpg</command> (voir ci-dessous) ou via l'instruction <literal>EXEC |
|---|
| 341 |
SQL SET AUTOCOMMIT TO ON</literal>. En mode de validation automatique, chaque |
|---|
| 342 |
commande est automatiquement validée sauf si elle est à l'intérieur d'un bloc |
|---|
| 343 |
de transaction explicite. Ce mode peut être explicitement désactivé en |
|---|
| 344 |
utilisant <literal>EXEC SQL SET AUTOCOMMIT TO OFF</literal>. |
|---|
| 345 |
</para> |
|---|
| 346 |
</sect1> |
|---|
| 347 |
|
|---|
| 348 |
<sect1 id="ecpg-set-connection"> |
|---|
| 349 |
<title>Choisir une connexion</title> |
|---|
| 350 |
|
|---|
| 351 |
<para> |
|---|
| 352 |
Les instructions SQL affichées dans la section précédente sont exécutées à |
|---|
| 353 |
partir de la connexion courante, c'est-à-dire la dernière à avoir été ouverte. |
|---|
| 354 |
Il y a deux façons de gérer l'utilisation de plusieurs connexions dans une |
|---|
| 355 |
application. |
|---|
| 356 |
</para> |
|---|
| 357 |
|
|---|
| 358 |
<para> |
|---|
| 359 |
La première option est de choisir explicitement une connexion pour chaque |
|---|
| 360 |
instruction SQL, par exemple |
|---|
| 361 |
<programlisting> |
|---|
| 362 |
EXEC SQL AT <replaceable>nom-connexion</replaceable> SELECT ...; |
|---|
| 363 |
</programlisting> |
|---|
| 364 |
Cette option est particulièrement adaptée si l'application a besoin |
|---|
| 365 |
d'utiliser plusieurs connexions en ordre divers. |
|---|
| 366 |
</para> |
|---|
| 367 |
|
|---|
| 368 |
<para> |
|---|
| 369 |
La seconde option est d'exécuter une instruction pour basculer la connexion |
|---|
| 370 |
courante. L'instruction est : |
|---|
| 371 |
<programlisting> |
|---|
| 372 |
EXEC SQL SET CONNECTION <replaceable>connection-name</replaceable>; |
|---|
| 373 |
</programlisting> |
|---|
| 374 |
Cette option est particulièrement intéressante si un grand nombre |
|---|
| 375 |
d'instructions doivent être exécutées à partir de la même connexion. Elle ne tient pas |
|---|
| 376 |
compte des threads. |
|---|
| 377 |
</para> |
|---|
| 378 |
</sect1> |
|---|
| 379 |
|
|---|
| 380 |
<sect1 id="ecpg-variables"> |
|---|
| 381 |
<title>Utiliser des variables hôtes</title> |
|---|
| 382 |
|
|---|
| 383 |
<para> |
|---|
| 384 |
Dans la <xref linkend="ecpg-commands">, nous avons vu comment exécuter des |
|---|
| 385 |
instructions SQL à partir d'un programme SQL embarqué. Quelques-unes de ces |
|---|
| 386 |
instructions n'utilisent que des valeurs fixes. Elles n'offrent pas la |
|---|
| 387 |
possibilité d'insérer des valeurs fournies par l'utilisateur dans les |
|---|
| 388 |
instructions. Elles ne permettent pas non plus au programme de traiter |
|---|
| 389 |
les valeurs renvoyées par la requête. |
|---|
| 390 |
Ces types d'instructions ne sont pas vraiment utiles dans les |
|---|
| 391 |
applications réelles. Cette section explique en détail comment |
|---|
| 392 |
échanger des données entre votre programme C et les instructions SQL embarquées |
|---|
| 393 |
en utilisant un mécanisme simple appelé <firstterm>variables |
|---|
| 394 |
hôtes</firstterm>. |
|---|
| 395 |
</para> |
|---|
| 396 |
|
|---|
| 397 |
<sect2> |
|---|
| 398 |
<title>Aperçu</title> |
|---|
| 399 |
|
|---|
| 400 |
<para> |
|---|
| 401 |
Échanger des données entre le programme C et les instructions SQL est |
|---|
| 402 |
particulièrement simple en SQL embarqué. Plutôt que de laisser le programme |
|---|
| 403 |
copier les données dans l'instruction, ce qui implique un certain nombre de |
|---|
| 404 |
complications, dont la bonne mise entre guillemets de la valeur, il est plus simple |
|---|
| 405 |
d'écrire le nom de la variable C dans l'instruction SQL en la préfixant par un |
|---|
| 406 |
caractère deux-points. Par exemple : |
|---|
| 407 |
<programlisting> |
|---|
| 408 |
EXEC SQL INSERT INTO unetable VALUES (:v1, 'foo', :v2); |
|---|
| 409 |
</programlisting> |
|---|
| 410 |
Cette instruction fait référence à deux variables C nommées |
|---|
| 411 |
<varname>v1</varname> et <varname>v2</varname>, et utilise également une |
|---|
| 412 |
chaîne littérale SQL pour illustrer l'absence de restriction à l'utilisation |
|---|
| 413 |
d'un type de données ou d'un autre. |
|---|
| 414 |
</para> |
|---|
| 415 |
|
|---|
| 416 |
<para> |
|---|
| 417 |
Ce style d'insertions de variables C dans des instructions SQL fonctionne |
|---|
| 418 |
dans tous les cas où l'on attend une expression de valeur dans une instruction SQL. Dans |
|---|
| 419 |
l'environnement SQL, nous appelons les références à des variables C |
|---|
| 420 |
des <firstterm>variables hôtes</firstterm>. |
|---|
| 421 |
</para> |
|---|
| 422 |
</sect2> |
|---|
| 423 |
|
|---|
| 424 |
<sect2> |
|---|
| 425 |
<title>Sections de déclaration</title> |
|---|
| 426 |
|
|---|
| 427 |
<para> |
|---|
| 428 |
Pour passer des données du programme à la base de données, |
|---|
| 429 |
comme paramètre d'une requête par exemple, ou pour passer des données de la |
|---|
| 430 |
base au programme, les variables C supposées contenir ces données doivent être |
|---|
| 431 |
déclarées dans des sections spécialement marquées pour que le préprocesseur |
|---|
| 432 |
du SQL embarqué soit averti de leur présence. |
|---|
| 433 |
</para> |
|---|
| 434 |
|
|---|
| 435 |
<para> |
|---|
| 436 |
Cette section commence avec |
|---|
| 437 |
<programlisting> |
|---|
| 438 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 439 |
</programlisting> |
|---|
| 440 |
et se termine avec |
|---|
| 441 |
<programlisting> |
|---|
| 442 |
EXEC SQL END DECLARE SECTION; |
|---|
| 443 |
</programlisting> |
|---|
| 444 |
Entre ces lignes, on trouvera des déclarations normales de variables C, comme |
|---|
| 445 |
<programlisting> |
|---|
| 446 |
int x; |
|---|
| 447 |
char foo[16], bar[16]; |
|---|
| 448 |
</programlisting> |
|---|
| 449 |
Il peut y avoir autant de sections de déclarations dans un programme que |
|---|
| 450 |
souhaité. |
|---|
| 451 |
</para> |
|---|
| 452 |
|
|---|
| 453 |
<para> |
|---|
| 454 |
Les déclarations sont aussi placées dans le fichier de sortie comme des |
|---|
| 455 |
variables C normales. Du coup, il n'est plus besoin de les déclarer à |
|---|
| 456 |
nouveau. Les variables qui n'ont pas pour but d'être utilisées dans des |
|---|
| 457 |
commandes SQL peuvent être normalement déclarées en dehors des sections |
|---|
| 458 |
spéciales. |
|---|
| 459 |
</para> |
|---|
| 460 |
|
|---|
| 461 |
<para> |
|---|
| 462 |
La définition d'une structure ou union doit aussi être saisie dans une |
|---|
| 463 |
section <literal>DECLARE</>. Sinon, le préprocesseur, ne connaissant pas leur |
|---|
| 464 |
définition, ne pourra pas gérer ces types. |
|---|
| 465 |
</para> |
|---|
| 466 |
|
|---|
| 467 |
<para> |
|---|
| 468 |
Le type spécial <type>VARCHAR</type> est converti dans une <type>struct</> |
|---|
| 469 |
nommée pour chaque variable. Une déclaration telle que |
|---|
| 470 |
<programlisting> |
|---|
| 471 |
VARCHAR var[180]; |
|---|
| 472 |
</programlisting> |
|---|
| 473 |
est convertie en |
|---|
| 474 |
<programlisting> |
|---|
| 475 |
struct varchar_var { int len; char arr[180]; } var; |
|---|
| 476 |
</programlisting> |
|---|
| 477 |
Cette structure est utilisable pour créer une interface des données SQL de type |
|---|
| 478 |
<type>varchar</type>. |
|---|
| 479 |
</para> |
|---|
| 480 |
</sect2> |
|---|
| 481 |
|
|---|
| 482 |
<sect2> |
|---|
| 483 |
<title><command>SELECT INTO</command> et <command>FETCH |
|---|
| 484 |
INTO</command></title> |
|---|
| 485 |
|
|---|
| 486 |
<para> |
|---|
| 487 |
Nous savons maintenant insérer des données engendrées par un |
|---|
| 488 |
programme dans une commande SQL. Mais comment récupérer les résultats d'une |
|---|
| 489 |
requête ? Dans ce but, le SQL embarqué fournit des variantes spéciales |
|---|
| 490 |
des commandes habituelles <command>SELECT</command> et |
|---|
| 491 |
<command>FETCH</command>. Ces commandes ont une clause |
|---|
| 492 |
<literal>INTO</literal> particulière qui spécifie les variables hôtes dans |
|---|
| 493 |
lesquelles seront stockées les valeurs récupérées. |
|---|
| 494 |
</para> |
|---|
| 495 |
|
|---|
| 496 |
<para> |
|---|
| 497 |
Voici un exemple : |
|---|
| 498 |
<programlisting> |
|---|
| 499 |
/* |
|---|
| 500 |
* Soit la table suivante : |
|---|
| 501 |
* CREATE TABLE test1 (a int, b varchar(50)); |
|---|
| 502 |
*/ |
|---|
| 503 |
|
|---|
| 504 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 505 |
int v1; |
|---|
| 506 |
VARCHAR v2; |
|---|
| 507 |
EXEC SQL END DECLARE SECTION; |
|---|
| 508 |
|
|---|
| 509 |
... |
|---|
| 510 |
|
|---|
| 511 |
EXEC SQL SELECT a, b INTO :v1, :v2 FROM test; |
|---|
| 512 |
</programlisting> |
|---|
| 513 |
La clause <literal>INTO</literal> apparaît donc entre les champs du |
|---|
| 514 |
<command>select</command> et la clause <literal>FROM</literal>. |
|---|
| 515 |
Le nombre d'éléments dans la liste du <command>select</command> |
|---|
| 516 |
et celui de la liste après <literal>INTO</literal> (aussi appelée liste |
|---|
| 517 |
cible) doivent être identiques. |
|---|
| 518 |
</para> |
|---|
| 519 |
|
|---|
| 520 |
<para> |
|---|
| 521 |
Voici un exemple utilisant la commande <command>FETCH</command> : |
|---|
| 522 |
<programlisting> |
|---|
| 523 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 524 |
int v1; |
|---|
| 525 |
VARCHAR v2; |
|---|
| 526 |
EXEC SQL END DECLARE SECTION; |
|---|
| 527 |
|
|---|
| 528 |
... |
|---|
| 529 |
|
|---|
| 530 |
EXEC SQL DECLARE foo CURSOR FOR SELECT a, b FROM test; |
|---|
| 531 |
|
|---|
| 532 |
... |
|---|
| 533 |
|
|---|
| 534 |
do { |
|---|
| 535 |
... |
|---|
| 536 |
EXEC SQL FETCH NEXT FROM foo INTO :v1, :v2; |
|---|
| 537 |
... |
|---|
| 538 |
} while (...); |
|---|
| 539 |
</programlisting> |
|---|
| 540 |
Ici, la clause <literal>INTO</literal> apparaît après toutes les autres |
|---|
| 541 |
clauses. |
|---|
| 542 |
</para> |
|---|
| 543 |
|
|---|
| 544 |
<para> |
|---|
| 545 |
Ces deux méthodes ne permettent de récupérer qu'une ligne à la |
|---|
| 546 |
fois. Pour traiter des ensembles de résultats |
|---|
| 547 |
contenant potentiellement plus d'une ligne, il faut utiliser un |
|---|
| 548 |
curseur, comme indiqué dans le second exemple. |
|---|
| 549 |
</para> |
|---|
| 550 |
</sect2> |
|---|
| 551 |
|
|---|
| 552 |
<sect2> |
|---|
| 553 |
<title>Indicateurs</title> |
|---|
| 554 |
|
|---|
| 555 |
<para> |
|---|
| 556 |
Les exemples ci-dessus ne gèrent pas les valeurs nulles (NULL). En fait, ces |
|---|
| 557 |
exemples de récupération afficheront une erreur s'ils récupèrent une |
|---|
| 558 |
valeur nulle à partir de la base de données. Pour être capable de passer des |
|---|
| 559 |
valeurs nulles à la base de données ou de récupérer des valeurs nulles de la |
|---|
| 560 |
base de données, il est nécessaire d'ajouter une deuxième spécification de |
|---|
| 561 |
variable hôte pour chaque variable hôte contenant des données. Cette seconde |
|---|
| 562 |
variable est appelée l'<firstterm>indicateur</firstterm> et contient un |
|---|
| 563 |
drapeau indiquant si la valeur est nulle, auquel cas la valeur de la variable |
|---|
| 564 |
hôte réelle est ignorée. Voici un exemple qui gère correctement la |
|---|
| 565 |
récupération de valeurs nulles : |
|---|
| 566 |
<programlisting> |
|---|
| 567 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 568 |
VARCHAR val; |
|---|
| 569 |
int val_ind; |
|---|
| 570 |
EXEC SQL END DECLARE SECTION: |
|---|
| 571 |
|
|---|
| 572 |
... |
|---|
| 573 |
|
|---|
| 574 |
EXEC SQL SELECT b INTO :val :val_ind FROM test1; |
|---|
| 575 |
</programlisting> |
|---|
| 576 |
La variable indicateur <varname>val_ind</varname> vaudra zéro si la valeur |
|---|
| 577 |
est non nulle et elle sera négative si la valeur est nulle. |
|---|
| 578 |
</para> |
|---|
| 579 |
|
|---|
| 580 |
<para> |
|---|
| 581 |
L'indicateur a une autre fonction : si la valeur de l'indicateur est |
|---|
| 582 |
positive, cela signifie que la valeur est non nulle mais qu'elle a été |
|---|
| 583 |
tronquée lors de son stockage dans la variable hôte. |
|---|
| 584 |
</para> |
|---|
| 585 |
</sect2> |
|---|
| 586 |
</sect1> |
|---|
| 587 |
|
|---|
| 588 |
<sect1 id="ecpg-dynamic"> |
|---|
| 589 |
<title>SQL dynamique</title> |
|---|
| 590 |
|
|---|
| 591 |
<para> |
|---|
| 592 |
Dans de nombreux cas, les instructions SQL particulières qu'une application |
|---|
| 593 |
doit exécuter sont connues au moment de l'écriture de l'application. |
|---|
| 594 |
Néanmoins, dans certains cas, les instructions SQL sont composées à |
|---|
| 595 |
l'exécution ou fournies par une source externe. Dans ces cas, il n'est pas possible |
|---|
| 596 |
d'embarquer directement les instructions SQL dans le code source C. Pour ce faire, il |
|---|
| 597 |
existe une fonction permettant d'appeler des instructions SQL arbitraires |
|---|
| 598 |
fournies par l'intermédiaire d'une variable de type chaîne. |
|---|
| 599 |
</para> |
|---|
| 600 |
|
|---|
| 601 |
<para> |
|---|
| 602 |
La façon la plus simple d'exécuter une instruction SQL arbitraire est |
|---|
| 603 |
d'utiliser la commande <command>EXECUTE IMMEDIATE</command>. Par |
|---|
| 604 |
exemple : |
|---|
| 605 |
<programlisting> |
|---|
| 606 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 607 |
const char *stmt = "CREATE TABLE test1 (...);"; |
|---|
| 608 |
EXEC SQL END DECLARE SECTION; |
|---|
| 609 |
|
|---|
| 610 |
EXEC SQL EXECUTE IMMEDIATE :stmt; |
|---|
| 611 |
</programlisting> |
|---|
| 612 |
Les instructions de ce type ne peuvent pas être utilisées pour récupérer des |
|---|
| 613 |
données (c'est-à-dire un <command>SELECT</command>). |
|---|
| 614 |
</para> |
|---|
| 615 |
|
|---|
| 616 |
<para> |
|---|
| 617 |
Une façon plus puissante d'exécuter des instructions SQL arbitraires est de |
|---|
| 618 |
les préparer une seule fois et de les exécuter ensuite aussi souvent que nécessaire. |
|---|
| 619 |
Il est |
|---|
| 620 |
également possible de préparer une version généralisée d'une instruction, puis |
|---|
| 621 |
d'exécuter les versions spécifiques en substituant les paramètres. Lors de la |
|---|
| 622 |
préparation de l'instruction, il suffit d'écrire des points d'interrogation |
|---|
| 623 |
aux endroits où des paramètres seront substitués par la suite. Par exemple : |
|---|
| 624 |
<programlisting> |
|---|
| 625 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 626 |
const char *stmt = "INSERT INTO test1 VALUES(?, ?);"; |
|---|
| 627 |
EXEC SQL END DECLARE SECTION; |
|---|
| 628 |
|
|---|
| 629 |
EXEC SQL PREPARE mystmt FROM :stmt; |
|---|
| 630 |
... |
|---|
| 631 |
EXEC SQL EXECUTE mystmt USING 42, 'foobar'; |
|---|
| 632 |
</programlisting> |
|---|
| 633 |
Si l'instruction exécutée retourne des valeurs, il est nécessaire d'ajouter une |
|---|
| 634 |
clause <literal>INTO</literal> : |
|---|
| 635 |
<programlisting> |
|---|
| 636 |
EXEC SQL BEGIN DECLARE SECTION; |
|---|
| 637 |
const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?"; |
|---|
| 638 |
int v1, v2; |
|---|
| 639 |
VARCHAR v3; |
|---|
| 640 |
EXEC SQL END DECLARE SECTION; |
|---|
| 641 |
|
|---|
| 642 |
EXEC SQL PREPARE mystmt FROM :stmt; |
|---|
| 643 |
... |
|---|
| 644 |
EXEC SQL EXECUTE mystmt INTO v1, v2, v3 USING 37; |
|---|
| 645 |
</programlisting> |
|---|
| 646 |
Une commande <command>EXECUTE</command> peut avoir une clause |
|---|
| 647 |
<literal>INTO</literal>, une clause <literal>USING</literal>, les deux ou |
|---|
| 648 |
aucune. |
|---|
| 649 |
</para> |
|---|
| 650 |
|
|---|
| 651 |
<para> |
|---|
| 652 |
Lorsqu'une instruction préparée n'est plus utile, il est préférable de la |
|---|
| 653 |
désallouer : |
|---|
| 654 |
<programlisting> |
|---|
| 655 |
EXEC SQL DEALLOCATE PREPARE <replaceable>name</replaceable>; |
|---|
| 656 |
</programlisting> |
|---|
| 657 |
</para> |
|---|
| 658 |
</sect1> |
|---|
| 659 |
|
|---|
| 660 |
<sect1 id="ecpg-descriptors"> |
|---|
| 661 |
<title>Utiliser les zones des descripteurs SQL</title> |
|---|
| 662 |
|
|---|
| 663 |
<para> |
|---|
| 664 |
Une zone de descripteur SQL est une méthode plus sophistiquée pour traiter |
|---|
| 665 |
le résultat d'un <command>SELECT</command> ou d'un <command>FETCH</command>. |
|---|
| 666 |
La zone du descripteur SQL groupe les données d'une ligne avec les éléments |
|---|
| 667 |
de métadonnées en une seule structure de données. Les métadonnées sont |
|---|
| 668 |
particulièrement utiles lors de l'exécution d'instructions SQL dynamiques |
|---|
| 669 |
pour lesquelles la nature des colonnes de résultats n'est pas forcément |
|---|
| 670 |
connue à l'avance. |
|---|
| 671 |
</para> |
|---|
| 672 |
|
|---|
| 673 |
<para> |
|---|
| 674 |
Une zone de descripteur SQL consiste en un en-tête, contenant des |
|---|
| 675 |
informations sur le descripteur complet, et un ou plusieurs éléments |
|---|
| 676 |
des zones du descripteur, décrivant basiquement une colonne de la ligne de |
|---|
| 677 |
résultat. |
|---|
| 678 |
</para> |
|---|
| 679 |
|
|---|
| 680 |
<para> |
|---|
| 681 |
Avant d'utiliser une zone de descripteur SQL, il est nécessaire d'en |
|---|
| 682 |
allouer une : |
|---|
| 683 |
<programlisting> |
|---|
| 684 |
EXEC SQL ALLOCATE DESCRIPTOR <replaceable>identifiant</replaceable>; |
|---|
| 685 |
</programlisting> |
|---|
| 686 |
L'identifiant sert de <quote>nom de variable</quote> à la zone du |
|---|
| 687 |
descripteur. <comment>La portée du descripteur alloué est QUOI ?</comment> |
|---|
| 688 |
Lorsque le descripteur n'est plus utilisé, il est recommandé de le désallouer : |
|---|
| 689 |
<programlisting> |
|---|
| 690 |
EXEC SQL DEALLOCATE DESCRIPTOR <replaceable>identifiant</replaceable>; |
|---|
| 691 |
</programlisting> |
|---|
| 692 |
</para> |
|---|
| 693 |
|
|---|
| 694 |
<para> |
|---|
| 695 |
Pour utiliser la zone d'un descripteur, il faut le spécifier comme cible de |
|---|
| 696 |
stockage dans une clause <literal>INTO</literal> à la place de la liste des |
|---|
| 697 |
variables hôtes : |
|---|
| 698 |
<programlisting> |
|---|
| 699 |
EXEC SQL FETCH NEXT FROM moncurseur INTO DESCRIPTOR mondesc; |
|---|
| 700 |
</programlisting> |
|---|
| 701 |
</para> |
|---|
| 702 |
|
|---|
| 703 |
<para> |
|---|
| 704 |
Comment récupérer les données de la zone du descripteur ? |
|---|
| 705 |
Celle-ci peut être envisagée comme une structure contenant des champs nommés. Pour |
|---|
| 706 |
récupérer la valeur d'un champ à partir de l'en-tête et la stocker dans une |
|---|
| 707 |
variable hôte, on utilise la commande suivante : |
|---|
| 708 |
<programlisting> |
|---|
| 709 |
EXEC SQL GET DESCRIPTOR <replaceable>nom</replaceable> :<replaceable>varhote</replaceable> = <replaceable>champ</replaceable>; |
|---|
| 710 |
</programlisting> |
|---|
| 711 |
Actuellement, il n'existe qu'un seul champ d'en-tête défini : |
|---|
| 712 |
<replaceable>COUNT</replaceable>, qui indique le nombre d'éléments dans |
|---|
| 713 |
la zone de descripteur (c'est-à-dire le nombre de colonnes contenues dans le |
|---|
| 714 |
résultat). La variable hôte nécessite d'être du type entier. Pour récupérer |
|---|
| 715 |
un champ à partir de l'élément de la zone du descripteur, on utilise la commande |
|---|
| 716 |
suivante : |
|---|
| 717 |
<programlisting> |
|---|
| 718 |
EXEC SQL GET DESCRIPTOR <replaceable>nom</replaceable> VALUE |
|---|
| 719 |
<replaceable>numero</replaceable> :<replaceable>varhote</replaceable> = |
|---|
| 720 |
<replaceable>champ</replaceable>; |
|---|
| 721 |
</programlisting> |
|---|
| 722 |
<replaceable>numero</replaceable> peut être un entier littéral ou une |
|---|
| 723 |
variable hôte contenant un entier. Les champs possibles sont : |
|---|
| 724 |
|
|---|
| 725 |
<variablelist> |
|---|
| 726 |
<varlistentry> |
|---|
| 727 |
<term><literal>CARDINALITY</literal> (integer)</term> |
|---|
| 728 |
<listitem> |
|---|
| 729 |
<para> |
|---|
| 730 |
nombre de lignes dans l'ensemble du résultat |
|---|
| 731 |
</para> |
|---|
| 732 |
</listitem> |
|---|
| 733 |
</varlistentry> |
|---|
| 734 |
|
|---|
| 735 |
<varlistentry> |
|---|
| 736 |
<term><literal>DATA</literal></term> |
|---|
| 737 |
<listitem> |
|---|
| 738 |
<para> |
|---|
| 739 |
élément de données en cours (de fait, le type de données de ce champ |
|---|
| 740 |
dépend de la requête) |
|---|
| 741 |
</para> |
|---|
| 742 |
</listitem> |
|---|
| 743 |
</varlistentry> |
|---|
| 744 |
|
|---|
| 745 |
|
|---|
| 746 |
<varlistentry> |
|---|
| 747 |
<term><literal>DATETIME_INTERVAL_CODE</literal> (integer)</term> |
|---|
| 748 |
<listitem> |
|---|
| 749 |
<para> |
|---|
| 750 |
? |
|---|
| 751 |
</para> |
|---|
| 752 |
</listitem> |
|---|
| 753 |
</varlistentry> |
|---|
| 754 |
|
|---|
| 755 |
<varlistentry> |
|---|
| 756 |
<term><literal>DATETIME_INTERVAL_PRECISION</literal> (integer)</term> |
|---|
| 757 |
<listitem> |
|---|
| 758 |
<para> |
|---|
| 759 |
non implémenté |
|---|
| 760 |
</para> |
|---|
| 761 |
</listitem> |
|---|
| 762 |
</varlistentry> |
|---|
| 763 |
|
|---|
| 764 |
<varlistentry> |
|---|
| 765 |
<term><literal>INDICATOR</literal> (integer)</term> |
|---|
| 766 |
<listitem> |
|---|
| 767 |
<para> |
|---|
| 768 |
l'indicateur (indiquant une valeur nulle ou une troncature de la |
|---|
| 769 |
valeur) |
|---|
| 770 |
</para> |
|---|
| 771 |
</listitem> |
|---|
| 772 |
</varlistentry> |
|---|
| 773 |
|
|---|
| 774 |
<varlistentry> |
|---|
| 775 |
<term><literal>KEY_MEMBER</literal> (integer)</term> |
|---|
| 776 |
<listitem> |
|---|
| 777 |
<para> |
|---|
| 778 |
non implémenté |
|---|
| 779 |
</para> |
|---|
| 780 |
</listitem> |
|---|
| 781 |
</varlistentry> |
|---|
| 782 |
|
|---|
| 783 |
<varlistentry> |
|---|
| 784 |
<term><literal>LENGTH</literal> (integer)</term> |
|---|
| 785 |
<listitem> |
|---|
| 786 |
<para> |
|---|
| 787 |
longueur de la donnée en caractères |
|---|
| 788 |
</para> |
|---|
| 789 |
</listitem> |
|---|
| 790 |
</varlistentry> |
|---|
| 791 |
|
|---|
| 792 |
<varlistentry> |
|---|
| 793 |
<term><literal>NAME</literal> (string)</term> |
|---|
| 794 |
<listitem> |
|---|
| 795 |
<para> |
|---|
| 796 |
nom de la colonne |
|---|
| 797 |
</para> |
|---|
| 798 |
</listitem> |
|---|
| 799 |
</varlistentry> |
|---|
| 800 |
|
|---|
| 801 |
<varlistentry> |
|---|
| 802 |
<term><literal>NULLABLE</literal> (integer)</term> |
|---|
| 803 |
<listitem> |
|---|
| 804 |
<para> |
|---|
| 805 |
non implémenté |
|---|
| 806 |
</para> |
|---|
| 807 |
</listitem> |
|---|
| 808 |
</varlistentry> |
|---|
| 809 |
|
|---|
| 810 |
<varlistentry> |
|---|
| 811 |
<term><literal>OCTET_LENGTH</literal> (integer)</term> |
|---|
| 812 |
<listitem> |
|---|
| 813 |
<para> |
|---|
| 814 |
longueur en octets de la représentation en caractères de la donnée |
|---|
| 815 |
</para> |
|---|
| 816 |
</listitem> |
|---|
| 817 |
</varlistentry> |
|---|
| 818 |
|
|---|
| 819 |
<varlistentry> |
|---|
| 820 |
<term><literal>PRECISION</literal> (integer)</term> |
|---|
| 821 |
<listitem> |
|---|
| 822 |
<para> |
|---|
| 823 |
précision (pour le type <type>numeric</type>) |
|---|
| 824 |
</para> |
|---|
| 825 |
</listitem> |
|---|
| 826 |
</varlistentry> |
|---|
| 827 |
|
|---|
| 828 |
<varlistentry> |
|---|
| 829 |
<term><literal>RETURNED_LENGTH</literal> (integer)</term> |
|---|
| 830 |
<listitem> |
|---|
| 831 |
<para> |
|---|
| 832 |
longueur de la donnée en caractère |
|---|
| 833 |
</para> |
|---|
| 834 |
</listitem> |
|---|
| 835 |
</varlistentry> |
|---|
| 836 |
|
|---|
| 837 |
<varlistentry> |
|---|
| 838 |
<term><literal>RETURNED_OCTET_LENGTH</literal> (integer)</term> |
|---|
| 839 |
<listitem> |
|---|
| 840 |
<para> |
|---|
| 841 |
longueur en octets de la représentation en caractères de la donnée |
|---|
| 842 |
</para> |
|---|
| 843 |
</listitem> |
|---|
| 844 |
</varlistentry> |
|---|
| 845 |
|
|---|
| 846 |
<varlistentry> |
|---|
| 847 |
<term><literal>SCALE</literal> (integer)</term> |
|---|
| 848 |
<listitem> |
|---|
| 849 |
<para> |
|---|
| 850 |
échelle (pour le type <type>numeric</type>) |
|---|
| 851 |
</para> |
|---|
| 852 |
</listitem> |
|---|
| 853 |
</varlistentry> |
|---|
| 854 |
|
|---|
| 855 |
<varlistentry> |
|---|
| 856 |
<term><literal>TYPE</literal> (integer)</term> |
|---|
| 857 |
<listitem> |
|---|
| 858 |
<para> |
|---|
| 859 |
code numérique du type de données de la colonne |
|---|
| 860 |
</para> |
|---|
| 861 |
</listitem> |
|---|
| 862 |
</varlistentry> |
|---|
| 863 |
</variablelist> |
|---|
| 864 |
</para> |
|---|
| 865 |
</sect1> |
|---|
| 866 |
|
|---|
| 867 |
<sect1 id="ecpg-errors"> |
|---|
| 868 |
<title>Gestion des erreurs</title> |
|---|
| 869 |
|
|---|
| 870 |
<para> |
|---|
| 871 |
Cette section décrit la gestion des conditions exceptionnelles |
|---|
| 872 |
et des avertissements dans un programme SQL embarqué. Il existe |
|---|
| 873 |
plusieurs fonctions non exclusives pour cela. |
|---|
| 874 |
</para> |
|---|
| 875 |
|
|---|
| 876 |
<sect2> |
|---|
| 877 |
<title>Configurer des rappels</title> |
|---|
| 878 |
|
|---|
| 879 |
<para> |
|---|
| 880 |
Une méthode simple de récupération des erreurs et des avertissements consiste à |
|---|
| 881 |
configurer une action spécifique à exécuter à chaque fois qu'une condition |
|---|
| 882 |
particulière survient. En général : |
|---|
| 883 |
<programlisting> |
|---|
| 884 |
EXEC SQL WHENEVER <replaceable>condition</replaceable> <replaceable>action</replaceable>; |
|---|
| 885 |
</programlisting> |
|---|
| 886 |
</para> |
|---|
| 887 |
|
|---|
| 888 |
<para> |
|---|
| 889 |
<replaceable>condition</replaceable> peut prendre une des valeurs |
|---|
| 890 |
suivantes : |
|---|
| 891 |
|
|---|
| 892 |
<variablelist> |
|---|
| 893 |
<varlistentry> |
|---|
| 894 |
<term><literal>SQLERROR</literal></term> |
|---|
| 895 |
<listitem> |
|---|
| 896 |
<para> |
|---|
| 897 |
L'action spécifiée est appelée lorsqu'une erreur survient |
|---|
| 898 |
pendant l'exécution d'une instruction SQL. |
|---|
| 899 |
</para> |
|---|
| 900 |
</listitem> |
|---|
| 901 |
</varlistentry> |
|---|
| 902 |
|
|---|
| 903 |
<varlistentry> |
|---|
| 904 |
<term><literal>SQLWARNING</literal></term> |
|---|
| 905 |
<listitem> |
|---|
| 906 |
<para> |
|---|
| 907 |
L'action spécifiée est appelée lorsqu'un avertissement |
|---|
| 908 |
survient pendant l'exécution d'une instruction SQL. |
|---|
| 909 |
</para> |
|---|
| 910 |
</listitem> |
|---|
| 911 |
</varlistentry> |
|---|
| 912 |
|
|---|
| 913 |
<varlistentry> |
|---|
| 914 |
<term><literal>NOT FOUND</literal></term> |
|---|
| 915 |
<listitem> |
|---|
| 916 |
<para> |
|---|
| 917 |
L'action spécifiée est appelée lorsqu'une instruction ne |
|---|
| 918 |
récupère ou n'affecte aucune ligne (cette condition n'est pas une |
|---|
| 919 |
erreur mais il peut être intéressant de la gérer de façon particulière). |
|---|
| 920 |
</para> |
|---|
| 921 |
</listitem> |
|---|
| 922 |
</varlistentry> |
|---|
| 923 |
</variablelist> |
|---|
| 924 |
</para> |
|---|
| 925 |
|
|---|
| 926 |
<para> |
|---|
| 927 |
<replaceable>action</replaceable> peut avoir une des valeurs |
|---|
| 928 |
suivantes : |
|---|
| 929 |
|
|---|
| 930 |
<variablelist> |
|---|
| 931 |
<varlistentry> |
|---|
| 932 |
<term><literal>CONTINUE</literal></term> |
|---|
| 933 |
<listitem> |
|---|
| 934 |
<para> |
|---|
| 935 |
Signifie effectivement que la condition est ignorée. Ceci est la |
|---|
| 936 |
valeur par défaut. |
|---|
| 937 |
</para> |
|---|
| 938 |
</listitem> |
|---|
| 939 |
</varlistentry> |
|---|
| 940 |
|
|---|
| 941 |
<varlistentry> |
|---|
| 942 |
<term><literal>GOTO <replaceable>label</replaceable></literal></term> |
|---|
| 943 |
<term><literal>GO TO <replaceable>label</replaceable></literal></term> |
|---|
| 944 |
<listitem> |
|---|
| 945 |
<para> |
|---|
| 946 |
Saute au label spécifié (en utilisant une instruction C |
|---|
| 947 |
<literal>goto</literal>). |
|---|
| 948 |
</para> |
|---|
| 949 |
</listitem> |
|---|
| 950 |
</varlistentry> |
|---|
| 951 |
|
|---|
| 952 |
<varlistentry> |
|---|
| 953 |
<term><literal>SQLPRINT</literal></term> |
|---|
| 954 |
<listitem> |
|---|
| 955 |
<para> |
|---|
| 956 |
Affiche un message sur la sortie standard. Ceci est utile pour des |
|---|
| 957 |
programmes simples ou lors d'un prototypage. Les détails du message ne |
|---|
| 958 |
peuvent pas être configurés. |
|---|
| 959 |
</para> |
|---|
| 960 |
</listitem> |
|---|
| 961 |
</varlistentry> |
|---|
| 962 |
|
|---|
| 963 |
<varlistentry> |
|---|
| 964 |
<term><literal>STOP</literal></term> |
|---|
| 965 |
<listitem> |
|---|
| 966 |
<para> |
|---|
| 967 |
Appel de <literal>exit(1)</literal>, ce qui terminera le programme. |
|---|
| 968 |
</para> |
|---|
| 969 |
</listitem> |
|---|
| 970 |
</varlistentry> |
|---|
| 971 |
|
|---|
| 972 |
<varlistentry> |
|---|
| 973 |
<term><literal>BREAK</literal></term> |
|---|
| 974 |
<listitem> |
|---|
| 975 |
<para> |
|---|
| 976 |
Exécute l'instruction C <literal>break</literal>. Ceci devrait être |
|---|
| 977 |
utilisé uniquement dans des boucles ou dans des instructions |
|---|
| 978 |
<literal>switch</literal>. |
|---|
| 979 |
</para> |
|---|
| 980 |
</listitem> |
|---|
| 981 |
</varlistentry> |
|---|
| 982 |
|
|---|
| 983 |
<varlistentry> |
|---|
| 984 |
<term><literal>CALL <replaceable>nom</replaceable> |
|---|
| 985 |
(<replaceable>args</replaceable>)</literal></term> |
|---|
| 986 |
<term><literal>DO <replaceable>nom</replaceable> |
|---|
| 987 |
(<replaceable>args</replaceable>)</literal></term> |
|---|
| 988 |
<listitem> |
|---|
| 989 |
<para> |
|---|
| 990 |
Appelle les fonctions C spécifiées avec les arguments spécifiés. |
|---|
| 991 |
</para> |
|---|
| 992 |
</listitem> |
|---|
| 993 |
</varlistentry> |
|---|
| 994 |
</variablelist> |
|---|
| 995 |
|
|---|
| 996 |
Le standard SQL ne définit que les actions |
|---|
| 997 |
<literal>CONTINUE</literal> et <literal>GOTO</literal> (et |
|---|
| 998 |
<literal>GO TO</literal>). |
|---|
| 999 |
</para> |
|---|
| 1000 |
|
|---|
| 1001 |
<para> |
|---|
| 1002 |
Voici un exemple utilisable dans un programme simple. Il affiche un message |
|---|
| 1003 |
lorsqu'un avertissement survient et termine le programme quand une erreur se |
|---|
| 1004 |
produit. |
|---|
| 1005 |
<programlisting> |
|---|
| 1006 |
EXEC SQL WHENEVER SQLWARNING SQLPRINT; |
|---|
| 1007 |
EXEC SQL WHENEVER SQLERROR STOP; |
|---|
| 1008 |
</programlisting> |
|---|
| 1009 |
</para> |
|---|
| 1010 |
|
|---|
| 1011 |
<para> |
|---|
| 1012 |
L'instruction <literal>EXEC SQL WHENEVER</literal> est une directive du |
|---|
| 1013 |
préprocesseur SQL, pas une instruction C. Les actions sur les erreurs |
|---|
| 1014 |
et avertissements qu'elle définit s'appliquent à toutes les instructions |
|---|
| 1015 |
SQL embarquées qui apparaissent avant l'endroit où le gestionnaire est défini, |
|---|
| 1016 |
à moins qu'une action différente n'ait été définie pour la même condition |
|---|
| 1017 |
entre le premier <literal>EXEC SQL WHENEVER</literal> et l'instruction SQL |
|---|
| 1018 |
qui a engendré la condition, quelque soit le flux de contrôle du programme C. |
|---|
| 1019 |
De ce fait, aucun des deux extraits de programme C qui suivent n'aura le |
|---|
| 1020 |
comportement désiré. |
|---|
| 1021 |
<programlisting> |
|---|
| 1022 |
/* |
|---|
| 1023 |
* MAUVAIS |
|---|
| 1024 |
*/ |
|---|
| 1025 |
int main(int argc, char *argv[]) |
|---|
| 1026 |
{ |
|---|
| 1027 |
... |
|---|
| 1028 |
if (verbose) { |
|---|
| 1029 |
EXEC SQL WHENEVER SQLWARNING SQLPRINT; |
|---|
| 1030 |
} |
|---|
| 1031 |
... |
|---|
| 1032 |
EXEC SQL SELECT ...; |
|---|
| 1033 |
... |
|---|
| 1034 |
} |
|---|
| 1035 |
</programlisting> |
|---|
| 1036 |
|
|---|
| 1037 |
<programlisting> |
|---|
| 1038 |
/* |
|---|
| 1039 |
* MAUVAIS |
|---|
| 1040 |
*/ |
|---|
| 1041 |
int main(int argc, char *argv[]) |
|---|
| 1042 |
{ |
|---|
| 1043 |
... |
|---|
| 1044 |
set_error_handler(); |
|---|
| 1045 |
... |
|---|
| 1046 |
EXEC SQL SELECT ...; |
|---|
| 1047 |
... |
|---|
| 1048 |
} |
|---|
| 1049 |
|
|---|
| 1050 |
static void set_error_handler(void) |
|---|
| 1051 |
{ |
|---|
| 1052 |
EXEC SQL WHENEVER SQLERROR STOP; |
|---|
| 1053 |
} |
|---|
| 1054 |
</programlisting> |
|---|
| 1055 |
</para> |
|---|
| 1056 |
</sect2> |
|---|
| 1057 |
|
|---|
| 1058 |
<sect2> |
|---|
| 1059 |
<title>sqlca</title> |
|---|
| 1060 |
|
|---|
| 1061 |
<para> |
|---|
| 1062 |
Pour une gestion plus puissante des erreurs, l'interface du SQL embarqué |
|---|
| 1063 |
fournit une variable globale de nom <varname>sqlca</varname> qui a la |
|---|
| 1064 |
structure suivante : |
|---|
| 1065 |
<programlisting> |
|---|
| 1066 |
struct |
|---|
| 1067 |
{ |
|---|
| 1068 |
char sqlcaid[8]; |
|---|
| 1069 |
long sqlabc; |
|---|
| 1070 |
long sqlcode; |
|---|
| 1071 |
struct |
|---|
| 1072 |
{ |
|---|
| 1073 |
int sqlerrml; |
|---|
| 1074 |
char sqlerrmc[70]; |
|---|
| 1075 |
} sqlerrm; |
|---|
| 1076 |
char sqlerrp[8]; |
|---|
| 1077 |
long sqlerrd[6]; |
|---|
| 1078 |
char sqlwarn[8]; |
|---|
| 1079 |
char sqlstate[5]; |
|---|
| 1080 |
} sqlca; |
|---|
| 1081 |
</programlisting> |
|---|
| 1082 |
(Dans un programme multithreadé, chaque thread obtient automatiquement sa |
|---|
| 1083 |
propre copie de <varname>sqlca</varname>. Ceci fonctionne de façon similaire |
|---|
| 1084 |
à la gestion de la variable globale C standard <varname>errno</varname>.) |
|---|
| 1085 |
</para> |
|---|
| 1086 |
|
|---|
| 1087 |
<para> |
|---|
| 1088 |
<varname>sqlca</varname> couvre à la fois les avertissements et les |
|---|
| 1089 |
erreurs. Si plusieurs avertissements ou erreurs surviennent lors de |
|---|
| 1090 |
l'exécution d'une instruction, alors <varname>sqlca</varname> ne contiendra |
|---|
| 1091 |
que les informations relatives à la dernière. |
|---|
| 1092 |
</para> |
|---|
| 1093 |
|
|---|
| 1094 |
<para> |
|---|
| 1095 |
Si aucune erreur ne survient dans la dernière instruction <acronym>SQL</acronym>, |
|---|
| 1096 |
<literal>sqlca.sqlcode</literal> vaudra 0 et |
|---|
| 1097 |
<literal>sqlca.sqlstate</literal> vaudra <literal>"00000"</literal>. Si un |
|---|
| 1098 |
avertissement ou une erreur a eu lieu, alors |
|---|
| 1099 |
<literal>sqlca.sqlcode</literal> sera négatif et |
|---|
| 1100 |
<literal>sqlca.sqlstate</literal> sera différent de |
|---|
| 1101 |
<literal>"00000"</literal>. Un <literal>sqlca.sqlcode</literal> positif |
|---|
| 1102 |
indique une condition sans dommage, telle que <quote>aucune ligne renvoyée |
|---|
| 1103 |
par la dernière requête</quote>. <literal>sqlcode</literal> et |
|---|
| 1104 |
<literal>sqlstate</literal> sont deux schémas de code d'erreur |
|---|
| 1105 |
différents ; les détails apparaissent ci-dessous. |
|---|
| 1106 |
</para> |
|---|
| 1107 |
|
|---|
| 1108 |
<para> |
|---|
| 1109 |
Si la dernière instruction SQL a réussi, alors |
|---|
| 1110 |
<literal>sqlca.sqlerrd[1]</literal> contient l'OID de la ligne traitée, si |
|---|
| 1111 |
applicable, et <literal>sqlca.sqlerrd[2]</literal> contient le nombre de |
|---|
| 1112 |
lignes traitées ou renvoyées, si applicable à la commande. |
|---|
| 1113 |
</para> |
|---|
| 1114 |
|
|---|
| 1115 |
<para> |
|---|
| 1116 |
Dans le cas d'une erreur ou d'un avertissement, |
|---|
| 1117 |
<literal>sqlca.sqlerrm.sqlerrmc</literal> contiendra une chaîne décrivant |
|---|
| 1118 |
l'erreur. Le champ <literal>sqlca.sqlerrm.sqlerrml</literal> contient la |
|---|
| 1119 |
longueur du message d'erreur stocké dans |
|---|
| 1120 |
<literal>sqlca.sqlerrm.sqlerrmc</literal> (le résultat de |
|---|
| 1121 |
<function>strlen()</function>, sans réel intérêt pour un |
|---|
| 1122 |
programmeur C). |
|---|
| 1123 |
</para> |
|---|
| 1124 |
|
|---|
| 1125 |
<para> |
|---|
| 1126 |
Dans le cas d'un avertissement, |
|---|
| 1127 |
<literal>sqlca.sqlwarn[2]</literal> est positionné à <literal>W</literal>. |
|---|
| 1128 |
(Dans tous les autres cas, il est positionné à quelque chose de différent de |
|---|
| 1129 |
<literal>W</literal>.) Si <literal>sqlca.sqlwarn[1]</literal> est positionné |
|---|
| 1130 |
à <literal>W</literal>, alors une valeur a été tronquée lors de son stockage |
|---|
| 1131 |
dans une variable hôte. <literal>sqlca.sqlwarn[0]</literal> est |
|---|
| 1132 |
positionné à <literal>W</literal> si un autre élément est positionné pour |
|---|
| 1133 |
indiquer un avertissement. |
|---|
| 1134 |
</para> |
|---|
| 1135 |
|
|---|
| 1136 |
<para> |
|---|
| 1137 |
Les champs <structfield>sqlcaid</structfield>, |
|---|
| 1138 |
<structfield>sqlcabc</structfield>, |
|---|
| 1139 |
<structfield>sqlerrp</structfield>, et les éléments restant de |
|---|
| 1140 |
<structfield>sqlerrd</structfield> et |
|---|
| 1141 |
<structfield>sqlwarn</structfield> ne contiennent actuellement |
|---|
| 1142 |
aucune information utile. |
|---|
| 1143 |
</para> |
|---|
| 1144 |
|
|---|
| 1145 |
<para> |
|---|
| 1146 |
La structure <varname>sqlca</varname> n'est pas définie dans le standard |
|---|
| 1147 |
SQL mais elle est implémentée dans plusieurs autres systèmes de bases de données SQL. |
|---|
| 1148 |
Leurs définitions sont similaires dans leur esprit, mais l'écriture d'applications |
|---|
| 1149 |
portables nécessite une étude attentive des autres implémentations. |
|---|
| 1150 |
</para> |
|---|
| 1151 |
</sect2> |
|---|
| 1152 |
|
|---|
| 1153 |
<sect2> |
|---|
| 1154 |
<title><literal>SQLSTATE</literal> contre <literal>SQLCODE</literal></title> |
|---|
| 1155 |
|
|---|
| 1156 |
<para> |
|---|
| 1157 |
Les champs <literal>sqlca.sqlstate</literal> et |
|---|
| 1158 |
<literal>sqlca.sqlcode</literal> sont deux schémas différents fournissant |
|---|
| 1159 |
des codes d'erreur. Les deux sont spécifiés dans le standard SQL mais |
|---|
| 1160 |
|
|---|