]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/cats/dbi.c
Removed workaround for bug in Ingres with insert into tables with sequences from...
[bacula/bacula] / bacula / src / cats / dbi.c
index 7cbfc1868f509fbc18e87026a560a2c0fdd07713..78d1e330c293939360064a692ac236c738a0081a 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2003-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2003-2010 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
  *    based upon work done by Dan Langille, December 2003 and
  *    by Kern Sibbald, March 2000
  *
- *    Version $Id$
+ */
+/*
+ * This code only compiles against a recent version of libdbi. The current
+ * release found on the libdbi website (0.8.3) won't work for this code.
+ *
+ * You find the libdbi library on http://sourceforge.net/projects/libdbi
+ *
+ * A fairly recent version of libdbi from CVS works, so either make sure
+ * your distribution has a fairly recent version of libdbi installed or
+ * clone the CVS repositories from sourceforge and compile that code and
+ * install it.
+ *
+ * You need:
+ * cvs co :pserver:anonymous@libdbi.cvs.sourceforge.net:/cvsroot/libdbi
+ * cvs co :pserver:anonymous@libdbi-drivers.cvs.sourceforge.net:/cvsroot/libdbi-drivers
  */
 
 
  */
 
 /* List of open databases */
-static BQUEUE db_list = {&db_list, &db_list};
+static dlist *db_list = NULL;
 
 /* Control allocated fields by my_dbi_getvalue */
-static BQUEUE dbi_getvalue_list = {&dbi_getvalue_list, &dbi_getvalue_list};
+static dlist *dbi_getvalue_list = NULL;
 
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -80,7 +94,8 @@ db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char
                  const char *db_address, int db_port, const char *db_socket,
                  int mult_db_connections)
 {
-   B_DB *mdb;
+   B_DB *mdb = NULL;
+   DBI_FIELD_GET *field;
    char db_driver[10];
    char db_driverdir[256];
 
@@ -116,9 +131,13 @@ db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char
       return NULL;
    }
    P(mutex);                          /* lock DB queue */
+   if (db_list == NULL) {
+      db_list = New(dlist(mdb, &mdb->link));
+      dbi_getvalue_list = New(dlist(field, &field->link));
+   }
    if (!mult_db_connections) {
       /* Look to see if DB already open */
-      for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
+      foreach_dlist(mdb, db_list) {
          if (bstrcmp(mdb->db_name, db_name) &&
              bstrcmp(mdb->db_address, db_address) &&
              bstrcmp(mdb->db_driver, db_driver) &&
@@ -153,7 +172,6 @@ db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char
    }
    mdb->db_type        = db_type;
    mdb->db_port        = db_port;
-   mdb->have_insert_id = TRUE;
    mdb->errmsg         = get_pool_memory(PM_EMSG); /* get error message buffer */
    *mdb->errmsg        = 0;
    mdb->cmd            = get_pool_memory(PM_EMSG); /* get command buffer */
@@ -165,7 +183,7 @@ db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char
    mdb->esc_name       = get_pool_memory(PM_FNAME);
    mdb->esc_path      = get_pool_memory(PM_FNAME);
    mdb->allow_transactions = mult_db_connections;
-   qinsert(&db_list, &mdb->bq);            /* put db in list */
+   db_list->append(mdb);                   /* put db in list */
    V(mutex);
    return mdb;
 }
@@ -278,10 +296,9 @@ db_open_database(JCR *jcr, B_DB *mdb)
    }
 
    if ( dbstat != 0 ) {
-      Mmsg3(&mdb->errmsg, _("Unable to connect to DBI interface.\n"
-                       "Type=%s Database=%s User=%s\n"
-                       "It is probably not running or your password is incorrect.\n"),
-                        mdb->db_driver, mdb->db_name, mdb->db_user);
+      Mmsg3(&mdb->errmsg, _("Unable to connect to DBI interface. Type=%s Database=%s User=%s\n"
+         "Possible causes: SQL server not running; password incorrect; max_connections exceeded.\n"),
+         mdb->db_driver, mdb->db_name, mdb->db_user);
       V(mutex);
       return 0;
    }
