Précédent   Forum des professionnels en informatique > Bases de données > Firebird > SQL
SQL Forum d'entraide sur le SQL pour Firebird
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 19/10/2006, 16h11   #1
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
Par défaut Problème SELECT sur une vue sous FB 2.0

Bonjour tout le monde,

Je vous expose mon problème.

Enfin tout d'abord, un petit apercu de l'infrastructure...
Je suis sur une Ubuntu 5.04. Sur celle-ci, j'ai un serveur Firebird 2.0 RC5 (j'ai également fait le test avec Firebird 1.5.1 avec les mêmes résultats).
J'utilise l'API native fournie avec Firebird.

Maintenant la base de données (enfin pour le test, c'est vraiment ridicule mais ca permet de bien fixer le problème).
Une table: TOTO qui contient un champ "nb".
Une vue: VTOTO qui représente un "SELECT nb FROM TOTO".

Jusque la, c'est pas trop dur.
Voici le code permettant d'afficher toutes les valeurs contenues dans TOTO.nb

Code :
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
 
 
 
#include <stdio.h>
#include <ibase.h>
#include <string.h>
#include <stdlib.h>
 
#define USER		"POLYSOUDE"
#define PASSWD		"POLYSOUDE"
#define DB_NAME		"localhost:/home/yme/tmp/test.fdb"
 
void db_print_error(ISC_STATUS *stat)
{
	IF (stat != NULL)
	{
		isc_print_status(stat);
		printf("\nCode de l'erreur SQL:\n");
		isc_print_sqlerror(isc_sqlcode(stat),stat);
	}
}
 
int main(int argc, char **argv) 
{
	char param[256];
	char *ptr_param;
	int param_len;
	isc_stmt_handle stmt = 0;
	isc_tr_handle h_trans = 0;
	ISC_STATUS stat[20];
	isc_db_handle h_db = 0;
 
	ptr_param = param;
	*ptr_param++ = isc_dpb_version1;
	*ptr_param++ = isc_dpb_user_name;
	*ptr_param++ = strlen(USER);
	strncpy(ptr_param, USER, strlen(USER));		//il ne faut pas copier le 0 de fin de chaine
	ptr_param += strlen(USER);
	*ptr_param++ = isc_dpb_password;
	*ptr_param++ = strlen(PASSWD);
	strncpy(ptr_param, PASSWD, strlen(PASSWD));
	ptr_param += strlen(PASSWD);
	param_len = ptr_param - param;
 
	IF (isc_attach_database(stat, 0, DB_NAME, &h_db, param_len, param))
	//   IF (isc_attach_database(stat, 0, NOM_BASE, db, 0, NULL))
	{
		db_print_error(stat);
		RETURN 1;
	}
 
	char query[] = "SELECT nb FROM TOTO";
	long nb;
	XSQLDA *sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1));
	sqlda->sqln = 1;
	sqlda->sqld = 1;
	sqlda->version = SQLDA_VERSION1;
 
	sqlda->sqlvar[0].sqldata = (char *)&nb;
	sqlda->sqlvar[0].sqltype = SQL_LONG;		//Le champ nom de la bdd ne peut pas contenir NULL. ON ne vérifie donc pas si celui-ci est NULL.
 
	IF (isc_start_transaction(stat, &h_trans, 1, &h_db, 0, NULL))
	{
		db_print_error(stat);
		RETURN 1;
	}
 
	IF (isc_dsql_allocate_statement(stat, &h_db, &stmt))
	{
		db_print_error(stat);
		RETURN 1;
	}
 
	IF (isc_dsql_prepare(stat, &h_trans, &stmt, 0, query, 1, sqlda))
	{
		db_print_error(stat);
		RETURN 1;
	}
 
	IF (isc_dsql_execute(stat, &h_trans, &stmt, 1, NULL))
	{
		db_print_error(stat);
		RETURN 1;
	}
 
	int res = 0;
	do
	{
		res = isc_dsql_fetch(stat, &stmt, 1, sqlda);
 
		IF (res != 100 && res != 0)		//Erreur. Lorsque res vaut 100, il n'y a plus de données à lire
			db_print_error(stat);
		else
		if (res == 0)
			printf("nb: %ld\n", nb);
 
	} while (res == 0);
 
	if (isc_dsql_free_statement(stat, &stmt, DSQL_close))		//on libère les données précédemment allouées
	{
		db_print_error(stat);
		return 1;
	}
 
	if (isc_commit_transaction(stat, &h_trans))
	{
		db_print_error(stat);
		return 1;
	}
 
	return 0;
}
Rien de bien sorcier mais c'est juste pour le test.
Ca marche très bien.
Le problème se produit lorsque je veux faire la meme chose mais sur la vue (on remplace donc la requete par "SELECT nb FROM VTOTO".
Et la, ca marche plus du tout.

Voici le résultat de l'erreur:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
Dynamic SQL Error
-SQL error code = -804
-Incorrect VALUES within SQLDA structure
 
Code de l'erreur SQL:
SQLCODE: -804
SQL ERROR:
An error was found in the application program input parameters for the SQL statement.
 
ISC STATUS:
Dynamic SQL Error
-SQL error code = -804
-Incorrect values within SQLDA structure
Sachant que le type de la donnée est exactement pareil, je vois pas pourquoi ca marche pas.

Aidez moi SVP.
Merci d'avance pour vos réponses.
Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 16h29   #2
Expert Confirmé

 
Homme Philippe Makowski
Consultant spécialité Firebird
Inscription : mai 2002
Messages : 2 215
Détails du profil
Informations personnelles :
Nom : Homme Philippe Makowski
Âge : 49
Localisation : France

Informations professionnelles :
Activité : Consultant spécialité Firebird
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 2 215
Points : 3 318
Points : 3 318
donnes nous les définitions de la table et de la vue
__________________
Philippe Makowski
IBPhoenix - Firebird
Membre de l'April
makowski est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 16h55   #3
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
La table: TOTO (nb INTEGER NOT NULL)
La vue: SELECT nb FROM TOTO
Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 16h56   #4
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
J'espère avoir bien répondu à ce que tu demandais !

Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 17h57   #5
Expert Confirmé

 
Homme Philippe Makowski
Consultant spécialité Firebird
Inscription : mai 2002
Messages : 2 215
Détails du profil
Informations personnelles :
Nom : Homme Philippe Makowski
Âge : 49
Localisation : France

Informations professionnelles :
Activité : Consultant spécialité Firebird
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 2 215
Points : 3 318
Points : 3 318
donnes moi stp exactement le code de création de tes objets
__________________
Philippe Makowski
IBPhoenix - Firebird
Membre de l'April
makowski est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 20h20   #6
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
CREATE TABLE TOTO (nb INTEGER NOT NULL);
CREATE VIEW VTOTO AS SELECT nb FROM TOTO;


Puis pour insérer les données:
INSERT INTO TOTO VALUES (5);
Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 20h53   #7
Expert Confirmé

 
Homme Philippe Makowski
Consultant spécialité Firebird
Inscription : mai 2002
Messages : 2 215
Détails du profil
Informations personnelles :
Nom : Homme Philippe Makowski
Âge : 49
Localisation : France

Informations professionnelles :
Activité : Consultant spécialité Firebird
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 2 215
Points : 3 318
Points : 3 318
bizzare ton histoire
tu pourrais mettre ici le source compilable ?
et la version du compilateur utilisé ?
c'est pour essayer de le reproduire et éventuellement le rentrer dans le gestionnaire de bug
__________________
Philippe Makowski
IBPhoenix - Firebird
Membre de l'April
makowski est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 21h45   #8
Membre du Club
 
Inscription : mai 2002
Messages : 56
Détails du profil
Informations personnelles :
Âge : 33
Localisation : France, Moselle (Lorraine)

Informations forums :
Inscription : mai 2002
Messages : 56
Points : 65
Points : 65
Envoyer un message via ICQ à PierreY
Citation:
Envoyé par makowski
bizzare ton histoire
tu pourrais mettre ici le source compilable ?
et la version du compilateur utilisé ?
c'est pour essayer de le reproduire et éventuellement le rentrer dans le gestionnaire de bug
J'ai son source compilable :

Code :
1
2
3
pierre@azumi ~ $ gcc -o select_toto select_toto.c -lfbclient
pierre@azumi ~ $ ./select_toto 
nb: 47489453391877
Et vu le résultat, je pense que le code, même avec select nb from toto n'est pas bon. Je vais comparer avec les autres exemple de l'API, mais l'affectation de sqlda n'est pas correcte.

@+
PierreY est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 22h03   #9
Membre du Club
 
Inscription : mai 2002
Messages : 56
Détails du profil
Informations personnelles :
Âge : 33
Localisation : France, Moselle (Lorraine)

Informations forums :
Inscription : mai 2002
Messages : 56
Points : 65
Points : 65
Envoyer un message via ICQ à PierreY
Citation:
Envoyé par PierreY
nb: 47489453391877
Et vu le résultat, je pense que le code, même avec select nb from toto n'est pas bon. Je vais comparer avec les autres exemple de l'API, mais l'affectation de sqlda n'est pas correcte.
C'est bon, j'ai trouvé, c'est bien l'affectation du sqlda qui est mauvaise :

Code :
1
2
3
4
5
 
  sqlda->sqlvar[0].sqldata = (char *)&nb;
  sqlda->sqlvar[0].sqltype = SQL_LONG + 1;
  sqlda->sqlvar[0].sqllen = sizeof(nb); 
  sqlda->sqlvar[0].sqlind = &flag;
il ne faut pas oublier d'ajouter 1 au sqltype et d'attribuer la taille du type à sqllen quand il ne s'agit pas d'une chaîne (voir l'exemple api4.c)

Et la boucle de lecture est mal écrite (oui Barbibulle, je suis d'accord, ce n'est pas la seule bonne méthode )

Avertissement : Attention, le moteur de coloration syntaxique met certains mots clés (if, return) en majuscules et rend le bout de code incompilable.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
 
	long res;
    	while ((res = isc_dsql_fetch(stat, &stmt, 1, sqlda)) == 0)
    	{
        	printf("nb: %ld\n", nb);
	}
 
	IF (res != 100L)
    	{
		db_print_error(stat);
        	RETURN 1;
    	}
Est plus propre et, à mon humbre avis, plus lisible.

@+

--
Pierre Y.
PierreY est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 22h06   #10
Membre du Club
 
Inscription : mai 2002
Messages : 56
Détails du profil
Informations personnelles :
Âge : 33
Localisation : France, Moselle (Lorraine)

Informations forums :
Inscription : mai 2002
Messages : 56
Points : 65
Points : 65
Envoyer un message via ICQ à PierreY
Citation:
Envoyé par PierreY
C'est bon, j'ai trouvé, c'est bien l'affectation du sqlda qui est mauvaise
J'oubliais : ca marche avec select NB from V_TOTO :-)
PierreY est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 22h10   #11
Membre du Club
 
Inscription : mai 2002
Messages : 56
Détails du profil
Informations personnelles :
Âge : 33
Localisation : France, Moselle (Lorraine)

Informations forums :
Inscription : mai 2002
Messages : 56
Points : 65
Points : 65
Envoyer un message via ICQ à PierreY
Ca n'a pas beaucoup de conséquences dans cet exemple, mais attention, il faut libérer la mémoire de sqlda à la fin :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* ... */
 
IF (isc_dsql_free_statement(stat, &stmt, DSQL_close))
{
  db_print_error(stat);
  RETURN 1;
}
 
IF (isc_commit_transaction(stat, &h_trans))
{
  db_print_error(stat);
  RETURN 1;
}
 
// ici
free(sqlda);
 
RETURN 0;
}
PierreY est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2006, 22h33   #12
Expert Confirmé

 
Homme Philippe Makowski
Consultant spécialité Firebird
Inscription : mai 2002
Messages : 2 215
Détails du profil
Informations personnelles :
Nom : Homme Philippe Makowski
Âge : 49
Localisation : France

Informations professionnelles :
Activité : Consultant spécialité Firebird
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 2 215
Points : 3 318
Points : 3 318
Merci Pierre,
j'avais peur de refaire des tests de régressions pour une RC6
__________________
Philippe Makowski
IBPhoenix - Firebird
Membre de l'April
makowski est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2006, 07h30   #13
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
Merci beaucoup les gars.
Juste une question car ca me parait étrange.
Tout d'abors, je croyais qu'il fallait +1 dans le cas où on voulait gérer le fait qu'un champ soit null ou pas (hors, d'après la structure de ma base, pas celle de l'exemple, je suis sur qu'il ne peut pas etre null, donc ca me sert à rien).
Il me semble que le +1 permet d'activer le nullité en activant le bit 0 pour effectuer un masque dans les traitements après (dites si je me trompe).

