[asterisk-commits] tilghman: branch tilghman/adaptive_realtime r116556 - /team/tilghman/adaptive...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed May 14 23:42:59 CDT 2008


Author: tilghman
Date: Wed May 14 23:42:59 2008
New Revision: 116556

URL: http://svn.digium.com/view/asterisk?view=rev&rev=116556
Log:
Implement first half of what's required for the postgres backend

Modified:
    team/tilghman/adaptive_realtime/res/res_config_odbc.c
    team/tilghman/adaptive_realtime/res/res_config_pgsql.c

Modified: team/tilghman/adaptive_realtime/res/res_config_odbc.c
URL: http://svn.digium.com/view/asterisk/team/tilghman/adaptive_realtime/res/res_config_odbc.c?view=diff&rev=116556&r1=116555&r2=116556
==============================================================================
--- team/tilghman/adaptive_realtime/res/res_config_odbc.c (original)
+++ team/tilghman/adaptive_realtime/res/res_config_odbc.c Wed May 14 23:42:59 2008
@@ -892,8 +892,8 @@
 	}
 
 	while ((elm = va_arg(ap, char *))) {
-		type = va_arg(ap, int);
-		size = va_arg(ap, require_type);
+		type = va_arg(ap, require_type);
+		size = va_arg(ap, int);
 		/* Check if the field matches the criteria */
 		AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
 			if (strcmp(col->name, elm) == 0) {

Modified: team/tilghman/adaptive_realtime/res/res_config_pgsql.c
URL: http://svn.digium.com/view/asterisk/team/tilghman/adaptive_realtime/res/res_config_pgsql.c?view=diff&rev=116556&r1=116555&r2=116556
==============================================================================
--- team/tilghman/adaptive_realtime/res/res_config_pgsql.c (original)
+++ team/tilghman/adaptive_realtime/res/res_config_pgsql.c Wed May 14 23:42:59 2008
@@ -49,6 +49,24 @@
 
 #define MAX_DB_OPTION_SIZE 64
 
+struct columns {
+	char *name;
+	char *type;
+	int len;
+	unsigned int notnull:1;
+	unsigned int hasdefault:1;
+	AST_LIST_ENTRY(columns) list;
+};
+
+struct tables {
+	ast_mutex_t lock;
+	AST_LIST_HEAD_NOLOCK(psql_columns, columns) columns;
+	AST_LIST_ENTRY(tables) list;
+	char name[0];
+};
+
+static AST_LIST_HEAD_STATIC(psql_tables, tables);
+
 static char dbhost[MAX_DB_OPTION_SIZE] = "";
 static char dbuser[MAX_DB_OPTION_SIZE] = "";
 static char dbpass[MAX_DB_OPTION_SIZE] = "";
@@ -64,6 +82,98 @@
 static struct ast_cli_entry cli_realtime[] = {
 	AST_CLI_DEFINE(handle_cli_realtime_pgsql_status, "Shows connection information for the PostgreSQL RealTime driver"),
 };
+
+static void destroy_table(struct tables *table)
+{
+	struct columns *column;
+	ast_mutex_lock(&table->lock);
+	while ((column = AST_LIST_REMOVE_HEAD(&table->columns, list))) {
+		ast_free(column);
+	}
+	ast_mutex_unlock(&table->lock);
+	ast_mutex_destroy(&table->lock);
+	ast_free(table);
+}
+
+static struct tables *find_table(const char *tablename)
+{
+	struct columns *column;
+	struct tables *table;
+	struct ast_str *sql = ast_str_create(330);
+	char *pgerror;
+	PGresult *result;
+	char *fname, *ftype, *flen, *fnotnull, *fdef;
+	int i, rows;
+
+	AST_LIST_LOCK(&psql_tables);
+	AST_LIST_TRAVERSE(&psql_tables, table, list) {
+		if (!strcasecmp(table->name, tablename)) {
+			ast_mutex_lock(&table->lock);
+			AST_LIST_UNLOCK(&psql_tables);
+			return table;
+		}
+	}
+
+	/* Not found, scan the table */
+	ast_str_set(&sql, 0, "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc FROM pg_class c, pg_type t, pg_attribute a LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum WHERE c.oid = a.attrelid AND a.atttypid = t.oid AND (a.attnum > 0) AND c.relname = '%s' ORDER BY c.relname, attnum", tablename);
+	result = PQexec(pgsqlConn, sql->str);
+	if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+		pgerror = PQresultErrorMessage(result);
+		ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
+		PQclear(result);
+		AST_LIST_UNLOCK(&psql_tables);
+		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");
+		AST_LIST_UNLOCK(&psql_tables);
+		return NULL;
+	}
+	strcpy(table->name, tablename); /* SAFE */
+	ast_mutex_init(&table->lock);
+	AST_LIST_HEAD_INIT_NOLOCK(&table->columns);
+	
+	rows = PQntuples(result);
+	for (i = 0; i < rows; i++) {
+		fname = PQgetvalue(result, i, 0);
+		ftype = PQgetvalue(result, i, 1);
+		flen = PQgetvalue(result, i, 2);
+		fnotnull = PQgetvalue(result, i, 3);
+		fdef = PQgetvalue(result, i, 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))) {
+			ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", tablename, fname);
+			destroy_table(table);
+			AST_LIST_UNLOCK(&psql_tables);
+			return NULL;
+		}
+
+		sscanf(flen, "%d", &column->len);
+		column->name = (char *)column + sizeof(*column);
+		column->type = (char *)column + sizeof(*column) + strlen(fname) + 1;
+		strcpy(column->name, fname);
+		strcpy(column->type, ftype);
+		if (*fnotnull == 't') {
+			column->notnull = 1;
+		} else {
+			column->notnull = 0;
+		}
+		if (!ast_strlen_zero(fdef)) {
+			column->hasdefault = 1;
+		} else {
+			column->hasdefault = 0;
+		}
+		AST_LIST_INSERT_TAIL(&table->columns, column, list);
+	}
+	PQclear(result);
+
+	AST_LIST_INSERT_TAIL(&psql_tables, table, list);
+	ast_mutex_lock(&table->lock);
+	AST_LIST_UNLOCK(&psql_tables);
+	return table;
+}
 
 static struct ast_variable *realtime_pgsql(const char *database, const char *table, va_list ap)
 {
@@ -752,6 +862,51 @@
 	return cfg;
 }
 
