[asterisk-addons-commits] tilghman: trunk r644 - /trunk/res/res_config_mysql.c

SVN commits to the Asterisk addons project asterisk-addons-commits at lists.digium.com
Thu Jun 12 22:55:26 CDT 2008


Author: tilghman
Date: Thu Jun 12 22:55:23 2008
New Revision: 644

URL: http://svn.digium.com/view/asterisk-addons?view=rev&rev=644
Log:
Also alter columns if the requirements type allows it (rather than just adding columns)

Modified:
    trunk/res/res_config_mysql.c

Modified: trunk/res/res_config_mysql.c
URL: http://svn.digium.com/view/asterisk-addons/trunk/res/res_config_mysql.c?view=diff&rev=644&r1=643&r2=644
==============================================================================
--- trunk/res/res_config_mysql.c (original)
+++ trunk/res/res_config_mysql.c Thu Jun 12 22:55:23 2008
@@ -80,6 +80,8 @@
 struct columns {
 	char *name;
 	char *type;
+	char *dflt;
+	char null;
 	int len;
 	AST_LIST_ENTRY(columns) list;
 };
@@ -99,7 +101,7 @@
 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);
 
-enum { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR } requirements;
+static enum { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR } requirements = RQ_WARN;
 
 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"),
@@ -123,7 +125,7 @@
 	struct columns *column;
 	struct tables *table;
 	struct ast_str *sql = ast_str_create(30);
-	char *fname, *ftype, *flen;
+	char *fname, *ftype, *flen, *fdflt, *fnull;
 	MYSQL_RES *result;
 	MYSQL_ROW row;
 
@@ -167,9 +169,15 @@
 		while ((row = mysql_fetch_row(result))) {
 			fname = row[0];
 			ftype = row[1];
+			fnull = row[2];
+			fdflt = row[4];
 			ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
 
-			if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + 2))) {
+			if (fdflt == NULL) {
+				fdflt = "";
+			}
+
+			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);
 				AST_LIST_UNLOCK(&mysql_tables);
@@ -186,8 +194,11 @@
 
 			column->name = (char *)column + sizeof(*column);
 			column->type = (char *)column + sizeof(*column) + strlen(fname) + 1;
+			column->dflt = (char *)column + sizeof(*column) + strlen(fname) + 1 + strlen(ftype) + 1;
 			strcpy(column->name, fname);
 			strcpy(column->type, ftype);
+			strcpy(column->dflt, fdflt);
+			column->null = (strcmp(fnull, "YES") == 0 ? 1 : 0);
 			AST_LIST_INSERT_TAIL(&table->columns, column, list);
 		}
 		mysql_free_result(result);
@@ -533,6 +544,7 @@
 		ast_str_append(&sql, 0, ", %s = '%s'", newparam, buf->str);
 	}
 	va_end(ap);
+	ast_mutex_unlock(&table->lock);
 
 	if ((valsz = strlen(lookup)) * 2 + 1 > buf->len) {
 		ast_str_make_space(&buf, valsz * 2 + 1);
@@ -548,7 +560,6 @@
 		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_mutex_unlock(&table->lock);
 		ast_free(sql);
 		ast_free(buf);
 		return -1;
@@ -812,6 +823,100 @@
 	return cur ? 0 : -1;
 }
 