Encore un truc: pourquoi ca marche pour une table et pas pour une vue ??!!!!

Merci encore. J'ai pas encore testé mais je suis confiant sur ce que vous me dites.

Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2006, 07h43   #14
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
Autre petit point: il est bizarre ton résultat. Moi, ca marche la requete sur la table, j'obtiens bien la valeur que j'ai mis dans la table (et pas un truc de fou ).
Par contre, dans la ligne de linkage, je suis obliger de lier la librairie pthread sinon ca ne linke pas (-lpthread).

Autre chose, le vrai problème ne se situe pas sur le type de donnée (SQL_LONG ou SQL_LONG + 1) mais sur le fait que je n'ai pas attribué de variable pour stocker le fait que le résultat est NULL ou pas.
Ce qui me parait étrange, c'est que je spécifie que je ne veut pas tenir compte de la nullité de la variable (j'utilise SQL_LONG et pas SQL_LONG + 1).

C'est bizarre, non?? (j'espère avoir été clair??? )

Encore merci pour toutes vos réponses.
Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2006, 08h19   #15
Membre du Club
 
Inscription : mai 2002
Messages : 56
Détails du profil
Informations personnelles :
Âge : 33
Localisation : France, Moselle (Lorraine)

Informations forums :
Inscription : mai 2002
Messages : 56
Points : 65
Points : 65
Envoyer un message via ICQ à PierreY
Citation:
Envoyé par Pepere72
Autre petit point: il est bizarre ton résultat.
Peut-etre un petit coup de bol lié à des conditions d'exécution particulières ? Genre avec les infos de débuggage ou dans un environnement de développement... que sais-je ;-)

