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 06/07/2006, 17h37   #1
Invité régulier
 
Inscription : juillet 2006
Messages : 19
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 19
Points : 5
Points : 5
Par défaut [PRO*C] Allocation dynamique d'un tableau de VARCHAR

Bonjour,

Je souhaite récupérer des données de la base avant d'en insérer d'autres. Comme je manipule de très grosses masses de données, je dois procéder par blocs dont la taille n'est pas fixée à la compilation.
Je n'ai pas de problème avec les types scalaires (int...) mais pour VARCHAR, je dois dire que je bloque.

Voici du code qui ne passe pas mais qui donne, je pense une bonne idée de ce que je veux faire :
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
int i; /* Compteur */
EXEC SQL BEGIN DECLARE SECTION;
	int bloc; /* Taille d'un bloc */
	int* tNum; /*Numeros des gens */
	VARCHAR** tNom; /* Noms des gens */
EXEC SQL END DECLARE SECTION;
 
bloc = 100; /* Recupere dynamiquement (parametrable) */
 
tNum = (int*) malloc(bloc * sizeof(*tNum));
 
/* Le probleme est juste la... */
tNom = (VARCHAR**) malloc(bloc * sizeof(*tNom));
FOR(i = 0; i < bloc; i++) {
	tNom[i] = (VARCHAR*) malloc(20 * sizeof(**tNom)); /* 20 : Taille d'un nom */
}
 
EXEC SQL DECLARE c_gens CURSOR FOR SELECT num, nom FROM gens;
/* Gestion des erreurs */
 
EXEC SQL OPEN c_gens;
/* Gestion des erreurs */
 
EXEC SQL FOR :bloc FETCH c_gens INTO :tNum, :tNom;
/* Gestion des erreurs */
while(/* encore des lignes, je sais faire mais le probleme n'est pas la */) {
	/* Traitements sur tNum et tNom */
 
	EXEC SQL FOR :bloc INSERT INTO client(num, nom) VALUES (:tNum, :tNom);
 
	EXEC SQL FOR :bloc FETCH c_gens INTO :tNum, :tNom;
	/* Gestion des erreurs */
}
 
free(tNum);
FOR(i = 0; i < bloc; i++) {
	free(tNom[i]);
}
free(tNom);
En fait le problème vient du fait que VARCHAR n'est pas simplement un tableau de caractères comme en C classique, le précompilateur Pro*C créé une structure.

La question est : peut-on faire une allocation dynamique d'un tableau de VARCHAR pour l'utilisation de Host Array ?

Merci par avance !

Edit : Pro*C/C++: Release 9.2.0.4.0
NéalZheimer est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/07/2006, 10h35   #2
Invité régulier
 
Inscription : juillet 2006
Messages : 19
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 19
Points : 5
Points : 5
Par défaut Bon forum ?

Mon message est-il sur le bon forum ou aurait-il plus sa place dans la section C ?
J'ai pas mal hésité en postant...
NéalZheimer est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/07/2006, 11h41   #3
Rédacteur

 
Avatar de SheikYerbouti
 
Inscription : mai 2003
Messages : 6 533
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 6 533
Points : 6 469
Points : 6 469
Il est bien sur le bon forum, cependant les programmeurs Pro*C ne sont pas nombreux...
N'avez-vous trouvé aucun example dans la doc Pro*C ?
la structure décrivant les Varchar2 y est très bien expliquée, il me semble.
__________________
Rédacteur Oracle (Oracle ACE)
Guide Oracle ,Guide PL/SQL, Guide Forms 9i/10g, Index de recherche
Je ne réponds pas aux questions techniques par MP
Blogs: Forms-PL/SQL-J2EE - Forms Java Beans
SheikYerbouti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/07/2006, 11h46   #4
Invité régulier
 
Inscription : juillet 2006
Messages : 19
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 19
Points : 5
Points : 5
Je comprends qu'il n'y aie pas beaucoup de développeurs Pro*C, moi-même, si j'avais le choix...
Les seuls exemples que j'ai pu trouver portent sur des tableaux fixes :
Code :
1
2
#define BLOC 100
VARCHAR tNom[BLOC][9 * NBXXXX];
J'ai lu une page sur l'allocation dynamique des tableaux de VARCHAR mais je n'ai pas été convaincu par la portabilité de la méthode (lors de la compilation sous différents environnements).

Je pense que je vais essayer de me passer de l'allocation dynamique, tant pis.

Merci quand même.

PS : Pour la "beauté de l'art", si quelqu'un trouve un début de solution, je suis tout de même interressé
NéalZheimer est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/07/2006, 12h10   #5
Rédacteur

 
Avatar de SheikYerbouti
 
Inscription : mai 2003
Messages : 6 533
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 6 533
Points : 6 469
Points : 6 469
J'ai trouvé cceci dans la doc. Peut-être cela vous aidera t-il...

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
 