@@ -336,7 +353,7 @@ db_close_database(JCR *jcr, B_DB *mdb)
    sql_free_result(mdb);
    mdb->ref_count--;
    if (mdb->ref_count == 0) {
-      qdchain(&mdb->bq);
+      db_list->remove(mdb);
       if (mdb->connected && mdb->db) {
          //sql_close(mdb);
          dbi_shutdown_r(mdb->instance);
@@ -373,10 +390,17 @@ db_close_database(JCR *jcr, B_DB *mdb)
           free(mdb->db_driver);
       }
       free(mdb);
+      if (db_list->size() == 0) {
+         delete db_list;
+         db_list = NULL;
+      }
    }
    V(mutex);
 }
 
+void db_check_backend_thread_safe()
+{ }
+
 void db_thread_cleanup()
 { }
 
@@ -516,7 +540,7 @@ DBI_ROW my_dbi_fetch_row(B_DB *mdb)
          Dmsg4(500, "my_dbi_fetch_row row[%d] field: '%p' in queue: '%p' has value: '%s'\n",
                j, mdb->row[j], mdb->field_get->value, mdb->row[j]);
          // insert in queue to future free
-         qinsert(&dbi_getvalue_list, &mdb->field_get->bq);
+         dbi_getvalue_list->append(mdb->field_get);
       }
       // increment the row number for the next call
       mdb->row_number++;
@@ -692,7 +716,7 @@ void my_dbi_free_result(B_DB *mdb)
     * Using a queue to store all pointer allocate is a good way to free all things
     * when necessary
     */