+static int require_pgsql(const char *database, const char *tablename, va_list ap)
+{
+	struct columns *column;
+	struct tables *table = find_table(tablename);
+	char *elm;
+	int type, size, res = 0;
+
+	if (!table) {
+		ast_log(LOG_WARNING, "Table %s not found in database.  This table should exist if you're using realtime.\n", tablename);
+	}
+
+	while ((elm = va_arg(ap, char *))) {
+		type = va_arg(ap, require_type);
+		size = va_arg(ap, int);
+		AST_LIST_TRAVERSE(&table->columns, column, list) {
+			if (strcmp(column->name, elm) == 0) {
+				/* Char can hold anything, as long as it is large enough */
+				if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) && (size > column->len)) {
+					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;
+				} else if (strncmp(column->type, "int", 3) == 0) {
+					int typesize = atoi(column->type + 3);
+					/* Integers can hold only other integers */
+					if (type == RQ_INTEGER && ((typesize == 2 && size > 4) || (typesize == 4 && size > 10))) {
+						ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
+						res = -1;
+					} else if (type != RQ_INTEGER) {
+						ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n", column->name, type == RQ_CHAR ? "char" : "something else ", size, column->type);
+						res = -1;
+					}
+				} else if (strncmp(column->type, "float", 5) == 0 && type != RQ_INTEGER && 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;
+				}
+				break;
+			}
+		}
+	}
+	ast_mutex_unlock(&table->lock);
+	return res;
+}
+
 static struct ast_config_engine pgsql_engine = {
 	.name = "pgsql",
 	.load_func = config_pgsql,
@@ -759,7 +914,8 @@
 	.realtime_multi_func = realtime_multi_pgsql,
 	.store_func = store_pgsql,
 	.destroy_func = destroy_pgsql,
-	.update_func = update_pgsql
+	.update_func = update_pgsql,
+	.require_func = require_pgsql,
 };
 
 static int load_module(void)
@@ -776,6 +932,7 @@
 
 static int unload_module(void)
 {
+	struct tables *table;
 	/* Acquire control before doing anything to the module itself. */
 	ast_mutex_lock(&pgsql_lock);
 
@@ -786,6 +943,13 @@
 	ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
 	ast_config_engine_deregister(&pgsql_engine);
 	ast_verb(1, "PostgreSQL RealTime unloaded.\n");
+
+	/* Destroy cached table info */
+	AST_LIST_LOCK(&psql_tables);
+	while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) {
+		destroy_table(table);
+	}
+	AST_LIST_UNLOCK(&psql_tables);
 
 	/* Unlock so something else can destroy the lock. */
 	ast_mutex_unlock(&pgsql_lock);




More information about the asterisk-commits mailing list