[asterisk-addons-commits] tilghman: trunk r688 - in /trunk: ./ channels/ configs/ res/

SVN commits to the Asterisk addons project asterisk-addons-commits at lists.digium.com
Fri Nov 7 01:04:54 CST 2008


Author: tilghman
Date: Fri Nov  7 01:04:53 2008
New Revision: 688

URL: http://svn.digium.com/view/asterisk-addons?view=rev&rev=688
Log:
Revamp res_config_mysql to allow for multiple read/write handle configurations
within realtime.
(closes issue #13603)
 Reported by: atis
 Patch by: me

Modified:
    trunk/UPGRADE.txt
    trunk/channels/chan_mobile.c
    trunk/configs/res_mysql.conf.sample
    trunk/res/res_config_mysql.c

Modified: trunk/UPGRADE.txt
URL: http://svn.digium.com/view/asterisk-addons/trunk/UPGRADE.txt?view=diff&rev=688&r1=687&r2=688
==============================================================================
--- trunk/UPGRADE.txt (original)
+++ trunk/UPGRADE.txt Fri Nov  7 01:04:53 2008
@@ -1,3 +1,10 @@
+res_config_mysql
+================
+ - A greater variation of database handles has been made available, such that
+   you can now configure realtime mysql to connect to multiple hosts and
+   separate read queries from write queries.  Please familiarize yourself with
+   the sample res_config_mysql.conf, as the new behavior is now specified there.
+
 cdr_addon_mysql
 ===============
  - Module has been completely revamped, with some options in the config file no

Modified: trunk/channels/chan_mobile.c
URL: http://svn.digium.com/view/asterisk-addons/trunk/channels/chan_mobile.c?view=diff&rev=688&r1=687&r2=688
==============================================================================
--- trunk/channels/chan_mobile.c (original)
+++ trunk/channels/chan_mobile.c Fri Nov  7 01:04:53 2008
@@ -568,7 +568,7 @@
 	struct mbl_pvt *pvt;
 	char *dest_dev = NULL;
 	char *dest_num = NULL;
-	int oldformat, group;
+	int oldformat, group = -1;
 
 	if (!data) {
 		ast_log(LOG_WARNING, "Channel requested with no data\n");
@@ -590,13 +590,15 @@
 	if (dest_num)
 		*dest_num++ = 0x00;
 
-	/* Find requested device and make sure its connected. */
+	if (((dest_dev[0] == 'g') || (dest_dev[0] == 'G')) && ((dest_dev[1] >= '0') && (dest_dev[1] <= '9'))) {
+		group = atoi(&dest_dev[1]);
+	}
+
+	/* Find requested device and make sure it's connected. */
 	AST_RWLIST_RDLOCK(&devices);
 	AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
-		if (((dest_dev[0] == 'g') || (dest_dev[0] == 'G')) && ((dest_dev[1] >= '0') && (dest_dev[1] <= '9'))) {
-			group = atoi(dest_dev+1);
-			if (pvt->group == group)
-				break;
+		if (group > -1 && pvt->group == group && pvt->connected && !pvt->owner) {
+			break;
 		} else if (!strcmp(pvt->id, dest_dev)) {
 			break;
 		}
@@ -609,14 +611,14 @@
 	}
 
 	if ((pvt->type == MBL_TYPE_PHONE) && !dest_num) {
-		ast_log(LOG_WARNING, "Cant determine destination number.\n");
+		ast_log(LOG_WARNING, "Can't determine destination number.\n");
 		*cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
 		return NULL;
 	}
 
 	chn = mbl_new(AST_STATE_DOWN, pvt, NULL);
 	if (!chn) {
-		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
+		ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
 		*cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
 		return NULL;
 	}

Modified: trunk/configs/res_mysql.conf.sample
URL: http://svn.digium.com/view/asterisk-addons/trunk/configs/res_mysql.conf.sample?view=diff&rev=688&r1=687&r2=688
==============================================================================
--- trunk/configs/res_mysql.conf.sample (original)
+++ trunk/configs/res_mysql.conf.sample Fri Nov  7 01:04:53 2008
@@ -6,20 +6,29 @@
 ; to the local host is assumed and dbsock is used instead of TCP/IP
 ; to connect to the server.
 ;
-; In addition to a [general] section, this file may also be configured
-; with separate [read] and [write] sections, which permits separation
-; of read-only queries from queries which alter the database.  This
-; enables the use of master and slave replication servers for
-; scalability.
+; Multiple database contexts may be configured, with the caveat that
+; all context names should be unique and must not contain the slash ('/')
+; character.  If you wish to separate reads from writes in your database
+; configuration, you specify the database (NOT HERE, in other files)
+; separated by a slash, read database first.  If your database
+; specification does not contain a slash, the implication is that reads
+; and writes should be performed to the same database.
+;
+; For example, in extconfig.conf, you could specify a line like:
+;    sippeers => mysql,readhost.asterisk/writehost.asterisk,sipfriends
+; and then define the contexts [readhost.asterisk] and [writehost.asterisk]
+; below.
 ;
 ; The requirements parameter is available only in Asterisk 1.6.1 and
-; later and must be present in the [general] context.  It specifies
-; the behavior when a column name is required by the system.  The
-; default behavior is "warn" and simply sends a warning to the logger
-; that the column does not exist (or is of the wrong type or precision).
-; The other two possibilities are "createclose", which adds the column
-; with the right type and length, and "createchar", which adds the
-; column as a char type, with the appropriate length to accept the data.
+; later and must be present in all contexts.  It specifies the behavior
+; when a column name is required by the system.  The default behavior is
+; "warn" and simply sends a warning to the logger that the column does
+; not exist (or is of the wrong type or precision).  The other two
+; possibilities are "createclose", which adds the column with the right
+; type and length, and "createchar", which adds the column as a char
+; type, with the appropriate length to accept the data.  Note that with
+; the MySQL driver, both "createclose" and "createchar" will, on occasion,
+; widen a table column width to meet the requirements specified.
 ;
 [general]
 ;dbhost = 127.0.0.1

Modified: trunk/res/res_config_mysql.c
URL: http://svn.digium.com/view/asterisk-addons/trunk/res/res_config_mysql.c?view=diff&rev=688&r1=687&r2=688
==============================================================================
--- trunk/res/res_config_mysql.c (original)
+++ trunk/res/res_config_mysql.c Fri Nov  7 01:04:53 2008
@@ -52,10 +52,14 @@
 #include <asterisk/options.h>
 #include <asterisk/cli.h>
 #include <asterisk/utils.h>
+#include <asterisk/threadstorage.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <mysql/mysql.h>
 #include <mysql/mysql_version.h>
 #include <mysql/errmsg.h>
@@ -64,7 +68,18 @@
 #define	READHANDLE	0
 #define	WRITEHANDLE	1
 
-static struct mysql_conn {
+AST_THREADSTORAGE(sql_buf);
+AST_THREADSTORAGE(sql2_buf);
+AST_THREADSTORAGE(find_buf);
+AST_THREADSTORAGE(scratch_buf);
+AST_THREADSTORAGE(modify_buf);
+AST_THREADSTORAGE(modify2_buf);
+AST_THREADSTORAGE(modify3_buf);
+
+enum requirements { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR };
+
+struct mysql_conn {
+	AST_LIST_ENTRY(mysql_conn) list;
 	ast_mutex_t	lock;
 	MYSQL       handle;
 	char        host[50];
@@ -75,7 +90,9 @@
 	int         port;
 	int         connected;
 	time_t      connect_time;
-} dbread, dbwrite;
+	enum requirements requirements;
+	char        unique_name[0];
+};
 
 struct columns {
 	char *name;
@@ -90,10 +107,12 @@
 	ast_mutex_t lock;
 	AST_LIST_HEAD_NOLOCK(mysql_columns, columns) columns;
 	AST_LIST_ENTRY(tables) list;
+	struct mysql_conn *database;
 	char name[0];
 };
 
 static AST_LIST_HEAD_STATIC(mysql_tables, tables);
+static AST_LIST_HEAD_STATIC(databases, mysql_conn);
 
 static int parse_config(int reload);
 static int mysql_reconnect(struct mysql_conn *conn);
@@ -101,17 +120,44 @@
 static char *handle_cli_realtime_mysql_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static int load_mysql_config(struct ast_config *config, const char *category, struct mysql_conn *conn);
 static int require_mysql(const char *database, const char *tablename, va_list ap);
-
-static enum { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR } requirements = RQ_WARN;
+static int internal_require(const char *database, const char *table, ...) attribute_sentinel;
 
 static struct ast_cli_entry cli_realtime_mysql_status[] = {
 	AST_CLI_DEFINE(handle_cli_realtime_mysql_status, "Shows connection information for the MySQL RealTime driver"),
 	AST_CLI_DEFINE(handle_cli_realtime_mysql_cache, "Shows cached tables within the MySQL realtime driver"),
 };
 
-AST_THREADSTORAGE(sql_buf);
-AST_THREADSTORAGE(where_buf);
-AST_THREADSTORAGE(escapebuf_buf);
+static struct mysql_conn *find_database(const char *database, int for_write)
+{
+	char *whichdb;
+	const char *ptr;
+	struct mysql_conn *cur;
+
+	if ((ptr = strchr(database, '/'))) {
+		/* Multiple databases encoded within string */
+		if (for_write) {
+			whichdb = ast_strdupa(ptr + 1);
+		} else {
+			whichdb = alloca(ptr - database + 1);
+			strncpy(whichdb, database, ptr - database);
+			whichdb[ptr - database] = '\0';
+		}
+	} else {
+		whichdb = ast_strdupa(database);
+	}
+
+	AST_LIST_LOCK(&databases);
+	AST_LIST_TRAVERSE(&databases, cur, list) {
+		if (!strcmp(cur->unique_name, whichdb)) {
+			ast_mutex_lock(&cur->lock);
+			break;
+		}
+	}
+	AST_LIST_UNLOCK(&databases);
+	return cur;
+}
+
+#define release_database(a)	ast_mutex_unlock(&(a)->lock)
 
 static int internal_require(const char *database, const char *table, ...)
 {
@@ -135,20 +181,26 @@
 	ast_free(table);
 }
 
-static struct tables *find_table(const char *tablename)
+static struct tables *find_table(const char *database, const char *tablename)
 {
 	struct columns *column;
 	struct tables *table;
-	struct ast_str *sql = ast_str_create(30);
+	struct ast_str *sql = ast_str_thread_get(&find_buf, 30);
 	char *fname, *ftype, *flen, *fdflt, *fnull;
+	struct mysql_conn *dbh;
 	MYSQL_RES *result;
 	MYSQL_ROW row;
+
+	if (!(dbh = find_database(database, 1))) {
+		return NULL;
+	}
 
 	AST_LIST_LOCK(&mysql_tables);
 	AST_LIST_TRAVERSE(&mysql_tables, table, list) {
 		if (!strcasecmp(table->name, tablename)) {
 			ast_mutex_lock(&table->lock);
 			AST_LIST_UNLOCK(&mysql_tables);
+			release_database(dbh);
 			return table;
 		}
 	}
@@ -156,31 +208,31 @@
 	/* Not found, scan the table */
 	ast_str_set(&sql, 0, "DESC %s", tablename);
 
-	ast_mutex_lock(&dbread.lock);
-	if (!mysql_reconnect(&dbread)) {
-		ast_mutex_unlock(&dbread.lock);
+	if (!mysql_reconnect(dbh)) {
+		release_database(dbh);
 		AST_LIST_UNLOCK(&mysql_tables);
 		return NULL;
 	}
 
-	if (mysql_real_query(&dbread.handle, sql->str, sql->used)) {
-		ast_log(LOG_ERROR, "Failed to query database columns: %s\n", mysql_error(&dbread.handle));
+	if (mysql_real_query(&dbh->handle, sql->str, sql->used)) {
+		ast_log(LOG_ERROR, "Failed to query database columns: %s\n", mysql_error(&dbh->handle));
+		release_database(dbh);
 		AST_LIST_UNLOCK(&mysql_tables);
-		ast_mutex_unlock(&dbread.lock);
 		return NULL;
 	}
 
 	if (!(table = ast_calloc(1, sizeof(*table) + strlen(tablename) + 1))) {
 		ast_log(LOG_ERROR, "Unable to allocate memory for new table structure\n");
+		release_database(dbh);
 		AST_LIST_UNLOCK(&mysql_tables);
-		ast_mutex_unlock(&dbread.lock);
 		return NULL;
 	}
 	strcpy(table->name, tablename); /* SAFE */
+	table->database = dbh;
 	ast_mutex_init(&table->lock);
 	AST_LIST_HEAD_INIT_NOLOCK(&table->columns);
 
-	if ((result = mysql_store_result(&dbread.handle))) {
+	if ((result = mysql_store_result(&dbh->handle))) {
 		while ((row = mysql_fetch_row(result))) {
 			fname = row[0];
 			ftype = row[1];
@@ -195,8 +247,8 @@
 			if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + strlen(fdflt) + 3))) {
 				ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", tablename, fname);
 				destroy_table(table);
+				release_database(dbh);
 				AST_LIST_UNLOCK(&mysql_tables);
-				ast_mutex_unlock(&dbread.lock);
 				return NULL;
 			}
 
@@ -219,11 +271,18 @@
 		mysql_free_result(result);
 	}
 
-	ast_mutex_unlock(&dbread.lock);
 	AST_LIST_INSERT_TAIL(&mysql_tables, table, list);
 	ast_mutex_lock(&table->lock);
 	AST_LIST_UNLOCK(&mysql_tables);
+	release_database(dbh);
 	return table;
+}
+
+static void release_table(struct tables *table)
+{
+	if (table) {
+		ast_mutex_unlock(&table->lock);
+	}
 }
 
 static struct columns *find_column(struct tables *table, const char *colname)
@@ -241,20 +300,27 @@
 
 static struct ast_variable *realtime_mysql(const char *database, const char *table, va_list ap)
 {
+	struct mysql_conn *dbh;
 	MYSQL_RES *result;
 	MYSQL_ROW row;
 	MYSQL_FIELD *fields;
 	int numFields, i, valsz;
-	char sql[512];
-	char buf[511]; /* Keep this size uneven as it is 2n+1. */
+	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
+	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
 	char *stringp;
 	char *chunk;
 	char *op;
 	const char *newparam, *newval;
 	struct ast_variable *var=NULL, *prev=NULL;
 
+	if (!(dbh = find_database(database, 0))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: %s\n", database);
+		return NULL;
+	}
+
 	if (!table) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
+		release_database(dbh);
 		return NULL;
 	}
 
@@ -263,13 +329,13 @@
 	newval = va_arg(ap, const char *);
 	if (!newparam || !newval)  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
+		release_database(dbh);
 		return NULL;
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&dbread.lock);
-	if (!mysql_reconnect(&dbread)) {
-		ast_mutex_unlock(&dbread.lock);
+	if (!mysql_reconnect(dbh)) {
+		release_database(dbh);
 		return NULL;
 	}
 
@@ -281,35 +347,31 @@
 	else 
 		op = "";
 
-	if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
-		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
-	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf);
+	ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+	mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf->str);
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if (!strchr(newparam, ' ')) 
 			op = " ="; 
 		else
 			op = "";
-		if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
-			valsz = (sizeof(buf) - 1) / 2;
-		mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, buf);
+		ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+		mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, buf->str);
 	}
 	va_end(ap);
 