+static int modify_mysql(const char *tablename, struct columns *column, require_type type, int len)
+{
+	struct ast_str *sql = ast_str_create(100), *escbuf = ast_str_create(strlen(column->dflt) * 2 + 1);
+	struct ast_str *typestr = ast_str_create(30);
+	int waschar = strncasecmp(column->type, "char", 4) == 0 ? 1 : 0;
+	int wasvarchar = strncasecmp(column->type, "varchar", 7) == 0 ? 1 : 0;
+	int res = 0;
+
+	do {
+		if (type == RQ_CHAR || waschar || wasvarchar) {
+			if (wasvarchar) {
+				ast_str_set(&typestr, 0, "VARCHAR(%d)", len);
+			} else {
+				ast_str_set(&typestr, 0, "CHAR(%d)", len);
+			}
+		} else if (type == RQ_UINTEGER1) {
+			ast_str_set(&typestr, 0, "tinyint(3) unsigned");
+		} else if (type == RQ_INTEGER1) {
+			ast_str_set(&typestr, 0, "tinyint(4)");
+		} else if (type == RQ_UINTEGER2) {
+			ast_str_set(&typestr, 0, "smallint(5) unsigned");
+		} else if (type == RQ_INTEGER2) {
+			ast_str_set(&typestr, 0, "smallint(6)");
+		} else if (type == RQ_UINTEGER3) {
+			ast_str_set(&typestr, 0, "mediumint(8) unsigned");
+		} else if (type == RQ_INTEGER3) {
+			ast_str_set(&typestr, 0, "mediumint(8)");
+		} else if (type == RQ_UINTEGER4) {
+			ast_str_set(&typestr, 0, "int(10) unsigned");
+		} else if (type == RQ_INTEGER4) {
+			ast_str_set(&typestr, 0, "int(11)");
+		} else if (type == RQ_UINTEGER8) {
+			ast_str_set(&typestr, 0, "bigint(19) unsigned");
+		} else if (type == RQ_INTEGER8) {
+			ast_str_set(&typestr, 0, "bigint(20)");
+		} else if (type == RQ_DATETIME) {
+			ast_str_set(&typestr, 0, "datetime");
+		} else if (type == RQ_DATE) {
+			ast_str_set(&typestr, 0, "date");
+		} else if (type == RQ_FLOAT) {
+			ast_str_set(&typestr, 0, "FLOAT(%d,2)", len);
+		} else {
+			ast_log(LOG_ERROR, "Unknown type (should NEVER happen)\n");
+			res = -1;
+			break;
+		}
+		ast_str_set(&sql, 0, "ALTER TABLE %s MODIFY %s %s", tablename, column->name, typestr->str);
+		if (!column->null) {
+			ast_str_append(&sql, 0, " NOT NULL");
+		}
+		if (!ast_strlen_zero(column->dflt)) {
+			ast_str_makespace(&escbuf, strlen(column->dflt) * 2 + 1);
+			mysql_real_escape_string(&dbwrite.handle, escbuf->str, column->dflt, strlen(column->dflt));
+			ast_str_append(&sql, 0, " DEFAULT '%s'", escbuf->str);
+		}
+
+		ast_mutex_lock(&dbwrite.lock);
+		if (!mysql_reconnect(&dbwrite)) {
+			ast_mutex_unlock(&dbwrite.lock);
+			ast_log(LOG_ERROR, "Unable to add column: %s\n", sql->str);
+			res = -1;
+			break;
+		}
+
+		/* 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));
+			res = -1;
+		}
+		ast_mutex_unlock(&dbwrite.lock);
+	} while (0);
+
+	ast_free(sql);
+	ast_free(typestr);
+	ast_free(escbuf);
+	return res;
+}
+
+#define PICK_WHICH_ALTER_ACTION(stringtype) \
+	if (requirements == RQ_WARN) {                                                                       \
+		ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for "            \
+			"the required data length: %d (detected stringtype)\n",                                      \
+			tablename, database, column->name, size);                                                    \
+		res = -1;                                                                                        \
+	} else if (requirements == RQ_CREATECLOSE && modify_mysql(tablename, column, type, size) == 0) {     \
+		table_altered = 1;                                                                               \
+	} else if (requirements == RQ_CREATECHAR && modify_mysql(tablename, column, RQ_CHAR, size) == 0) {   \
+		table_altered = 1;                                                                               \
+	} else {                                                                                             \
+		res = -1;                                                                                        \
+	}
+
 static int require_mysql(const char *database, const char *tablename, va_list ap)
 {
 	struct columns *column;
@@ -832,38 +937,50 @@
 				/* Char can hold anything, as long as it is large enough */
 				if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
 					if ((size > column->len) && column->len != -1) {
-						ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len);
-						res = -1;
+						if (requirements == RQ_WARN) {
+							ast_log(LOG_WARNING, "Realtime table %s@%s: Column '%s' should be at least %d long, but is only %d long.\n", database, tablename, column->name, size, column->len);
+							res = -1;
+						} else if (modify_mysql(tablename, column, type, size) == 0) {
+							table_altered = 1;
+						} else {
+							res = -1;
+						}
 					}
 				} else if (strcasestr(column->type, "unsigned")) {
 					if (!ast_rq_is_int(type)) {
-						ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' cannot be type '%s' (need %s)\n", database, tablename, column->name, column->type,
-							type == RQ_CHAR ? "char" : type == RQ_FLOAT ? "float" : type == RQ_DATETIME ? "datetime" : type == RQ_DATE ? "date" : "a rather stiff drink");
-						res = -1;
+						if (requirements == RQ_WARN) {
+							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' cannot be type '%s' (need %s)\n",
+								database, tablename, column->name, column->type,
+								type == RQ_CHAR ? "char" : type == RQ_FLOAT ? "float" :
+								type == RQ_DATETIME ? "datetime" : type == RQ_DATE ? "date" : "a rather stiff drink");
+							res = -1;
+						} else if (requirements == RQ_CREATECLOSE && modify_mysql(tablename, column, type, size) == 0) {
+							table_altered = 1;
+						} else if (requirements == RQ_CREATECHAR && modify_mysql(tablename, column, RQ_CHAR, size) == 0) {
+							table_altered = 1;
+						} else {
+							res = -1;
+						}
 					} else if (strncasecmp(column->type, "tinyint", 1) == 0) {
 						if (type != RQ_UINTEGER1) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned tinyint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(unsigned tinyint)
 						}
 					} else if (strncasecmp(column->type, "smallint", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned smallint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(unsigned smallint)
 						}
 					} else if (strncasecmp(column->type, "mediumint", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
 							type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
 							type != RQ_UINTEGER3) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned mediumint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(unsigned mediumint)
 						}
 					} else if (strncasecmp(column->type, "int", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
 							type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
 							type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
 							type != RQ_UINTEGER4) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned int)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(unsigned int)
 						}
 					} else if (strncasecmp(column->type, "bigint", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
@@ -871,39 +988,45 @@
 							type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
 							type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
 							type != RQ_UINTEGER8) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned bigint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(unsigned bigint)
 						}
 					}
 				} else if (strcasestr(column->type, "int")) {
 					if (!ast_rq_is_int(type)) {
-						ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' cannot be type '%s' (need %s)\n", database, tablename, column->name, column->type,
-							type == RQ_CHAR ? "char" : type == RQ_FLOAT ? "float" : type == RQ_DATETIME ? "datetime" : type == RQ_DATE ? "date" : "to get a life, rather than writing silly error messages");
-						res = -1;
+						if (requirements == RQ_WARN) {
+							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' cannot be type '%s' (need %s)\n",
+								database, tablename, column->name, column->type,
+								type == RQ_CHAR ? "char" : type == RQ_FLOAT ? "float" :
+								type == RQ_DATETIME ? "datetime" : type == RQ_DATE ? "date" :
+								"to get a life, rather than writing silly error messages");
+							res = -1;
+						} else if (requirements == RQ_CREATECLOSE && modify_mysql(tablename, column, type, size) == 0) {
+							table_altered = 1;
+						} else if (requirements == RQ_CREATECHAR && modify_mysql(tablename, column, RQ_CHAR, size) == 0) {
+							table_altered = 1;
+						} else {
+							res = -1;
+						}
 					} else if (strncasecmp(column->type, "tinyint", 1) == 0) {
 						if (type != RQ_INTEGER1) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned tinyint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(tinyint)
 						}
 					} else if (strncasecmp(column->type, "smallint", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned smallint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(smallint)
 						}
 					} else if (strncasecmp(column->type, "mediumint", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
 							type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
 							type != RQ_INTEGER3) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned mediumint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(mediumint)
 						}
 					} else if (strncasecmp(column->type, "int", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
 							type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
 							type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
 							type != RQ_INTEGER4) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned int)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(int)
 						}
 					} else if (strncasecmp(column->type, "bigint", 1) == 0) {
 						if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
@@ -911,16 +1034,52 @@
 							type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
 							type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
 							type != RQ_INTEGER8) {
-							ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' may not be large enough for the required data length: %d (detected unsigned bigint)\n", tablename, database, column->name, size);
-							res = -1;
+							PICK_WHICH_ALTER_ACTION(bigint)
 						}
 					}
 				} else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
