Précédent   Forum des professionnels en informatique > Bases de données > Oracle > Interfaces de programmation
Interfaces de programmation Forum d'entraide sur l'utilisation des API Oracle : Pré-compilateurs, OCI, OCCI, etc.
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 13/02/2008, 19h44   #1
Membre habitué
 
Inscription : avril 2004
Messages : 421
Détails du profil
Informations forums :
Inscription : avril 2004
Messages : 421
Points : 120
Points : 120
Par défaut [OCI] Récuperer le type d'une colonne

bonjour,

voila, je dois d'utiliser la librairie OCI (et non OCIlib malheureusement) pour realiser une requete du type select * from table1.

Tout ce passe bien jusqu'a ce que j'essaie de recuperer la premiere ligne.

j'ai fait un OCIPrepare , suivi d'un OCI execute, jusque la tout va bien.

le probleme c'est pour recuperer le resultat. Si j'ai bien compris (la doc etant pas tres clair la dessus), je recuperer d'abord le nombre de colonne que la reponse contient, suivi du type de chaque colonne puis je fais un OCIDefine, puis un fetch pour recuperer chaque ligne.

la ou cela coince, c'est pour recuperer le type et faire l'appel du define.
dans le define il faut faudra dire de quelle type sera la case. Soit SQLT_INT soit SQLT_STR;

or quand je fait type == SQLT_INT ou type == SQLT_STR tout les deux sont faut.

Comment savoir de quelle type sont les réponses?

merci

a++
elekis est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2008, 20h54   #2
Rédacteur/Modérateur
 
Avatar de Vincent Rogier
 
vincent rogier
Inscription : juillet 2007
Messages : 2 355
Détails du profil
Informations personnelles :
Nom : vincent rogier
Âge : 34

Informations forums :
Inscription : juillet 2007
Messages : 2 355
Points : 3 108
Points : 3 108
Et Pourquoi pas OCILIB ?

Poste ton code ! Comment tu as recupéré le type ? Il faut savoir que OCI ne te fournira jamais SQLT_INT quand tu décris une colonne..

Il te fournira dans 99 % cas SQLT_NUM pour la famille des number qui regoupre quasiment tous les numériques sauf les FLOAT (double, float, real, ..)

En fait SQLT_INT est utilisé quant tu appelles OCIDefine().

Résumons, tu as une colonnes de type sql INT (qui est en fait un NUMBER).

Tu décris la colonne et tu obtiens SQL_NUM. SI tu veux récupérer la valeur sous forme de int en C , tu passes SQLT_INT pour définir la colonne et Oracle fera la conversion et mettra dans ton buffer des int...