-	ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", sql);
+	ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", sql->str);
 
 	/* Execution. */
-	if (mysql_real_query(&dbread.handle, sql, strlen(sql))) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "MySQL RealTime: Query: %s\n", sql);
-		ast_debug(1, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbread.handle));
-		ast_mutex_unlock(&dbread.lock);
-		return NULL;
-	}
-
-	if ((result = mysql_store_result(&dbread.handle))) {
+	if (mysql_real_query(&dbh->handle, sql->str, sql->used)) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		release_database(dbh);
+		return NULL;
+	}
+
+	if ((result = mysql_store_result(&dbh->handle))) {
 		numFields = mysql_num_fields(result);
 		fields = mysql_fetch_fields(result);
 
@@ -332,10 +394,10 @@
 			}
 		}
 	} else {
-		ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
-	}
-
-	ast_mutex_unlock(&dbread.lock);
+		ast_debug(1, "MySQL RealTime: Could not find any rows in table %s.\n", table);
+	}
+
+	release_database(dbh);
 	mysql_free_result(result);
 
 	return var;
@@ -343,12 +405,13 @@
 
 static struct ast_config *realtime_multi_mysql(const char *database, const char *table, va_list ap)
 {
+	struct mysql_conn *dbh;
 	MYSQL_RES *result;
 	MYSQL_ROW row;
 	MYSQL_FIELD *fields;
 	int numFields, i, valsz;
-	char sql[512];
-	char buf[511]; /* Keep this size uneven as it is 2n+1. */
+	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
+	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
 	const char *initfield = NULL;
 	char *stringp;
 	char *chunk;
@@ -358,15 +421,21 @@
 	struct ast_config *cfg = NULL;
 	struct ast_category *cat = NULL;
 
+	if (!(dbh = find_database(database, 0))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s'\n", database);
+		return NULL;
+	}
+
 	if (!table) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
+		release_database(dbh);
 		return NULL;
 	}
 	
