[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