Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

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

10 réponses

1 2
Avatar
Stéphane Zuckerman
On Tue, 13 Jun 2006, Alextophi wrote:

bonjour,

je souhaite récupérer le resultat des plusieurs connexions à des
bases de données SQL.

exemple: Actuellement j'ai un tableau qui contient 4 entrées :
$Instances[0]; # Serveur1instanceA
$Instances[1]; # Serveur2instanceB
$Instances[2]; # Serveur3instanceC
$Instances[3]; # Serveur4instanceD

Je boucle dessus pour établir une connexion et récupérer un info.

For ($i=0; $i<$#Instances; $i++) {
$SQLDSN = "DRIVER=SQL
Server;SERVER=$Instances[$i];UID=$username;PWD=$password;DATABASE=msdb";
$dbh = DBI->connect("DBI:ODBC:$SQLDSN", "$username", "$password" );

ETC ETC ....

}

Mais le probleme est que si la connexion échoue (pas de réseau ou
autre banalité), SQL retourne une erreur et donc le script s'arrète
et je perds le bénéfice des autres résultats.

-Comment contourner ça...?


Pourquoi « et donc » ? Normalement c'est à toi, programmeur, de dire si on
arrête ou pas, non ? Je ne me souviens pas avoir eu mes scripts qui
faisaient d'eux-même un die ou un exit sans que je le leur dise...

--
"Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
que je veux !"
"The obvious mathematical breakthrough would be development of an easy
way to factor large prime numbers." (Bill Gates, The Road Ahead)

Avatar
Alextophi

Pourquoi « et donc » ? Normalement c'est à toi, programmeur, de dir e si on
arrête ou pas, non ? Je ne me souviens pas avoir eu mes scripts qui
faisaient d'eux-même un die ou un exit sans que je le leur dise...


Etrangement Si .. ! je ne comprends pas moi non plus.

Dans ma boucle, je fais une tentative de connexion avec un 'DBI ->
connect' puis en retour le '$DBI::errstr' avorte le script.. Peut-etre
une erreur de type 'erreur fatale' . ou 'ché pa koi' ?

ch.

Avatar
Stéphane Zuckerman
On Tue, 13 Jun 2006, Alextophi wrote:

Pourquoi « et donc » ? Normalement c'est à toi, programmeur, de dire si on
arrête ou pas, non ? Je ne me souviens pas avoir eu mes scripts qui
faisaient d'eux-même un die ou un exit sans que je le leur dise...


Etrangement Si .. ! je ne comprends pas moi non plus.

Dans ma boucle, je fais une tentative de connexion avec un 'DBI ->
connect' puis en retour le '$DBI::errstr' avorte le script.. Peut-etre
une erreur de type 'erreur fatale' . ou 'ché pa koi' ?


Oui enfin là c'est vraiment étrange... Tu ne pourrais pas nous copier ton
code après le connect ? Plus exactement, si tu commentes TOUT le code qui
suit le connect dans ta boucle, est-ce que ça quitte quand même ?

--
"Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
que je veux !"
"The obvious mathematical breakthrough would be development of an easy
way to factor large prime numbers." (Bill Gates, The Road Ahead)


Avatar
Alextophi

Oui enfin là c'est vraiment étrange... Tu ne pourrais pas nous copier ton
code après le connect ? Plus exactement, si tu commentes TOUT le code q ui
suit le connect dans ta boucle, est-ce que ça quitte quand même ?



Voici la sequence de connexion lors de l'execution :