-	cfg = ast_config_new();
-	if (!cfg) {
+	if (!(cfg = ast_config_new())) {
 		/* If I can't alloc memory at this point, why bother doing anything else? */
 		ast_log(LOG_WARNING, "Out of memory!\n");
+		release_database(dbh);
 		return NULL;
 	}
 
@@ -376,6 +445,7 @@
 	if (!newparam || !newval)  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
 		ast_config_destroy(cfg);
+		release_database(dbh);
 		return NULL;
 	}
 
@@ -385,9 +455,8 @@
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&dbread.lock);
-	if (!mysql_reconnect(&dbread)) {
-		ast_mutex_unlock(&dbread.lock);
+	if (!mysql_reconnect(dbh)) {
+		release_database(dbh);
 		ast_config_destroy(cfg);
 		return NULL;
 	}
@@ -400,38 +469,34 @@
 	else
 		op = "";
 
-	if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
-		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
-	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf);
+	ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+	mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf->str);
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if (!strchr(newparam, ' ')) op = " ="; else op = "";
-		if ((valsz = strlen(newval)) * 2 + 1 > sizeof(buf))
-			valsz = (sizeof(buf) - 1) / 2;
-		mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, buf);
+		ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+		mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, buf->str);
 	}
 
 	if (initfield) {
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
+		ast_str_append(&sql, 0, " ORDER BY %s", initfield);
 	}
 
 	va_end(ap);
 