Peut-être qu'il ne te manque que cette ligne ?

Code :
1
2
 
  sqlda->sqlvar[0].sqllen = sizeof(nb);
PierreY est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2006, 08h24   #16
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
A propos du résultat, en tout cas, j'ai compilé un paquet de fois et ca marche tout le temps (pour la requete sur la table).
J'ai fais un test, apparemment, on n'est pas obligé de paramétrer sqllen, ca marche très bien sans mais par contre sqlind est obligatoire (alors que dans la doc, c'est écrit que si on utilise SQL_LONG, il n'y a pas besoin de sqlind) ???

De plus, pourquoi y'a-t-il une différence de traitement entre un table et une vue??? (puisque ca marche pour la table!!).
Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2006, 09h49   #17
Membre du Club
 
Inscription : mai 2002
Messages : 56
Détails du profil
Informations personnelles :
Âge : 33
Localisation : France, Moselle (Lorraine)

Informations forums :
Inscription : mai 2002
Messages : 56
Points : 65
Points : 65
Envoyer un message via ICQ à PierreY
Citation:
Envoyé par Pepere72
A propos du résultat, en tout cas, j'ai compilé un paquet de fois et ca marche tout le temps (pour la requete sur la table).
J'ai fais un test, apparemment, on n'est pas obligé de paramétrer sqllen, ca marche très bien sans mais par contre sqlind est obligatoire (alors que dans la doc, c'est écrit que si on utilise SQL_LONG, il n'y a pas besoin de sqlind) ???

