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
30 /* # line 37 "myingres.sc" */
35 extern IISQLCA sqlca; /* SQL Communications Area */
42 * ---Implementations---
46 return (sqlca.sqlcode < 0) ? sqlca.sqlcode : 0;
48 short INGgetCols(const char *query)
50 /* # line 57 "myingres.sc" */
53 /* # line 59 "myingres.sc" */
57 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
58 memset(sqlda, 0, (IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE)));
60 stmt = bstrdup(query);
61 /* # line 71 "myingres.sc" */ /* prepare */
64 IIsqPrepare(0,(char *)"s1",(char *)0,0,stmt);
66 /* # line 72 "myingres.sc" */ /* host code */
71 /* # line 77 "myingres.sc" */ /* describe */
74 IIsqDescribe(0,(char *)"s1",sqlda,0);
76 /* # line 78 "myingres.sc" */ /* host code */
87 static inline IISQLDA *INGgetDescriptor(short numCols, const char *query)
89 /* # line 93 "myingres.sc" */
92 /* # line 95 "myingres.sc" */
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 */
103 IIsqPrepare(0,(char *)"s2",sqlda,0,stmt);
105 /* # line 109 "myingres.sc" */ /* host code */
107 for (i = 0; i < sqlda->sqld; ++i) {
109 * Negative type indicates nullable coulumns, so an indicator
110 * is allocated, otherwise it's null
112 if (sqlda->sqlvar[i].sqltype > 0) {
113 sqlda->sqlvar[i].sqlind = NULL;
115 sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
118 * Alloc space for variable like indicated in sqllen
119 * for date types sqllen is always 0 -> allocate by type
121 switch (abs(sqlda->sqlvar[i].sqltype)) {
123 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSW_LEN);
126 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSWO_LEN);
128 case IISQ_TSTMP_TYPE:
129 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN);
133 * plus one to avoid zero mem allocs
135 sqlda->sqlvar[i].sqldata = (char *)malloc(sqlda->sqlvar[i].sqllen+1);
141 static void INGfreeDescriptor(IISQLDA *sqlda)
147 for (i = 0; i < sqlda->sqld; ++i) {
148 if (sqlda->sqlvar[i].sqldata) {
149 free(sqlda->sqlvar[i].sqldata);
151 if (sqlda->sqlvar[i].sqlind) {
152 free(sqlda->sqlvar[i].sqlind);
158 static inline int INGgetTypeSize(IISQLVAR *ingvar)
162 * TODO: add date types (at least TSTMP,TSW TSWO)
164 switch (ingvar->sqltype) {
172 inglength = ingvar->sqllen;
177 static inline INGresult *INGgetINGresult(IISQLDA *sqlda)
180 INGresult *result = NULL;
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;
206 static inline void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
209 if (row == NULL || sqlda == NULL) {
212 for (i = 0; i < sqlda->sqld; ++i) {
213 if (row->sqlvar[i].sqldata) {
214 free(row->sqlvar[i].sqldata);
216 if (row->sqlvar[i].sqlind) {
217 free(row->sqlvar[i].sqlind);
223 static void INGfreeINGresult(INGresult *ing_res)
231 * Free all rows and fields, then res, not descriptor!
233 * Use of rows is a nasty workaround til I find the reason,
234 * why aggregates like max() don't work
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;
244 if (ing_res->fields) {
245 free(ing_res->fields);
249 static inline ING_ROW *INGgetRowSpace(INGresult *ing_res)
252 unsigned short len; /* used for VARCHAR type length */
253 IISQLDA *sqlda = ing_res->sqlda;
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);
262 for (i = 0; i < sqlda->sqld; ++i) {
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)
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));
271 *vars[i].sqlind = NULL;
274 * if sqlind pointer exists AND points to -1 -> column is 'null'
276 if ( *vars[i].sqlind && (*vars[i].sqlind == -1)) {
277 vars[i].sqldata = NULL;
279 switch (ing_res->fields[i].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';
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';
292 vars[i].sqldata = (char *)malloc(20);
293 memset(vars[i].sqldata, 0, 20);
294 switch (sqlda->sqlvar[i].sqllen) {
296 bsnprintf(vars[i].sqldata, 20, "%d",*(short*)sqlda->sqlvar[i].sqldata);
299 bsnprintf(vars[i].sqldata, 20, "%ld",*(int*)sqlda->sqlvar[i].sqldata);
302 bsnprintf(vars[i].sqldata, 20, "%lld",*(long*)sqlda->sqlvar[i].sqldata);
306 case IISQ_TSTMP_TYPE:
307 vars[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN+1);
308 vars[i].sqldata[IISQ_TSTMP_LEN] = '\0';
311 vars[i].sqldata = (char *)malloc(IISQ_TSWO_LEN+1);
312 vars[i].sqldata[IISQ_TSWO_LEN] = '\0';
315 vars[i].sqldata = (char *)malloc(IISQ_TSW_LEN+1);
316 vars[i].sqldata[IISQ_TSW_LEN] = '\0';
323 static inline int INGfetchAll(const char *query, INGresult *ing_res)
329 desc = ing_res->sqlda;
330 /* # line 363 "myingres.sc" */ /* host code */
331 if ((check = INGcheck()) < 0) {
334 /* # line 367 "myingres.sc" */ /* open */
337 IIcsOpen((char *)"c2",11417,2807);
338 IIwritio(0,(short *)0,1,32,0,(char *)"s2");
339 IIcsQuery((char *)"c2",11417,2807);
341 /* # line 368 "myingres.sc" */ /* host code */
342 if ((check = INGcheck()) < 0) {
345 /* for (linecount = 0; sqlca.sqlcode == 0; ++linecount) */
347 /* # line 374 "myingres.sc" */ /* fetch */
350 if (IIcsRetScroll((char *)"c2",11417,2807,-1,-1) != 0) {
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 */
359 * Initialize list when encountered first time
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;
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;
371 } while ( (sqlca.sqlcode == 0) || (sqlca.sqlcode == -40202) );
372 /* # line 394 "myingres.sc" */ /* close */
375 IIcsClose((char *)"c2",11417,2807);
377 /* # line 396 "myingres.sc" */ /* host code */
378 ing_res->status = ING_COMMAND_OK;
379 ing_res->num_rows = linecount;
382 static inline ING_STATUS INGresultStatus(INGresult *res)
385 return ING_NO_RESULT;
390 static void INGrowSeek(INGresult *res, int row_number)
392 ING_ROW *trow = NULL;
393 if (res->act_row->row_number == row_number) {
397 * TODO: real error handling
399 if (row_number<0 || row_number>res->num_rows) {
402 for (trow = res->first_row; trow->row_number != row_number; trow = trow->next) ;
405 * Note - can be null - if row_number not found, right?
408 char *INGgetvalue(INGresult *res, int row_number, int column_number)
410 if (row_number != res->act_row->row_number) {
411 INGrowSeek(res, row_number);
413 return res->act_row->sqlvar[column_number].sqldata;
415 bool INGgetisnull(INGresult *res, int row_number, int column_number)
417 if (row_number != res->act_row->row_number) {
418 INGrowSeek(res, row_number);
420 return (*res->act_row->sqlvar[column_number].sqlind == -1) ? true : false;
422 int INGntuples(const INGresult *res)
424 return res->num_rows;
426 int INGnfields(const INGresult *res)
428 return res->num_fields;
430 char *INGfname(const INGresult *res, int column_number)
432 if ((column_number > res->num_fields) || (column_number < 0)) {
435 return res->fields[column_number].name;
438 short INGftype(const INGresult *res, int column_number)
440 return res->fields[column_number].type;
442 int INGexec(INGconn *conn, const char *query)
445 /* # line 477 "myingres.sc" */
449 /* # line 480 "myingres.sc" */
451 stmt = bstrdup(query);
453 /* # line 485 "myingres.sc" */ /* execute */
457 IIsyncup((char *)0,0);
459 /* # line 487 "myingres.sc" */ /* host code */
461 if ((check = INGcheck()) < 0) {
464 /* # line 493 "myingres.sc" */ /* inquire_ingres */
466 IILQisInqSqlio((short *)0,1,30,sizeof(rowcount),&rowcount,8);
468 /* # line 494 "myingres.sc" */ /* host code */
469 if ((check = INGcheck()) < 0) {
474 INGresult *INGquery(INGconn *conn, const char *query)
477 * TODO: error handling
479 IISQLDA *desc = NULL;
480 INGresult *res = NULL;
482 int cols = INGgetCols(query);
483 desc = INGgetDescriptor(cols, query);
487 res = INGgetINGresult(desc);
491 rows = INGfetchAll(query, res);
493 INGfreeDescriptor(desc);
494 INGfreeINGresult(res);
499 void INGclear(INGresult *res)
504 INGfreeDescriptor(res->sqlda);
505 INGfreeINGresult(res);
507 INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
510 if (dbname == NULL || strlen(dbname) == 0) {
513 dbconn = (INGconn *)malloc(sizeof(INGconn));
514 memset(dbconn, 0, sizeof(INGconn));
515 /* # line 553 "myingres.sc" */
522 /* # line 559 "myingres.sc" */
524 bstrncpy(ingdbname, dbname, sizeof(ingdbname));
526 bstrncpy(ingdbuser, user, sizeof(ingdbuser));
527 if (passwd != NULL) {
528 bstrncpy(ingdbpasw, passwd, sizeof(ingdbpasw));
530 memset(ingdbpasw, 0, sizeof(ingdbpasw));
532 /* # line 570 "myingres.sc" */ /* connect */
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);
540 /* # line 574 "myingres.sc" */ /* host code */
542 /* # line 575 "myingres.sc" */ /* connect */
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);
549 /* # line 576 "myingres.sc" */ /* host code */
551 /* # line 578 "myingres.sc" */ /* inquire_sql */
553 IILQisInqSqlio((short *)0,1,32,31,conn_name,13);
555 /* # line 579 "myingres.sc" */ /* inquire_sql */
557 IILQisInqSqlio((short *)0,1,30,sizeof(sess_id),&sess_id,11);
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);
569 void INGdisconnectDB(INGconn *dbconn)
571 /* # line 594 "myingres.sc" */
574 /* # line 596 "myingres.sc" */
576 sess_id = dbconn->session_id;
577 /* # line 600 "myingres.sc" */ /* disconnect */
580 IILQsidSessID(sess_id);
583 /* # line 602 "myingres.sc" */ /* host code */
584 if (dbconn != NULL) {
589 char *INGerrorMessage(const INGconn *conn)
591 /* # line 610 "myingres.sc" */
594 /* # line 612 "myingres.sc" */
596 /* # line 614 "myingres.sc" */ /* inquire_ingres */
598 IILQisInqSqlio((short *)0,1,32,255,errbuf,63);
600 /* # line 615 "myingres.sc" */ /* host code */
601 memcpy(conn->msg, &errbuf, 256);
604 char *INGcmdTuples(INGresult *res)
606 return res->numrowstring;
609 int INGputCopyEnd(INGconn *conn, const char *errormsg);
610 int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);
612 /* # line 629 "myingres.sc" */