-	ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", sql);
+	ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", sql->str);
 
 	/* Execution. */
-	if (mysql_real_query(&dbread.handle, sql, strlen(sql))) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "MySQL RealTime: Query: %s\n", sql);
-		ast_debug(1, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbread.handle));
-		ast_mutex_unlock(&dbread.lock);
+	if (mysql_real_query(&dbh->handle, sql->str, sql->used)) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		release_database(dbh);
 		ast_config_destroy(cfg);
 		return NULL;
 	}
 
-	if ((result = mysql_store_result(&dbread.handle))) {
+	if ((result = mysql_store_result(&dbh->handle))) {
 		numFields = mysql_num_fields(result);
 		fields = mysql_fetch_fields(result);
 
@@ -458,10 +523,10 @@
 			ast_category_append(cfg, cat);
 		}
 	} else {
-		ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
-	}
-
-	ast_mutex_unlock(&dbread.lock);
+		ast_debug(1, "MySQL RealTime: Could not find any rows in table %s.\n", table);
+	}
+
+	release_database(dbh);
 	mysql_free_result(result);
 
 	return cfg;
@@ -469,32 +534,35 @@
 
 static int update_mysql(const char *database, const char *tablename, const char *keyfield, const char *lookup, va_list ap)
 {
+	struct mysql_conn *dbh;
 	my_ulonglong numrows;
 	int valsz;
 	const char *newparam, *newval;
-	struct ast_str *sql = ast_str_create(100), *buf = ast_str_create(513);
+	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&scratch_buf, 100);
 	struct tables *table;
 	struct columns *column = NULL;
 
