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