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 with help of Marco van Wieringen April 2010
30 /* # line 37 "myingres.sc" */
48 #define sqlca (*(IIsqlca()))
51 * ---Implementations---
53 short INGgetCols(INGconn *dbconn, const char *query, bool transaction)
55 /* # line 52 "myingres.sc" */
59 /* # line 55 "myingres.sc" */
63 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + IISQDA_VAR_SIZE);
64 memset(sqlda, 0, (IISQDA_HEAD_SIZE + IISQDA_VAR_SIZE));
66 stmt = bstrdup(query);
68 * Switch to the correct default session for this thread.
70 sess_id = dbconn->session_id;
71 /* # line 71 "myingres.sc" */ /* set_sql */
73 IILQssSetSqlio(11,(short *)0,1,30,sizeof(sess_id),&sess_id);
75 /* # line 75 "myingres.sc" */ /* prepare */
78 IIsqPrepare(0,(char *)"s1",(char *)0,0,stmt);
79 if (sqlca.sqlcode < 0)
82 /* # line 76 "myingres.sc" */ /* describe */
85 IIsqDescribe(0,(char *)"s1",sqlda,0);
86 if (sqlca.sqlcode < 0)
89 /* # line 80 "myingres.sc" */ /* host code */
92 * If we are not in a transaction we commit our work now.
95 /* # line 86 "myingres.sc" */ /* commit */
100 /* # line 87 "myingres.sc" */ /* host code */
104 * Switch to no default session for this thread.
106 /* # line 93 "myingres.sc" */ /* set_sql */
108 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
110 /* # line 94 "myingres.sc" */ /* host code */
115 static inline IISQLDA *INGgetDescriptor(short numCols, const char *query)
117 /* # line 101 "myingres.sc" */
120 /* # line 103 "myingres.sc" */
124 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
125 memset(sqlda, 0, (IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE)));
126 sqlda->sqln = numCols;
127 stmt = bstrdup(query);
128 /* # line 115 "myingres.sc" */ /* prepare */
131 IIsqPrepare(0,(char *)"s2",sqlda,0,stmt);
133 /* # line 117 "myingres.sc" */ /* host code */
134 for (i = 0; i < sqlda->sqld; ++i) {
136 * Negative type indicates nullable columns, 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);
169 static void INGfreeDescriptor(IISQLDA *sqlda)
175 for (i = 0; i < sqlda->sqld; ++i) {
176 if (sqlda->sqlvar[i].sqldata) {
177 free(sqlda->sqlvar[i].sqldata);
179 if (sqlda->sqlvar[i].sqlind) {
180 free(sqlda->sqlvar[i].sqlind);
186 static inline int INGgetTypeSize(IISQLVAR *ingvar)
190 * TODO: add date types (at least TSTMP,TSW TSWO)
192 switch (ingvar->sqltype) {
200 inglength = ingvar->sqllen;
205 static inline INGresult *INGgetINGresult(IISQLDA *sqlda)
208 INGresult *result = NULL;
212 result = (INGresult *)malloc(sizeof(INGresult));
213 memset(result, 0, sizeof(INGresult));
214 result->sqlda = sqlda;
215 result->num_fields = sqlda->sqld;
216 result->num_rows = 0;
217 result->first_row = NULL;
218 result->status = ING_EMPTY_RESULT;
219 result->act_row = NULL;
220 memset(result->numrowstring, 0, sizeof(result->numrowstring));
221 if (result->num_fields) {
222 result->fields = (INGRES_FIELD *)malloc(sizeof(INGRES_FIELD) * result->num_fields);
223 memset(result->fields, 0, sizeof(INGRES_FIELD) * result->num_fields);
224 for (i = 0; i < result->num_fields; ++i) {
225 memset(result->fields[i].name, 0, 34);
226 bstrncpy(result->fields[i].name, sqlda->sqlvar[i].sqlname.sqlnamec, sqlda->sqlvar[i].sqlname.sqlnamel);
227 result->fields[i].max_length = INGgetTypeSize(&sqlda->sqlvar[i]);
228 result->fields[i].type = abs(sqlda->sqlvar[i].sqltype);
229 result->fields[i].flags = (sqlda->sqlvar[i].sqltype < 0) ? 1 : 0;
234 static inline void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
237 if (row == NULL || sqlda == NULL) {
240 for (i = 0; i < sqlda->sqld; ++i) {
241 if (row->sqlvar[i].sqldata) {
242 free(row->sqlvar[i].sqldata);
244 if (row->sqlvar[i].sqlind) {
245 free(row->sqlvar[i].sqlind);
251 static void INGfreeINGresult(INGresult *ing_res)
259 * Free all rows and fields, then res, not descriptor!
261 * Use of rows is a nasty workaround til I find the reason,
262 * why aggregates like max() don't work
264 rows = ing_res->num_rows;
265 ing_res->act_row = ing_res->first_row;
266 while (ing_res->act_row != NULL && rows > 0) {
267 rowtemp = ing_res->act_row->next;
268 INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
269 ing_res->act_row = rowtemp;
272 if (ing_res->fields) {
273 free(ing_res->fields);
277 static inline ING_ROW *INGgetRowSpace(INGresult *ing_res)
280 unsigned short len; /* used for VARCHAR type length */
281 IISQLDA *sqlda = ing_res->sqlda;
283 IISQLVAR *vars = NULL;
284 row = (ING_ROW *)malloc(sizeof(ING_ROW));
285 memset(row, 0, sizeof(ING_ROW));
286 vars = (IISQLVAR *)malloc(sizeof(IISQLVAR) * sqlda->sqld);
287 memset(vars, 0, sizeof(IISQLVAR) * sqlda->sqld);
290 for (i = 0; i < sqlda->sqld; ++i) {
292 * Make strings out of the data, then the space and assign
293 * (why string? at least it seems that way, looking into the sources)
295 vars[i].sqlind = (short *)malloc(sizeof(short));
296 if (sqlda->sqlvar[i].sqlind) {
297 memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
299 *vars[i].sqlind = NULL;
302 * if sqlind pointer exists AND points to -1 -> column is 'null'
304 if ( *vars[i].sqlind && (*vars[i].sqlind == -1)) {
305 vars[i].sqldata = NULL;
307 switch (ing_res->fields[i].type) {
309 len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
310 vars[i].sqldata = (char *)malloc(len+1);
311 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
312 vars[i].sqldata[len] = '\0';
315 vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
316 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
317 vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
320 vars[i].sqldata = (char *)malloc(20);
321 memset(vars[i].sqldata, 0, 20);
322 switch (sqlda->sqlvar[i].sqllen) {
324 bsnprintf(vars[i].sqldata, 20, "%d",*(short*)sqlda->sqlvar[i].sqldata);
327 bsnprintf(vars[i].sqldata, 20, "%ld",*(int*)sqlda->sqlvar[i].sqldata);
330 bsnprintf(vars[i].sqldata, 20, "%lld",*(long*)sqlda->sqlvar[i].sqldata);
334 case IISQ_TSTMP_TYPE:
335 vars[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN+1);
336 vars[i].sqldata[IISQ_TSTMP_LEN] = '\0';
339 vars[i].sqldata = (char *)malloc(IISQ_TSWO_LEN+1);
340 vars[i].sqldata[IISQ_TSWO_LEN] = '\0';
343 vars[i].sqldata = (char *)malloc(IISQ_TSW_LEN+1);
344 vars[i].sqldata[IISQ_TSW_LEN] = '\0';
351 static inline int INGfetchAll(const char *query, INGresult *ing_res)
356 desc = ing_res->sqlda;
357 /* # line 371 "myingres.sc" */ /* open */
360 IIcsOpen((char *)"c2",30801,28581);
361 IIwritio(0,(short *)0,1,32,0,(char *)"s2");
362 IIcsQuery((char *)"c2",30801,28581);
363 if (sqlca.sqlcode < 0)
366 /* # line 375 "myingres.sc" */ /* host code */
369 /* # line 377 "myingres.sc" */ /* fetch */
372 if (IIcsRetScroll((char *)"c2",30801,28581,-1,-1) != 0) {
377 /* # line 379 "myingres.sc" */ /* host code */
378 if (sqlca.sqlcode == 0 || sqlca.sqlcode == -40202) {
380 * Allocate space for fetched row
382 row = INGgetRowSpace(ing_res);
384 * Initialize list when encountered first time
386 if (ing_res->first_row == 0) {
387 ing_res->first_row = row; /* head of the list */
388 ing_res->first_row->next = NULL;
389 ing_res->act_row = ing_res->first_row;
391 ing_res->act_row->next = row; /* append row to old act_row */
392 ing_res->act_row = row; /* set row as act_row */
393 row->row_number = linecount++;
395 } while ( (sqlca.sqlcode == 0) || (sqlca.sqlcode == -40202) );
396 /* # line 400 "myingres.sc" */ /* close */
399 IIcsClose((char *)"c2",30801,28581);
401 /* # line 402 "myingres.sc" */ /* host code */
402 ing_res->status = ING_COMMAND_OK;
403 ing_res->num_rows = linecount;
407 static inline ING_STATUS INGresultStatus(INGresult *res)
410 return ING_NO_RESULT;
415 static void INGrowSeek(INGresult *res, int row_number)
417 ING_ROW *trow = NULL;
418 if (res->act_row->row_number == row_number) {
422 * TODO: real error handling
424 if (row_number<0 || row_number>res->num_rows) {
427 for (trow = res->first_row; trow->row_number != row_number; trow = trow->next) ;
430 * Note - can be null - if row_number not found, right?
433 char *INGgetvalue(INGresult *res, int row_number, int column_number)
435 if (row_number != res->act_row->row_number) {
436 INGrowSeek(res, row_number);
438 return res->act_row->sqlvar[column_number].sqldata;
440 bool INGgetisnull(INGresult *res, int row_number, int column_number)
442 if (row_number != res->act_row->row_number) {
443 INGrowSeek(res, row_number);
445 return (*res->act_row->sqlvar[column_number].sqlind == -1) ? true : false;
447 int INGntuples(const INGresult *res)
449 return res->num_rows;
451 int INGnfields(const INGresult *res)
453 return res->num_fields;
455 char *INGfname(const INGresult *res, int column_number)
457 if ((column_number > res->num_fields) || (column_number < 0)) {
460 return res->fields[column_number].name;
463 short INGftype(const INGresult *res, int column_number)
465 return res->fields[column_number].type;
467 int INGexec(INGconn *dbconn, const char *query, bool transaction)
470 /* # line 485 "myingres.sc" */
475 /* # line 489 "myingres.sc" */
478 stmt = bstrdup(query);
480 * Switch to the correct default session for this thread.
482 sess_id = dbconn->session_id;
483 /* # line 498 "myingres.sc" */ /* set_sql */
485 IILQssSetSqlio(11,(short *)0,1,30,sizeof(sess_id),&sess_id);
487 /* # line 502 "myingres.sc" */ /* execute */
491 IIsyncup((char *)0,0);
492 if (sqlca.sqlcode < 0)
495 /* # line 503 "myingres.sc" */ /* inquire_ingres */
497 IILQisInqSqlio((short *)0,1,30,sizeof(rowcount),&rowcount,8);
499 /* # line 507 "myingres.sc" */ /* host code */
501 * If we are not in a transaction we commit our work now.
504 /* # line 511 "myingres.sc" */ /* commit */
509 /* # line 512 "myingres.sc" */ /* host code */
513 * Switch to no default session for this thread.
515 /* # line 518 "myingres.sc" */ /* set_sql */
517 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
519 /* # line 519 "myingres.sc" */ /* host code */
523 INGresult *INGquery(INGconn *dbconn, const char *query, bool transaction)
526 * TODO: error handling
528 IISQLDA *desc = NULL;
529 INGresult *res = NULL;
531 int cols = INGgetCols(dbconn, query, transaction);
532 /* # line 532 "myingres.sc" */
535 /* # line 534 "myingres.sc" */
538 * Switch to the correct default session for this thread.
540 sess_id = dbconn->session_id;
541 /* # line 540 "myingres.sc" */ /* set_sql */
543 IILQssSetSqlio(11,(short *)0,1,30,sizeof(sess_id),&sess_id);
545 /* # line 542 "myingres.sc" */ /* host code */
546 desc = INGgetDescriptor(cols, query);
550 res = INGgetINGresult(desc);
554 rows = INGfetchAll(query, res);
556 INGfreeDescriptor(desc);
557 INGfreeINGresult(res);
563 * If we are not in a transaction we commit our work now.
566 /* # line 566 "myingres.sc" */ /* commit */
571 /* # line 567 "myingres.sc" */ /* host code */
574 * Switch to no default session for this thread.
576 /* # line 571 "myingres.sc" */ /* set_sql */
578 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
580 /* # line 572 "myingres.sc" */ /* host code */
583 void INGclear(INGresult *res)
588 INGfreeDescriptor(res->sqlda);
589 INGfreeINGresult(res);
591 void INGcommit(const INGconn *dbconn)
593 /* # line 587 "myingres.sc" */
596 /* # line 589 "myingres.sc" */
598 if (dbconn != NULL) {
599 sess_id = dbconn->session_id;
600 /* # line 593 "myingres.sc" */ /* disconnect */
603 IILQsidSessID(sess_id);
606 /* # line 595 "myingres.sc" */ /* host code */
610 /* # line 598 "myingres.sc" */ /* commit */
615 /* # line 600 "myingres.sc" */ /* host code */
617 * Switch to no default session for this thread.
619 /* # line 603 "myingres.sc" */ /* set_sql */
621 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
623 /* # line 604 "myingres.sc" */ /* host code */
626 INGconn *INGconnectDB(char *dbname, char *user, char *passwd, int session_id)
628 /* # line 609 "myingres.sc" */
632 char ingdbpasswd[32];
634 /* # line 614 "myingres.sc" */
637 if (dbname == NULL || strlen(dbname) == 0) {
640 sess_id = session_id;
641 bstrncpy(ingdbname, dbname, sizeof(ingdbname));
642 /* # line 626 "myingres.sc" */ /* host code */
644 bstrncpy(ingdbuser, user, sizeof(ingdbuser));
645 if (passwd != NULL) {
646 bstrncpy(ingdbpasswd, passwd, sizeof(ingdbpasswd));
648 memset(ingdbpasswd, 0, sizeof(ingdbpasswd));
650 /* # line 633 "myingres.sc" */ /* connect */
653 IILQsidSessID(sess_id);
655 IIsqConnect(0,ingdbname,(char *)"-dbms_password",ingdbpasswd,(char *)0,
656 (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
657 (char *)0, (char *)0, (char *)0, (char *)0);
658 if (sqlca.sqlcode < 0)
661 /* # line 638 "myingres.sc" */ /* host code */
663 /* # line 639 "myingres.sc" */ /* connect */
666 IILQsidSessID(sess_id);
667 IIsqConnect(0,ingdbname,(char *)0, (char *)0, (char *)0, (char *)0,
668 (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
669 (char *)0, (char *)0, (char *)0);
670 if (sqlca.sqlcode < 0)
673 /* # line 642 "myingres.sc" */ /* host code */
675 /* # line 646 "myingres.sc" */ /* host code */
676 dbconn = (INGconn *)malloc(sizeof(INGconn));
677 memset(dbconn, 0, sizeof(INGconn));
678 bstrncpy(dbconn->dbname, ingdbname, sizeof(dbconn->dbname));
679 bstrncpy(dbconn->user, ingdbuser, sizeof(dbconn->user));
680 bstrncpy(dbconn->password, ingdbpasswd, sizeof(dbconn->password));
681 dbconn->session_id = sess_id;
682 dbconn->msg = (char *)malloc(257);
683 memset(dbconn->msg, 0, 257);
685 * Switch to no default session for this thread undo default settings from SQL CONNECT.
687 /* # line 659 "myingres.sc" */ /* set_sql */
689 IILQssSetSqlio(11,(short *)0,1,30,sizeof(-97),(void *)IILQint(-97));
691 /* # line 661 "myingres.sc" */ /* host code */
695 void INGdisconnectDB(INGconn *dbconn)
697 /* # line 667 "myingres.sc" */
700 /* # line 669 "myingres.sc" */
702 if (dbconn != NULL) {
703 sess_id = dbconn->session_id;
704 /* # line 673 "myingres.sc" */ /* disconnect */
707 IILQsidSessID(sess_id);
710 /* # line 675 "myingres.sc" */ /* host code */
715 char *INGerrorMessage(const INGconn *dbconn)
717 /* # line 682 "myingres.sc" */
720 /* # line 684 "myingres.sc" */
722 /* # line 686 "myingres.sc" */ /* inquire_ingres */
724 IILQisInqSqlio((short *)0,1,32,255,errbuf,63);
726 /* # line 687 "myingres.sc" */ /* host code */
727 strncpy(dbconn->msg, errbuf, sizeof(dbconn->msg));
730 char *INGcmdTuples(INGresult *res)
732 return res->numrowstring;
735 int INGputCopyEnd(INGconn *dbconn, const char *errormsg);
736 int INGputCopyData(INGconn *dbconn, const char *buffer, int nbytes);
738 /* # line 701 "myingres.sc" */