+	if (!(dbh = find_database(database, 1))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s'.\n", database);
+		return -1;
+	}
+		
 	if (!tablename) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
-		ast_free(sql);
-		ast_free(buf);
-		return -1;
-	}
-
-	if (!(table = find_table(tablename))) {
+		release_database(dbh);
+		return -1;
+	}
+
+	if (!(table = find_table(database, tablename))) {
 		ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
-		ast_free(sql);
-		ast_free(buf);
+		release_database(dbh);
 		return -1;
 	}
 
 	if (!(column = find_column(table, keyfield))) {
 		ast_log(LOG_ERROR, "MySQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", keyfield, tablename);
-		ast_mutex_unlock(&table->lock);
-		ast_free(sql);
-		ast_free(buf);
+		release_table(table);
+		release_database(dbh);
 		return -1;
 	}
 
@@ -503,43 +571,36 @@
 	newval = va_arg(ap, const char *);
 	if (!newparam || !newval)  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
-		ast_mutex_unlock(&table->lock);
-		ast_free(sql);
-		ast_free(buf);
+		release_table(table);
+		release_database(dbh);
 		return -1;
 	}
 
 	/* Check that the column exists in the table */
 	if (!(column = find_column(table, newparam))) {
 		ast_log(LOG_ERROR, "MySQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
-		ast_mutex_unlock(&table->lock);
-		ast_free(sql);
-		ast_free(buf);
+		release_table(table);
+		release_database(dbh);
 		return -1;
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&dbwrite.lock);
-	if (!mysql_reconnect(&dbwrite)) {
-		ast_mutex_unlock(&table->lock);
-		ast_mutex_unlock(&dbwrite.lock);
-		ast_free(sql);
-		ast_free(buf);
+	if (!mysql_reconnect(dbh)) {
+		release_table(table);
+		release_database(dbh);
 		return -1;
 	}
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if ((valsz = strlen(newval)) * 2 + 1 > buf->len) {
-		ast_str_make_space(&buf, valsz * 2 + 1);
-	}
-	mysql_real_escape_string(&dbwrite.handle, buf->str, newval, valsz);
+	ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+	mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
 	ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, buf->str);
 
 	/* If the column length isn't long enough, give a chance to lengthen it. */
 	if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-		internal_require(database, tablename, newparam, RQ_CHAR, buf->used);
+		internal_require(database, tablename, newparam, RQ_CHAR, buf->used, SENTINEL);
 	}
 
 	while ((newparam = va_arg(ap, const char *))) {
@@ -551,44 +612,34 @@
 			continue;
 		}
 
-		if ((valsz = strlen(newval)) * 2 + 1 > buf->len) {
-			ast_str_make_space(&buf, valsz * 2 + 1);
-		}
-		mysql_real_escape_string(&dbwrite.handle, buf->str, newval, valsz);
+		ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+		mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
 		ast_str_append(&sql, 0, ", %s = '%s'", newparam, buf->str);
 
 		/* If the column length isn't long enough, give a chance to lengthen it. */
 		if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-			internal_require(database, tablename, newparam, RQ_CHAR, buf->used);
+			internal_require(database, tablename, newparam, RQ_CHAR, buf->used, SENTINEL);
 		}
 	}
 	va_end(ap);