/*
* The sqlvcp.pc program demonstrates how you can use the
* sqlvcp() function to determine the actual size of a
* VARCHAR struct. The size is then used as an offset to
* increment a pointer that steps through an array of
* VARCHARs.
*
* This program also demonstrates the use of the sqlgls()
* function, to get the text of the last SQL statement executed.
* sqlgls() is described in the "Error Handling" chapter of
* The Programmer’s Guide to the Oracle Pro*C/C++ Precompiler.
*/
#include <stdio.h>
#include <sqlca.h>
#include <sqlcpr.h>
/* Fake a VARCHAR pointer type. */
struct my_vc_ptr
{
UNSIGNED short len;
UNSIGNED char arr[32767];
};
/* Define a type for the VARCHAR pointer */
typedef struct my_vc_ptr my_vc_ptr;
my_vc_ptr *vc_ptr;
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR *names;
int LIMIT; /* for use in FETCH FOR clause */
char *username = "scott/tiger";
EXEC SQL END DECLARE SECTION;
void sql_error();
extern void sqlvcp(), sqlgls();
main()
{
See Also: Chapter 9, "Handling Runtime Errors"
VARCHAR VARIABLES
Datatypes AND Host VARIABLES 4-27
UNSIGNED int vcplen, function_code, padlen, buflen;
int i;
char stmt_buf[120];
EXEC SQL WHENEVER SQLERROR DO sql_error();
EXEC SQL CONNECT :username;
printf("\nConnected.\n");
/* Find number of rows in table. */
EXEC SQL SELECT COUNT(*) INTO :LIMIT FROM emp;
/* Declare a cursor for the FETCH statement. */
EXEC SQL DECLARE emp_name_cursor CURSOR FOR
SELECT ename FROM emp;
EXEC SQL FOR :LIMIT OPEN emp_name_cursor;
/* Set the desired DATA length for the VARCHAR. */
vcplen = 10;
/* Use SQLVCP to help find the length to malloc. */
sqlvcp(&vcplen, &padlen);
printf("Actual array length of VARCHAR is %ld\n", padlen);
/* Allocate the names buffer for names.
Set the limit variable for the FOR clause. */
names = (VARCHAR *) malloc((sizeof (short) +
(int) padlen) * LIMIT);
IF (names == 0)
{
printf("Memory allocation error.\n");
exit(1);
}
/* Set the maximum lengths before the FETCH.
* Note the "trick" to get an effective VARCHAR *.
*/
FOR (vc_ptr = (my_vc_ptr *) names, i = 0; i < LIMIT; i++)
{
vc_ptr->len = (short) padlen;
vc_ptr = (my_vc_ptr *)((char *) vc_ptr +
padlen + sizeof (short));
}
/* Execute the FETCH. */
EXEC SQL FOR :LIMIT FETCH emp_name_cursor INTO :names;
VARCHAR VARIABLES
4-28 Pro*C/C++ Precompiler Programmer’s Guide
/* Print the results. */
printf("Employee names--\n");
FOR (vc_ptr = (my_vc_ptr *) names, i = 0; i < LIMIT; i++)
{
printf
("%.*s\t(%d)\n", vc_ptr->len, vc_ptr->arr, vc_ptr->len);
vc_ptr = (my_vc_ptr *)((char *) vc_ptr +
padlen + sizeof (short));
}
/* Get statistics about the most recent
* SQL statement using SQLGLS. Note that
* the most recent statement in this example
* is not a FETCH, but rather "SELECT ENAME FROM EMP"
* (the cursor).
*/
buflen = (long) sizeof (stmt_buf);
/* The returned value should be 1, indicating no error. */
sqlgls(stmt_buf, &buflen, &function_code);
IF (buflen != 0)
{
/* Print out the SQL statement. */
printf("The SQL statement was--\n%.*s\n", buflen, stmt_buf);
/* Print the returned length. */
printf("The statement length is %ld\n", buflen);
/* Print the attributes. */
printf("The function code is %ld\n", function_code);
EXEC SQL COMMIT RELEASE;
exit(0);
}
else
{
printf("The SQLGLS function returned an error.\n");
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
}
void
sql_error()
{
char err_msg[512];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
buf_len = sizeof (err_msg);
sqlglm(err_msg, &buf_len, &msg_len);
printf("%.*s\n", msg_len, err_msg);
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
__________________
Rédacteur Oracle (Oracle ACE)
Guide Oracle ,Guide PL/SQL, Guide Forms 9i/10g, Index de recherche
Je ne réponds pas aux questions techniques par MP
Blogs: Forms-PL/SQL-J2EE - Forms Java Beans
SheikYerbouti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/07/2006, 13h02   #6
Invité régulier
 
Inscription : juillet 2006
Messages : 19
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 19
Points : 5
Points : 5
Merci bien !
C'est exactement le genre de chose à laquelle je pensais.
NéalZheimer 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 21h39.


 
 
 
 
Partenaires

Hébergement Web