Bonjours à tous,
J'ai un gros problème dans mon programme dont voici l'exlication :
Ce programme mélange du C et du Perl, mais le probleme vient plus du Perl, donc...
J'ai le main en C suivant :
Ce main a pour role d'établir l'environnement Perl donc et fait appel aux deux fonctions "Connexion" et "RqtPerl"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 int main (int argc, char **argv, char **env) { char *args[] = { "select * from question" }; char *embedding[] = { "", "Bidon.pm" }; time_t deb, fin; int arg = 2, i, j, nbligne, nbchamp; char ***retour; time(&deb); my_perl = perl_alloc(); // PL_perl_destruct_level = 1; perl_construct(my_perl); perl_parse(my_perl, xs_init, arg, embedding, NULL); Connexion(); retour = RqtPerl(args,sizeof(args) / sizeof(args[0]), &nbligne, &nbchamp); perl_destruct(my_perl); perl_free(my_perl); time(&fin); printf("Temp execution = %d secondes\n",fin-deb); printf("%d et %d\n",sizeof(**retour),sizeof(*retour)); printf("\n\nEcriture du retour :\n\n"); for(i=0; i< nbligne; i++){ for(j=0; j < nbchamp; j++){ printf("%s ",retour[i][j]); } printf("\n"); } }
Voici le code de Connexion :
Cette fonction fait appel à la fonction Perl 'connexion' situé dans Bidon.pm et qui est chargé de créer un objet connexion (qui établi la connexion sur une DB).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 static void Connexion ( ) { int count = 0; dSP; ENTER; SAVETMPS; PUSHMARK(SP); // Empilement des paramètres de connexion à la base : printf("%s %s %s %s\n",driver,base,pwd,user); XPUSHs(sv_2mortal(newSVpv(driver,0))); XPUSHs(sv_2mortal(newSVpv(base,0))); XPUSHs(sv_2mortal(newSVpv(user,0))); XPUSHs(sv_2mortal(newSVpv(pwd,0))); PUTBACK; count = perl_call_pv("connexion", G_SCALAR ); printf("retour = %d\n",count); if( count == 1 ) { printf("retour connexion\n"); connexion = POPs; } else { connexion = NULL; printf("retour de connexion NULL\n"); } PUTBACK; FREETMPS; LEAVE; }
La valeur retourné dans le C est une référence sur l'objet connexion créé et je la stocke dans une varable globale définie dans une .h :
Voici le code de Bidon.pm et Connexion.pm :
Code : Sélectionner tout - Visualiser dans une fenêtre à part SV *connexion
Bidon.pm :
Et Connexion.pm dont Bidon.pm fait appel :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 #!C:\Perl\bin\perl.exe use strict; use lib 'C:/Documents and Settings/stvivotn/Mes documents/essais/debug/'; use Rqt; use Connexion; sub connexion { # Réception des paramètres de connexion: my $DRIVER = shift; my $BASE = shift; my $USER = shift; my $PWD = shift; # Création d'une connexion à la base pour toute la durée du programme. my $connexion = Connexion->new($DRIVER,$BASE,$USER,$PWD); return \$connexion; } sub deconnexion { my ($self) = shift; $self->deconnexion(); print "deconnexion"; } sub lance { my $nb = @_; print "nb = $nb\n"; my $connexion = shift; print "con = $connexion\n"; my $i = 0; my $resultats; my @list; ####print "nb arguments de la liste = $nb\n"; # Traitement des paramètres : while( $i < $nb ) { print "boucle $i\n"; my $sql = $_[$i++]; # Recherche du mot clé de la requete: if( $sql =~ /select/ ) { print "entree select\n"; my $rqt; ($rqt,@list) = Rqt->new(1,$sql,$connexion); #push(@list,$resultat); ###print "Nb lignes affectees par selection = $rqt :\n"; if($rqt =~ /0E0/){ $rqt = 0; } } elsif( $sql =~ /insert/ ) { my ($rqt) = Rqt->new(2,$sql,$connexion); if($rqt =~ /0E0/){ $rqt = 0; } print "Nb lignes affectees par insertion = $rqt\n"; push(@list,$rqt); } elsif( $sql =~ /delete/ ) { my ($rqt) = Rqt->new(3,$sql,$connexion); if($rqt =~ /0E0/){ $rqt = 0; } print "Nb lignes affectees par suppression = $rqt\n"; push(@list,$rqt); } elsif( $sql =~ /update/ ) { my ($rqt) = Rqt->new(4,$sql,$connexion); if($rqt =~ /0E0/){ $rqt = 0; } print "Nb lignes affectees par update = $rqt\n"; push(@list,$rqt); } else { print "Pas de correspondance de mot cle\n"; } } return \@list; }
Voilà, donc, ensuite le code de la fonction C nommée 'RqtPerl' :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package Connexion; use DBI; use strict; use lib 'C:/Documents and Settings/stvivotn/Mes documents/essais/debug/'; ############################## # CONSTRUCTEUR # # @param : # # driver / base / user / pwd # ############################## sub new { #print "entre dans Connexion\n"; my $classouref = shift; my $class = ref($classouref) || $classouref; print $class."\n"; # vérification des arguments : my $nb = @_; print $nb."\n"; die "Connexion intérrompue : Connexion::new : arg != 4\n" if ($nb != 4 ); my($driver, $base, $user, $pwd) = @_; print "driver = $driver, base = $base, pwd = $pwd, user = $user\n"; # tentative d'établissement de la connexion : my $dbh = DBI->connect("DBI:".$driver.":".$base,$user,$pwd, {RaiseError => 1, AutoCommit => 0 }) or die $DBI::errstr; my $self = {}; $self->{'connexion'}=$dbh; bless ($self, $class); # retourne l'identifiant de connexion brute et non un objet Connexion. return \$self; } sub get_connexion { my ($self) = shift; return ($self->{'connexion'}); } sub deconnexion { my $self = shift; $self->{'connexion'}->disconnect(); } 1;
Cette fonction execute une ou plusieur requete passée ne paramètre.. cette fonction ne pose aucun probleme.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 static char *** RqtPerl(char * arg[], int taille, int *nbligne, int *nbchamp) { int count = 0, i = 0, j=0; // Pointeur sur pointeur sur pointeur sur char retourné // par la fonction. Représente le tableau à double entrée // des lignes retournée lors d'une requete de type 'SELECT' : char ***tableau = NULL; // Pointeur sur les éléments de la pile et du tableau // retourné par le Perl en cas de requete de type 'SELECT' : SV *tmp, *champ; AV *tab, *ligne; // initialise le pointeur de pile dSP; ENTER; // tout ce qui est cree a partir d'ici est une variable temporaire SAVETMPS; // sauvegarde du pointeur de pile PUSHMARK(SP); printf("connexion de la forme : %s\n",(char *)connexion); // depos des requetes dans la pile : XPUSHs(sv_2mortal(newSVsv(SvRV(connexion)))); while( i < taille ) XPUSHs(sv_2mortal(newSVpv(arg[i++],0))); // rend global le pointeur local de pile PUTBACK; // appelle la fonction count = perl_call_pv("lance", G_ARRAY); // rafraichit le pointeur de pile pour avoir les élément // retourné par la fonction Perl 'lance' appellée. SPAGAIN; // Un objet est retourné sur la pile : if(count != 0) { printf("retour C = %d\n",count); // Onrécupère cet objet qui est de type tableau : tab = (AV *) SvRV(POPs); *nbligne = av_len(tab)+1; tableau = malloc((*nbligne) * sizeof( **tableau) ); i=0; while( i < (*nbligne) ) { tmp = *av_fetch(tab, i, 0); if( SvTYPE(SvRV(tmp)) == SVt_NV ){ printf("Entier de taille %d\n",SvLEN(tmp)); } else if(SvTYPE(SvRV(tmp)) == SVt_PVAV ) { ligne = (AV *) SvRV(tmp); (*nbchamp) = av_len(ligne)+1; tableau[i] = malloc((*nbchamp) * sizeof( *tableau )); for( j=0; j<(*nbchamp); j++ ) { champ = *av_fetch(ligne, j, 0); tableau[i][j] = malloc( sizeof( SvLEN(champ) ) ); strcpy(tableau[i][j], (char *)SvRV(champ)); } } i++; } } // retire la valeur de retour de la pile PUTBACK; // libere la valeur de retour FREETMPS; // Et retire les arguments empiles LEAVE; // La liste des champ et des lignes est alors retournée avec // pour valeur le résultat d'une requete select ou NULL : return tableau; }
Elle appelle la fonction Perl 'lance' du fichier 'Bidon.pm' et dont le code est donné ci-dessus.
'lance' appelle d'autre fonction Perl située dans 'Connexion.pm' et dans 'Rqt.pm' dont voici le code :
Rqt.pm :
Le but de ce fichier est la création d'u objet requete, puis l'éxécution de cette requete.. et c'est la que mon probleme survient en fait :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 package Rqt; use strict; use lib 'C:/Documents and Settings/stvivotn/Mes documents/essais/debug/'; ############################################ # CONSTRUCTEUR # # @param : # # driver / base / user / pwd / [connexion] # ############################################ sub new { my $classouref = shift; my $class = ref($classouref) || $classouref; # vérification du nombre de paramètre passés au constructeur : my $nbparam = @_; die 'Usage : Rqt->new($mode,$requete,$connexion)\n' if($nbparam != 3); my $self = {}; $self->{'mode'} = shift; # mode requete $self->{'sql'} = shift; # requete my $conn = shift; print "connexion dans rqt -> new = $conn\n"; $self->{'connexion'} = $conn; # connexion base bless ($self, $class); $self->execute_sql(); } sub execute_sql { my ($self) = shift; die 'Usage Rqt->execute_sql($connexion)\n' if( (my $nb = @_) != 0); my $ret; my ( $sth ); eval { $sth = $self->{'connexion'}->get_connexion()->prepare( $self->{'sql'} ); $ret = $sth->execute( ); }; die "Erreur d execution\n" if $@; # Si la requete est une selection, on retourne le nombre # de ligne et le résultat de la sélection. if($self->{'mode'} == '1') { #my @list_champ = @{ $sth->{ NAME } }; my @rqt_retour; while ( my @row = $sth->fetchrow_array ) { push(@rqt_retour,\@row); } return ($ret,@rqt_retour); } else { return $ret; } } 1;
La requete ne peut pas s'éxécuter car l'objet de connexion qui est passé en paramètre à la fonction 'lance' de 'Bidon.pm' est vide !!
Cet objet connexion est créé comme je l'ai dit plus haut dans la première fonction C et est stocké dans la variable globale connexion (de type SV *).
Elle n'est pas nulle lorsque je la passe en paramètre à 'lance', et 'lance' recoit bien deux paramètres (la connexion et une requete). Seulement si je met une trace pour afficher le contenu de la variable '$connexion' récupérée au début de la fonction 'lance', rien ne s'affiche (valeur nulle donc..).
Je pense donc que je passe mal la connexion en paramètre, ou alors que je la récupère mal de ma première fonction, ou alors les deux (m'étonnerais pas !).
Je vous demande donc votre avis à tous la dessus, est-ce que vous voyez d'ou peut venir l'erreur ?
merci beaucoup d'avance.
++
Partager