-	ast_mutex_unlock(&table->lock);
-
-	if ((valsz = strlen(lookup)) * 2 + 1 > buf->len) {
-		ast_str_make_space(&buf, valsz * 2 + 1);
-	}
-	mysql_real_escape_string(&dbwrite.handle, buf->str, lookup, valsz);
+
+	ast_str_make_space(&buf, (valsz = strlen(lookup)) * 2 + 1);
+	mysql_real_escape_string(&dbh->handle, buf->str, lookup, valsz);
 	ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, buf->str);
 
 	ast_debug(1, "MySQL RealTime: Update SQL: %s\n", sql->str);
 
 	/* Execution. */
-	if (mysql_real_query(&dbwrite.handle, sql->str, sql->used)) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "MySQL RealTime: Query: %s\n", sql->str);
-		ast_debug(1, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbwrite.handle));
-		ast_mutex_unlock(&dbwrite.lock);
-		ast_free(sql);
-		ast_free(buf);
-		return -1;
-	}
-
-	ast_free(sql);
-	ast_free(buf);
-
-	numrows = mysql_affected_rows(&dbwrite.handle);
-	ast_mutex_unlock(&dbwrite.lock);
+	if (mysql_real_query(&dbh->handle, sql->str, sql->used)) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		release_table(table);
+		release_database(dbh);
+		return -1;
+	}
+
+	numrows = mysql_affected_rows(&dbh->handle);
+	release_table(table);
+	release_database(dbh);
 
 	ast_debug(1, "MySQL RealTime: Updated %llu rows on table: %s\n", numrows, tablename);
 
@@ -607,16 +658,17 @@
 		if ((size = strlen(var)) * 2 + 1 > (buf)->len) { \
 			ast_str_make_space(&(buf), size * 2 + 1); \
 		} \
-		mysql_real_escape_string(&dbwrite.handle, (buf)->str, var, size); \
+		mysql_real_escape_string(&dbh->handle, (buf)->str, var, size); \
 	} while (0)
 
 static int update2_mysql(const char *database, const char *tablename, va_list ap)
 {
+	struct mysql_conn *dbh;
 	my_ulonglong numrows;
 	int first = 1;
 	const char *newparam, *newval;
-	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&escapebuf_buf, 100);
-	struct ast_str *where = ast_str_thread_get(&where_buf, 100);
+	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&scratch_buf, 100);
+	struct ast_str *where = ast_str_thread_get(&sql2_buf, 100);
 	struct tables *table;
 	struct columns *column = NULL;
 
@@ -625,12 +677,20 @@
 		return -1;
 	}
 
-	if (!(table = find_table(tablename))) {
+	if (!(dbh = find_database(database, 1))) {
+		ast_log(LOG_ERROR, "Invalid database specified: %s\n", database);
+		return -1;
+	}
+
+	if (!(table = find_table(database, tablename))) {
 		ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
+		release_database(dbh);
 		return -1;
 	}
 
 	if (!sql || !buf || !where) {
+		release_database(dbh);
+		release_table(table);
 		return -1;
 	}
 
@@ -638,22 +698,23 @@
 	ast_str_set(&where, 0, "WHERE");
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&dbwrite.lock);
-	if (!mysql_reconnect(&dbwrite)) {
-		ast_mutex_unlock(&table->lock);
-		ast_mutex_unlock(&dbwrite.lock);
+	if (!mysql_reconnect(dbh)) {
+		release_table(table);
+		release_database(dbh);
 		return -1;
 	}
 
 	while ((newparam = va_arg(ap, const char *))) {
 		if (!(column = find_column(table, newparam))) {
 			ast_log(LOG_ERROR, "Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
-			ast_mutex_unlock(&table->lock);
+			release_table(table);
+			release_database(dbh);
 			return -1;
 		}
 		if (!(newval = va_arg(ap, const char *))) {
 			ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
-			ast_mutex_unlock(&table->lock);
+			release_table(table);
+			release_database(dbh);
 			return -1;
 		}
 		ESCAPE_STRING(buf, newval);
@@ -662,7 +723,7 @@
 
 		/* If the column length isn't long enough, give a chance to lengthen it. */
 		if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-			internal_require(database, tablename, newparam, RQ_CHAR, buf->used);
+			internal_require(database, tablename, newparam, RQ_CHAR, buf->used, SENTINEL);
 		}
 	}
 
@@ -670,7 +731,8 @@
 	while ((newparam = va_arg(ap, const char *))) {
 		if (!(newval = va_arg(ap, const char *))) {
 			ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
-			ast_mutex_unlock(&table->lock);
+			release_table(table);
+			release_database(dbh);
 			return -1;
 		}
 
@@ -685,27 +747,26 @@
 
 		/* If the column length isn't long enough, give a chance to lengthen it. */
 		if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-			internal_require(database, tablename, newparam, RQ_CHAR, strlen(newval));
+			internal_require(database, tablename, newparam, RQ_CHAR, strlen(newval), SENTINEL);
 		}
 	}
 	va_end(ap);
