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" */
48 #define sqlca (*(IIsqlca()))
51 * ---Implementations---
55 return (sqlca.sqlcode < 0) ? sqlca.sqlcode : 0;
57 short INGgetCols(INGconn *conn, const char *query, bool transaction)
59 /* # line 57 "myingres.sc" */
63 /* # line 60 "myingres.sc" */
67 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
68 memset(sqlda, 0, (IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE)));
70 stmt = bstrdup(query);
72 * Switch to the correct default session for this thread.
74 sess_id = conn->session_id;
75 /* # line 76 "myingres.sc" */ /* set_sql */
77 IILQssSetSqlio(11,(short *)0,1,30,sizeof(sess_id),&sess_id);
79 /* # line 78 "myingres.sc" */ /* prepare */
82 IIsqPrepare(0,(char *)"s1",(char *)0,0,stmt);
84 /* # line 79 "myingres.sc" */ /* host code */
89 /* # line 84 "myingres.sc" */ /* describe */
92 IIsqDescribe(0,(char *)"s1",sqlda,0);
94 /* # line 85 "myingres.sc" */ /* host code */
102 * If we are not in a transaction we commit our work now.
105 /* # line 97 "myingres.sc" */ /* commit */
110 /* # line 98 "myingres.sc" */ /* host code */
113 * Switch to no default session for this thread.
115 /* # line 102 "myingres.sc" */ /* set_sql */
117 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
119 /* # line 103 "myingres.sc" */ /* host code */
124 static inline IISQLDA *INGgetDescriptor(short numCols, const char *query)
126 /* # line 110 "myingres.sc" */
129 /* # line 112 "myingres.sc" */
133 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
134 memset(sqlda, 0, (IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE)));
135 sqlda->sqln = numCols;
136 stmt = bstrdup(query);
137 /* # line 124 "myingres.sc" */ /* prepare */
140 IIsqPrepare(0,(char *)"s2",sqlda,0,stmt);
142 /* # line 126 "myingres.sc" */ /* host code */
144 for (i = 0; i < sqlda->sqld; ++i) {
146 * Negative type indicates nullable coulumns, so an indicator
147 * is allocated, otherwise it's null
149 if (sqlda->sqlvar[i].sqltype > 0) {
150 sqlda->sqlvar[i].sqlind = NULL;
152 sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
155 * Alloc space for variable like indicated in sqllen
156 * for date types sqllen is always 0 -> allocate by type
158 switch (abs(sqlda->sqlvar[i].sqltype)) {
160 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSW_LEN);
163 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSWO_LEN);
165 case IISQ_TSTMP_TYPE:
166 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN);
170 * plus one to avoid zero mem allocs
172 sqlda->sqlvar[i].sqldata = (char *)malloc(sqlda->sqlvar[i].sqllen+1);
178 static void INGfreeDescriptor(IISQLDA *sqlda)
184 for (i = 0; i < sqlda->sqld; ++i) {
185 if (sqlda->sqlvar[i].sqldata) {
186 free(sqlda->sqlvar[i].sqldata);
188 if (sqlda->sqlvar[i].sqlind) {
189 free(sqlda->sqlvar[i].sqlind);
195 static inline int INGgetTypeSize(IISQLVAR *ingvar)
199 * TODO: add date types (at least TSTMP,TSW TSWO)
201 switch (ingvar->sqltype) {
209 inglength = ingvar->sqllen;
214 static inline INGresult *INGgetINGresult(IISQLDA *sqlda)
217 INGresult *result = NULL;
221 result = (INGresult *)malloc(sizeof(INGresult));
222 memset(result, 0, sizeof(INGresult));
223 result->sqlda = sqlda;
224 result->num_fields = sqlda->sqld;
225 result->num_rows = 0;
226 result->first_row = NULL;
227 result->status = ING_EMPTY_RESULT;
228 result->act_row = NULL;
229 memset(result->numrowstring, 0, sizeof(result->numrowstring));
230 if (result->num_fields) {
231 result->fields = (INGRES_FIELD *)malloc(sizeof(INGRES_FIELD) * result->num_fields);
232 memset(result->fields, 0, sizeof(INGRES_FIELD) * result->num_fields);
233 for (i = 0; i < result->num_fields; ++i) {
234 memset(result->fields[i].name, 0, 34);
235 bstrncpy(result->fields[i].name, sqlda->sqlvar[i].sqlname.sqlnamec, sqlda->sqlvar[i].sqlname.sqlnamel);
236 result->fields[i].max_length = INGgetTypeSize(&sqlda->sqlvar[i]);
237 result->fields[i].type = abs(sqlda->sqlvar[i].sqltype);
238 result->fields[i].flags = (sqlda->sqlvar[i].sqltype < 0) ? 1 : 0;
243 static inline void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
246 if (row == NULL || sqlda == NULL) {
249 for (i = 0; i < sqlda->sqld; ++i) {
250 if (row->sqlvar[i].sqldata) {
251 free(row->sqlvar[i].sqldata);
253 if (row->sqlvar[i].sqlind) {
254 free(row->sqlvar[i].sqlind);
260 static void INGfreeINGresult(INGresult *ing_res)
268 * Free all rows and fields, then res, not descriptor!
270 * Use of rows is a nasty workaround til I find the reason,
271 * why aggregates like max() don't work
273 rows = ing_res->num_rows;
274 ing_res->act_row = ing_res->first_row;
275 while (ing_res->act_row != NULL && rows > 0) {
276 rowtemp = ing_res->act_row->next;
277 INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
278 ing_res->act_row = rowtemp;
281 if (ing_res->fields) {
282 free(ing_res->fields);
286 static inline ING_ROW *INGgetRowSpace(INGresult *ing_res)
289 unsigned short len; /* used for VARCHAR type length */
290 IISQLDA *sqlda = ing_res->sqlda;
292 IISQLVAR *vars = NULL;
293 row = (ING_ROW *)malloc(sizeof(ING_ROW));
294 memset(row, 0, sizeof(ING_ROW));
295 vars = (IISQLVAR *)malloc(sizeof(IISQLVAR) * sqlda->sqld);
296 memset(vars, 0, sizeof(IISQLVAR) * sqlda->sqld);
299 for (i = 0; i < sqlda->sqld; ++i) {
301 * Make strings out of the data, then the space and assign
302 * (why string? at least it seems that way, looking into the sources)
304 vars[i].sqlind = (short *)malloc(sizeof(short));
305 if (sqlda->sqlvar[i].sqlind) {
306 memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
308 *vars[i].sqlind = NULL;
311 * if sqlind pointer exists AND points to -1 -> column is 'null'
313 if ( *vars[i].sqlind && (*vars[i].sqlind == -1)) {
314 vars[i].sqldata = NULL;
316 switch (ing_res->fields[i].type) {
318 len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
319 vars[i].sqldata = (char *)malloc(len+1);
320 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
321 vars[i].sqldata[len] = '\0';
324 vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
325 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
326 vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
329 vars[i].sqldata = (char *)malloc(20);
330 memset(vars[i].sqldata, 0, 20);
331 switch (sqlda->sqlvar[i].sqllen) {
333 bsnprintf(vars[i].sqldata, 20, "%d",*(short*)sqlda->sqlvar[i].sqldata);
336 bsnprintf(vars[i].sqldata, 20, "%ld",*(int*)sqlda->sqlvar[i].sqldata);
339 bsnprintf(vars[i].sqldata, 20, "%lld",*(long*)sqlda->sqlvar[i].sqldata);
343 case IISQ_TSTMP_TYPE:
344 vars[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN+1);
345 vars[i].sqldata[IISQ_TSTMP_LEN] = '\0';
348 vars[i].sqldata = (char *)malloc(IISQ_TSWO_LEN+1);
349 vars[i].sqldata[IISQ_TSWO_LEN] = '\0';
352 vars[i].sqldata = (char *)malloc(IISQ_TSW_LEN+1);
353 vars[i].sqldata[IISQ_TSW_LEN] = '\0';
360 static inline int INGfetchAll(const char *query, INGresult *ing_res)
366 desc = ing_res->sqlda;
367 /* # line 380 "myingres.sc" */ /* host code */
368 if ((check = INGcheck()) < 0) {
371 /* # line 384 "myingres.sc" */ /* open */
374 IIcsOpen((char *)"c2",19193,19709);
375 IIwritio(0,(short *)0,1,32,0,(char *)"s2");
376 IIcsQuery((char *)"c2",19193,19709);
378 /* # line 385 "myingres.sc" */ /* host code */
379 if ((check = INGcheck()) < 0) {
382 /* for (linecount = 0; sqlca.sqlcode == 0; ++linecount) */
384 /* # line 391 "myingres.sc" */ /* fetch */
387 if (IIcsRetScroll((char *)"c2",19193,19709,-1,-1) != 0) {
392 /* # line 393 "myingres.sc" */ /* host code */
393 if ( (sqlca.sqlcode == 0) || (sqlca.sqlcode == -40202) ) {
394 row = INGgetRowSpace(ing_res); /* alloc space for fetched row */
396 * Initialize list when encountered first time
398 if (ing_res->first_row == 0) {
399 ing_res->first_row = row; /* head of the list */
400 ing_res->first_row->next = NULL;
401 ing_res->act_row = ing_res->first_row;
403 ing_res->act_row->next = row; /* append row to old act_row */
404 ing_res->act_row = row; /* set row as act_row */
405 row->row_number = linecount;
408 } while ( (sqlca.sqlcode == 0) || (sqlca.sqlcode == -40202) );
409 /* # line 411 "myingres.sc" */ /* close */
412 IIcsClose((char *)"c2",19193,19709);
414 /* # line 413 "myingres.sc" */ /* host code */
415 ing_res->status = ING_COMMAND_OK;
416 ing_res->num_rows = linecount;
419 static inline ING_STATUS INGresultStatus(INGresult *res)
422 return ING_NO_RESULT;
427 static void INGrowSeek(INGresult *res, int row_number)
429 ING_ROW *trow = NULL;
430 if (res->act_row->row_number == row_number) {
434 * TODO: real error handling
436 if (row_number<0 || row_number>res->num_rows) {
439 for (trow = res->first_row; trow->row_number != row_number; trow = trow->next) ;
442 * Note - can be null - if row_number not found, right?
445 char *INGgetvalue(INGresult *res, int row_number, int column_number)
447 if (row_number != res->act_row->row_number) {
448 INGrowSeek(res, row_number);
450 return res->act_row->sqlvar[column_number].sqldata;
452 bool INGgetisnull(INGresult *res, int row_number, int column_number)
454 if (row_number != res->act_row->row_number) {
455 INGrowSeek(res, row_number);
457 return (*res->act_row->sqlvar[column_number].sqlind == -1) ? true : false;
459 int INGntuples(const INGresult *res)
461 return res->num_rows;
463 int INGnfields(const INGresult *res)
465 return res->num_fields;
467 char *INGfname(const INGresult *res, int column_number)
469 if ((column_number > res->num_fields) || (column_number < 0)) {
472 return res->fields[column_number].name;
475 short INGftype(const INGresult *res, int column_number)
477 return res->fields[column_number].type;
479 int INGexec(INGconn *conn, const char *query, bool transaction)
482 /* # line 494 "myingres.sc" */
487 /* # line 498 "myingres.sc" */
489 stmt = bstrdup(query);
492 * Switch to the correct default session for this thread.
494 sess_id = conn->session_id;
495 /* # line 507 "myingres.sc" */ /* set_sql */
497 IILQssSetSqlio(11,(short *)0,1,30,sizeof(sess_id),&sess_id);
499 /* # line 508 "myingres.sc" */ /* execute */
503 IIsyncup((char *)0,0);
505 /* # line 510 "myingres.sc" */ /* host code */
507 if ((check = INGcheck()) < 0) {
511 /* # line 517 "myingres.sc" */ /* inquire_ingres */
513 IILQisInqSqlio((short *)0,1,30,sizeof(rowcount),&rowcount,8);
515 /* # line 518 "myingres.sc" */ /* host code */
516 if ((check = INGcheck()) < 0) {
522 * If we are not in a transaction we commit our work now.
525 /* # line 528 "myingres.sc" */ /* commit */
530 /* # line 529 "myingres.sc" */ /* host code */
533 * Switch to no default session for this thread.
535 /* # line 533 "myingres.sc" */ /* set_sql */
537 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
539 /* # line 534 "myingres.sc" */ /* host code */
542 INGresult *INGquery(INGconn *conn, const char *query, bool transaction)
545 * TODO: error handling
547 IISQLDA *desc = NULL;
548 INGresult *res = NULL;
550 int cols = INGgetCols(conn, query);
551 /* # line 546 "myingres.sc" */
554 /* # line 548 "myingres.sc" */
557 * Switch to the correct default session for this thread.
559 sess_id = conn->session_id;
560 /* # line 554 "myingres.sc" */ /* set_sql */
562 IILQssSetSqlio(11,(short *)0,1,30,sizeof(sess_id),&sess_id);
564 /* # line 556 "myingres.sc" */ /* host code */
565 desc = INGgetDescriptor(cols, query);
569 res = INGgetINGresult(desc);
573 rows = INGfetchAll(query, res);
575 INGfreeDescriptor(desc);
576 INGfreeINGresult(res);
582 * If we are not in a transaction we commit our work now.
585 /* # line 580 "myingres.sc" */ /* commit */
590 /* # line 581 "myingres.sc" */ /* host code */
593 * Switch to no default session for this thread.
595 /* # line 585 "myingres.sc" */ /* set_sql */
597 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
599 /* # line 586 "myingres.sc" */ /* host code */
602 void INGclear(INGresult *res)
607 INGfreeDescriptor(res->sqlda);
608 INGfreeINGresult(res);
610 void INGcommit(onst INGconn *conn)
612 /* # line 601 "myingres.sc" */
615 /* # line 603 "myingres.sc" */
617 if (dbconn != NULL) {
618 sess_id = dbconn->session_id;
619 /* # line 607 "myingres.sc" */ /* disconnect */
622 IILQsidSessID(sess_id);
625 /* # line 609 "myingres.sc" */ /* host code */
629 /* # line 612 "myingres.sc" */ /* commit */
634 /* # line 614 "myingres.sc" */ /* host code */
636 * Switch to no default session for this thread.
638 /* # line 617 "myingres.sc" */ /* set_sql */
640 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
642 /* # line 618 "myingres.sc" */ /* host code */
645 INGconn *INGconnectDB(char *dbname, char *user, char *passwd, int session_id)
648 if (dbname == NULL || strlen(dbname) == 0) {
651 dbconn = (INGconn *)malloc(sizeof(INGconn));
652 memset(dbconn, 0, sizeof(INGconn));
653 /* # line 632 "myingres.sc" */
657 char ingdbpasswd[32];
659 /* # line 637 "myingres.sc" */
661 sess_id = session_id;
662 bstrncpy(ingdbname, dbname, sizeof(ingdbname));
664 bstrncpy(ingdbuser, user, sizeof(ingdbuser));
665 if (passwd != NULL) {
666 bstrncpy(ingdbpasswd, passwd, sizeof(ingdbpasswd));
668 memset(ingdbpasswd, 0, sizeof(ingdbpasswd));
670 /* # line 649 "myingres.sc" */ /* connect */
673 IILQsidSessID(sess_id);
675 IIsqConnect(0,ingdbname,(char *)"-dbms_password",ingdbpasswd,(char *)0,
676 (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
677 (char *)0, (char *)0, (char *)0, (char *)0);
679 /* # line 654 "myingres.sc" */ /* host code */
681 /* # line 655 "myingres.sc" */ /* connect */
684 IILQsidSessID(sess_id);
685 IIsqConnect(0,ingdbname,(char *)0, (char *)0, (char *)0, (char *)0,
686 (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
687 (char *)0, (char *)0, (char *)0);
689 /* # line 658 "myingres.sc" */ /* host code */
691 if (INGcheck() < 0) {
694 bstrncpy(dbconn->dbname, ingdbname, sizeof(dbconn->dbname));
695 bstrncpy(dbconn->user, ingdbuser, sizeof(dbconn->user));
696 bstrncpy(dbconn->password, ingdbpasswd, sizeof(dbconn->password));
697 dbconn->session_id = sess_id;
698 dbconn->msg = (char*)malloc(257);
699 memset(dbconn->msg, 0, 257);
701 * Switch to no default session for this thread undo default settings from SQL CONNECT.
703 /* # line 673 "myingres.sc" */ /* set_sql */
705 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
707 /* # line 675 "myingres.sc" */ /* host code */
710 void INGdisconnectDB(INGconn *dbconn)
712 /* # line 680 "myingres.sc" */
715 /* # line 682 "myingres.sc" */
717 if (dbconn != NULL) {
718 sess_id = dbconn->session_id;
719 /* # line 686 "myingres.sc" */ /* disconnect */
722 IILQsidSessID(sess_id);
725 /* # line 688 "myingres.sc" */ /* host code */
730 char *INGerrorMessage(const INGconn *conn)
732 /* # line 695 "myingres.sc" */
735 /* # line 697 "myingres.sc" */
737 /* # line 699 "myingres.sc" */ /* inquire_ingres */
739 IILQisInqSqlio((short *)0,1,32,255,errbuf,63);
741 /* # line 700 "myingres.sc" */ /* host code */
742 memcpy(conn->msg, &errbuf, 256);
745 char *INGcmdTuples(INGresult *res)
747 return res->numrowstring;
750 int INGputCopyEnd(INGconn *conn, const char *errormsg);
751 int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);
753 /* # line 714 "myingres.sc" */