]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/myingres.c
As we have a multithreaded application let tell that to esqlcc so it can optimize...
[bacula/bacula] / bacula / src / cats / myingres.c
1 /*
2    Bacula® - The Network Backup Solution
3    Copyright (C) 2009-2010 Free Software Foundation Europe e.V.
4    The main author of Bacula is Kern Sibbald, with contributions from
5    many others, a complete list can be found in the file AUTHORS.
6    This program is Free Software; you can redistribute it and/or
7    modify it under the terms of version two of the GNU General Public
8    License as published by the Free Software Foundation and included
9    in the file LICENSE.
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    General Public License for more details.
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA.
18    Bacula® is a registered trademark of Kern Sibbald.
19    The licensor of Bacula is the Free Software Foundation Europe
20    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
21    Switzerland, email:ftf@fsfeurope.org.
22 */
23 /*
24  * Bacula Catalog Database routines specific to Ingres
25  *   These are Ingres specific routines
26  *
27  *    Stefan Reddig, June 2009
28  */
29 #include "bacula.h"
30 /* # line 37 "myingres.sc" */   
31 #ifdef HAVE_INGRES
32 #include <eqpname.h>
33 #include <eqdefcc.h>
34 #include <eqsqlca.h>
35 IISQLCA *IIsqlca();
36 #define sqlca (*(IIsqlca()))
37 #include <eqsqlda.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include "myingres.h"
42 /*
43  * ---Implementations---
44  */
45 int INGcheck()
46 {
47    return (sqlca.sqlcode < 0) ? sqlca.sqlcode : 0;
48 }
49 short INGgetCols(const char *query)
50 {
51 /* # line 57 "myingres.sc" */   
52   
53   char *stmt;
54 /* # line 59 "myingres.sc" */   
55   
56    short number = 1;
57    IISQLDA *sqlda;
58    sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
59    memset(sqlda, 0, (IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE)));
60    sqlda->sqln = number;
61    stmt = bstrdup(query);
62 /* # line 71 "myingres.sc" */   /* prepare */
63   {
64     IIsqInit(&sqlca);
65     IIsqPrepare(0,(char *)"s1",(char *)0,0,stmt);
66   }
67 /* # line 72 "myingres.sc" */   /* host code */
68    if (INGcheck() < 0) {
69       number = -1;
70       goto bail_out;
71    }
72 /* # line 77 "myingres.sc" */   /* describe */
73   {
74     IIsqInit(&sqlca);
75     IIsqDescribe(0,(char *)"s1",sqlda,0);
76   }
77 /* # line 78 "myingres.sc" */   /* host code */
78    if (INGcheck() < 0) {
79       number = -1;
80       goto bail_out;
81    }
82    number = sqlda->sqld;
83 bail_out:
84    free(stmt);
85    free(sqlda);
86    return number;
87 }
88 static inline IISQLDA *INGgetDescriptor(short numCols, const char *query)
89 {
90 /* # line 93 "myingres.sc" */   
91   
92   char *stmt;
93 /* # line 95 "myingres.sc" */   
94   
95    int i;
96    IISQLDA *sqlda;
97    sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
98    memset(sqlda, 0, (IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE)));
99    sqlda->sqln = numCols;
100    stmt = bstrdup(query);
101 /* # line 107 "myingres.sc" */  /* prepare */
102   {
103     IIsqInit(&sqlca);
104     IIsqPrepare(0,(char *)"s2",sqlda,0,stmt);
105   }
106 /* # line 109 "myingres.sc" */  /* host code */
107    free(stmt);
108    for (i = 0; i < sqlda->sqld; ++i) {
109       /*
110        * Negative type indicates nullable coulumns, so an indicator
111        * is allocated, otherwise it's null
112        */
113       if (sqlda->sqlvar[i].sqltype > 0) {
114          sqlda->sqlvar[i].sqlind = NULL;
115       } else {
116          sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
117       }
118       /*
119        * Alloc space for variable like indicated in sqllen
120        * for date types sqllen is always 0 -> allocate by type
121        */
122       switch (abs(sqlda->sqlvar[i].sqltype)) {
123       case IISQ_TSW_TYPE:
124          sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSW_LEN);
125          break;
126       case IISQ_TSWO_TYPE:
127          sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSWO_LEN);
128          break;
129       case IISQ_TSTMP_TYPE:
130          sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN);
131          break;
132       default:
133          /*
134           * plus one to avoid zero mem allocs
135           */
136          sqlda->sqlvar[i].sqldata = (char *)malloc(sqlda->sqlvar[i].sqllen+1);
137          break;
138       }
139    }
140    return sqlda;
141 }
142 static void INGfreeDescriptor(IISQLDA *sqlda)
143 {
144    int i;
145    if (!sqlda) {
146       return;
147    }
148    for (i = 0; i < sqlda->sqld; ++i) {
149       if (sqlda->sqlvar[i].sqldata) {
150          free(sqlda->sqlvar[i].sqldata);
151       }
152       if (sqlda->sqlvar[i].sqlind) {
153          free(sqlda->sqlvar[i].sqlind);
154       }
155    }
156    free(sqlda);
157    sqlda = NULL;
158 }
159 static inline int INGgetTypeSize(IISQLVAR *ingvar)
160 {
161    int inglength = 0;
162    /*
163     * TODO: add date types (at least TSTMP,TSW TSWO)
164     */
165    switch (ingvar->sqltype) {
166    case IISQ_DTE_TYPE:
167       inglength = 25;
168       break;
169    case IISQ_MNY_TYPE:
170       inglength = 8;
171       break;
172    default:
173       inglength = ingvar->sqllen;
174       break;
175    }
176    return inglength;
177 }
178 static inline INGresult *INGgetINGresult(IISQLDA *sqlda)
179 {
180    int i;
181    INGresult *result = NULL;
182    if (!sqlda) {
183       return NULL;
184    }
185    result = (INGresult *)malloc(sizeof(INGresult));
186    memset(result, 0, sizeof(INGresult));
187    result->sqlda = sqlda;
188    result->num_fields = sqlda->sqld;
189    result->num_rows = 0;
190    result->first_row = NULL;
191    result->status = ING_EMPTY_RESULT;
192    result->act_row = NULL;
193    memset(result->numrowstring, 0, sizeof(result->numrowstring));
194    if (result->num_fields) {
195       result->fields = (INGRES_FIELD *)malloc(sizeof(INGRES_FIELD) * result->num_fields);
196       memset(result->fields, 0, sizeof(INGRES_FIELD) * result->num_fields);
197       for (i = 0; i < result->num_fields; ++i) {
198          memset(result->fields[i].name, 0, 34);
199          bstrncpy(result->fields[i].name, sqlda->sqlvar[i].sqlname.sqlnamec, sqlda->sqlvar[i].sqlname.sqlnamel);
200          result->fields[i].max_length = INGgetTypeSize(&sqlda->sqlvar[i]);
201          result->fields[i].type = abs(sqlda->sqlvar[i].sqltype);
202          result->fields[i].flags = (sqlda->sqlvar[i].sqltype < 0) ? 1 : 0;
203       }
204    }
205    return result;
206 }
207 static inline void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
208 {
209    int i;
210    if (row == NULL || sqlda == NULL) {
211       return;
212    }
213    for (i = 0; i < sqlda->sqld; ++i) {
214       if (row->sqlvar[i].sqldata) {
215          free(row->sqlvar[i].sqldata);
216       }
217       if (row->sqlvar[i].sqlind) {
218          free(row->sqlvar[i].sqlind);
219       }
220    }
221    free(row->sqlvar);
222    free(row);
223 }
224 static void INGfreeINGresult(INGresult *ing_res)
225 {
226    int rows;
227    ING_ROW *rowtemp;
228    if (!ing_res) {
229       return;
230    }
231    /*
232     * Free all rows and fields, then res, not descriptor!
233     *
234     * Use of rows is a nasty workaround til I find the reason,
235     * why aggregates like max() don't work
236     */
237    rows = ing_res->num_rows;
238    ing_res->act_row = ing_res->first_row;
239    while (ing_res->act_row != NULL && rows > 0) {
240       rowtemp = ing_res->act_row->next;
241       INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
242       ing_res->act_row = rowtemp;
243       --rows;
244    }
245    if (ing_res->fields) {
246       free(ing_res->fields);
247    }
248    free(ing_res);
249 }
250 static inline ING_ROW *INGgetRowSpace(INGresult *ing_res)
251 {
252    int i;
253    unsigned short len; /* used for VARCHAR type length */
254    IISQLDA *sqlda = ing_res->sqlda;
255    ING_ROW *row = NULL;
256    IISQLVAR *vars = NULL;
257    row = (ING_ROW *)malloc(sizeof(ING_ROW));
258    memset(row, 0, sizeof(ING_ROW));
259    vars = (IISQLVAR *)malloc(sizeof(IISQLVAR) * sqlda->sqld);
260    memset(vars, 0, sizeof(IISQLVAR) * sqlda->sqld);
261    row->sqlvar = vars;
262    row->next = NULL;
263    for (i = 0; i < sqlda->sqld; ++i) {
264       /*
265        * Make strings out of the data, then the space and assign 
266        * (why string? at least it seems that way, looking into the sources)
267        */
268       vars[i].sqlind = (short *)malloc(sizeof(short));
269       if (sqlda->sqlvar[i].sqlind) {
270          memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
271       } else {
272          *vars[i].sqlind = NULL;
273       }
274       /*
275        * if sqlind pointer exists AND points to -1 -> column is 'null'
276        */
277       if ( *vars[i].sqlind && (*vars[i].sqlind == -1)) {
278          vars[i].sqldata = NULL;
279       } else {
280          switch (ing_res->fields[i].type) {
281          case IISQ_VCH_TYPE:
282             len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
283             vars[i].sqldata = (char *)malloc(len+1);
284             memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
285             vars[i].sqldata[len] = '\0';
286             break;
287          case IISQ_CHA_TYPE:
288             vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
289             memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
290             vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
291             break;
292          case IISQ_INT_TYPE:
293             vars[i].sqldata = (char *)malloc(20);
294             memset(vars[i].sqldata, 0, 20);
295             switch (sqlda->sqlvar[i].sqllen) {
296             case 2:
297                bsnprintf(vars[i].sqldata, 20, "%d",*(short*)sqlda->sqlvar[i].sqldata);
298                break;
299             case 4:
300                bsnprintf(vars[i].sqldata, 20, "%ld",*(int*)sqlda->sqlvar[i].sqldata);
301                break;
302             case 8:
303                bsnprintf(vars[i].sqldata, 20, "%lld",*(long*)sqlda->sqlvar[i].sqldata);
304                break;
305             }
306             break;
307          case IISQ_TSTMP_TYPE:
308             vars[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN+1);
309             vars[i].sqldata[IISQ_TSTMP_LEN] = '\0';
310             break;
311          case IISQ_TSWO_TYPE:
312             vars[i].sqldata = (char *)malloc(IISQ_TSWO_LEN+1);
313             vars[i].sqldata[IISQ_TSWO_LEN] = '\0';
314             break;
315          case IISQ_TSW_TYPE:
316             vars[i].sqldata = (char *)malloc(IISQ_TSW_LEN+1);
317             vars[i].sqldata[IISQ_TSW_LEN] = '\0';
318             break;
319          }
320       }
321    }
322    return row;
323 }
324 static inline int INGfetchAll(const char *query, INGresult *ing_res)
325 {
326    int linecount = 0;
327    ING_ROW *row;
328    IISQLDA *desc;
329    int check = -1;
330    desc = ing_res->sqlda;
331 /* # line 363 "myingres.sc" */  /* host code */
332    if ((check = INGcheck()) < 0) {
333       return check;
334    }
335 /* # line 367 "myingres.sc" */  /* open */
336   {
337     IIsqInit(&sqlca);
338     IIcsOpen((char *)"c2",19318,7414);
339     IIwritio(0,(short *)0,1,32,0,(char *)"s2");
340     IIcsQuery((char *)"c2",19318,7414);
341   }
342 /* # line 368 "myingres.sc" */  /* host code */
343    if ((check = INGcheck()) < 0) {
344       return check;
345    }
346    /* for (linecount = 0; sqlca.sqlcode == 0; ++linecount) */
347    do {
348 /* # line 374 "myingres.sc" */  /* fetch */
349   {
350     IIsqInit(&sqlca);
351     if (IIcsRetScroll((char *)"c2",19318,7414,-1,-1) != 0) {
352       IIcsDaGet(0,desc);
353       IIcsERetrieve();
354     } /* IIcsRetrieve */
355   }
356 /* # line 376 "myingres.sc" */  /* host code */
357       if ( (sqlca.sqlcode == 0) || (sqlca.sqlcode == -40202) ) {
358          row = INGgetRowSpace(ing_res); /* alloc space for fetched row */
359          /*
360           * Initialize list when encountered first time
361           */
362          if (ing_res->first_row == 0) {
363             ing_res->first_row = row; /* head of the list */
364             ing_res->first_row->next = NULL;
365             ing_res->act_row = ing_res->first_row;
366          }      
367          ing_res->act_row->next = row; /* append row to old act_row */
368          ing_res->act_row = row; /* set row as act_row */
369          row->row_number = linecount;
370          ++linecount;
371       }
372    } while ( (sqlca.sqlcode == 0) || (sqlca.sqlcode == -40202) );
373 /* # line 394 "myingres.sc" */  /* close */
374   {
375     IIsqInit(&sqlca);
376     IIcsClose((char *)"c2",19318,7414);
377   }
378 /* # line 396 "myingres.sc" */  /* host code */
379    ing_res->status = ING_COMMAND_OK;
380    ing_res->num_rows = linecount;
381    return linecount;
382 }
383 static inline ING_STATUS INGresultStatus(INGresult *res)
384 {
385    if (res == NULL) {
386       return ING_NO_RESULT;
387    } else {
388       return res->status;
389    }
390 }
391 static void INGrowSeek(INGresult *res, int row_number)
392 {
393    ING_ROW *trow = NULL;
394    if (res->act_row->row_number == row_number) {
395       return;
396    }
397    /*
398     * TODO: real error handling
399     */
400    if (row_number<0 || row_number>res->num_rows) {
401       return;
402    }
403    for (trow = res->first_row; trow->row_number != row_number; trow = trow->next) ;
404    res->act_row = trow;
405    /*
406     * Note - can be null - if row_number not found, right?
407     */
408 }
409 char *INGgetvalue(INGresult *res, int row_number, int column_number)
410 {
411    if (row_number != res->act_row->row_number) {
412       INGrowSeek(res, row_number);
413    }
414    return res->act_row->sqlvar[column_number].sqldata;
415 }
416 bool INGgetisnull(INGresult *res, int row_number, int column_number)
417 {
418    if (row_number != res->act_row->row_number) {
419       INGrowSeek(res, row_number);
420    }
421    return (*res->act_row->sqlvar[column_number].sqlind == -1) ? true : false;
422 }
423 int INGntuples(const INGresult *res)
424 {
425    return res->num_rows;
426 }
427 int INGnfields(const INGresult *res)
428 {
429    return res->num_fields;
430 }
431 char *INGfname(const INGresult *res, int column_number)
432 {
433    if ((column_number > res->num_fields) || (column_number < 0)) {
434       return NULL;
435    } else {
436       return res->fields[column_number].name;
437    }
438 }
439 short INGftype(const INGresult *res, int column_number)
440 {
441    return res->fields[column_number].type;
442 }
443 int INGexec(INGconn *conn, const char *query)
444 {
445    int check;
446 /* # line 477 "myingres.sc" */  
447   
448   int rowcount;
449   char *stmt;
450 /* # line 480 "myingres.sc" */  
451   
452    stmt = bstrdup(query);
453    rowcount = -1;
454 /* # line 485 "myingres.sc" */  /* execute */
455   {
456     IIsqInit(&sqlca);
457     IIsqExImmed(stmt);
458     IIsyncup((char *)0,0);
459   }
460 /* # line 487 "myingres.sc" */  /* host code */
461    free(stmt);
462    if ((check = INGcheck()) < 0) {
463       return check;
464    }
465 /* # line 493 "myingres.sc" */  /* inquire_ingres */
466   {
467     IILQisInqSqlio((short *)0,1,30,sizeof(rowcount),&rowcount,8);
468   }
469 /* # line 494 "myingres.sc" */  /* host code */
470    if ((check = INGcheck()) < 0) {
471       return check;
472    }
473    return rowcount;
474 }
475 INGresult *INGquery(INGconn *conn, const char *query)
476 {
477    /*
478     * TODO: error handling
479     */
480    IISQLDA *desc = NULL;
481    INGresult *res = NULL;
482    int rows = -1;
483    int cols = INGgetCols(query);
484    desc = INGgetDescriptor(cols, query);
485    if (!desc) {
486       return NULL;
487    }
488    res = INGgetINGresult(desc);
489    if (!res) {
490       return NULL;
491    }
492    rows = INGfetchAll(query, res);
493    if (rows < 0) {
494      INGfreeDescriptor(desc);
495      INGfreeINGresult(res);
496      return NULL;
497    }
498    return res;
499 }
500 void INGclear(INGresult *res)
501 {
502    if (res == NULL) {
503       return;
504    }
505    INGfreeDescriptor(res->sqlda);
506    INGfreeINGresult(res);
507 }
508 INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
509 {
510    INGconn *dbconn;
511    if (dbname == NULL || strlen(dbname) == 0) {
512       return NULL;
513    }
514    dbconn = (INGconn *)malloc(sizeof(INGconn));
515    memset(dbconn, 0, sizeof(INGconn));
516 /* # line 553 "myingres.sc" */  
517   
518   char ingdbname[24];
519   char ingdbuser[32];
520   char ingdbpasw[32];
521   char conn_name[32];
522   int sess_id;
523 /* # line 559 "myingres.sc" */  
524   
525    bstrncpy(ingdbname, dbname, sizeof(ingdbname));
526    if (user != NULL) {
527       bstrncpy(ingdbuser, user, sizeof(ingdbuser));
528       if (passwd != NULL) {
529          bstrncpy(ingdbpasw, passwd, sizeof(ingdbpasw));
530       } else {
531          memset(ingdbpasw, 0, sizeof(ingdbpasw));
532       }
533 /* # line 570 "myingres.sc" */  /* connect */
534   {
535     IIsqInit(&sqlca);
536     IIsqUser(ingdbuser);
537     IIsqConnect(0,ingdbname,(char *)"-dbms_password",ingdbpasw,(char *)0, 
538     (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, 
539     (char *)0, (char *)0, (char *)0, (char *)0);
540   }
541 /* # line 574 "myingres.sc" */  /* host code */
542    } else {
543 /* # line 575 "myingres.sc" */  /* connect */
544   {
545     IIsqInit(&sqlca);
546     IIsqConnect(0,ingdbname,(char *)0, (char *)0, (char *)0, (char *)0, 
547     (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, 
548     (char *)0, (char *)0, (char *)0);
549   }
550 /* # line 576 "myingres.sc" */  /* host code */
551    }   
552 /* # line 578 "myingres.sc" */  /* inquire_sql */
553   {
554     IILQisInqSqlio((short *)0,1,32,31,conn_name,13);
555   }
556 /* # line 579 "myingres.sc" */  /* inquire_sql */
557   {
558     IILQisInqSqlio((short *)0,1,30,sizeof(sess_id),&sess_id,11);
559   }
560 /* # line 581 "myingres.sc" */  /* host code */
561    bstrncpy(dbconn->dbname, ingdbname, sizeof(dbconn->dbname));
562    bstrncpy(dbconn->user, ingdbuser, sizeof(dbconn->user));
563    bstrncpy(dbconn->password, ingdbpasw, sizeof(dbconn->password));
564    bstrncpy(dbconn->connection_name, conn_name, sizeof(dbconn->connection_name));
565    dbconn->session_id = sess_id;
566    dbconn->msg = (char*)malloc(257);
567    memset(dbconn->msg, 0, 257);
568    return dbconn;
569 }
570 void INGdisconnectDB(INGconn *dbconn)
571 {
572 /* # line 594 "myingres.sc" */  
573   
574   int sess_id;
575 /* # line 596 "myingres.sc" */  
576   
577    sess_id = dbconn->session_id;
578 /* # line 600 "myingres.sc" */  /* disconnect */
579   {
580     IIsqInit(&sqlca);
581     IILQsidSessID(sess_id);
582     IIsqDisconnect();
583   }
584 /* # line 602 "myingres.sc" */  /* host code */
585    if (dbconn != NULL) {
586       free(dbconn->msg);
587       free(dbconn);
588    }
589 }
590 char *INGerrorMessage(const INGconn *conn)
591 {
592 /* # line 610 "myingres.sc" */  
593   
594   char errbuf[256];
595 /* # line 612 "myingres.sc" */  
596   
597 /* # line 614 "myingres.sc" */  /* inquire_ingres */
598   {
599     IILQisInqSqlio((short *)0,1,32,255,errbuf,63);
600   }
601 /* # line 615 "myingres.sc" */  /* host code */
602    memcpy(conn->msg, &errbuf, 256);
603    return conn->msg;
604 }
605 char *INGcmdTuples(INGresult *res)
606 {
607    return res->numrowstring;
608 }
609 /* TODO?
610 int INGputCopyEnd(INGconn *conn, const char *errormsg);
611 int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);
612 */
613 /* # line 629 "myingres.sc" */  
614 #endif