Bon, je ne suis peut être pas très clair (j'ai faim... faut aller bouffer..).

Tu peux regarder le source d'OCILIB pour apprendre comment fonctionne OCI.

N'hésites pas, je suis à ta disposition.
__________________
Vincent Rogier.

Rubrique ORACLE : Accueil - Forum - Tutoriels - FAQ - Livres - Blog

Vous voulez contribuer à la rubrique Oracle ? Contactez la rubrique !

OCILIB (C Driver for Oracle)

Librairie C Open Source multi-plateformes pour accéder et manipuler des bases de données Oracle
Vincent Rogier est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2008, 21h05   #3
Membre habitué
 
Inscription : avril 2004
Messages : 421
Détails du profil
Informations forums :
Inscription : avril 2004
Messages : 421
Points : 120
Points : 120
bonjour et merci.

Le truc c'est que j'ai pas le code ici (je l'ai oublié. je le mettrais demain matin)

pourquoi pas ocilib, c'est assez compliquer mais en gros on peut pas (malheureusement). en fait, je dois faire une espece de portage dans un language totalement exotique etc... Peut etre par la suite pourquoi pas...mais c'est pas moi le patron

merci pour tout en cas.
elekis est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/02/2008, 07h47   #4
Membre habitué
 
Inscription : avril 2004
Messages : 421
Détails du profil
Informations forums :
Inscription : avril 2004
Messages : 421
Points : 120
Points : 120
bonjour, voila quoi ressemble plus ou moins mon code (j'ai omis tout l'indispensable)


j'essaie de recuperer la commande sqlsuivante

'SELECT * FROM "table3"'

pour cela

Code :
1
2
 
OCIStmtPrepare(	stmthp,errhp,(text *) Y_fmt,(ub4) Y_size,(ub4)OCI_NTV_SYNTAX,(ub4) OCI_DEFAULT);

puis je l'execute

Code :
1
2
 
OCIStmtExecute(svchp, stmthp,  errhp,  (ub4) 0, (ub4) 0, (CONST OCISnapshot *) 0,  (OCISnapshot *) 0,(ub4) OCI_DEFAULT);
puis je recupere le nombre de colonne que contient la reponse
Code :
1
2
 
OCIAttrGet((dvoid *)stmthp, OCI_HTYPE_STMT, (dvoid *)&Y_RESULT,(ub4 *)0, OCI_ATTR_PARAM_COUNT, errhp);
puis pour chaque colonne, je recupere le type (que je sauvegarde)


Code :
1
2
3
4
 
Y_parmstatus = OCIParamGet((dvoid *)stmthp, OCI_HTYPE_STMT, errhp,(dvoid **)&mypard, (ub4) Y_number);
 
OCIAttrGet(	(dvoid*) mypard, (ub4) OCI_DTYPE_PARAM, (dvoid*) &Y_dtype,(ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE,(OCIError *) errhp  );
et puis enfin, je fait un define (avant de faire un fetch)
et c'est la que j'ai un probleme car je dois savoir le type

Code :
1
2
3
4
5
6
 
IF type[i] == SQLT_INT  THEN
OCIDefineByPos(	stmthp,&defnp,errhp,Y_col,(dvoid *)SQL_INT,(sb4) 1024,SQLT_INT,NULL,NULL,NULL,OCI_DEFAULT);
ELSE IF type[i] == SQLT_STR
OCIDefineByPos(	stmthp,&defnp,errhp,Y_col,(dvoid *)SQL_STR,(sb4) 1024,SQLT_INT,NULL,NULL,NULL,OCI_DEFAULT);
END;
J'ai essayer STR_NUM, et ca fonctione pour ce qui est nombre mais pas pour ce qui SQL_STR en fait, les codes (si je fait un print du type) sont 2 et 112.
ce qui fait que c'est un SQLT_CLOB or normalement cela doit etre un char...
bizarre, en plus,cela me vaut une belle erreur

Fetch - ORA-00932: inconsistent datatypes: expected NUMBER got DTY0
mis bon, ca c'est pas pour tout de suite.

salutation et merci pour tout.

a++
elekis est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/02/2008, 19h15   #5
Rédacteur/Modérateur
 
Avatar de Vincent Rogier
 
vincent rogier
Inscription : juillet 2007
Messages : 2 355
Détails du profil
Informations personnelles :
Nom : vincent rogier
Âge : 34

Informations forums :
Inscription : juillet 2007
Messages : 2 355
Points : 3 108
Points : 3 108
Déja tu pourrais aussi poster le DDL de la table

De même que Oracle ne renverra jamais SQLT_INT pour un number même entier (car SQLT_INT ne sert que dans l'autre sens, c'est à dire pour lui inqiuer que son number, tu veux le récuperer dans un int), SQLT_STR ne te sera jamais renvoyé par ORACLE... C'est en général un type que tu fournit à OCIDefine() pour qu'il te renvoi le buffer (char, varchar, ...) sous forme de chaines C à zéro terminal.

Donc, pour résumer :
  • certains SQLT_XXX sont utilisés par Oracle comme retour de OCIParamGet() avec OCI_ATTR_DATA_TYPE
  • les autres sont pour toi afin de dire à ORacle comment tu veux qu'il te retourne buffer lors de l'appel à OCIDefine()
Par exemple, voici le code extrait d'OCIB qui sert à mapper les champs (tous les types Oracle tirés de ocidfn.h sont traités dans le switch):

col->ocode est le code SQLT_XXX récupéré d'Oracle
col->icode est le code SQLT_XXX qui sera fournit à OCIDefine()

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
 
 
    /* .... */
 
    col->icode = col->ocode;
 
    /* ... */
 
    switch (col->icode)
    {
        case SQLT_INT:
        case SQLT_UIN:
 
            col->type    = OCI_CDT_INTEGER;
            col->bufsize = sizeof(int);
            break;
 
        case SQLT_FLT:
        case SQLT_BFLOAT:
        case SQLT_BDOUBLE:
        case SQLT_IBFLOAT:
        case SQLT_IBDOUBLE:
 
            col->type    = OCI_CDT_DOUBLE;
            col->bufsize = sizeof(double);
            break;
 
        case SQLT_VNU:
        case SQLT_PDN:
        case SQLT_NUM:
 
            /* OCILIB tries to map few NUMBER based columns (INT, INTEGER, ...)
               to C int types intead of double for perfomance.
               So, it tries to detect decimal columns from columns atributes */
 
            IF (col->scale == 0 && col->prec != 0 && col->prec <= 38)
            {
                col->icode   = SQLT_INT;
                col->type    = OCI_CDT_INTEGER;
                col->bufsize = sizeof(int);
            }
            else
            {
                col->icode   = SQLT_FLT;
                col->type    = OCI_CDT_DOUBLE;
                col->bufsize = sizeof(double);
            }
 
            break;
 
        case SQLT_DAT:
        case SQLT_ODT:
 
            col->icode   = SQLT_ODT;
            col->type    = OCI_CDT_DATETIME;
            col->bufsize = sizeof(OCIDate);
            break;
 
        case SQLT_CUR:
        case SQLT_RSET:
 
            col->type     = OCI_CDT_CURSOR;
            col->bufsize  = sizeof(OCIStmt *);
            col->dtype    = OCI_HTYPE_STMT;
            break;
 
        case SQLT_RDD:
        case SQLT_RID:
 
            col->icode   = SQLT_STR;
            col->type    = OCI_CDT_TEXT;
            col->bufsize = (OCI_SIZE_ROWID+1) * sizeof(dtext);
            break;
 
        case SQLT_BIN:
 
            col->type    = OCI_CDT_RAW;
            col->bufsize = col->size;
            break;
 
        case SQLT_BLOB:
 
            col->type    = OCI_CDT_LOB;
            col->subtype = OCI_BLOB;
            col->dtype   = OCI_DTYPE_LOB;
            col->bufsize = sizeof(OCILobLocator *);
            break;
 
        case SQLT_CLOB:
 
            col->type    = OCI_CDT_LOB;
            col->dtype   = OCI_DTYPE_LOB;
            col->bufsize = sizeof(OCILobLocator *);
 
            IF (col->csfrm == SQLCS_NCHAR)
                col->subtype = OCI_NCLOB;
            else
                col->subtype = OCI_CLOB;
 
            break;
 
        case SQLT_BFILE:
 
            col->type    = OCI_CDT_FILE;
            col->subtype = OCI_BFILE;
            col->dtype   = OCI_DTYPE_LOB;
            col->bufsize = sizeof(OCILobLocator *);
            break;
 
        case SQLT_CFILE:
 
            col->type    = OCI_CDT_FILE;
            col->subtype = OCI_CFILE;
            col->bufsize = sizeof(OCILobLocator *);
            col->dtype   = OCI_DTYPE_LOB;
            break;
 
        case SQLT_LNG:
        case SQLT_LVC:
        case SQLT_LBI:
        case SQLT_LVB:
        case SQLT_VBI:
 
            IF ((col->icode == SQLT_LNG || col->icode == SQLT_LVC) &&
                (stmt != NULL && stmt->long_mode == OCI_LONG_IMPLICIT))
            {
                 col->type = OCI_CDT_TEXT;
                 col->bufsize = (OCI_SIZE_LONG+1);
            }
            else
            {
                IF (stmt != NULL)
                {
                    stmt->fetch_mode = OCI_DYNAMIC_FETCH;
                    stmt->piecewise  = TRUE;
                }
 
                col->type    = OCI_CDT_LONG;
                col->bufsize = INT_MAX;
 
                IF (col->icode == SQLT_LBI ||
                    col->icode == SQLT_LVB ||
                    col->icode == SQLT_VBI)
                {
                    col->subtype = OCI_BLONG;
                }
                else
                {
                    col->subtype = OCI_CLONG;
                }
 
            }
 
            break;
 
#if OCI_VERSION_COMPILE >= OCI_9
 
        case SQLT_TIMESTAMP:
 
            col->type    = OCI_CDT_TIMESTAMP;
            col->subtype = OCI_TIMESTAMP;
            col->dtype   = OCI_DTYPE_TIMESTAMP;
            col->bufsize = sizeof(OCIDateTime *);
            break;
 
        case SQLT_TIMESTAMP_TZ:
 
            col->type    = OCI_CDT_TIMESTAMP;
            col->subtype = OCI_TIMESTAMP_TZ;
            col->dtype   = OCI_DTYPE_TIMESTAMP_TZ;
            col->bufsize = sizeof(OCIDateTime *);
            break;
 
        case SQLT_TIMESTAMP_LTZ:
 
            col->type    = OCI_CDT_TIMESTAMP;
            col->subtype = OCI_TIMESTAMP_LTZ;
            col->dtype   = OCI_DTYPE_TIMESTAMP_LTZ;
            col->bufsize = sizeof(OCIDateTime *);
            break;
 
        case SQLT_INTERVAL_YM:
 
            col->type    = OCI_CDT_INTERVAL;
            col->subtype = OCI_INTERVAL_YM;
            col->dtype   = OCI_DTYPE_INTERVAL_YM;
            col->bufsize = sizeof(OCIInterval *);
            break;
 
        case SQLT_INTERVAL_DS:
 
            col->type    = OCI_CDT_INTERVAL;
            col->subtype = OCI_INTERVAL_DS;
            col->dtype   = OCI_DTYPE_INTERVAL_DS;
            col->bufsize = sizeof(OCIInterval *);
            break;
 
#endif
        case SQLT_NTY:
        case SQLT_PNTY:
        {
            col->icode   = SQLT_NTY;
            col->type    = OCI_CDT_OBJECT;                    
            col->bufsize = sizeof(void *);
            break;
        }
        case SQLT_REF:
 
            /* not supported datatypes */
 
            OCI_ErrorDatatypes(col->icode);
            RETURN FALSE;
 
        case SQLT_CHR:
        case SQLT_STR:
        case SQLT_VCS:
        case SQLT_AFC:
        case SQLT_AVC:
        case SQLT_VST:
        case SQLT_LAB:
        case SQLT_OSL:
        case SQLT_SLS:
        DEFAULT:
 
            col->icode   = SQLT_STR;
            col->type    = OCI_CDT_TEXT;
            col->bufsize = (col->size + 1) * sizeof(dtext);
            break;
    }
 
    RETURN TRUE
 
    /* .... */
__________________
Vincent Rogier.

Rubrique ORACLE : Accueil - Forum - Tutoriels - FAQ - Livres - Blog

Vous voulez contribuer à la rubrique Oracle ? Contactez la rubrique !

OCILIB (C Driver for Oracle)

Librairie C Open Source multi-plateformes pour accéder et manipuler des bases de données Oracle
Vincent Rogier est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/02/2008, 20h14   #6
Membre habitué
 
Inscription : avril 2004
Messages : 421
Détails du profil
Informations forums :
Inscription : avril 2004
Messages : 421
Points : 120
Points : 120
wouahh... merci pour tout.
je regarderais cela demain a mon aise.


a++ et encore merci
elekis est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/02/2008, 15h42   #7
Membre habitué
 
Inscription : avril 2004
Messages : 421
Détails du profil
Informations forums :
Inscription : avril 2004
Messages : 421
Points : 120
Points : 120
salut,

premierement merci pour tout mais il y a un truc que je comprend pas.
voila comment je creer une mini base sql.
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
CREATE TABLE table1 (	
			id NUMBER PRIMARY KEY,
			field1	NUMBER,
			field2	FLOAT,
			field3 INTEGER
		);
INSERT INTO table1 VALUES (1,1,1,1);
INSERT INTO table1 VALUES (2,2,2,2);
INSERT INTO table1 VALUES (3,3,3.3,3);
INSERT INTO table1 VALUES (4,4,4,4);
INSERT INTO table1 VALUES (5,5,5,5);
INSERT INTO table1 VALUES (6,6,6,6);
 
 
DESCRIBE table1;
SELECT * FROM table1;
Comme tu me l'as dit, il ne me renvoi que un SQLT_NUM indépendamment de la colonne.
et toi pour faire la difference, tu fais le code suivant

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
 
  IF (col->scale == 0 && col->prec != 0 && col->prec <= 38)
            {
                col->icode   = SQLT_INT;
                col->type    = OCI_CDT_INTEGER;
                col->bufsize = sizeof(int);
            }
            else
            {
                col->icode   = SQLT_FLT;
                col->type    = OCI_CDT_DOUBLE;
                col->bufsize = sizeof(double);
            }
En fait, je comprend pas trop ton if . j'ai essayer d'aller voir le code source, mais c'est pas mieux... comment fait tu cette difference.

salutation

merci

a++
elekis est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/02/2008, 16h07   #8
Rédacteur/Modérateur
 
Avatar de Vincent Rogier
 
vincent rogier
Inscription : juillet 2007
Messages : 2 355
Détails du profil
Informations personnelles :
Nom : vincent rogier
Âge : 34

Informations forums :
Inscription : juillet 2007
Messages : 2 355
Points : 3 108
Points : 3 108
il faut que tu récupère l'attribut precision et scale de ta colonne

Code :
1
2
3
4
5
6
7
8
9
10
11
 
 
     /* scale */
 
    OCI_CALL(con, OCIAttrGet(param, OCI_DTYPE_PARAM, &col->scale,
                             NULL, OCI_ATTR_SCALE, con->err))
 
    /* precision */
 
    OCI_CALL(con, OCIAttrGet(param, OCI_DTYPE_PARAM, &col->prec,
                             NULL, OCI_ATTR_PRECISION, con->err))
en fait dans oracle tout est number ou float. Pour savoir le type réel SQL de la colonne, if faut étudier les valeur precision et scale de la colonne.

le test que tu mentionnes détermine que la colonne est de type entier sans valeurs décimale si le scale = 0 et que la precision est comprise entre entre 1 et 38. Sinon, c'est du double ! C'est comme ca...
__________________
Vincent Rogier.

Rubrique ORACLE : Accueil - Forum - Tutoriels - FAQ - Livres - Blog

Vous voulez contribuer à la rubrique Oracle ? Contactez la rubrique !

OCILIB (C Driver for Oracle)

Librairie C Open Source multi-plateformes pour accéder et manipuler des bases de données Oracle
Vincent Rogier est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/02/2008, 18h37   #9
Membre habitué
 
Inscription : avril 2004
Messages : 421
Détails du profil
Informations forums :
Inscription : avril 2004
Messages : 421
Points : 120
Points : 120
merci

a++
elekis est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 19h06.


 
 
 
 
Partenaires

Hébergement Web