-	ast_mutex_unlock(&table->lock);
+	release_table(table);
 
 	ast_str_append(&sql, 0, " %s", where->str);
 
 	ast_debug(1, "MySQL RealTime: Update SQL: %s\n", sql->str);
 
 	/* Execution. */
-	if (mysql_real_query(&dbwrite.handle, sql->str, sql->used)) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "MySQL RealTime: Query: %s\n", sql->str);
-		ast_debug(1, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbwrite.handle));
-		ast_mutex_unlock(&dbwrite.lock);
-		return -1;
-	}
-
-	numrows = mysql_affected_rows(&dbwrite.handle);
-	ast_mutex_unlock(&dbwrite.lock);
+	if (mysql_real_query(&dbh->handle, sql->str, sql->used)) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		release_table(table);
+		release_database(dbh);
+		return -1;
+	}
+
+	numrows = mysql_affected_rows(&dbh->handle);
+	release_database(dbh);
 
 	ast_debug(1, "MySQL RealTime: Updated %llu rows on table: %s\n", numrows, tablename);
 
@@ -720,16 +781,22 @@
  
 static int store_mysql(const char *database, const char *table, va_list ap)
 {
+	struct mysql_conn *dbh;
 	my_ulonglong insertid;
-	char sql[512];
-	char buf[511]; /* Keep this size uneven as it is 2n+1. */
-	char fields[512];
-	char values[512];
+	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
+	struct ast_str *sql2 = ast_str_thread_get(&sql2_buf, 16);
+	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
 	int valsz;
 	const char *newparam, *newval;
 
+	if (!(dbh = find_database(database, 1))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s'.\n", database);
+		return -1;
+	}
+
 	if (!table) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
+		release_database(dbh);
 		return -1;
 	}
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
@@ -737,52 +804,51 @@
 	newval = va_arg(ap, const char *);
 	if (!newparam || !newval)  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime storage requires at least 1 parameter and 1 value to search on.\n");
+		release_database(dbh);
 		return -1;
 	}
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&dbwrite.lock);
-	if (!mysql_reconnect(&dbwrite)) {
-		ast_mutex_unlock(&dbwrite.lock);
+	if (!mysql_reconnect(dbh)) {
+		release_database(dbh);
 		return -1;
 	}
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 		If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-	if ((valsz = strlen(newval)) * 2 + 1 > sizeof(buf))
-		valsz = (sizeof(buf) - 1) / 2;
-	if (newval) {
-		mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
-	} else { 
-		buf[0] = '\0';
-	}
-	snprintf(fields, sizeof(fields), "%s", newparam);
-	snprintf(values, sizeof(values), "'%s'", buf);
+	ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+	mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
+
+	ast_str_set(&sql, 0, "INSERT INTO %s (%s", table, newparam);
+	ast_str_set(&sql2, 0, ") VALUES ('%s'", buf->str);
+
+	internal_require(database, table, newparam, RQ_CHAR, valsz, SENTINEL);
+
 	while ((newparam = va_arg(ap, const char *))) {
-		newval = va_arg(ap, const char *);
-		if (newval) {
-			if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
-				valsz = (sizeof(buf) - 1) / 2;
-			mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
+		if ((newval = va_arg(ap, const char *))) {
+			ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+			mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
 		} else {
-			buf[0] = '\0';
-		}
-		snprintf(fields + strlen(fields), sizeof(fields), ", %s", newparam);
-		snprintf(values + strlen(values), sizeof(values), ", '%s'", buf);
+			valsz = 0;
+			ast_str_reset(buf);
+		}
+		if (internal_require(database, table, newparam, RQ_CHAR, valsz, SENTINEL) == 0) {
+			ast_str_append(&sql, 0, ", %s", newparam);
+			ast_str_append(&sql2, 0, ", '%s'", buf->str);
+		}
 	}
 	va_end(ap);
-	snprintf(sql, sizeof(sql), "INSERT into %s (%s) values (%s)", table, fields, values);
-	ast_debug(1,"MySQL RealTime: Insert SQL: %s\n", sql);
+	ast_str_append(&sql, 0, "%s)", sql2->str);
+	ast_debug(1,"MySQL RealTime: Insert SQL: %s\n", sql->str);
 
 	/* Execution. */
-	if (mysql_real_query(&dbwrite.handle, sql, strlen(sql))) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "MySQL RealTime: Query: %s\n", sql);
-		ast_debug(1, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbwrite.handle));
-		ast_mutex_unlock(&dbwrite.lock);
-		return -1;
-	}
-
-	insertid = mysql_insert_id(&dbwrite.handle);
-	ast_mutex_unlock(&dbwrite.lock);
+	if (mysql_real_query(&dbh->handle, sql->str, sql->used)) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		release_database(dbh);
+		return -1;
+	}
+
+	/*!\note The return value is non-portable and may change in future versions. */
+	insertid = mysql_insert_id(&dbh->handle);
+	release_database(dbh);
 
 	ast_debug(1, "MySQL RealTime: row inserted on table: %s, id: %llu\n", table, insertid);
 