---------------------------------------------
Traitement de l'instance SERVERBALIBALO_P2, [1 sur 4]
DBI connect('DRIVER=SQL
Server;SERVER=SERVERBALIBALO_P2;UID=;PWD=;DATABASE=msdb','',...)
failed: [Microsoft][ODBC SQL Server Driver][DBMSLPCN]Ce serveur SQL
n'existe pas ou son accÞs est refusÚ. (SQL-08001)
[Microsoft][ODBC SQL Server Driver][DBMSLPCN]ConnectionOpen
(Connect()). (SQL-01000)(DBD: db_login/SQLConnect err=-1) at col_sql.pl
line 165
Can't call method "prepare" on an undefined value at col_sql.pl line
177.
---------------------------------------------

voici les lignes incriminées !

164 $SQLDSN = "DRIVER=SQL
Server;SERVER=$Instances[$i];UID=$username;PWD=$password;DATABASE =msdb";
165 $dbh2 =
DBI->connect("DBI:ODBC:$SQLDSN","$username","$password" );
166
167 # Format de la Requête SQL 8.0 -2000- (msdb)
168 my $ReqJobSQL = ("SELECT dbo.sysjobs.job_id,
dbo.sysjobs.name, jobs_sch.enabled, jobs_sch.freq_type,
jobs_sch.freq_interval, jobs_sch.active_start_date,
jobs_sch.active_start_time, jobs_sch.active_end_date,
jobs_sch.active_end_time,dbo.sysjobservers.last_run_duration,
jobs_sch.freq_subday_type,jobs_sch.freq_subday_interval
FROM dbo.sysjobs
LEFT OUTER join dbo.sysjobservers ON dbo.sysjobs.job_id =
dbo.sysjobservers.job_id
LEFT OUTER join dbo.sysjobschedules jobs_sch ON jobs_sch.job_id =
dbo.sysjobs.job_id");
176 # Préparation de la requête SQL
177 my $rmsdb = $dbh2 -> prepare($ReqJobSQL);
178 $rmsdb -> execute();


Le probleme n'est pas de savoir pourquoi il ne se connecte pas à
l'instance SQL, mias de savoir pour quoi le programme qui seul à la
ligne 177 !

Ch.

Avatar
Paul Gaborit
À (at) 13 Jun 2006 07:06:34 -0700,
"Alextophi" écrivait (wrote):
Mais le probleme est que si la connexion échoue (pas de réseau ou
autre banalité), SQL retourne une erreur et donc le script s'arrète
et je perds le bénéfice des autres résultats.

-Comment contourner ça...?


Il suffit de tester la valeur de $dbh après la tentative de
connexion. Si c'est une valeur indéfinie (undef), c'est que la
connexion ne s'est pas déroulée et que le message d'erreur associé est
dans $DBI::errstr (et aussi $DBI::err).

De manière générale, il faut toujours tester les valeurs de retour des
appels externes (système et autres bibliothèques) pour gérer tous les
cas d'erreur.

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

Avatar
Alextophi

Il suffit de tester la valeur de $dbh après la tentative de
connexion. Si c'est une valeur indéfinie (undef), c'est que la
connexion ne s'est pas déroulée et que le message d'erreur associé est
dans $DBI::errstr (et aussi $DBI::err).

De manière générale, il faut toujours tester les valeurs de retour des
appels externes (système et autres bibliothèques) pour gérer tous l es
cas d'erreur.



Mon script perl programme quitte quand meme, avec ou sans test de
retour.
Car plutot que se dire je tente de ne connecter, puis je continu si j'y
arrive ou non, en fait il quitte quand il échoue.
! ?? je comprends rien !

Avatar
Paul Gaborit
À (at) 14 Jun 2006 06:26:50 -0700,
"Alextophi" écrivait (wrote):

Il suffit de tester la valeur de $dbh après la tentative de
connexion. Si c'est une valeur indéfinie (undef), c'est que la
connexion ne s'est pas déroulée et que le message d'erreur associé est
dans $DBI::errstr (et aussi $DBI::err).

De manière générale, il faut toujours tester les valeurs de retour des
appels externes (système et autres bibliothèques) pour gérer tous les
cas d'erreur.



Mon script perl programme quitte quand meme, avec ou sans test de
retour.
Car plutot que se dire je tente de ne connecter, puis je continu si j'y
arrive ou non, en fait il quitte quand il échoue.


Avec quel message d'erreur ?

La méthode 'connect' de DBI peut soit échouer si elle n'arrive pas à
se connecter (c'est le cas que j'évoquais) soit mourir (par exemple si
le DBD demandé n'existe pas). Ce n'est pas le même type d'erreur. Dans
le premier cas, c'est une erreur externe au script alors que, dans le
second cas, c'est une erreur interne (d'où l'appel à 'die').

Pour capter le 'die', vous pouvez toujours utiliser :

eval {
#... code de tentative de connexion
}
if ($@) {
print "Err: $@n";
}

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


Avatar
Jean-Charles Gibier
À (at) 14 Jun 2006 06:26:50 -0700,
"Alextophi" écrivait (wrote):

Il suffit de tester la valeur de $dbh après la tentative de
connexion. Si c'est une valeur indéfinie (undef), c'est que la
connexion ne s'est pas déroulée et que le message d'erreur associé est
dans $DBI::errstr (et aussi $DBI::err).

De manière générale, il faut toujours tester les valeurs de retour des
appels externes (système et autres bibliothèques) pour gérer tous les
cas d'erreur.


Mon script perl programme quitte quand meme, avec ou sans test de
retour.
Car plutot que se dire je tente de ne connecter, puis je continu si j'y
arrive ou non, en fait il quitte quand il échoue.


Avec quel message d'erreur ?

La méthode 'connect' de DBI peut soit échouer si elle n'arrive pas à
se connecter (c'est le cas que j'évoquais) soit mourir (par exemple si
le DBD demandé n'existe pas). Ce n'est pas le même type d'erreur. Dans
le premier cas, c'est une erreur externe au script alors que, dans le
second cas, c'est une erreur interne (d'où l'appel à 'die').

Pour capter le 'die', vous pouvez toujours utiliser :

eval {
#... code de tentative de connexion
}
if ($@) {
print "Err: $@n";
}



Je confirme, personnellement c'est la seule méthode que j'ai trouvé
(ça s'assimile ça à un try/catch en fait)

Toutefois il me semble qu'il y a ';' derrière le bloc d'évaluation.

eval {
#... code de tentative de connexion
};



Avatar
Paul Gaborit
À (at) Wed, 14 Jun 2006 17:27:29 +0200,
Jean-Charles Gibier écrivait (wrote):
Toutefois il me semble qu'il y a ';' derrière le bloc d'évaluation.

eval {
#... code de tentative de connexion
};


Exact ! Le ';' est indispensable pour ne pas avoir d'erreur lors de la
compilation.

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

Avatar
espie
In article ,
Paul Gaborit <Paul.Gaborit+ wrote:

À (at) Wed, 14 Jun 2006 17:27:29 +0200,
Jean-Charles Gibier

écrivait (wrote):
Toutefois il me semble qu'il y a ';' derrière le bloc d'évaluation.

eval {
#... code de tentative de connexion
};


Exact ! Le ';' est indispensable pour ne pas avoir d'erreur lors de la
compilation.


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.

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

sans verifier que quoi que ce soit s'est bien passe. En particulier que
$stmt est bien defini.

C'est la moindre des choses de verifier la valeur de la variable avant
de s'en servir !

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.

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


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)

package Sql;


use DBI;
sub connect
{
my ($class, $name, $user, $pass, $attrs) = @_;
my $db = DBI->connect($name, $user, $pass, $attrs);
if (defined $db) {
return bless {
db => $db,
debug => (defined $attrs && $attrs->{debug})
}, $class;
} else {
return undef;
}
}

our $AUTOLOAD;

sub AUTOLOAD
{
my $method = $AUTOLOAD;
my $self = shift;
$method =~ s/.*:://;
$self->{db}->$method(@_);
}

sub prepare
{
my ($self, $string) = @_;
my $statement;
eval {
$statement = $self->{db}->prepare($string);
if (!defined $statement) {
print STDERR "tIn $stringn";
}
};
if ($@) {
die "$@tIn $string";
}
if ($self->{debug}) {
print "Prepared $stringn";
}
bless { stmt => $statement, string => $string }, "Sql::Statement";
}

sub do
{
my ($self, $string, @rest) = @_;
my $result;
eval {
$result = $self->{db}->do($string, @rest);
};
if ($@) {
die "$@tIn $string";
}
if ($self->{debug}) {
print "Done $stringn";
}
return $result;
}

package Sql::Statement;

our $AUTOLOAD;

sub AUTOLOAD
{
my $method = $AUTOLOAD;
my $self = shift;
$method =~ s/.*:://;
$self->{stmt}->$method(@_) if defined $self->{stmt};
}

1;


1 2