De plus, pourquoi y'a-t-il une différence de traitement entre un table et une vue??? (puisque ca marche pour la table!!).
Je pense qu'il n'y a pas de différence de traitement du point de vue de l'API du moins, parce que l'API ne sait même pas que tu t'adresses à une vue.

Concernant l'utilisation de SQLDA, franchement, j'en sais rien, je ne sais pas si c'est obligatoire d'affecter sqlind, je ne sais pas pourquoi il faut mettre + 1 ou pas et si sqllen est obligatoire. Je sais seulement que dans les librairies qui encapsulent l'API de Fb/Ib, les mecs qui les ont écrites ont choisi d'affecter systématiquement toutes les options (avec le +1, le sqlind et le sqllen)

Si on s'en tient aux exemples de l'API et à ce qu'on trouve dans ces libs et qui marche, je dirais que le mieux est de faire les choses en fonction du pire des cas non ?

Peut-être qu'Henri, s'il passe par là pourra apporter des précisions ?
PierreY est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2006, 10h27   #18
Membre du Club
 
Inscription : mai 2002
Messages : 56
Détails du profil
Informations personnelles :
Âge : 33
Localisation : France, Moselle (Lorraine)

Informations forums :
Inscription : mai 2002
Messages : 56
Points : 65
Points : 65
Envoyer un message via ICQ à PierreY
Citation:
Envoyé par Pepere72
A propos du résultat, en tout cas, j'ai compilé un paquet de fois et ca marche tout le temps (pour la requete sur la table).
J'ai fais un test, apparemment, on n'est pas obligé de paramétrer sqllen, ca marche très bien sans mais par contre sqlind est obligatoire (alors que dans la doc, c'est écrit que si on utilise SQL_LONG, il n'y a pas besoin de sqlind) ???

