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