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