De plus, pourquoi y'a-t-il une différence de traitement entre un table et une vue??? (puisque ca marche pour la table!!).
Je viens de tester avec Delphi 2006 et le compilateur C++ de Borland. J'ai pris ton code, corrigé les erreurs de syntaxe dues à la mise en forme du code dans ce forum, corrigé les erreurs dans le code levées par BCC (il n'aime pas les déclarations en plein milieu du code) et j'arrive à reproduire ton problème, ça marche pour la table mais pas pour la vue.

Et j'ai trouvé la raison :-)

Il ne faut pas affecter sqlda.sqlvar[0] avant d'avoir appellé isc_dsql_prepare, si je déplace tes deux lignes de code juste avant le isql_dsql_execute, tout fonctionne, je pense que isc_dsql_prepare (ré)-initialise des trucs dans sqlvar, probablement pour indiquer le type des données qui seront renvoyées lors du isc_dsql_execute. (Faut aller fouiller dans les sources de Firebird)

D'ailleurs c'est ce que j'avais fait hier soir en testant avec gcc puisque j'ai reproduit la structure des exemples de l'API... et j'ai oublié de dire que je l'avais fait.

Bonne journée ;-)
PierreY est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2006, 10h55   #19
Invité de passage
 
Inscription : juin 2002
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 8
Points : 0
Points : 0
Merci pour tout Pierre.

Je teste ca dès que je peux (peut etre pas aujourd'hui) et je te confirme ca.

Bonne journée et bon WE
Pepere72 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 17h52.


 
 
 
 
Partenaires

Hébergement Web