[asterisk-commits] file: trunk r414696 - in /trunk: ./ funcs/func_odbc.c res/res_config_odbc.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed May 28 06:37:53 CDT 2014


Author: file
Date: Wed May 28 06:37:50 2014
New Revision: 414696

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=414696
Log:
res_config_odbc: Use dynamically sized buffers to store row data so values do not get truncated.

ASTERISK-23582 #close
ASTERISk-23582 #comment Reported by: Walter Doekes

Review: https://reviewboard.asterisk.org/r/3557/
........

Merged revisions 414693 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 414694 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 414695 from http://svn.asterisk.org/svn/asterisk/branches/12

Modified:
    trunk/   (props changed)
    trunk/funcs/func_odbc.c
    trunk/res/res_config_odbc.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-12-merged' - no diff available.

Modified: trunk/funcs/func_odbc.c
URL: http://svnview.digium.com/svn/asterisk/trunk/funcs/func_odbc.c?view=diff&rev=414696&r1=414695&r2=414696
==============================================================================
--- trunk/funcs/func_odbc.c (original)
+++ trunk/funcs/func_odbc.c Wed May 28 06:37:50 2014
@@ -109,9 +109,9 @@
 	AST_RWLIST_ENTRY(acf_odbc_query) list;
 	char readhandle[5][30];
 	char writehandle[5][30];
-	char sql_read[2048];
-	char sql_write[2048];
-	char sql_insert[2048];
+	char *sql_read;
+	char *sql_write;
+	char *sql_insert;
 	unsigned int flags;
 	int rowlimit;
 	struct ast_custom_function *acf;
@@ -855,6 +855,23 @@
 	return 0;
 }
 
+static int free_acf_query(struct acf_odbc_query *query)
+{
+	if (query) {
+		if (query->acf) {
+			if (query->acf->name)
+				ast_free((char *)query->acf->name);
+			ast_string_field_free_memory(query->acf);
+			ast_free(query->acf);
+		}
+		ast_free(query->sql_read);
+		ast_free(query->sql_write);
+		ast_free(query->sql_insert);
+		ast_free(query);
+	}
+	return 0;
+}
+
 static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
 {
 	const char *tmp;
@@ -899,35 +916,35 @@
  	}
 
 	if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")))
-		ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
+		(*query)->sql_read = ast_strdup(tmp);
 	else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) {
 		ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s.  Please use 'readsql' instead.\n", catg);
-		ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
+		(*query)->sql_read = ast_strdup(tmp);
 	}
 
 	if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) {
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
 		return EINVAL;
 	}
 
 	if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")))
-		ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
+		(*query)->sql_write = ast_strdup(tmp);
 	else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) {
 		ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s.  Please use 'writesql' instead.\n", catg);
-		ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
+		(*query)->sql_write = ast_strdup(tmp);
 	}
 
 	if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) {
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
 		return EINVAL;
 	}
 
 	if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
-		ast_copy_string((*query)->sql_insert, tmp, sizeof((*query)->sql_insert));
+		(*query)->sql_insert = ast_strdup(tmp);
 	}
 
 	/* Allow escaping of embedded commas in fields to be turned off */
@@ -946,13 +963,12 @@
 
 	(*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
 	if (! (*query)->acf) {
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		return ENOMEM;
 	}
 	if (ast_string_field_init((*query)->acf, 128)) {
-		ast_free((*query)->acf);
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		return ENOMEM;
 	}
@@ -968,9 +984,7 @@
 	}
 
 	if (!((*query)->acf->name)) {
-		ast_string_field_free_memory((*query)->acf);
-		ast_free((*query)->acf);
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		return ENOMEM;
 	}
@@ -982,10 +996,7 @@
 	}
 
 	if (ast_strlen_zero((*query)->acf->syntax)) {
-		ast_free((char *)(*query)->acf->name);
-		ast_string_field_free_memory((*query)->acf);
-		ast_free((*query)->acf);
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		return ENOMEM;
 	}
@@ -997,10 +1008,7 @@
 	}
 
 	if (ast_strlen_zero((*query)->acf->synopsis)) {
-		ast_free((char *)(*query)->acf->name);
-		ast_string_field_free_memory((*query)->acf);
-		ast_free((*query)->acf);
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		return ENOMEM;
 	}
