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