/*
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;
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];
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) &&
}
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 */
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;
}
}
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;
}
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);
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()
{ }
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++;
* 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);
*/
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");
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;
}
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
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) {
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 */
/* 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 */
/* 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 */
/* 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 "
/* 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 "
/* 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 */