-   while((f=(DBI_FIELD_GET *)qremove(&dbi_getvalue_list))) {
+   foreach_dlist(f, dbi_getvalue_list) {
       Dmsg2(500, "my_dbi_free_result field value: '%p' in queue: '%p'\n", f->value, f);
       free(f->value);
       free(f);
@@ -728,7 +752,7 @@ const char *my_dbi_strerror(B_DB *mdb)
  */
 int my_dbi_batch_start(JCR *jcr, B_DB *mdb)
 {
-   char *query = "COPY batch FROM STDIN";
+   const char *query = "COPY batch FROM STDIN";
 
    Dmsg0(500, "my_dbi_batch_start started\n");
 
@@ -924,7 +948,7 @@ int my_dbi_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
 
    if (ar->Digest == NULL || ar->Digest[0] == 0) {
-      digest = "0";
+      *digest = '\0';
    } else {
       digest = ar->Digest;
    }
@@ -1208,7 +1232,7 @@ char *my_dbi_getvalue(dbi_result *result, int row_number, unsigned int column_nu
    return buf;
 }
 
-int my_dbi_sql_insert_id(B_DB *mdb, char *table_name)
+static int my_dbi_sequence_last(B_DB *mdb, const char *table_name)
 {
    /*
     Obtain the current value of the sequence that
@@ -1228,8 +1252,8 @@ int my_dbi_sql_insert_id(B_DB *mdb, char *table_name)
     everything else can use the PostgreSQL formula.
    */
 
-   char      sequence[30];
-   uint64_t    id = 0;
+   char sequence[30];
+   uint64_t id = 0;
 
    if (mdb->db_type == SQL_TYPE_POSTGRESQL) {
 
@@ -1251,8 +1275,27 @@ int my_dbi_sql_insert_id(B_DB *mdb, char *table_name)
    return id;
 }
 
+int my_dbi_insert_autokey_record(B_DB *mdb, const char *query, const char *table_name)
+{
+   /*
+    * First execute the insert query and then retrieve the currval.
+    */
+   if (my_dbi_query(mdb, query)) {
+      return 0;
+   }
+
+   mdb->num_rows = sql_affected_rows(mdb);
+   if (mdb->num_rows != 1) {
+      return 0;
+   }
+
+   mdb->changes++;
+
+   return my_dbi_sequence_last(mdb, table_name);
+}
+
 #ifdef HAVE_BATCH_FILE_INSERT
-const char *my_dbi_batch_lock_path_query[4] = {
+const char *my_dbi_batch_lock_path_query[5] = {
    /* Mysql */
    "LOCK TABLES Path write, batch write, Path as p write",
    /* Postgresql */
@@ -1260,9 +1303,12 @@ const char *my_dbi_batch_lock_path_query[4] = {
    /* SQLite */
    "BEGIN",
    /* SQLite3 */
-   "BEGIN"};
+   "BEGIN",
+   /* Ingres */
+   "BEGIN"
+};
 
-const char *my_dbi_batch_lock_filename_query[4] = {
+const char *my_dbi_batch_lock_filename_query[5] = {
    /* Mysql */
    "LOCK TABLES Filename write, batch write, Filename as f write",
    /* Postgresql */
@@ -1270,9 +1316,12 @@ const char *my_dbi_batch_lock_filename_query[4] = {
    /* SQLite */
    "BEGIN",
    /* SQLite3 */
-   "BEGIN"};
+   "BEGIN",
+   /* Ingres */
+   "BEGIN"
+};
 
-const char *my_dbi_batch_unlock_tables_query[4] = {
+const char *my_dbi_batch_unlock_tables_query[5] = {
    /* Mysql */
    "UNLOCK TABLES",
    /* Postgresql */
@@ -1280,20 +1329,12 @@ const char *my_dbi_batch_unlock_tables_query[4] = {
    /* SQLite */
    "COMMIT",
    /* SQLite3 */
-   "COMMIT"};
-
-const char *my_dbi_match[4] = {
-   /* Mysql */
-   "MATCH",
-   /* Postgresql */
-   "~",
-   /* SQLite */
-   "MATCH",
-   /* SQLite3 */
-   "MATCH"
+   "COMMIT",
+   /* Ingres */
+   "COMMIT"
 };
 
-const char *my_dbi_batch_fill_path_query[4] = {
+const char *my_dbi_batch_fill_path_query[5] = {
    /* Mysql */
    "INSERT INTO Path (Path) "
    "SELECT a.Path FROM "
@@ -1311,9 +1352,15 @@ const char *my_dbi_batch_fill_path_query[4] = {
    /* SQLite3 */
    "INSERT INTO Path (Path)"
    " SELECT DISTINCT Path FROM batch"
-   " EXCEPT SELECT Path FROM Path"};
+   " EXCEPT SELECT Path FROM Path",
+   /* Ingres */
+   "INSERT INTO Path (Path) "
+   "SELECT a.Path FROM "
+   "(SELECT DISTINCT Path FROM batch) AS a "
+   "WHERE NOT EXISTS (SELECT Path FROM Path WHERE Path = a.Path) "
+};
 
-const char *my_dbi_batch_fill_filename_query[4] = {
+const char *my_dbi_batch_fill_filename_query[5] = {
    /* Mysql */
    "INSERT INTO Filename (Name) "
    "SELECT a.Name FROM "
@@ -1332,8 +1379,28 @@ const char *my_dbi_batch_fill_filename_query[4] = {
    /* SQLite3 */
    "INSERT INTO Filename (Name)"
    " SELECT DISTINCT Name FROM batch "
-   " EXCEPT SELECT Name FROM Filename"};
+   " EXCEPT SELECT Name FROM Filename",
+   /* Ingres */
+   "INSERT INTO Filename (Name) "
+   "SELECT a.Name FROM "
+   "(SELECT DISTINCT Name FROM batch) as a "
+   "WHERE NOT EXISTS "
+   "(SELECT Name FROM Filename WHERE Name = a.Name)"
+};
 
 #endif /* HAVE_BATCH_FILE_INSERT */
 
+const char *my_dbi_match[5] = {
+   /* Mysql */
+   "MATCH",
+   /* Postgresql */
+   "~",
+   /* SQLite */
+   "MATCH",
+   /* SQLite3 */
+   "MATCH",
+   /* Ingres */
+   "~"
+};
+
 #endif /* HAVE_DBI */