]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/myingres.sc
Merge branch 'master' of git://bacula.git.sourceforge.net/gitroot/bacula/bacula
[bacula/bacula] / bacula / src / cats / myingres.sc
1 EXEC SQL INCLUDE SQLCA;
2 EXEC SQL INCLUDE SQLDA;
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "myingres.h"
9
10 #define INGRES_DEBUG 0
11 #define DEBB(x) if (INGRES_DEBUG >= x) {
12 #define DEBE }
13
14 /* ---Implementations--- */
15 int INGcheck()
16 {
17     EXEC SQL BEGIN DECLARE SECTION;
18                 char errbuf[256];
19     EXEC SQL END DECLARE SECTION;
20     
21         if (sqlca.sqlcode < 0) 
22         {
23                 EXEC SQL INQUIRE_INGRES(:errbuf = ERRORTEXT);
24                 printf("Ingres-DBMS-Fehler: %s\n", errbuf);
25                 return sqlca.sqlcode;
26     } 
27         else 
28                 return 0;
29 }
30
31 short INGgetCols(const char *stmt)
32 {
33     short number = 1;
34     IISQLDA *sqlda;
35     sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
36     if (sqlda == (IISQLDA *)0)
37         { printf("Failure allocating %d SQLDA elements\n",number); }
38     sqlda->sqln = number;
39     
40     EXEC SQL BEGIN DECLARE SECTION;
41         char stmt_buffer[2000];
42     EXEC SQL END DECLARE SECTION;
43     
44     strcpy(stmt_buffer,stmt);
45     
46     EXEC SQL PREPARE s1 from :stmt_buffer;
47     EXEC SQL DESCRIBE s1 into :sqlda;
48     
49     number = sqlda->sqld;
50     free(sqlda);
51     return number;
52 }
53
54 IISQLDA *INGgetDescriptor(short numCols, const char *stmt)
55 {
56     IISQLDA *sqlda;
57     sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
58     if (sqlda == (IISQLDA *)0) 
59         { printf("Failure allocating %d SQLDA elements\n",numCols); }
60     
61     sqlda->sqln = numCols;
62     
63     EXEC SQL BEGIN DECLARE SECTION;
64         char stmt_buffer[2000];
65     EXEC SQL END DECLARE SECTION;
66
67     strcpy(stmt_buffer,stmt);
68
69     EXEC SQL PREPARE s2 INTO :sqlda FROM :stmt_buffer;
70
71     int i;
72     for (i=0;i<sqlda->sqld;++i)
73     {
74         sqlda->sqlvar[i].sqldata =
75             (char *)malloc(sqlda->sqlvar[i].sqllen);
76         if (sqlda->sqlvar[i].sqldata == (char *)0)
77             { printf("Failure allocating %d bytes for SQLVAR data\n",sqlda->sqlvar[i].sqllen); }
78
79         sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
80         if (sqlda->sqlvar[i].sqlind == (short *)0) 
81             { printf("Failure allocating sqlind\n"); }
82     }
83     
84     return sqlda;
85 }
86 void INGfreeDescriptor(IISQLDA *sqlda)
87 {
88     int i;
89     for ( i = 0 ; i < sqlda->sqld ; ++i )
90     {
91         free(sqlda->sqlvar[i].sqldata);
92         free(sqlda->sqlvar[i].sqlind);
93     }
94     free(sqlda);
95     sqlda = NULL;
96 }
97
98 int INGgetTypeSize(IISQLVAR *ingvar)
99 {
100     int inglength = 0;
101     
102         switch (ingvar->sqltype)
103     {
104                 case IISQ_DTE_TYPE:
105                 inglength = 25;
106                     break;
107                 case IISQ_MNY_TYPE:
108                     inglength = 8;
109                     break;
110                 default:
111                     inglength = ingvar->sqllen;
112     }
113     
114         return inglength;
115 }
116
117 INGresult *INGgetINGresult(IISQLDA *sqlda)
118 {
119     INGresult *result = NULL;
120     
121     result = (INGresult *)calloc(1, sizeof(INGresult));
122     if (result == (INGresult *)0) 
123         { printf("Failure allocating INGresult\n"); }
124     
125     result->sqlda       = sqlda;
126     result->num_fields  = sqlda->sqld;
127     result->num_rows    = 0;
128     result->first_row   = NULL;
129     result->status      = ING_EMPTY_RESULT;
130     result->act_row     = NULL;
131     strcpy(result->numrowstring,"");
132     
133     result->fields = (INGRES_FIELD *)calloc(1, sizeof(INGRES_FIELD) * result->num_fields);
134     if (result->fields == (INGRES_FIELD *)0)
135         { printf("Failure allocating %d INGRES_FIELD elements\n",result->num_fields); }
136
137     DEBB(2)
138         printf("INGgetINGresult, before loop over %d fields\n", result->num_fields);
139     DEBE
140
141     int i;
142     for (i=0;i<result->num_fields;++i)
143     {
144         memset(result->fields[i].name,'\0',34);
145         strncpy(result->fields[i].name,
146             sqlda->sqlvar[i].sqlname.sqlnamec,
147             sqlda->sqlvar[i].sqlname.sqlnamel);
148         result->fields[i].max_length    = INGgetTypeSize(&sqlda->sqlvar[i]);
149         result->fields[i].type          = abs(sqlda->sqlvar[i].sqltype);
150         result->fields[i].flags         = (abs(sqlda->sqlvar[i].sqltype)<0) ? 1 : 0;
151     }
152
153     return result;
154 }
155
156 void INGfreeINGresult(INGresult *ing_res)
157 {
158     /* TODO: free all rows and fields, then res, not descriptor! */
159     if( ing_res != NULL )
160     {
161         /* use of rows is a nasty workaround til I find the reason,
162            why aggregates like max() don't work
163          */
164         int rows = ing_res->num_rows;
165         ING_ROW *rowtemp;
166         ing_res->act_row = ing_res->first_row;
167         while (ing_res->act_row != NULL && rows > 0)
168         {
169             rowtemp = ing_res->act_row->next;
170             INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
171             ing_res->act_row = rowtemp;
172             --rows;
173         }
174         free(ing_res->fields);
175     }
176     free(ing_res);
177     ing_res = NULL;
178 }
179
180 ING_ROW *INGgetRowSpace(INGresult *ing_res)
181 {
182     IISQLDA *sqlda = ing_res->sqlda;
183     ING_ROW *row = NULL;
184     IISQLVAR *vars = NULL;
185     row = (ING_ROW *)calloc(1,sizeof(ING_ROW));
186     if (row == (ING_ROW *)0)
187         { printf("Failure allocating ING_ROW\n"); }
188
189     vars = (IISQLVAR *)calloc(1,sizeof(IISQLVAR) * sqlda->sqld);
190     if (vars == (IISQLVAR *)0)
191         { printf("Failure allocating %d SQLVAR elements\n",sqlda->sqld); }
192
193     row->sqlvar = vars;
194     row->next = NULL;
195
196     int i;
197     unsigned short len; /* used for VARCHAR type length */
198     for (i=0;i<sqlda->sqld;++i)
199     {
200         /* make strings out of the data, then the space and assign 
201             (why string? at least it seems that way, looking into the sources)
202          */
203         switch (abs(ing_res->fields[i].type))
204         {
205             case IISQ_VCH_TYPE:
206                 len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
207                 DEBB(2)
208                     printf("length of varchar: %d\n", len);
209                 DEBE
210                 vars[i].sqldata = (char *)malloc(len+1);
211                 if (vars[i].sqldata == (char *)0)
212                     { printf("Failure allocating %d bytes for SQLVAR data\n",len+1); }
213                 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
214                 vars[i].sqldata[len] = '\0';
215                 break;
216             case IISQ_CHA_TYPE:
217                 vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
218                 if (vars[i].sqldata == (char *)0)
219                     { printf("Failure allocating %d bytes for SQLVAR data\n",ing_res->fields[i].max_length); }
220                 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
221                 vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
222                 break;
223             case IISQ_INT_TYPE:
224                 vars[i].sqldata = (char *)malloc(20);
225                 memset(vars[i].sqldata,'\0',20);
226                 sprintf(vars[i].sqldata,"%d",*(int*)sqlda->sqlvar[i].sqldata);
227                 break;
228         }
229         vars[i].sqlind = (short *)malloc(sizeof(short));
230         if (sqlda->sqlvar[i].sqlind == (short *)0) 
231             { printf("Failure allocating sqlind\n"); }
232         memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
233         DEBB(2)
234             printf("INGgetRowSpace, Field %d, type %d, length %d, name %s\n",
235             i, sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqllen, ing_res->fields[i].name);
236         DEBE
237     }
238     
239     return row;
240 }
241
242
243 void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
244 {
245     int i;
246     if (row == NULL || sqlda == NULL)
247     {
248         printf("INGfreeRowSpace: one argument is NULL!\n");
249         return;
250     }
251
252     for ( i = 0 ; i < sqlda->sqld ; ++i )
253     {
254         free(row->sqlvar[i].sqldata);
255         free(row->sqlvar[i].sqlind);
256     }
257     free(row->sqlvar);
258     free(row);
259 }
260
261 int INGfetchAll(const char *stmt, INGresult *ing_res)
262 {
263     int linecount = 0;
264     ING_ROW *row;
265     IISQLDA *desc;
266     
267     EXEC SQL BEGIN DECLARE SECTION;
268         char    stmt_buffer[2000];
269     EXEC SQL END DECLARE SECTION;
270     
271     strcpy(stmt_buffer,stmt);
272     desc = ing_res->sqlda;
273     
274     EXEC SQL DECLARE c2 CURSOR FOR s2;
275     INGcheck();
276     
277     EXEC SQL OPEN c2;
278     INGcheck();
279         
280     /* for (linecount=0;sqlca.sqlcode==0;++linecount) */
281     while(sqlca.sqlcode==0)
282     {
283         EXEC SQL FETCH c2 USING DESCRIPTOR :desc;
284         INGcheck();
285
286         if (sqlca.sqlcode == 0)
287         {
288             row = INGgetRowSpace(ing_res); /* alloc space for fetched row */
289                 
290             /* initialize list when encountered first time */
291             if (ing_res->first_row == 0) 
292             {
293                 ing_res->first_row = row; /* head of the list */
294                 ing_res->first_row->next = NULL;
295                 ing_res->act_row = ing_res->first_row;
296             }   
297             ing_res->act_row->next = row; /* append row to old act_row */
298             ing_res->act_row = row; /* set row as act_row */
299             row->row_number = linecount;
300             ++linecount;
301                 
302             DEBB(2)
303             int i;
304             printf("Row %d ", linecount);
305             for (i=0;i<ing_res->num_fields;++i)
306                 { printf("F%d:%s ",i,row->sqlvar[i].sqldata); }
307             printf("\n");
308             DEBE
309         
310         }
311     }
312     
313     EXEC SQL CLOSE c2;
314     
315     ing_res->status = ING_COMMAND_OK;
316     ing_res->num_rows = linecount;
317     return linecount;
318 }
319
320 ING_STATUS INGresultStatus(INGresult *res)
321 {
322     if (res == NULL) {return ING_NO_RESULT;}
323     return res->status;
324 }
325
326 void INGrowSeek(INGresult *res, int row_number)
327 {
328     if (res->act_row->row_number == row_number) { return; }
329     
330     /* TODO: real error handling */
331     if (row_number<0 || row_number>res->num_rows) { return;}
332
333     ING_ROW *trow = res->first_row;
334     while ( trow->row_number != row_number )
335     { trow = trow->next; }
336     res->act_row = trow;
337     /* note - can be null - if row_number not found, right? */
338 }
339
340 char *INGgetvalue(INGresult *res, int row_number, int column_number)
341 {
342     if (row_number != res->act_row->row_number)
343         { INGrowSeek(res, row_number); }
344     return res->act_row->sqlvar[column_number].sqldata;
345 }
346
347 int INGgetisnull(INGresult *res, int row_number, int column_number)
348 {
349     if (row_number != res->act_row->row_number)
350         { INGrowSeek(res, row_number); }
351     return (short)*res->act_row->sqlvar[column_number].sqlind;
352 }
353
354 int INGntuples(const INGresult *res)
355 {
356     return res->num_rows;
357 }
358
359 int INGnfields(const INGresult *res)
360 {
361     return res->num_fields;
362 }
363
364 char *INGfname(const INGresult *res, int column_number)
365 {
366     if ( (column_number > res->num_fields) || (column_number < 0) )
367         { return NULL; }
368     else
369         { return res->fields[column_number].name; }
370 }
371
372 short INGftype(const INGresult *res, int column_number)
373 {
374     return res->fields[column_number].type;
375 }
376
377 INGresult *INGexec(INGconn *conn, const char *query)
378 {
379     /* TODO: error handling -> res->status? */
380     IISQLDA *desc = NULL;
381     INGresult *res = NULL;
382     int cols = -1;
383
384     EXEC SQL BEGIN DECLARE SECTION;
385         char stmt[2000];
386     EXEC SQL END DECLARE SECTION;
387     strncpy(stmt,query,strlen(query));
388     stmt[strlen(query)]='\0';
389
390     DEBB(1)
391         printf("INGexec: query is >>%s<<\n",stmt);
392     DEBE
393
394     if ((cols = INGgetCols(query)) == 0)
395     {
396         DEBB(1)
397             printf("INGexec: non-select\n");
398         DEBE
399         /* non-select statement - TODO: EXECUTE IMMEDIATE */
400         EXEC SQL EXECUTE IMMEDIATE :stmt;
401     }
402     else
403     {
404         DEBB(1)
405             printf("INGexec: select\n");
406         DEBE
407         /* select statement */
408         desc = INGgetDescriptor(cols, query);
409         res = INGgetINGresult(desc);
410         INGfetchAll(query, res);
411     }
412     return res;
413 }
414
415 void INGclear(INGresult *res)
416 {
417     if (res == NULL) { return; }
418     IISQLDA *desc = res->sqlda;
419     INGfreeINGresult(res);
420     INGfreeDescriptor(desc);
421 }
422
423 INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
424 {
425     if (dbname == NULL || strlen(dbname) == 0)
426         { return NULL; }
427
428     INGconn *dbconn = (INGconn *)calloc(1,sizeof(INGconn));
429     if (dbconn == (INGconn *)0)
430         { printf("Failure allocating INGconn\n"); }
431
432     EXEC SQL BEGIN DECLARE SECTION;
433         char    ingdbname[24];
434         char    ingdbuser[32];
435         char    ingdbpasw[32];
436         char    conn_name[32];
437         int     sess_id;
438     EXEC SQL END DECLARE SECTION;
439
440     strcpy(ingdbname,dbname);
441     
442     if ( user != NULL)
443     {
444         DEBB(1)
445             printf("Connection: with user/passwd\n");
446         DEBE
447         strcpy(ingdbuser,user);
448         if ( passwd != NULL)
449             { strcpy(ingdbpasw,passwd); }
450         else
451             { strcpy(ingdbpasw, ""); }
452         EXEC SQL CONNECT
453             :ingdbname
454             identified by :ingdbuser
455             dbms_password = :ingdbpasw;
456     }
457     else
458     {
459         DEBB(1)
460             printf("Connection: w/ user/passwd\n");
461         DEBE
462         EXEC SQL CONNECT :ingdbname;
463     }   
464    
465     EXEC SQL INQUIRE_SQL(:conn_name = connection_name);
466     EXEC SQL INQUIRE_SQL(:sess_id = session);
467     
468     strcpy(dbconn->dbname,ingdbname);
469     strcpy(dbconn->user,ingdbuser);
470     strcpy(dbconn->password,ingdbpasw);
471     strcpy(dbconn->connection_name,conn_name);
472     dbconn->session_id = sess_id;
473
474     DEBB(1)
475         printf("Connected to '%s' with user/passwd %s/%s, sessID/name %i/%s\n",
476             dbconn->dbname,
477             dbconn->user,
478             dbconn->password,
479             dbconn->session_id,
480             dbconn->connection_name
481         );
482     DEBE
483
484     return dbconn;
485 }
486
487 void INGdisconnectDB(INGconn *dbconn)
488 {
489     /* TODO: use of dbconn */
490     EXEC SQL DISCONNECT;
491     free(dbconn);
492 }
493
494 char *INGerrorMessage(const INGconn *conn)
495 {
496     return NULL;
497 }
498
499 char    *INGcmdTuples(INGresult *res)
500 {
501     return res->numrowstring;
502 }
503
504
505 /*      TODO?
506 char *INGerrorMessage(const INGconn *conn);
507 int INGputCopyEnd(INGconn *conn, const char *errormsg);
508 int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);
509 */