-					ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
-					res = -1;
-				} else { /* There are other types that no module implements yet */
-					ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
-					res = -1;
+					if (requirements == RQ_WARN) {
+						ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+						res = -1;
+					} else if (requirements == RQ_CREATECLOSE && modify_mysql(tablename, column, type, size) == 0) {
+						table_altered = 1;
+					} else if (requirements == RQ_CREATECHAR && modify_mysql(tablename, column, RQ_CHAR, size) == 0) {
+						table_altered = 1;
+					} else {
+						res = -1;
+					}
+				} else if ((strncmp(column->type, "datetime", 8) == 0 || strncmp(column->type, "timestamp", 9)) && type != RQ_DATETIME) {
+					if (requirements == RQ_WARN) {
+						ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+						res = -1;
+					} else if (requirements == RQ_CREATECLOSE && modify_mysql(tablename, column, type, size) == 0) {
+						table_altered = 1;
+					} else if (requirements == RQ_CREATECHAR && modify_mysql(tablename, column, RQ_CHAR, size) == 0) {
+						table_altered = 1;
+					} else {
+						res = -1;
+					}
+				} else if ((strncmp(column->type, "date", 4) == 0) && type != RQ_DATE) {
+					if (requirements == RQ_WARN) {
+						ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+						res = -1;
+					} else if (requirements == RQ_CREATECLOSE && modify_mysql(tablename, column, type, size) == 0) {
+						table_altered = 1;
+					} else if (requirements == RQ_CREATECHAR && modify_mysql(tablename, column, RQ_CHAR, size) == 0) {
+						table_altered = 1;
+					} else {
+						res = -1;
+					}
+				} else { /* Other, possibly unsupported types? */
+					if (requirements == RQ_WARN) {
+						ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
+						res = -1;
+					} else if (requirements == RQ_CREATECLOSE && modify_mysql(tablename, column, type, size) == 0) {
+						table_altered = 1;
+					} else if (requirements == RQ_CREATECHAR && modify_mysql(tablename, column, RQ_CHAR, size) == 0) {
+						table_altered = 1;
+					} else {
+					}
 				}
 				break;
 			}
@@ -995,10 +1154,10 @@
 					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);
 				} else {
 					table_altered = 1;
 				}
+				ast_mutex_unlock(&dbwrite.lock);
 
 				ast_free(sql);
 				ast_free(fieldtype);
@@ -1050,7 +1209,6 @@
 	if (option_verbose > 1)
 		ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime driver loaded.\n");
 	ast_cli_register_multiple(cli_realtime_mysql_status, sizeof(cli_realtime_mysql_status) / sizeof(struct ast_cli_entry));
-
 	return 0;
 }
 




More information about the asterisk-addons-commits mailing list