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