res_config_odbc: Use dynamically sized buffers to store row data so values do not...
authorJoshua Colp <jcolp@digium.com>
Wed, 28 May 2014 11:37:50 +0000 (11:37 +0000)
committerJoshua Colp <jcolp@digium.com>
Wed, 28 May 2014 11:37:50 +0000 (11:37 +0000)
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

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@414696 65c4cc65-6c06-0410-ace0-fbb531ad65f3

funcs/func_odbc.c
res/res_config_odbc.c

index 5e7655f..1c3a174 100644 (file)
@@ -109,9 +109,9 @@ struct acf_odbc_query {
        AST_RWLIST_ENTRY(acf_odbc_query) list;
        char readhandle[5][30];
        char writehandle[5][30];
        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;
        unsigned int flags;
        int rowlimit;
        struct ast_custom_function *acf;
@@ -855,6 +855,23 @@ static int exec_odbcfinish(struct ast_channel *chan, const char *data)
        return 0;
 }
 
        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;
 static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
 {
        const char *tmp;
@@ -899,35 +916,35 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
        }
 
        if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")))
        }
 
        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);
        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])) {
        }
 
        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")))
                *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);
        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])) {
        }
 
        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"))) {
                *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 */
        }
 
        /* Allow escaping of embedded commas in fields to be turned off */
@@ -946,13 +963,12 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
 
        (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
        if (! (*query)->acf) {
 
        (*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)) {
                *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;
        }
                *query = NULL;
                return ENOMEM;
        }
@@ -968,9 +984,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
        }
 
        if (!((*query)->acf->name)) {
        }
 
        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;
        }
                *query = NULL;
                return ENOMEM;
        }
@@ -982,10 +996,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
        }
 
        if (ast_strlen_zero((*query)->acf->syntax)) {
        }
 
        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;
        }
                *query = NULL;
                return ENOMEM;
        }
@@ -997,10 +1008,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
        }
 
        if (ast_strlen_zero((*query)->acf->synopsis)) {
        }
 
        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;
        }
                *query = NULL;
                return ENOMEM;
        }
@@ -1042,19 +1050,14 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
                                        ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
                                        ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
        } else {
                                        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_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;
        }
                *query = NULL;
                return ENOMEM;
        }
@@ -1074,20 +1077,6 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
        return 0;
 }
 
        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;
-}
-
 static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        AST_DECLARE_APP_ARGS(args,
 static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        AST_DECLARE_APP_ARGS(args,
index 6fc9ea2..4806bd2 100644 (file)
@@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stringfields.h"
 
 AST_THREADSTORAGE(sql_buf);
 #include "asterisk/stringfields.h"
 
 AST_THREADSTORAGE(sql_buf);
+AST_THREADSTORAGE(rowdata_buf);
 
 struct custom_prepare_struct {
        const char *sql;
 
 struct custom_prepare_struct {
        const char *sql;
@@ -166,7 +167,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
        SQLHSTMT stmt;
        char sql[1024];
        char coltitle[256];
        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;
        char *op;
        const struct ast_variable *field = fields;
        char *stringp;
@@ -237,7 +238,6 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                return NULL;
        }
        for (x = 0; x < colcount; x++) {
                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, 
                colsize = 0;
                collen = sizeof(coltitle);
                res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
@@ -250,14 +250,25 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                        return NULL;
                }
 
                        return NULL;
                }
 
+               ast_str_reset(rowdata);
                indicator = 0;
                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. */
                        /* 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)) {
                }
 
                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
@@ -267,7 +278,8 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                        ast_odbc_release_obj(obj);
                        return NULL;
                }
                        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))) {
                while (stringp) {
                        chunk = strsep(&stringp, ";");
                        if (!ast_strlen_zero(ast_strip(chunk))) {
@@ -311,7 +323,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        SQLHSTMT stmt;
        char sql[1024];
        char coltitle[256];
        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;
        const char *initfield;
        char *op;
        const struct ast_variable *field = fields;
@@ -397,7 +409,6 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
                        continue;
                }
                for (x=0;x<colcount;x++) {
                        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, 
                        colsize = 0;
                        collen = sizeof(coltitle);
                        res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
@@ -408,17 +419,31 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
                                goto next_sql_fetch;
                        }
 
                                goto next_sql_fetch;
                        }
 
+                       ast_str_reset(rowdata);
                        indicator = 0;
                        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;
                                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;
                        }
 
                        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))) {
                        while (stringp) {
                                chunk = strsep(&stringp, ";");
                                if (!ast_strlen_zero(ast_strip(chunk))) {
@@ -799,16 +824,41 @@ static int destroy_odbc(const char *database, const char *table, const char *key
        return -1;
 }
 
        return -1;
 }
 
-
 struct config_odbc_obj {
        char *sql;
        unsigned long cat_metric;
        char category[128];
        char var_name[128];
 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;
 };
 
        SQLLEN err;
 };
 
+
+static SQLHSTMT length_determination_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->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;
 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
 {
        struct config_odbc_obj *q = data;
@@ -831,7 +881,7 @@ static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
        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, 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;
 }
 
        return sth;
 }
@@ -862,16 +912,64 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        if (!obj)
                return NULL;
 
        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 ");
        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);
 
        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;
        }
 
                return NULL;
        }
 
@@ -881,12 +979,14 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
                ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                ast_odbc_release_obj(obj);
                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);
                return NULL;
        }
 
        if (!rowcount) {
                ast_log(LOG_NOTICE, "found nothing\n");
                ast_odbc_release_obj(obj);
+               ast_free(q.var_val);
                return cfg;
        }
 
                return cfg;
        }
 
@@ -897,6 +997,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
                        if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
                                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                                ast_odbc_release_obj(obj);
                        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;
                                return NULL;
                        }
                        continue;
@@ -918,6 +1019,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
 
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
        ast_odbc_release_obj(obj);
 
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
        ast_odbc_release_obj(obj);
+       ast_free(q.var_val);
        return cfg;
 }
 
        return cfg;
 }