OVH Cloud OVH Cloud

Comment ne pas quitter un script suite à une erreur SQL

13 réponses
Avatar
Alextophi
bonjour,

je souhaite r=E9cup=E9rer le resultat des plusieurs connexions =E0 des
bases de donn=E9es SQL.

exemple: Actuellement j'ai un tableau qui contient 4 entr=E9es :
$Instances[0]; # Serveur1\instanceA
$Instances[1]; # Serveur2\instanceB
$Instances[2]; # Serveur3\instanceC
$Instances[3]; # Serveur4\instanceD

Je boucle dessus pour =E9tablir une connexion et r=E9cup=E9rer un info.

For ($i=3D0; $i<$#Instances; $i++) {
$SQLDSN =3D "DRIVER=3DSQL
Server\;SERVER=3D$Instances[$i]\;UID=3D$username\;PWD=3D$password\;DATABASE=
=3Dmsdb";
$dbh =3D DBI->connect("DBI:ODBC:$SQLDSN", "$username", "$password" );

ETC ETC ....

}

Mais le probleme est que si la connexion =E9choue (pas de r=E9seau ou
autre banalit=E9), SQL retourne une erreur et donc le script s'arr=E8te
et je perds le b=E9n=E9fice des autres r=E9sultats.

-Comment contourner =E7a...?

MERCI.

christophe

3 réponses

1 2
Avatar
Paul Gaborit
À (at) Sat, 1 Jul 2006 10:56:11 +0000 (UTC),
(Marc Espie) écrivait (wrote):
[...]
Normalement, DBI et ses amis ne font pas de die par defaut.
Il faut que le parametre RaiseError ait ete mis a 1 lors de la creation
du dbh.


Il y a au moins un cas où DBI fait appel à 'die' : lorsque le driver
demandé pour la connexion n'est pas installé (justement lors de la
création du database handle - le dbh, et donc avant que RaiseError
soit pris en compte).

D'où le besoin de 'eval'...

Bon, d'accord, ce n'est pas une situation 'normale' mais ça peut
arriver. ;-)

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
Patrick Mevzek
L'option a base de eval/die ne me parait pas du tout judicieuse dans ce
cas precis de figure. Autant pour une erreur `exceptionnelle', rattraper
le code lorsqu'il deconne peut etre utile, autant il est quand meme tres
facile, lors d'une connexion reseau a une DB, de regarder si la db
fonctionne des la connexion.


C'est en grande partie une question de goût, mais personnellement je
préfère:
{
op1
op2
op3
}
si problème qqpart faire op4

plutôt que
op1 et si problème faire op4
op2 et si problème faire op5
op3 et si problème faire op6
etc...

D'expèrience, on oublie des tests dans le dernier cas.
De plus cela rend difficile l'annulation d'opérations quand on a des
mélanges base de données (dans une transaction) et opérations hors
bases de données. Ca peut donner un code particulièrement abscons, de ce
que j'ai déjà pu voir alors que le eval {} est plus propre
D'autre part, cela sépare l'endroit où l'on fait l'opération de
l'endroit où l'on teste la réussite (cela peut être deux ou trois
fonctions plus haut, puisque le die() se propage dans la pile des
fonctions appelées), ce qui a des avantages.

Personnellement, je n'aime pas les messages d'erreur de DBI lors d'une
erreur de syntaxe SQL, car ils n'affichent pas la chaine SQL utilisee.


On peut jouer sur le niveau de trace.

De toute façon, on peut mettre en place un gestionnaire spécifique,
appelé à la place du die(), et cette fonction reçoit notamment le
dernier handle dans lequel on peut trouver la requête, les paramètres,
le code d'erreur SQL normalisé, etc...
Et peut après elle-même faire un die() ou utiliser un autre mécanisme
d'exceptions (ex: Exception::Class)

Je trouve que c'est la situation idéale, d'une part quand on encapsule
DBI dans une surcouche quelconque et qu'on encapsule aussi d'autre part
les erreurs dans une classe quelconque de gestion d'exceptions.

--
Patrick Mevzek . . . . . . Dot and Co (Paris, France)
<http://www.dotandco.net/> <http://www.dotandco.com/>
<http://www.dotandco.net/ressources/icann_registries/verisign_com_net/registrars_COM.fr>

Avatar
Jean-Charles Gibier
[...]


Normalement, DBI et ses amis ne font pas de die par defaut.
Il faut que le parametre RaiseError ait ete mis a 1 lors de la creation
du dbh.


C'est curieux, personnellement j'ai fait la tentative suivante 'erreur


------8<----
$dbhk = DBI->connect("DBI:$dbek:$databasek:$hostk",$userk,$passwordk, {
RaiseError => 1, PrintError => 1 })
|| die "Connection impossible ($databasek : $hostk)";
------8<----


Je me doute que le concepteur du module ont prévu de trapper les pb mais
c'est justement parce que DBI continuait à 'tuer' mon script en cas
d'erreur que je me suis rabattu sur une solution "eval". Serait ce de ma
part une mauvaise interprétation l'attribut 'PrintError' ?
Il va falloir que je "reteste" ;-)


La, visiblement, le code utilise fait un
my $stmt = $dbh->prepare(sql_code);
suivi de
$stmt->execute();



Oui c'est certain. Mais il ne me semble pas que ce test soit suffisant
pour ne pas se faire jeter

[...]


Mieux meme: il y a explicitement un $dbh->ping() qui est prevu pour verifier
que tout va bien, autant s'en servir.



"The ping method issues an empty query and checks the result status."
Or pour mon pb, il suffisait d'un "dupicate row" ou autre petite
anicroche pour fermer le processus.
Ceci dit c'est une découverte pour moi et je pense que ça va me servir
pour les connexions paramétrées par des DBM paranos qui se ferment au
bout de 5 secondes d'inactivité ;-)


Personnellement, je n'aime pas les messages d'erreur de DBI lors d'une erreur
de syntaxe SQL, car ils n'affichent pas la chaine SQL utilisee.

J'ai un petit module qui `wrappe' DBI. Il contient quelques autres
fonctions, mais a la base, c'est le code suivant, qui se contente de
rajouter une couche autour de DBI, et de tout forwarder vers celui-ci
(et pareil pour les statements sortis de prepare).

(si vous en avez besoin, copyright 2006 Marc espie, licence BSD)

[...]


Merci je vais mettre ça à l'épreuve chez moi ;-)

JCG

1 2