]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/cats/sql.c
fix variable name
[bacula/bacula] / bacula / src / cats / sql.c
index a0cc7899a6bdeefae14fb581c4eaad2381edb6d9..49e9762010fb35ba1743c2396bf137613c67f740 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 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.
 
 uint32_t bacula_db_version = 0;
 
-int db_type = -1;
+int db_type = -1;        /* SQL engine type index */
 
 /* Forward referenced subroutines */
 void print_dashes(B_DB *mdb);
 void print_result(B_DB *mdb);
 
-B_DB *db_init(JCR *jcr, const char *db_driver, const char *db_name, const char *db_user, 
-              const char *db_password, const char *db_address, int db_port, 
+B_DB *db_init(JCR *jcr, const char *db_driver, const char *db_name, const char *db_user,
+              const char *db_password, const char *db_address, int db_port,
               const char *db_socket, int mult_db_connections)
-{              
+{
 #ifdef HAVE_DBI
    char *p;
    if (!db_driver) {
@@ -68,13 +68,15 @@ B_DB *db_init(JCR *jcr, const char *db_driver, const char *db_name, const char *
    if (strlen(db_driver) < 5 || db_driver[3] != ':' || strncasecmp(db_driver, "dbi", 3) != 0) {
       Jmsg0(jcr, M_ABORT, 0, _("Invalid driver type, must be \"dbi:<type>\"\n"));
    }
-   p = (char *)(db_driver + 4);      
+   p = (char *)(db_driver + 4);
    if (strcasecmp(p, "mysql") == 0) {
       db_type = SQL_TYPE_MYSQL;
    } else if (strcasecmp(p, "postgresql") == 0) {
       db_type = SQL_TYPE_POSTGRESQL;
    } else if (strcasecmp(p, "sqlite") == 0) {
       db_type = SQL_TYPE_SQLITE;
+   } else if (strcasecmp(p, "sqlite3") == 0) {
+      db_type = SQL_TYPE_SQLITE3;
    } else {
       Jmsg1(jcr, M_ABORT, 0, _("Unknown database type: %s\n"), p);
    }
@@ -85,14 +87,14 @@ B_DB *db_init(JCR *jcr, const char *db_driver, const char *db_name, const char *
 #elif HAVE_SQLITE
    db_type = SQL_TYPE_SQLITE;
 #elif HAVE_SQLITE3
-   db_type = SQL_TYPE_SQLITE;
+   db_type = SQL_TYPE_SQLITE3;
 #endif
 
    return db_init_database(jcr, db_name, db_user, db_password, db_address,
              db_port, db_socket, mult_db_connections);
 }
 
-dbid_list::dbid_list() 
+dbid_list::dbid_list()
 {
    memset(this, 0, sizeof(dbid_list));
    max_ids = 1000;
@@ -101,8 +103,8 @@ dbid_list::dbid_list()
    PurgedFiles = NULL;
 }
 
-dbid_list::~dbid_list() 
-{ 
+dbid_list::~dbid_list()
+{
    free(DBId);
 }
 
@@ -110,7 +112,7 @@ dbid_list::~dbid_list()
 /*
  * Called here to retrieve an integer from the database
  */
-static int int_handler(void *ctx, int num_fields, char **row)
+int db_int_handler(void *ctx, int num_fields, char **row)
 {
    uint32_t *val = (uint32_t *)ctx;
 
@@ -142,7 +144,21 @@ int db_int64_handler(void *ctx, int num_fields, char **row)
    return 0;
 }
 
-
+/*
+ * Use to build a comma separated list of values from a query. "10,20,30"
+ */
+int db_list_handler(void *ctx, int num_fields, char **row)
+{
+   db_list_ctx *lctx = (db_list_ctx *)ctx;
+   if (num_fields == 1 && row[0]) {
+      if (lctx->list[0]) {
+         pm_strcat(lctx->list, ",");
+      }
+      pm_strcat(lctx->list, row[0]);
+      lctx->count++;
+   }
+   return 0;
+}
 
 /* NOTE!!! The following routines expect that the
  *  calling subroutine sets and clears the mutex
@@ -154,7 +170,7 @@ bool check_tables_version(JCR *jcr, B_DB *mdb)
    const char *query = "SELECT VersionId FROM Version";
 
    bacula_db_version = 0;
-   if (!db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version)) {
+   if (!db_sql_query(mdb, query, db_int_handler, (void *)&bacula_db_version)) {
       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
       return false;
    }
@@ -390,6 +406,41 @@ void db_start_transaction(JCR *jcr, B_DB *mdb)
    }
    db_unlock(mdb);
 #endif
+
+#ifdef HAVE_DBI
+   if (db_type == SQL_TYPE_SQLITE) {
+      if (!mdb->allow_transactions) {
+         return;
+      }
+      db_lock(mdb);
+      /* Allow only 10,000 changes per transaction */
+      if (mdb->transaction && mdb->changes > 10000) {
+         db_end_transaction(jcr, mdb);
+      }
+      if (!mdb->transaction) {
+         //my_sqlite_query(mdb, "BEGIN");  /* begin transaction */
+         db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
+         Dmsg0(400, "Start SQLite transaction\n");
+         mdb->transaction = 1;
+      }
+      db_unlock(mdb);
+   } else if (db_type == SQL_TYPE_POSTGRESQL) {
+      if (!mdb->allow_transactions) {
+         return;
+      }
+      db_lock(mdb);
+      /* Allow only 25,000 changes per transaction */
+      if (mdb->transaction && mdb->changes > 25000) {
+         db_end_transaction(jcr, mdb);
+      }
+      if (!mdb->transaction) {
+         db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
+         Dmsg0(400, "Start PosgreSQL transaction\n");
+         mdb->transaction = 1;
+      }
+      db_unlock(mdb);
+   }
+#endif
 }
 
 void db_end_transaction(JCR *jcr, B_DB *mdb)
@@ -437,6 +488,35 @@ void db_end_transaction(JCR *jcr, B_DB *mdb)
    mdb->changes = 0;
    db_unlock(mdb);
 #endif
+
+#ifdef HAVE_DBI
+   if (db_type == SQL_TYPE_SQLITE) {
+      if (!mdb->allow_transactions) {
+         return;
+      }
+      db_lock(mdb);
+      if (mdb->transaction) {
+         //my_sqlite_query(mdb, "COMMIT"); /* end transaction */
+         db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
+         mdb->transaction = 0;
+         Dmsg1(400, "End SQLite transaction changes=%d\n", mdb->changes);
+      }
+      mdb->changes = 0;
+      db_unlock(mdb);
+   } else if (db_type == SQL_TYPE_POSTGRESQL) {
+      if (!mdb->allow_transactions) {
+         return;
+      }
+      db_lock(mdb);
+      if (mdb->transaction) {
+         db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
+         mdb->transaction = 0;
+         Dmsg1(400, "End PostgreSQL transaction changes=%d\n", mdb->changes);
+      }
+      mdb->changes = 0;
+      db_unlock(mdb);
+   }
+#endif
 }
 
 /*
@@ -495,6 +575,21 @@ void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname)
    Dmsg2(500, "split path=%s file=%s\n", mdb->path, mdb->fname);
 }
 
+/*
+ * Set maximum field length to something reasonable
+ */
+static int max_length(int max_length)
+{
+   int max_len = max_length;
+   /* Sanity check */
+   if (max_len < 0) {
+      max_len = 2;
+   } else if (max_len > 100) {
+      max_len = 100;
+   }
+   return max_len;
+}
+
 /*
  * List dashes as part of header for listing SQL results in a table
  */
@@ -503,6 +598,7 @@ list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
 {
    SQL_FIELD  *field;
    int i, j;
+   int len;
 
    sql_field_seek(mdb, 0);
    send(ctx, "+");
@@ -511,7 +607,8 @@ list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
       if (!field) {
          break;
       }
-      for (j = 0; j < (int)field->max_length + 2; j++) {
+      len = max_length(field->max_length + 2);
+      for (j = 0; j < len; j++) {
          send(ctx, "-");
       }
       send(ctx, "+");
@@ -580,7 +677,8 @@ list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type t
       if (!field) {
          break;
       }
-      bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, field->name);
+      max_len = max_length(field->max_length);
+      bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
       send(ctx, buf);
    }
    send(ctx, "\n");
@@ -595,13 +693,14 @@ list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type t
          if (!field) {
             break;
          }
+         max_len = max_length(field->max_length);
          if (row[i] == NULL) {
-            bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, "NULL");
+            bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
          } else if (IS_NUM(field->type) && !jcr->gui && is_an_integer(row[i])) {
-            bsnprintf(buf, sizeof(buf), " %*s |", (int)field->max_length,
+            bsnprintf(buf, sizeof(buf), " %*s |", max_len,
                       add_commas(row[i], ewc));
          } else {
-            bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, row[i]);
+            bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
          }
          send(ctx, buf);
       }
@@ -644,7 +743,7 @@ bool db_open_batch_connexion(JCR *jcr, B_DB *mdb)
    int multi_db=false;
 
 #ifdef HAVE_BATCH_FILE_INSERT
-   multi_db=true;              /* we force a new connexion only if batch insert is enabled */
+   multi_db=true;               /* we force a new connexion only if batch insert is enabled */
 #endif
 
    if (!jcr->db_batch) {
@@ -674,4 +773,25 @@ bool db_open_batch_connexion(JCR *jcr, B_DB *mdb)
    return true;
 }
 
+/*
+ * !!! WARNING !!! Use this function only when bacula is stopped.
+ * ie, after a fatal signal and before exiting the program
+ * Print information about a B_DB object.
+ */
+void _dbg_print_db(JCR *jcr, FILE *fp)
+{
+   B_DB *mdb = jcr->db;
+
+   if (!mdb) {
+      return;
+   }
+
+   fprintf(fp, "B_DB=%p db_name=%s db_user=%s connected=%i\n",
+           mdb, NPRTB(mdb->db_name), NPRTB(mdb->db_user), mdb->connected);
+   fprintf(fp, "\tcmd=\"%s\" changes=%i\n", NPRTB(mdb->cmd), mdb->changes);
+   if (mdb->lock.valid == RWLOCK_VALID) { 
+      fprintf(fp, "\tRWLOCK=%p w_active=%i w_wait=%i\n", &mdb->lock, mdb->lock.w_active, mdb->lock.w_wait);
+   }
+}
+
 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/