Index: cdr/cdr_addon_mysql.c =================================================================== --- cdr/cdr_addon_mysql.c (revision 649) +++ cdr/cdr_addon_mysql.c (working copy) @@ -83,11 +83,12 @@ struct column { char *name; char *cdrname; + char *type; AST_LIST_ENTRY(column) list; }; /* Protected with mysql_lock */ -static AST_LIST_HEAD_NOLOCK_STATIC(columns, column); +static AST_RWLIST_HEAD_STATIC(columns, column); static MYSQL mysql = { { NULL }, }; @@ -149,7 +150,6 @@ static int mysql_log(struct ast_cdr *cdr) { - char sqldesc[128]; char *sql1 = ast_calloc(1, 4096), *sql2 = ast_calloc(1, 2048); int sql1size = 4096, sql2size = 2048; int retries = 5; @@ -204,54 +204,27 @@ ast_log(LOG_ERROR, "Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); } retries--; - if (retries) + if (retries) { goto db_reconnect; - else - ast_log(LOG_ERROR, "Retried to connect fives times, giving up.\n"); + } else { + ast_log(LOG_ERROR, "Retried to connect five times, giving up.\n"); + } } } if (connected) { - MYSQL_ROW row; - MYSQL_RES *result; int column_count = 0; + char *cdrname; + char workspace[2048], *value = NULL, *ptr; + int sql2len; + struct column *entry; snprintf(sql1, sql1size, "INSERT INTO %s (", dbtable ? dbtable->str : "cdr"); strcpy(sql2, ") VALUES ('"); - /* Get table description */ - snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? dbtable->str : "cdr"); - if (mysql_query(&mysql, sqldesc)) { - ast_log(LOG_ERROR, "Unable to query table description!!\n"); - mysql_close(&mysql); - connected = 0; - goto log_exit; - } - - if (!(result = mysql_store_result(&mysql))) { - ast_log(LOG_ERROR, "Unable to query table description!!\n"); - mysql_close(&mysql); - connected = 0; - goto log_exit; - } - - while ((row = mysql_fetch_row(result))) { - struct column *entry; - char *cdrname; - char workspace[2048], *value = NULL, *ptr; - int sql2len; - - ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]); - /* Check for an alias */ - AST_LIST_TRAVERSE(&columns, entry, list) { - /* This would probably be better off as a hash */ - if (!strcasecmp(entry->name, row[0])) - break; - } - - if (entry) { - cdrname = entry->cdrname; - } else if (!strcmp(row[0], "calldate")) { + AST_RWLIST_RDLOCK(&columns); + AST_RWLIST_TRAVERSE(&columns, entry, list) { + if (!strcmp(entry->name, "calldate")) { /*!\note * For some dumb reason, "calldate" used to be formulated using * the datetime the record was posted, rather than the start @@ -270,7 +243,7 @@ cdrname = "start"; } } else { - cdrname = row[0]; + cdrname = entry->cdrname; } /* Construct SQL */ @@ -279,14 +252,14 @@ strcat(sql2, "','"); } - if (strlen(sql1) + 2 + strlen(row[0]) > sql1size) { + if (strlen(sql1) + 2 + strlen(entry->name) > sql1size) { char *tmp = ast_realloc(sql1, sql1size * 2); if (!tmp) goto log_exit; sql1size *= 2; sql1 = tmp; } - strcat(sql1, row[0]); + strcat(sql1, entry->name); /* Need the type and value to determine if we want the raw value or not */ if ((!strcmp(cdrname, "start") || @@ -294,13 +267,13 @@ !strcmp(cdrname, "end") || !strcmp(cdrname, "disposition") || !strcmp(cdrname, "amaflags")) && - (strstr(row[1], "int") || - strstr(row[1], "dec") || - strstr(row[1], "float") || - strstr(row[1], "double") || - strstr(row[1], "real") || - strstr(row[1], "numeric") || - strstr(row[1], "fixed"))) + (strstr(entry->type, "int") || + strstr(entry->type, "dec") || + strstr(entry->type, "float") || + strstr(entry->type, "double") || + strstr(entry->type, "real") || + strstr(entry->type, "numeric") || + strstr(entry->type, "fixed"))) ast_cdr_getvar(cdr, cdrname, &value, workspace, sizeof(workspace), 0, 1); else ast_cdr_getvar(cdr, cdrname, &value, workspace, sizeof(workspace), 0, 0); @@ -329,7 +302,7 @@ sql2[sql2len] = '\0'; } } - mysql_free_result(result); + AST_RWLIST_UNLOCK(&columns); ast_debug(1, "Inserting a CDR record.\n"); if (strlen(sql1) + 3 + strlen(sql2) > sql1size) { @@ -379,8 +352,11 @@ } AST_LIST_UNLOCK(&unload_strings); - while ((entry = AST_LIST_REMOVE_HEAD(&columns, list))) + AST_RWLIST_WRLOCK(&columns); + while ((entry = AST_RWLIST_REMOVE_HEAD(&columns, list))) { ast_free(entry); + } + AST_RWLIST_UNLOCK(&columns); dbport = 0; ast_cdr_unregister(name); @@ -435,6 +411,9 @@ struct column *entry; char *temp; struct ast_str *compat; + MYSQL_ROW row; + MYSQL_RES *result; + char sqldesc[128]; #if MYSQL_VERSION_ID >= 50013 my_bool my_bool_true = 1; #endif @@ -481,24 +460,11 @@ return AST_MODULE_LOAD_FAILURE; /* Check for any aliases */ - while ((entry = AST_LIST_REMOVE_HEAD(&columns, list))) + AST_RWLIST_WRLOCK(&columns); + while ((entry = AST_LIST_REMOVE_HEAD(&columns, list))) { ast_free(entry); - - for (var = ast_variable_browse(cfg, "aliases"); var; var = var->next) { - struct column *entry = ast_calloc(1, sizeof(*entry) + strlen(var->name) + 1 + strlen(var->value) + 1); - if (!entry) - continue; - entry->cdrname = (char *)entry + sizeof(*entry); - entry->name = (char *)entry + sizeof(*entry) + strlen(var->name) + 1; - strcpy(entry->cdrname, var->name); - strcpy(entry->name, var->value); - - AST_LIST_INSERT_TAIL(&columns, entry, list); - ast_log(LOG_NOTICE, "Found an alias from CDR variable %s to DB column %s\n", entry->cdrname, entry->name); } - ast_config_destroy(cfg); - ast_debug(1, "Got hostname of %s\n", hostname->str); ast_debug(1, "Got port of %d\n", dbport); ast_debug(1, "Got a timeout of %d\n", timeout); @@ -535,7 +501,70 @@ connected = 1; records = 0; connect_time = time(NULL); + + /* Get table description */ + snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? dbtable->str : "cdr"); + if (mysql_query(&mysql, sqldesc)) { + ast_log(LOG_ERROR, "Unable to query table description!! Logging disabled.\n"); + mysql_close(&mysql); + connected = 0; + AST_RWLIST_UNLOCK(&columns); + ast_config_destroy(cfg); + return AST_MODULE_LOAD_SUCCESS; + } + + if (!(result = mysql_store_result(&mysql))) { + ast_log(LOG_ERROR, "Unable to query table description!! Logging disabled.\n"); + mysql_close(&mysql); + connected = 0; + AST_RWLIST_UNLOCK(&columns); + ast_config_destroy(cfg); + return AST_MODULE_LOAD_SUCCESS; + } + + while ((row = mysql_fetch_row(result))) { + struct column *entry; + int foundalias = 0; + + ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]); + /* Check for an alias */ + for (var = ast_variable_browse(cfg, "aliases"); var; var = var->next) { + if (strcasecmp(var->value, row[0])) { + continue; + } + + if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(var->name) + 1 + strlen(var->value) + 1 + strlen(row[1]) + 1))) { + continue; + } + + entry->cdrname = (char *)entry + sizeof(*entry); + entry->name = (char *)entry + sizeof(*entry) + strlen(var->name) + 1; + entry->type = (char *)entry + sizeof(*entry) + strlen(var->name) + 1 + strlen(var->value) + 1; + strcpy(entry->cdrname, var->name); + strcpy(entry->name, var->value); + strcpy(entry->type, row[1]); + + AST_LIST_INSERT_TAIL(&columns, entry, list); + ast_log(LOG_NOTICE, "Found an alias from CDR variable %s to DB column %s, type %s\n", entry->cdrname, entry->name, entry->type); + foundalias = 1; + break; + } + + if (!foundalias && (entry = ast_calloc(1, sizeof(*entry) + strlen(row[0]) + 1 + strlen(row[1]) + 1))) { + entry->cdrname = (char *)entry + sizeof(*entry); + entry->name = (char *)entry + sizeof(*entry); + entry->type = (char *)entry + sizeof(*entry) + strlen(row[0]) + 1; + strcpy(entry->name, row[0]); + strcpy(entry->type, row[1]); + + AST_LIST_INSERT_TAIL(&columns, entry, list); + ast_log(LOG_NOTICE, "Found a DB column %s, type %s\n", entry->name, entry->type); + } + } + mysql_free_result(result); } + AST_RWLIST_UNLOCK(&columns); + ast_config_destroy(cfg); res = ast_cdr_register(name, desc, mysql_log); if (res) {