2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-2007 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula Catalog Database routines specific to Ingres
30 * These are Ingres specific routines
32 * Stefan Reddig, June 2009
33 * based uopn work done
34 * by Dan Langille, December 2003 and
35 * by Kern Sibbald, March 2000
40 /* The following is necessary so that we do not include
41 * the dummy external definition of DB.
43 #define __SQL_C /* indicate that this is sql.c */
52 /* -----------------------------------------------------------------------
54 * Ingres dependent defines and subroutines
56 * -----------------------------------------------------------------------
59 /* List of open databases */ /* SRE: needed for ingres? */
60 static BQUEUE db_list = {&db_list, &db_list};
62 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
65 * Retrieve database type
74 * Initialize database data structure. In principal this should
75 * never have errors, or it is really fatal.
78 db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char *db_password,
79 const char *db_address, int db_port, const char *db_socket,
80 int mult_db_connections)
85 Jmsg(jcr, M_FATAL, 0, _("A user name for Ingres must be supplied.\n"));
88 P(mutex); /* lock DB queue */
89 if (!mult_db_connections) {
90 /* Look to see if DB already open */
91 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
92 if (bstrcmp(mdb->db_name, db_name) &&
93 bstrcmp(mdb->db_address, db_address) &&
94 mdb->db_port == db_port) {
95 Dmsg2(100, "DB REopen %d %s\n", mdb->ref_count, db_name);
98 return mdb; /* already open */
102 Dmsg0(100, "db_open first time\n");
103 mdb = (B_DB *)malloc(sizeof(B_DB));
104 memset(mdb, 0, sizeof(B_DB));
105 mdb->db_name = bstrdup(db_name);
106 mdb->db_user = bstrdup(db_user);
108 mdb->db_password = bstrdup(db_password);
111 mdb->db_address = bstrdup(db_address);
114 mdb->db_socket = bstrdup(db_socket);
116 mdb->db_port = db_port;
117 mdb->have_insert_id = TRUE;
118 mdb->errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */
120 mdb->cmd = get_pool_memory(PM_EMSG); /* get command buffer */
121 mdb->cached_path = get_pool_memory(PM_FNAME);
122 mdb->cached_path_id = 0;
124 mdb->fname = get_pool_memory(PM_FNAME);
125 mdb->path = get_pool_memory(PM_FNAME);
126 mdb->esc_name = get_pool_memory(PM_FNAME);
127 mdb->esc_path = get_pool_memory(PM_FNAME);
128 mdb->allow_transactions = mult_db_connections;
129 qinsert(&db_list, &mdb->bq); /* put db in list */
134 /* Check that the database correspond to the encoding we want */
135 static bool check_database_encoding(JCR *jcr, B_DB *mdb)
137 /* SRE: TODO! Needed?
141 if (!db_sql_query(mdb, "SELECT getdatabaseencoding()", NULL, NULL)) {
142 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
146 if ((row = sql_fetch_row(mdb)) == NULL) {
147 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
148 Jmsg(jcr, M_ERROR, 0, "Can't check database encoding %s", mdb->errmsg);
150 ret = bstrcmp(row[0], "SQL_ASCII");
153 _("Encoding error for database \"%s\". Wanted SQL_ASCII, got %s\n"),
154 mdb->db_name, row[0]);
155 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
156 Dmsg1(50, "%s", mdb->errmsg);
165 * Check for errors in DBMS work
167 static int sql_check(B_DB *mdb)
173 * Now actually open the database. This can generate errors,
174 * which are returned in the errmsg
176 * DO NOT close the database or free(mdb) here !!!!
179 db_open_database(JCR *jcr, B_DB *mdb)
185 if (mdb->connected) {
189 mdb->connected = false;
191 if ((errstat=rwl_init(&mdb->lock)) != 0) {
193 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
194 be.bstrerror(errstat));
200 bsnprintf(buf, sizeof(buf), "%d", mdb->db_port);
206 mdb->db = INGconnectDB(mdb->db_name, mdb->db_user, mdb->db_password);
208 Dmsg0(50, "Ingres real CONNECT done\n");
209 Dmsg3(50, "db_user=%s db_name=%s db_password=%s\n", mdb->db_user, mdb->db_name,
210 mdb->db_password==NULL?"(NULL)":mdb->db_password);
212 if (sql_check(mdb)) {
213 Mmsg2(&mdb->errmsg, _("Unable to connect to Ingres server.\n"
214 "Database=%s User=%s\n"
215 "It is probably not running or your password is incorrect.\n"),
216 mdb->db_name, mdb->db_user);
221 mdb->connected = true;
223 if (!check_tables_version(jcr, mdb)) {
228 //sql_query(mdb, "SET datestyle TO 'ISO, YMD'");
230 /* check that encoding is SQL_ASCII */
231 check_database_encoding(jcr, mdb);
238 db_close_database(JCR *jcr, B_DB *mdb)
243 db_end_transaction(jcr, mdb);
245 sql_free_result(mdb);
247 if (mdb->ref_count == 0) {
249 if (mdb->connected && mdb->db) {
252 rwl_destroy(&mdb->lock);
253 free_pool_memory(mdb->errmsg);
254 free_pool_memory(mdb->cmd);
255 free_pool_memory(mdb->cached_path);
256 free_pool_memory(mdb->fname);
257 free_pool_memory(mdb->path);
258 free_pool_memory(mdb->esc_name);
259 free_pool_memory(mdb->esc_path);
266 if (mdb->db_password) {
267 free(mdb->db_password);
269 if (mdb->db_address) {
270 free(mdb->db_address);
272 if (mdb->db_socket) {
273 free(mdb->db_socket);
280 void db_thread_cleanup()
284 * Return the next unique index (auto-increment) for
285 * the given table. Return NULL on error.
287 * For Ingres, NULL causes the auto-increment value SRE: true?
290 int db_next_index(JCR *jcr, B_DB *mdb, char *table, char *index)
292 strcpy(index, "NULL");
298 * Escape strings so that Ingres is happy
300 * NOTE! len is the length of the old string. Your new
301 * string must be long enough (max 2*old+1) to hold
302 * the escaped output.
306 db_escape_string(JCR *jcr, B_DB *mdb, char *snew, char *old, int len)
311 PQescapeStringConn(mdb->db, snew, old, len, &error);
313 Jmsg(jcr, M_FATAL, 0, _("PQescapeStringConn returned non-zero.\n"));*/
314 /* error on encoding, probably invalid multibyte encoding in the source string
315 see PQescapeStringConn documentation for details. */
316 /* Dmsg0(500, "PQescapeStringConn failed\n");
321 * Submit a general SQL command (cmd), and for each row returned,
322 * the sqlite_handler is called with the ctx.
324 bool db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
328 Dmsg0(500, "db_sql_query started\n");
331 if (sql_query(mdb, query) != 0) {
332 Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb));
334 Dmsg0(500, "db_sql_query failed\n");
337 Dmsg0(500, "db_sql_query succeeded. checking handler\n");
339 if (result_handler != NULL) {
340 Dmsg0(500, "db_sql_query invoking handler\n");
341 if ((mdb->result = sql_store_result(mdb)) != NULL) {
342 int num_fields = sql_num_fields(mdb);
344 Dmsg0(500, "db_sql_query sql_store_result suceeded\n");
345 while ((row = sql_fetch_row(mdb)) != NULL) {
347 Dmsg0(500, "db_sql_query sql_fetch_row worked\n");
348 if (result_handler(ctx, num_fields, row))
352 sql_free_result(mdb);
357 Dmsg0(500, "db_sql_query finished\n");
363 * Close database connection
365 void my_ingres_close(B_DB *mdb)
367 INGdisconnectDB(mdb->db);
368 //SRE: error handling?
371 INGRES_ROW my_ingres_fetch_row(B_DB *mdb)
374 INGRES_ROW row = NULL; // by default, return NULL
376 Dmsg0(500, "my_ingres_fetch_row start\n");
378 if (!mdb->row || mdb->row_size < mdb->num_fields) {
379 int num_fields = mdb->num_fields;
380 Dmsg1(500, "we have need space of %d bytes\n", sizeof(char *) * mdb->num_fields);
383 Dmsg0(500, "my_ingres_fetch_row freeing space\n");
386 num_fields += 20; /* add a bit extra */
387 mdb->row = (INGRES_ROW)malloc(sizeof(char *) * num_fields);
388 mdb->row_size = num_fields;
390 // now reset the row_number now that we have the space allocated
394 // if still within the result set
395 if (mdb->row_number < mdb->num_rows) {
396 Dmsg2(500, "my_ingres_fetch_row row number '%d' is acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
397 // get each value from this row
398 for (j = 0; j < mdb->num_fields; j++) {
399 mdb->row[j] = INGgetvalue(mdb->result, mdb->row_number, j);
400 Dmsg2(500, "my_ingres_fetch_row field '%d' has value '%s'\n", j, mdb->row[j]);
402 // increment the row number for the next call
407 Dmsg2(500, "my_ingres_fetch_row row number '%d' is NOT acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
410 Dmsg1(500, "my_ingres_fetch_row finishes returning %p\n", row);
416 int my_ingres_max_length(B_DB *mdb, int field_num) {
418 // for a given column, find the max length
425 for (i = 0; i < mdb->num_rows; i++) {
426 if (INGgetisnull(mdb->result, i, field_num)) {
427 this_length = 4; // "NULL"
429 this_length = cstrlen(INGgetvalue(mdb->result, i, field_num));
432 if (max_length < this_length) {
433 max_length = this_length;
440 INGRES_FIELD * my_ingres_fetch_field(B_DB *mdb)
444 Dmsg0(500, "my_ingres_fetch_field starts\n");
446 if (!mdb->fields || mdb->fields_size < mdb->num_fields) {
450 Dmsg1(500, "allocating space for %d fields\n", mdb->num_fields);
451 mdb->fields = (INGRES_FIELD *)malloc(sizeof(INGRES_FIELD) * mdb->num_fields);
452 mdb->fields_size = mdb->num_fields;
454 for (i = 0; i < mdb->num_fields; i++) {
455 Dmsg1(500, "filling field %d\n", i);
456 strcpy(mdb->fields[i].name,INGfname(mdb->result, i));
457 mdb->fields[i].max_length = my_ingres_max_length(mdb, i);
458 mdb->fields[i].type = INGftype(mdb->result, i);
459 mdb->fields[i].flags = 0;
461 Dmsg4(500, "my_ingres_fetch_field finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
462 mdb->fields[i].name, mdb->fields[i].max_length, mdb->fields[i].type,
463 mdb->fields[i].flags);
467 // increment field number for the next time around
469 Dmsg0(500, "my_ingres_fetch_field finishes\n");
470 return &mdb->fields[mdb->field_number++];
473 void my_ingres_data_seek(B_DB *mdb, int row)
475 // set the row number to be returned on the next call
476 // to my_ingres_fetch_row
477 mdb->row_number = row;
480 void my_ingres_field_seek(B_DB *mdb, int field)
482 mdb->field_number = field;
486 * Note, if this routine returns 1 (failure), Bacula expects
487 * that no result has been stored.
488 * This is where QUERY_DB comes with Ingres. SRE: true?
490 * Returns: 0 on success
494 int my_ingres_query(B_DB *mdb, const char *query)
496 Dmsg0(500, "my_ingres_query started\n");
497 // We are starting a new query. reset everything.
499 mdb->row_number = -1;
500 mdb->field_number = -1;
503 INGclear(mdb->result); /* hmm, someone forgot to free?? */
507 Dmsg1(500, "my_ingres_query starts with '%s'\n", query);
508 mdb->result = INGexec(mdb->db, query);
510 Dmsg1(50, "Query failed: %s\n", query);
514 mdb->status = INGresultStatus(mdb->result);
515 if (mdb->status == ING_COMMAND_OK) {
516 Dmsg1(500, "we have a result\n", query);
518 // how many fields in the set?
519 mdb->num_fields = (int)INGnfields(mdb->result);
520 Dmsg1(500, "we have %d fields\n", mdb->num_fields);
522 mdb->num_rows = INGntuples(mdb->result);
523 Dmsg1(500, "we have %d rows\n", mdb->num_rows);
525 mdb->status = 0; /* succeed */
527 Dmsg1(50, "Result status failed: %s\n", query);
531 Dmsg0(500, "my_ingres_query finishing\n");
535 Dmsg1(500, "we failed\n", query);
536 INGclear(mdb->result);
538 mdb->status = 1; /* failed */
542 void my_ingres_free_result(B_DB *mdb)
547 INGclear(mdb->result);
563 int my_ingres_currval(B_DB *mdb, const char *table_name)
569 #ifdef HAVE_BATCH_FILE_INSERT
571 int my_ingres_batch_start(JCR *jcr, B_DB *mdb)
577 /* set error to something to abort operation */
578 int my_ingres_batch_end(JCR *jcr, B_DB *mdb, const char *error)
584 int my_ingres_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
590 #endif /* HAVE_BATCH_FILE_INSERT */
593 * Escape strings so that Ingres is happy on COPY
595 * NOTE! len is the length of the old string. Your new
596 * string must be long enough (max 2*old+1) to hold
597 * the escaped output.
599 char *my_ingres_copy_escape(char *dest, char *src, size_t len)
601 /* we have to escape \t, \n, \r, \ */
604 while (len > 0 && *src) {
639 #ifdef HAVE_BATCH_FILE_INSERT
640 const char *my_ingres_batch_lock_path_query =
641 "BEGIN; LOCK TABLE Path IN SHARE ROW EXCLUSIVE MODE";
644 const char *my_ingres_batch_lock_filename_query =
645 "BEGIN; LOCK TABLE Filename IN SHARE ROW EXCLUSIVE MODE";
647 const char *my_ingres_batch_unlock_tables_query = "COMMIT";
649 const char *my_ingres_batch_fill_path_query =
650 "INSERT INTO Path (Path) "
651 "SELECT a.Path FROM "
652 "(SELECT DISTINCT Path FROM batch) AS a "
653 "WHERE NOT EXISTS (SELECT Path FROM Path WHERE Path = a.Path) ";
656 const char *my_ingres_batch_fill_filename_query =
657 "INSERT INTO Filename (Name) "
658 "SELECT a.Name FROM "
659 "(SELECT DISTINCT Name FROM batch) as a "
661 "(SELECT Name FROM Filename WHERE Name = a.Name)";
662 #endif /* HAVE_BATCH_FILE_INSERT */
664 #endif /* HAVE_INGRES */