@@ -1042,19 +1050,14 @@
 					ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
 					ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
 	} else {
-		ast_string_field_free_memory((*query)->acf);
-		ast_free((char *)(*query)->acf->name);
-		ast_free((*query)->acf);
-		ast_free(*query);
+		free_acf_query(*query);
+		*query = NULL;
 		ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute.  Ignoring.\n", catg);
 		return EINVAL;
 	}
 
 	if (ast_strlen_zero((*query)->acf->desc)) {
-		ast_string_field_free_memory((*query)->acf);
-		ast_free((char *)(*query)->acf->name);
-		ast_free((*query)->acf);
-		ast_free(*query);
+		free_acf_query(*query);
 		*query = NULL;
 		return ENOMEM;
 	}
@@ -1071,20 +1074,6 @@
 		(*query)->acf->write = acf_odbc_write;
 	}
 
-	return 0;
-}
-
-static int free_acf_query(struct acf_odbc_query *query)
-{
-	if (query) {
-		if (query->acf) {
-			if (query->acf->name)
-				ast_free((char *)query->acf->name);
-			ast_string_field_free_memory(query->acf);
-			ast_free(query->acf);
-		}
-		ast_free(query);
-	}
 	return 0;
 }
 

Modified: trunk/res/res_config_odbc.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_config_odbc.c?view=diff&rev=414696&r1=414695&r2=414696
==============================================================================
--- trunk/res/res_config_odbc.c (original)
+++ trunk/res/res_config_odbc.c Wed May 28 06:37:50 2014
@@ -48,6 +48,7 @@
 #include "asterisk/stringfields.h"
 
 AST_THREADSTORAGE(sql_buf);
+AST_THREADSTORAGE(rowdata_buf);
 
 struct custom_prepare_struct {
 	const char *sql;
@@ -166,7 +167,7 @@
 	SQLHSTMT stmt;
 	char sql[1024];
 	char coltitle[256];
-	char rowdata[2048];
+	struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
 	char *op;
 	const struct ast_variable *field = fields;
 	char *stringp;
@@ -237,7 +238,6 @@
 		return NULL;
 	}
 	for (x = 0; x < colcount; x++) {
-		rowdata[0] = '\0';
 		colsize = 0;
 		collen = sizeof(coltitle);
 		res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
@@ -250,14 +250,25 @@
 			return NULL;
 		}
 
+		ast_str_reset(rowdata);
 		indicator = 0;
-		res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
-		if (indicator == SQL_NULL_DATA)
-			rowdata[0] = '\0';
-		else if (ast_strlen_zero(rowdata)) {
+
+		res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
+		ast_str_update(rowdata);
+		if (indicator == SQL_NULL_DATA) {
+			ast_str_reset(rowdata);
+		} else if (!ast_str_strlen(rowdata)) {
 			/* Because we encode the empty string for a NULL, we will encode
 			 * actual empty strings as a string containing a single whitespace. */
-			ast_copy_string(rowdata, " ", sizeof(rowdata));
+			ast_str_set(&rowdata, -1, "%s", " ");
+		} else if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
+			if (indicator != ast_str_strlen(rowdata)) {
+				/* If the available space was not enough to contain the row data enlarge and read in the rest */
+				ast_str_make_space(&rowdata, indicator + 1);
+				res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
+					ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
+				ast_str_update(rowdata);
+			}
 		}
 
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
@@ -267,7 +278,8 @@
 			ast_odbc_release_obj(obj);
 			return NULL;
 		}
-		stringp = rowdata;
+
+		stringp = ast_str_buffer(rowdata);
 		while (stringp) {
 			chunk = strsep(&stringp, ";");
 			if (!ast_strlen_zero(ast_strip(chunk))) {
@@ -311,7 +323,7 @@
 	SQLHSTMT stmt;
 	char sql[1024];
 	char coltitle[256];
-	char rowdata[2048];
+	struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
 	const char *initfield;
 	char *op;
 	const struct ast_variable *field = fields;
@@ -397,7 +409,6 @@
 			continue;
 		}
 		for (x=0;x<colcount;x++) {
-			rowdata[0] = '\0';
 			colsize = 0;
 			collen = sizeof(coltitle);
 			res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
@@ -408,17 +419,31 @@
 				goto next_sql_fetch;
 			}
 
+			ast_str_reset(rowdata);
 			indicator = 0;
-			res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
-			if (indicator == SQL_NULL_DATA)
+
+			res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
+			ast_str_update(rowdata);
+			if (indicator == SQL_NULL_DATA) {
 				continue;
+			}
+
+			if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
+				if (indicator != ast_str_strlen(rowdata)) {
+					/* If the available space was not enough to contain the row data enlarge and read in the rest */
+					ast_str_make_space(&rowdata, indicator + 1);
+					res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
+						ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
+					ast_str_update(rowdata);
+				}
+			}
 
 			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 				ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
 				ast_category_destroy(cat);
 				goto next_sql_fetch;
 			}