@@ -796,14 +862,21 @@
 
 static int destroy_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 {
+	struct mysql_conn *dbh;
 	my_ulonglong numrows;
-	char sql[512];
-	char buf[511]; /* Keep this size uneven as it is 2n+1. */
+	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
+	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
 	int valsz;
 	const char *newparam, *newval;
 
+	if (!(dbh = find_database(database, 1))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s'.\n", database);
+		return -1;
+	}
+
 	if (!table) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
+		release_database(dbh);
 		return -1;
 	}
 
@@ -812,45 +885,40 @@
 	newval = va_arg(ap, const char *);*/
 	if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime destroying requires at least 1 parameter and 1 value to search on.\n");
+		release_database(dbh);
 		return -1;
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&dbwrite.lock);
-	if (!mysql_reconnect(&dbwrite)) {
-		ast_mutex_unlock(&dbwrite.lock);
+	if (!mysql_reconnect(dbh)) {
+		release_database(dbh);
 		return -1;
 	}
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-
-	if ((valsz = strlen (lookup)) * 2 + 1 > sizeof(buf))
-		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&dbwrite.handle, buf, lookup, valsz);
-	snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s'", table, keyfield, buf);
+	ast_str_make_space(&buf, (valsz = strlen(lookup)) * 2 + 1);
+	mysql_real_escape_string(&dbh->handle, buf->str, lookup, valsz);
+	ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, keyfield, buf->str);
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
-		if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
-			valsz = (sizeof(buf) - 1) / 2;
-		mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s = '%s'", newparam, buf);
+		ast_str_make_space(&buf, (valsz = strlen(newval)) * 2 + 1);
+		mysql_real_escape_string(&dbh->handle, buf->str, newval, valsz);
+		ast_str_append(&sql, 0, " AND %s = '%s'", newparam, buf->str);
 	}
 	va_end(ap);
 
-	ast_debug(1, "MySQL RealTime: Delete SQL: %s\n", sql);
+	ast_debug(1, "MySQL RealTime: Delete SQL: %s\n", sql->str);
 
 	/* Execution. */
-	if (mysql_real_query(&dbwrite.handle, sql, strlen(sql))) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "MySQL RealTime: Query: %s\n", sql);
-		ast_debug(1, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbwrite.handle));
-		ast_mutex_unlock(&dbwrite.lock);
-		return -1;
-	}
-
-	numrows = mysql_affected_rows(&dbwrite.handle);
-	ast_mutex_unlock(&dbwrite.lock);
+	if (mysql_real_query(&dbh->handle, sql->str, sql->used)) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		release_database(dbh);
+		return -1;
+	}
+
+	numrows = mysql_affected_rows(&dbh->handle);
+	release_database(dbh);
 
 	ast_debug(1, "MySQL RealTime: Deleted %llu rows on table: %s\n", numrows, table);
 
@@ -865,43 +933,46 @@
  
 static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *unused, const char *who_asked)
 {
+	struct mysql_conn *dbh;
 	MYSQL_RES *result;
 	MYSQL_ROW row;
 	my_ulonglong num_rows;
 	struct ast_variable *new_v;
 	struct ast_category *cur_cat;
-	char sql[250] = "";
+	struct ast_str *sql = ast_str_thread_get(&sql_buf, 200);
 	char last[80] = "";
 	int last_cat_metric = 0;
 
 	ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
-	last[0] = '\0';
 
 	if (!file || !strcmp(file, RES_CONFIG_MYSQL_CONF)) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Cannot configure myself.\n");
 		return NULL;
 	}
 
-	snprintf(sql, sizeof(sql), "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=0 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id", table, file);
-
-	ast_debug(1, "MySQL RealTime: Static SQL: %s\n", sql);
+	if (!(dbh = find_database(database, 0))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s'\n", database);
+		return NULL;
+	}
+
+	ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=1 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id", table, file);
+
+	ast_debug(1, "MySQL RealTime: Static SQL: %s\n", sql->str);
 
 	/* We now have our complete statement; Lets connect to the server and execute it. */
-	ast_mutex_lock(&dbread.lock);
-	if (!mysql_reconnect(&dbread)) {
-		ast_mutex_unlock(&dbread.lock);
-		return NULL;
-	}
-
-	if (mysql_real_query(&dbread.handle, sql, strlen(sql))) {

[... 784 lines stripped ...]



More information about the asterisk-addons-commits mailing list