mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 03:50:31 +00:00
res_config_odbc.c: Fix buffer size limitation creating invalid SQL.
Creating ODBC SQL queries resulted in queries too large to fit into the supplied buffer. The resulting truncated buffer contained an invalid SQL query. * Made SQL query generation code use a thread storage buffer that can increase in size as needed. * Fixed bad multi-line warning messages. ASTERISK-26263 #close Reported by: Jeppe Ryskov Larsen Change-Id: I23f3cdd43c2dac80bed3ded4dd77d18cb17f21ae
This commit is contained in:
@@ -47,6 +47,9 @@ ASTERISK_REGISTER_FILE()
|
|||||||
#include "asterisk/utils.h"
|
#include "asterisk/utils.h"
|
||||||
#include "asterisk/stringfields.h"
|
#include "asterisk/stringfields.h"
|
||||||
|
|
||||||
|
/*! Initial SQL query buffer size to allocate. */
|
||||||
|
#define SQL_BUF_SIZE 1024
|
||||||
|
|
||||||
AST_THREADSTORAGE(sql_buf);
|
AST_THREADSTORAGE(sql_buf);
|
||||||
AST_THREADSTORAGE(rowdata_buf);
|
AST_THREADSTORAGE(rowdata_buf);
|
||||||
|
|
||||||
@@ -114,7 +117,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
|
|||||||
|
|
||||||
res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
|
res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
|
ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", cps->sql);
|
||||||
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
|
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -161,13 +164,13 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
|
|||||||
*
|
*
|
||||||
* \retval var on success
|
* \retval var on success
|
||||||
* \retval NULL on failure
|
* \retval NULL on failure
|
||||||
*/
|
*/
|
||||||
static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
|
static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
|
||||||
{
|
{
|
||||||
struct odbc_obj *obj;
|
struct odbc_obj *obj;
|
||||||
SQLHSTMT stmt;
|
SQLHSTMT stmt;
|
||||||
char sql[1024];
|
|
||||||
char coltitle[256];
|
char coltitle[256];
|
||||||
|
struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
|
struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
|
||||||
char *op;
|
char *op;
|
||||||
const struct ast_variable *field = fields;
|
const struct ast_variable *field = fields;
|
||||||
@@ -183,29 +186,30 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
|
|||||||
SQLSMALLINT decimaldigits;
|
SQLSMALLINT decimaldigits;
|
||||||
SQLSMALLINT nullable;
|
SQLSMALLINT nullable;
|
||||||
SQLLEN indicator;
|
SQLLEN indicator;
|
||||||
struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
|
struct custom_prepare_struct cps = { .fields = fields, };
|
||||||
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
||||||
|
|
||||||
if (!table || !field) {
|
if (!table || !field || !sql || !rowdata) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = ast_odbc_request_obj2(database, connected_flag);
|
obj = ast_odbc_request_obj2(database, connected_flag);
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
|
ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
op = !strchr(field->name, ' ') ? " =" : "";
|
op = !strchr(field->name, ' ') ? " =" : "";
|
||||||
snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
|
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
|
||||||
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
||||||
while ((field = field->next)) {
|
while ((field = field->next)) {
|
||||||
op = !strchr(field->name, ' ') ? " =" : "";
|
op = !strchr(field->name, ' ') ? " =" : "";
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
|
ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
|
||||||
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cps.sql = ast_str_buffer(sql);
|
||||||
|
|
||||||
if (ast_string_field_init(&cps, 256)) {
|
if (ast_string_field_init(&cps, 256)) {
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -220,7 +224,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
|
|||||||
|
|
||||||
res = SQLNumResultCols(stmt, &colcount);
|
res = SQLNumResultCols(stmt, &colcount);
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
|
||||||
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
|
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -233,7 +237,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
|
||||||
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
|
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -244,7 +248,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
|
|||||||
res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
|
res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
|
||||||
&datatype, &colsize, &decimaldigits, &nullable);
|
&datatype, &colsize, &decimaldigits, &nullable);
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
|
||||||
if (var)
|
if (var)
|
||||||
ast_variables_destroy(var);
|
ast_variables_destroy(var);
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
@@ -273,7 +277,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
|
||||||
if (var)
|
if (var)
|
||||||
ast_variables_destroy(var);
|
ast_variables_destroy(var);
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
@@ -317,13 +321,13 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
|
|||||||
*
|
*
|
||||||
* \retval var on success
|
* \retval var on success
|
||||||
* \retval NULL on failure
|
* \retval NULL on failure
|
||||||
*/
|
*/
|
||||||
static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
|
static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
|
||||||
{
|
{
|
||||||
struct odbc_obj *obj;
|
struct odbc_obj *obj;
|
||||||
SQLHSTMT stmt;
|
SQLHSTMT stmt;
|
||||||
char sql[1024];
|
|
||||||
char coltitle[256];
|
char coltitle[256];
|
||||||
|
struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
|
struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
|
||||||
const char *initfield;
|
const char *initfield;
|
||||||
char *op;
|
char *op;
|
||||||
@@ -343,9 +347,9 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
|
|||||||
SQLSMALLINT decimaldigits;
|
SQLSMALLINT decimaldigits;
|
||||||
SQLSMALLINT nullable;
|
SQLSMALLINT nullable;
|
||||||
SQLLEN indicator;
|
SQLLEN indicator;
|
||||||
struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
|
struct custom_prepare_struct cps = { .fields = fields, };
|
||||||
|
|
||||||
if (!table || !field) {
|
if (!table || !field || !sql || !rowdata) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,15 +364,16 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
op = !strchr(field->name, ' ') ? " =" : "";
|
op = !strchr(field->name, ' ') ? " =" : "";
|
||||||
snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
|
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
|
||||||
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
||||||
while ((field = field->next)) {
|
while ((field = field->next)) {
|
||||||
op = !strchr(field->name, ' ') ? " =" : "";
|
op = !strchr(field->name, ' ') ? " =" : "";
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
|
ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
|
||||||
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
|
||||||
}
|
}
|
||||||
|
ast_str_append(&sql, 0, " ORDER BY %s", initfield);
|
||||||
|
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
|
cps.sql = ast_str_buffer(sql);
|
||||||
|
|
||||||
if (ast_string_field_init(&cps, 256)) {
|
if (ast_string_field_init(&cps, 256)) {
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
@@ -384,7 +389,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
|
|||||||
|
|
||||||
res = SQLNumResultCols(stmt, &colcount);
|
res = SQLNumResultCols(stmt, &colcount);
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
|
||||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -401,7 +406,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
|
|||||||
while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
|
while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
|
||||||
var = NULL;
|
var = NULL;
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cat = ast_category_new("","",99999);
|
cat = ast_category_new("","",99999);
|
||||||
@@ -415,7 +420,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
|
|||||||
res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
|
res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
|
||||||
&datatype, &colsize, &decimaldigits, &nullable);
|
&datatype, &colsize, &decimaldigits, &nullable);
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
|
||||||
ast_category_destroy(cat);
|
ast_category_destroy(cat);
|
||||||
goto next_sql_fetch;
|
goto next_sql_fetch;
|
||||||
}
|
}
|
||||||
@@ -440,7 +445,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
|
||||||
ast_category_destroy(cat);
|
ast_category_destroy(cat);
|
||||||
goto next_sql_fetch;
|
goto next_sql_fetch;
|
||||||
}
|
}
|
||||||
@@ -482,21 +487,21 @@ next_sql_fetch:;
|
|||||||
*
|
*
|
||||||
* \retval number of rows affected
|
* \retval number of rows affected
|
||||||
* \retval -1 on failure
|
* \retval -1 on failure
|
||||||
*/
|
*/
|
||||||
static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
|
static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
|
||||||
{
|
{
|
||||||
struct odbc_obj *obj;
|
struct odbc_obj *obj;
|
||||||
SQLHSTMT stmt;
|
SQLHSTMT stmt;
|
||||||
char sql[256];
|
|
||||||
SQLLEN rowcount=0;
|
SQLLEN rowcount=0;
|
||||||
|
struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
const struct ast_variable *field = fields;
|
const struct ast_variable *field = fields;
|
||||||
int res, count = 0, paramcount = 0;
|
int res, count = 0, paramcount = 0;
|
||||||
struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
|
struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
|
||||||
struct odbc_cache_tables *tableptr;
|
struct odbc_cache_tables *tableptr;
|
||||||
struct odbc_cache_columns *column = NULL;
|
struct odbc_cache_columns *column = NULL;
|
||||||
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
||||||
|
|
||||||
if (!table || !field || !keyfield) {
|
if (!table || !field || !keyfield || !sql) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,19 +515,19 @@ static int update_odbc(const char *database, const char *table, const char *keyf
|
|||||||
ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database);
|
ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "UPDATE %s SET ", table);
|
ast_str_set(&sql, 0, "UPDATE %s SET ", table);
|
||||||
while (field) {
|
while (field) {
|
||||||
if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
|
if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
|
||||||
if (paramcount++) {
|
if (paramcount++) {
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", ");
|
ast_str_append(&sql, 0, ", ");
|
||||||
}
|
}
|
||||||
/* NULL test for non-text columns */
|
/* NULL test for non-text columns */
|
||||||
if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) {
|
if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) {
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", field->name);
|
ast_str_append(&sql, 0, "%s=NULL", field->name);
|
||||||
cps.skip |= (1LL << count);
|
cps.skip |= (1LL << count);
|
||||||
} else {
|
} else {
|
||||||
/* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
|
/* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", field->name);
|
ast_str_append(&sql, 0, "%s=?", field->name);
|
||||||
}
|
}
|
||||||
} else { /* the column does not exist in the table */
|
} else { /* the column does not exist in the table */
|
||||||
cps.skip |= (1LL << count);
|
cps.skip |= (1LL << count);
|
||||||
@@ -530,9 +535,11 @@ static int update_odbc(const char *database, const char *table, const char *keyf
|
|||||||
++count;
|
++count;
|
||||||
field = field->next;
|
field = field->next;
|
||||||
}
|
}
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
|
ast_str_append(&sql, 0, " WHERE %s=?", keyfield);
|
||||||
ast_odbc_release_table(tableptr);
|
ast_odbc_release_table(tableptr);
|
||||||
|
|
||||||
|
cps.sql = ast_str_buffer(sql);
|
||||||
|
|
||||||
if (ast_string_field_init(&cps, 256)) {
|
if (ast_string_field_init(&cps, 256)) {
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -550,7 +557,7 @@ static int update_odbc(const char *database, const char *table, const char *keyf
|
|||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,17 +580,15 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
|
|||||||
int res, x = 1, first = 1;
|
int res, x = 1, first = 1;
|
||||||
struct update2_prepare_struct *ups = data;
|
struct update2_prepare_struct *ups = data;
|
||||||
const struct ast_variable *field;
|
const struct ast_variable *field;
|
||||||
struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
|
struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
SQLHSTMT stmt;
|
SQLHSTMT stmt;
|
||||||
struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
|
struct odbc_cache_tables *tableptr;
|
||||||
|
|
||||||
if (!sql) {
|
if (!sql) {
|
||||||
if (tableptr) {
|
|
||||||
ast_odbc_release_table(tableptr);
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tableptr = ast_odbc_find_table(ups->database, ups->table);
|
||||||
if (!tableptr) {
|
if (!tableptr) {
|
||||||
ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", ups->table, ups->database);
|
ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", ups->table, ups->database);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -628,7 +633,7 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
|
|||||||
|
|
||||||
res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
|
res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
|
ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql));
|
||||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -674,8 +679,9 @@ static int update2_odbc(const char *database, const char *table, const struct as
|
|||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
/* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
|
/* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
|
||||||
sql = ast_str_thread_get(&sql_buf, 16);
|
sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
|
ast_assert(sql != NULL);
|
||||||
|
ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,36 +704,47 @@ static int update2_odbc(const char *database, const char *table, const struct as
|
|||||||
*
|
*
|
||||||
* \retval number of rows affected
|
* \retval number of rows affected
|
||||||
* \retval -1 on failure
|
* \retval -1 on failure
|
||||||
*/
|
*/
|
||||||
static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
|
static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
|
||||||
{
|
{
|
||||||
struct odbc_obj *obj;
|
struct odbc_obj *obj;
|
||||||
SQLHSTMT stmt;
|
SQLHSTMT stmt;
|
||||||
char sql[256];
|
|
||||||
char keys[256];
|
|
||||||
char vals[256];
|
|
||||||
SQLLEN rowcount=0;
|
SQLLEN rowcount=0;
|
||||||
const struct ast_variable *field = fields;
|
const struct ast_variable *field = fields;
|
||||||
|
struct ast_str *keys;
|
||||||
|
struct ast_str *vals;
|
||||||
|
struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
int res;
|
int res;
|
||||||
struct custom_prepare_struct cps = { .sql = sql, .extra = NULL, .fields = fields, };
|
struct custom_prepare_struct cps = { .fields = fields, };
|
||||||
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
||||||
|
|
||||||
if (!table || !field) {
|
keys = ast_str_create(SQL_BUF_SIZE / 2);
|
||||||
|
vals = ast_str_create(SQL_BUF_SIZE / 4);
|
||||||
|
if (!table || !field || !keys || !vals || !sql) {
|
||||||
|
ast_free(vals);
|
||||||
|
ast_free(keys);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = ast_odbc_request_obj2(database, connected_flag);
|
obj = ast_odbc_request_obj2(database, connected_flag);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
|
ast_free(vals);
|
||||||
|
ast_free(keys);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(keys, sizeof(keys), "%s", field->name);
|
ast_str_set(&keys, 0, "%s", field->name);
|
||||||
ast_copy_string(vals, "?", sizeof(vals));
|
ast_str_set(&vals, 0, "?");
|
||||||
while ((field = field->next)) {
|
while ((field = field->next)) {
|
||||||
snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", field->name);
|
ast_str_append(&keys, 0, ", %s", field->name);
|
||||||
snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
|
ast_str_append(&vals, 0, ", ?");
|
||||||
}
|
}
|
||||||
snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
|
ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)",
|
||||||
|
table, ast_str_buffer(keys), ast_str_buffer(vals));
|
||||||
|
|
||||||
|
ast_free(vals);
|
||||||
|
ast_free(keys);
|
||||||
|
cps.sql = ast_str_buffer(sql);
|
||||||
|
|
||||||
if (ast_string_field_init(&cps, 256)) {
|
if (ast_string_field_init(&cps, 256)) {
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
@@ -746,7 +763,7 @@ static int store_odbc(const char *database, const char *table, const struct ast_
|
|||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,19 +787,19 @@ static int store_odbc(const char *database, const char *table, const struct ast_
|
|||||||
*
|
*
|
||||||
* \retval number of rows affected
|
* \retval number of rows affected
|
||||||
* \retval -1 on failure
|
* \retval -1 on failure
|
||||||
*/
|
*/
|
||||||
static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
|
static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
|
||||||
{
|
{
|
||||||
struct odbc_obj *obj;
|
struct odbc_obj *obj;
|
||||||
SQLHSTMT stmt;
|
SQLHSTMT stmt;
|
||||||
char sql[256];
|
|
||||||
SQLLEN rowcount=0;
|
SQLLEN rowcount=0;
|
||||||
|
struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
const struct ast_variable *field;
|
const struct ast_variable *field;
|
||||||
int res;
|
int res;
|
||||||
struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
|
struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
|
||||||
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
|
||||||
|
|
||||||
if (!table) {
|
if (!table || !sql) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,12 +808,13 @@ static int destroy_odbc(const char *database, const char *table, const char *key
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
|
ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table);
|
||||||
|
|
||||||
for (field = fields; field; field = field->next) {
|
for (field = fields; field; field = field->next) {
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", field->name);
|
ast_str_append(&sql, 0, "%s=? AND ", field->name);
|
||||||
}
|
}
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
|
ast_str_append(&sql, 0, "%s=?", keyfield);
|
||||||
|
|
||||||
|
cps.sql = ast_str_buffer(sql);
|
||||||
|
|
||||||
if (ast_string_field_init(&cps, 256)) {
|
if (ast_string_field_init(&cps, 256)) {
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
@@ -815,7 +833,7 @@ static int destroy_odbc(const char *database, const char *table, const char *key
|
|||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -893,9 +911,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
|
|||||||
struct ast_category *cur_cat;
|
struct ast_category *cur_cat;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
struct odbc_obj *obj;
|
struct odbc_obj *obj;
|
||||||
char sqlbuf[1024] = "";
|
struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
|
||||||
char *sql = sqlbuf;
|
|
||||||
size_t sqlleft = sizeof(sqlbuf);
|
|
||||||
unsigned int last_cat_metric = 0;
|
unsigned int last_cat_metric = 0;
|
||||||
SQLSMALLINT rowcount = 0;
|
SQLSMALLINT rowcount = 0;
|
||||||
SQLHSTMT stmt;
|
SQLHSTMT stmt;
|
||||||
@@ -906,21 +922,21 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
|
|||||||
|
|
||||||
memset(&q, 0, sizeof(q));
|
memset(&q, 0, sizeof(q));
|
||||||
|
|
||||||
if (!file || !strcmp (file, "res_config_odbc.conf"))
|
if (!file || !strcmp (file, "res_config_odbc.conf") || !sql) {
|
||||||
return NULL; /* cant configure myself with myself ! */
|
return NULL; /* cant configure myself with myself ! */
|
||||||
|
}
|
||||||
|
|
||||||
obj = ast_odbc_request_obj2(database, connected_flag);
|
obj = ast_odbc_request_obj2(database, connected_flag);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
q.sql = sqlbuf;
|
ast_str_set(&sql, 0, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'",
|
||||||
|
table, file);
|
||||||
ast_build_string(&sql, &sqlleft, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", table, file);
|
q.sql = ast_str_buffer(sql);
|
||||||
|
|
||||||
stmt = ast_odbc_prepare_and_execute(obj, length_determination_odbc_prepare, &q);
|
stmt = ast_odbc_prepare_and_execute(obj, length_determination_odbc_prepare, &q);
|
||||||
|
|
||||||
if (!stmt) {
|
if (!stmt) {
|
||||||
ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -928,7 +944,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
|
|||||||
res = SQLNumResultCols(stmt, &rowcount);
|
res = SQLNumResultCols(stmt, &rowcount);
|
||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
|
||||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -950,12 +966,11 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
|
|||||||
|
|
||||||
/* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
|
/* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
|
||||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
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_str_set(&sql, 0, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
|
||||||
ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
|
ast_str_append(&sql, 0, "WHERE filename='%s' AND commented=0 ", file);
|
||||||
ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
|
ast_str_append(&sql, 0, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
|
||||||
|
q.sql = ast_str_buffer(sql);
|
||||||
|
|
||||||
q.var_val_size += 1;
|
q.var_val_size += 1;
|
||||||
q.var_val = ast_malloc(q.var_val_size);
|
q.var_val = ast_malloc(q.var_val_size);
|
||||||
@@ -966,9 +981,8 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
|
stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
|
||||||
|
|
||||||
if (!stmt) {
|
if (!stmt) {
|
||||||
ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
ast_free(q.var_val);
|
ast_free(q.var_val);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -977,7 +991,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
|
|||||||
res = SQLNumResultCols(stmt, &rowcount);
|
res = SQLNumResultCols(stmt, &rowcount);
|
||||||
|
|
||||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||||
ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
|
ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
|
||||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||||
ast_odbc_release_obj(obj);
|
ast_odbc_release_obj(obj);
|
||||||
ast_free(q.var_val);
|
ast_free(q.var_val);
|
||||||
|
Reference in New Issue
Block a user