-			stringp = rowdata;
+			stringp = ast_str_buffer(rowdata);
 			while (stringp) {
 				chunk = strsep(&stringp, ";");
 				if (!ast_strlen_zero(ast_strip(chunk))) {
@@ -799,17 +824,18 @@
 	return -1;
 }
 
-
 struct config_odbc_obj {
 	char *sql;
 	unsigned long cat_metric;
 	char category[128];
 	char var_name[128];
-	char var_val[1024]; /* changed from 128 to 1024 via bug 8251 */
+	char *var_val;
+	unsigned long var_val_size;
 	SQLLEN err;
 };
 
-static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
+
+static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
 {
 	struct config_odbc_obj *q = data;
 	SQLHSTMT sth;
@@ -828,10 +854,34 @@
 		return NULL;
 	}
 
+	SQLBindCol(sth, 1, SQL_C_ULONG, &q->var_val_size, sizeof(q->var_val_size), &q->err);
+
+	return sth;
+}
+
+static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
+{
+	struct config_odbc_obj *q = data;
+	SQLHSTMT sth;
+	int res;
+
+	res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
+	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+		ast_verb(4, "Failure in AllocStatement %d\n", res);
+		return NULL;
+	}
+
+	res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
+	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+		ast_verb(4, "Error in PREPARE %d\n", res);
+		SQLFreeHandle(SQL_HANDLE_STMT, sth);
+		return NULL;
+	}
+
 	SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
 	SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
 	SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
-	SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
+	SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err);
 
 	return sth;
 }
@@ -862,16 +912,64 @@
 	if (!obj)
 		return NULL;
 
+	q.sql = sqlbuf;
+
+	ast_build_string(&sql, &sqlleft, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", table, file);
+
+	stmt = ast_odbc_prepare_and_execute(obj, length_determination_odbc_prepare, &q);
+
+	if (!stmt) {
+		ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
+		ast_odbc_release_obj(obj);
+		return NULL;
+	}
+
+	res = SQLNumResultCols(stmt, &rowcount);
+
+	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+		ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
+		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+		ast_odbc_release_obj(obj);
+		return NULL;
+	}
+
+	if (!rowcount) {
+		ast_log(LOG_NOTICE, "found nothing\n");
+		ast_odbc_release_obj(obj);
+		return cfg;
+	}
+
+	/* There will be only one result for this, the maximum length of a variable value */
+	if (SQLFetch(stmt) == SQL_NO_DATA) {
+		ast_log(LOG_NOTICE, "Failed to determine maximum length of a configuration value\n");
+		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+		ast_odbc_release_obj(obj);
+		return NULL;
+	}
+
+	/* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
+	SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+	sql = sqlbuf;
+	sqlleft = sizeof(sqlbuf);
+
 	ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
 	ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
 	ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
-	q.sql = sqlbuf;
+
+	q.var_val_size += 1;
+	q.var_val = ast_malloc(q.var_val_size);
+	if (!q.var_val) {
+		ast_log(LOG_WARNING, "Could not create buffer for reading in configuration values for '%s'\n", file);
+		ast_odbc_release_obj(obj);
+		return NULL;
+	}
 
 	stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
 
 	if (!stmt) {
 		ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
 		ast_odbc_release_obj(obj);
+		ast_free(q.var_val);
 		return NULL;
 	}
 
@@ -881,12 +979,14 @@
 		ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 		ast_odbc_release_obj(obj);
+		ast_free(q.var_val);
 		return NULL;
 	}
 
 	if (!rowcount) {
 		ast_log(LOG_NOTICE, "found nothing\n");
 		ast_odbc_release_obj(obj);
+		ast_free(q.var_val);
 		return cfg;
 	}
 
@@ -897,6 +997,7 @@
 			if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
 				SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 				ast_odbc_release_obj(obj);
+				ast_free(q.var_val);
 				return NULL;
 			}
 			continue;
@@ -918,6 +1019,7 @@
 
 	SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 	ast_odbc_release_obj(obj);
+	ast_free(q.var_val);
 	return cfg;
 }
 




More information about the asterisk-commits mailing list