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
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
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.
24 * Bacula Catalog Database routines specific to Ingres
25 * These are Ingres specific routines
27 * Stefan Reddig, June 2009
29 /* The following is necessary so that we do not include
30 * the dummy external definition of DB.
32 #define __SQL_C /* indicate that this is sql.c */
35 /* # line 43 "myingres.sc" */
40 extern IISQLCA sqlca; /* SQL Communications Area */
47 * ---Implementations---
51 return (sqlca.sqlcode < 0) ? sqlca.sqlcode : 0;
53 short INGgetCols(B_DB *mdb, const char *query)
55 bool stmt_free = false;
56 /* # line 64 "myingres.sc" */
59 /* # line 66 "myingres.sc" */
63 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
64 memset(sqlda, 0, (IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE)));
67 * See if we need to run this through the limit_filter.
69 if (strstr(query, "LIMIT") != NULL) {
70 stmt = mdb->limit_filter->replace(query);
72 stmt = bstrdup(query);
75 /* # line 86 "myingres.sc" */ /* prepare */
78 IIsqPrepare(0,(char *)"s1",(char *)0,0,stmt);
80 /* # line 87 "myingres.sc" */ /* host code */
85 /* # line 92 "myingres.sc" */ /* describe */
88 IIsqDescribe(0,(char *)"s1",sqlda,0);
90 /* # line 93 "myingres.sc" */ /* host code */
103 static inline IISQLDA *INGgetDescriptor(B_DB *mdb, short numCols, const char *query)
105 bool stmt_free = false;
106 /* # line 111 "myingres.sc" */
109 /* # line 113 "myingres.sc" */
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;
117 * See if we need to run this through the limit_filter.
119 if (strstr(query, "LIMIT") != NULL) {
120 stmt = mdb->limit_filter->replace(query);
122 stmt = bstrdup(query);
125 /* # line 133 "myingres.sc" */ /* prepare */
128 IIsqPrepare(0,(char *)"s2",sqlda,0,stmt);
130 /* # line 135 "myingres.sc" */ /* host code */
134 for (i = 0; i < sqlda->sqld; ++i) {
136 * Negative type indicates nullable coulumns, so an indicator
137 * is allocated, otherwise it's null
139 if (sqlda->sqlvar[i].sqltype > 0) {
140 sqlda->sqlvar[i].sqlind = NULL;
142 sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
145 * Alloc space for variable like indicated in sqllen
146 * for date types sqllen is always 0 -> allocate by type
148 switch (abs(sqlda->sqlvar[i].sqltype)) {
150 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSW_LEN);
153 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSWO_LEN);
155 case IISQ_TSTMP_TYPE:
156 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN);
160 * plus one to avoid zero mem allocs
162 sqlda->sqlvar[i].sqldata = (char *)malloc(sqlda->sqlvar[i].sqllen+1);
168 static void INGfreeDescriptor(IISQLDA *sqlda)
174 for (i = 0; i < sqlda->sqld; ++i) {
175 if (sqlda->sqlvar[i].sqldata) {
176 free(sqlda->sqlvar[i].sqldata);
178 if (sqlda->sqlvar[i].sqlind) {
179 free(sqlda->sqlvar[i].sqlind);
185 static inline int INGgetTypeSize(IISQLVAR *ingvar)
189 * TODO: add date types (at least TSTMP,TSW TSWO)
191 switch (ingvar->sqltype) {
199 inglength = ingvar->sqllen;
204 static inline INGresult *INGgetINGresult(IISQLDA *sqlda)
207 INGresult *result = NULL;
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;
233 static inline void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
236 if (row == NULL || sqlda == NULL) {
239 for (i = 0; i < sqlda->sqld; ++i) {
240 if (row->sqlvar[i].sqldata) {
241 free(row->sqlvar[i].sqldata);
243 if (row->sqlvar[i].sqlind) {
244 free(row->sqlvar[i].sqlind);
250 static void INGfreeINGresult(INGresult *ing_res)
258 * Free all rows and fields, then res, not descriptor!
260 * Use of rows is a nasty workaround til I find the reason,
261 * why aggregates like max() don't work
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;
271 if (ing_res->fields) {
272 free(ing_res->fields);
276 static inline ING_ROW *INGgetRowSpace(INGresult *ing_res)
279 unsigned short len; /* used for VARCHAR type length */
280 IISQLDA *sqlda = ing_res->sqlda;
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);
289 for (i = 0; i < sqlda->sqld; ++i) {
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)
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));
298 *vars[i].sqlind = NULL;
301 * if sqlind pointer exists AND points to -1 -> column is 'null'
303 if ( *vars[i].sqlind && (*vars[i].sqlind == -1)) {
304 vars[i].sqldata = NULL;
306 switch (ing_res->fields[i].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';
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';
319 vars[i].sqldata = (char *)malloc(20);
320 memset(vars[i].sqldata, 0, 20);
321 switch (sqlda->sqlvar[i].sqllen) {
323 bsnprintf(vars[i].sqldata, 20, "%d",*(short*)sqlda->sqlvar[i].sqldata);
326 bsnprintf(vars[i].sqldata, 20, "%ld",*(int*)sqlda->sqlvar[i].sqldata);
329 bsnprintf(vars[i].sqldata, 20, "%lld",*(long*)sqlda->sqlvar[i].sqldata);
333 case IISQ_TSTMP_TYPE:
334 vars[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN+1);
335 vars[i].sqldata[IISQ_TSTMP_LEN] = '\0';
338 vars[i].sqldata = (char *)malloc(IISQ_TSWO_LEN+1);
339 vars[i].sqldata[IISQ_TSWO_LEN] = '\0';
342 vars[i].sqldata = (char *)malloc(IISQ_TSW_LEN+1);
343 vars[i].sqldata[IISQ_TSW_LEN] = '\0';
350 static inline int INGfetchAll(const char *query, INGresult *ing_res)
356 desc = ing_res->sqlda;
357 /* # line 392 "myingres.sc" */ /* host code */
358 if ((check = INGcheck()) < 0) {
361 /* # line 396 "myingres.sc" */ /* open */
364 IIcsOpen((char *)"c2",4150,23546);
365 IIwritio(0,(short *)0,1,32,0,(char *)"s2");
366 IIcsQuery((char *)"c2",4150,23546);
368 /* # line 397 "myingres.sc" */ /* host code */
369 if ((check = INGcheck()) < 0) {
372 /* for (linecount = 0; sqlca.sqlcode == 0; ++linecount) */
374 /* # line 403 "myingres.sc" */ /* fetch */
377 if (IIcsRetScroll((char *)"c2",4150,23546,-1,-1) != 0) {
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 */
386 * Initialize list when encountered first time
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;
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;
398 } while ( (sqlca.sqlcode == 0) || (sqlca.sqlcode == -40202) );
399 /* # line 423 "myingres.sc" */ /* close */
402 IIcsClose((char *)"c2",4150,23546);
404 /* # line 425 "myingres.sc" */ /* host code */
405 ing_res->status = ING_COMMAND_OK;
406 ing_res->num_rows = linecount;
409 static inline ING_STATUS INGresultStatus(INGresult *res)
412 return ING_NO_RESULT;
417 static void INGrowSeek(INGresult *res, int row_number)
419 ING_ROW *trow = NULL;
420 if (res->act_row->row_number == row_number) {
424 * TODO: real error handling
426 if (row_number<0 || row_number>res->num_rows) {
429 for (trow = res->first_row; trow->row_number != row_number; trow = trow->next) ;
432 * Note - can be null - if row_number not found, right?
435 char *INGgetvalue(INGresult *res, int row_number, int column_number)
437 if (row_number != res->act_row->row_number) {
438 INGrowSeek(res, row_number);
440 return res->act_row->sqlvar[column_number].sqldata;
442 bool INGgetisnull(INGresult *res, int row_number, int column_number)
444 if (row_number != res->act_row->row_number) {
445 INGrowSeek(res, row_number);
447 return (*res->act_row->sqlvar[column_number].sqlind == -1) ? true : false;
449 int INGntuples(const INGresult *res)
451 return res->num_rows;
453 int INGnfields(const INGresult *res)
455 return res->num_fields;
457 char *INGfname(const INGresult *res, int column_number)
459 if ((column_number > res->num_fields) || (column_number < 0)) {
462 return res->fields[column_number].name;
465 short INGftype(const INGresult *res, int column_number)
467 return res->fields[column_number].type;
469 int INGexec(B_DB *mdb, INGconn *conn, const char *query)
471 bool stmt_free = false;
473 /* # line 507 "myingres.sc" */
477 /* # line 510 "myingres.sc" */
480 * See if we need to run this through the limit_filter.
482 if (strstr(query, "LIMIT") != NULL) {
483 stmt = mdb->limit_filter->replace(query);
485 stmt = bstrdup(query);
489 /* # line 523 "myingres.sc" */ /* execute */
493 IIsyncup((char *)0,0);
495 /* # line 525 "myingres.sc" */ /* host code */
499 if ((check = INGcheck()) < 0) {
502 /* # line 533 "myingres.sc" */ /* inquire_ingres */
504 IILQisInqSqlio((short *)0,1,30,sizeof(rowcount),&rowcount,8);
506 /* # line 534 "myingres.sc" */ /* host code */
507 if ((check = INGcheck()) < 0) {
512 INGresult *INGquery(B_DB *mdb, INGconn *conn, const char *query)
515 * TODO: error handling
517 IISQLDA *desc = NULL;
518 INGresult *res = NULL;
520 int cols = INGgetCols(mdb, query);
521 desc = INGgetDescriptor(mdb, cols, query);
526 res = INGgetINGresult(desc);
531 rows = INGfetchAll(query, res);
534 INGfreeDescriptor(desc);
535 INGfreeINGresult(res);
541 void INGclear(INGresult *res)
546 INGfreeDescriptor(res->sqlda);
547 INGfreeINGresult(res);
549 INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
552 if (dbname == NULL || strlen(dbname) == 0) {
555 dbconn = (INGconn *)malloc(sizeof(INGconn));
556 memset(dbconn, 0, sizeof(INGconn));
557 /* # line 590 "myingres.sc" */
564 /* # line 596 "myingres.sc" */
566 bstrncpy(ingdbname, dbname, sizeof(ingdbname));
568 bstrncpy(ingdbuser, user, sizeof(ingdbuser));
569 if (passwd != NULL) {
570 bstrncpy(ingdbpasw, passwd, sizeof(ingdbpasw));
572 memset(ingdbpasw, 0, sizeof(ingdbpasw));
574 /* # line 607 "myingres.sc" */ /* connect */
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);
582 /* # line 611 "myingres.sc" */ /* host code */
584 /* # line 612 "myingres.sc" */ /* connect */
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);
591 /* # line 613 "myingres.sc" */ /* host code */
593 /* # line 615 "myingres.sc" */ /* inquire_sql */
595 IILQisInqSqlio((short *)0,1,32,31,conn_name,13);
597 /* # line 616 "myingres.sc" */ /* inquire_sql */
599 IILQisInqSqlio((short *)0,1,30,sizeof(sess_id),&sess_id,11);
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);
611 void INGdisconnectDB(INGconn *dbconn)
614 * TODO: check for any real use of dbconn: maybe whenn multithreaded?
616 /* # line 634 "myingres.sc" */ /* disconnect */
621 /* # line 635 "myingres.sc" */ /* host code */
622 if (dbconn != NULL) {
627 char *INGerrorMessage(const INGconn *conn)
629 /* # line 643 "myingres.sc" */
632 /* # line 645 "myingres.sc" */
634 /* # line 647 "myingres.sc" */ /* inquire_ingres */
636 IILQisInqSqlio((short *)0,1,32,255,errbuf,63);
638 /* # line 648 "myingres.sc" */ /* host code */
639 memcpy(conn->msg, &errbuf, 256);
642 char *INGcmdTuples(INGresult *res)
644 return res->numrowstring;
647 int INGputCopyEnd(INGconn *conn, const char *errormsg);
648 int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);
650 /* # line 662 "myingres.sc" */