2004-06-11 00:12:35 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2004-06-11 00:12:35 +00:00
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
2004-06-11 00:12:35 +00:00
*
2004-10-05 06:46:11 +00:00
* Mark Spencer < markster @ digium . com >
2004-06-11 00:12:35 +00:00
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 2004 - 2005 Anthony Minessale II < anthmct @ yahoo . com >
2005-09-14 20:46:50 +00:00
*
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
* This program is free software , distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief odbc + odbc plugin for portable configuration engine
2005-09-14 20:46:50 +00:00
*
2005-12-30 21:18:06 +00:00
* \ author Mark Spencer < markster @ digium . com >
* \ author Anthony Minessale II < anthmct @ yahoo . com >
*
* \ arg http : //www.unixodbc.org
2004-06-11 00:12:35 +00:00
*/
2006-04-24 17:11:45 +00:00
/*** MODULEINFO
2008-11-04 15:07:54 +00:00
< depend > odbc < / depend >
2007-06-18 16:35:51 +00:00
< depend > ltdl < / depend >
2007-02-09 23:53:51 +00:00
< depend > res_odbc < / depend >
2008-10-06 23:14:33 +00:00
< use > unixodbc < / use >
< use > iodbc < / use >
2006-04-24 17:11:45 +00:00
* * */
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-04-21 06:02:45 +00:00
# include "asterisk/file.h"
# include "asterisk/channel.h"
# include "asterisk/pbx.h"
# include "asterisk/config.h"
# include "asterisk/module.h"
# include "asterisk/lock.h"
# include "asterisk/res_odbc.h"
# include "asterisk/utils.h"
2004-06-11 00:12:35 +00:00
2008-10-14 00:08:52 +00:00
AST_THREADSTORAGE ( sql_buf ) ;
2007-08-07 19:14:45 +00:00
struct custom_prepare_struct {
const char * sql ;
const char * extra ;
2007-08-07 21:00:10 +00:00
va_list ap ;
2008-06-05 19:07:27 +00:00
unsigned long long skip ;
2007-08-07 19:14:45 +00:00
} ;
static SQLHSTMT custom_prepare ( struct odbc_obj * obj , void * data )
{
2008-06-05 19:07:27 +00:00
int res , x = 1 , count = 0 ;
2007-08-07 19:14:45 +00:00
struct custom_prepare_struct * cps = data ;
const char * newparam , * newval ;
SQLHSTMT stmt ;
va_list ap ;
2007-08-07 21:00:10 +00:00
va_copy ( ap , cps - > ap ) ;
2007-08-07 19:14:45 +00:00
res = SQLAllocHandle ( SQL_HANDLE_STMT , obj - > con , & stmt ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Alloc Handle failed! \n " ) ;
return NULL ;
}
res = SQLPrepare ( stmt , ( unsigned char * ) cps - > sql , SQL_NTS ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Prepare failed![%s] \n " , cps - > sql ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
return NULL ;
}
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
2008-06-05 19:07:27 +00:00
if ( ( 1 < < count ) & cps - > skip ) {
continue ;
}
2007-08-07 19:14:45 +00:00
SQLBindParameter ( stmt , x + + , SQL_PARAM_INPUT , SQL_C_CHAR , SQL_CHAR , strlen ( newval ) , 0 , ( void * ) newval , 0 , NULL ) ;
}
va_end ( ap ) ;
if ( ! ast_strlen_zero ( cps - > extra ) )
SQLBindParameter ( stmt , x + + , SQL_PARAM_INPUT , SQL_C_CHAR , SQL_CHAR , strlen ( cps - > extra ) , 0 , ( void * ) cps - > extra , 0 , NULL ) ;
return stmt ;
}
2007-07-23 14:32:04 +00:00
/*!
* \ brief Excute an SQL query and return ast_variable list
* \ param database
* \ param table
2007-09-05 16:31:39 +00:00
* \ param ap list containing one or more field / operator / value set .
*
2007-07-23 14:32:04 +00:00
* Select database and preform query on table , prepare the sql statement
* Sub - in the values to the prepared statement and execute it . Return results
* as a ast_variable list .
*
* \ retval var on success
* \ retval NULL on failure
*/
2004-10-07 19:57:50 +00:00
static struct ast_variable * realtime_odbc ( const char * database , const char * table , va_list ap )
2004-07-08 20:16:28 +00:00
{
2006-04-18 18:16:32 +00:00
struct odbc_obj * obj ;
2004-10-05 06:46:11 +00:00
SQLHSTMT stmt ;
2004-11-22 05:03:03 +00:00
char sql [ 1024 ] ;
2004-10-05 06:46:11 +00:00
char coltitle [ 256 ] ;
char rowdata [ 2048 ] ;
2004-11-22 05:03:03 +00:00
char * op ;
2004-10-07 19:57:50 +00:00
const char * newparam , * newval ;
2004-10-05 06:46:11 +00:00
char * stringp ;
char * chunk ;
SQLSMALLINT collen ;
int res ;
int x ;
struct ast_variable * var = NULL , * prev = NULL ;
SQLULEN colsize ;
SQLSMALLINT colcount = 0 ;
SQLSMALLINT datatype ;
SQLSMALLINT decimaldigits ;
SQLSMALLINT nullable ;
2006-12-19 14:57:45 +00:00
SQLLEN indicator ;
2004-10-07 19:57:50 +00:00
va_list aq ;
2007-08-07 21:00:10 +00:00
struct custom_prepare_struct cps = { . sql = sql } ;
va_copy ( cps . ap , ap ) ;
2004-10-07 19:57:50 +00:00
va_copy ( aq , ap ) ;
2007-08-07 19:14:45 +00:00
2004-10-05 06:46:11 +00:00
if ( ! table )
return NULL ;
2006-09-20 04:57:20 +00:00
obj = ast_odbc_request_obj ( database , 0 ) ;
2004-10-05 06:46:11 +00:00
2007-08-07 19:14:45 +00:00
if ( ! obj ) {
ast_log ( LOG_ERROR , " No database handle available with the name of '%s' (check res_odbc.conf) \n " , database ) ;
2004-10-05 06:46:11 +00:00
return NULL ;
}
2004-10-07 19:57:50 +00:00
newparam = va_arg ( aq , const char * ) ;
2008-07-10 21:23:23 +00:00
if ( ! newparam ) {
ast_odbc_release_obj ( obj ) ;
2004-10-07 19:57:50 +00:00
return NULL ;
2008-07-10 21:23:23 +00:00
}
2004-10-07 19:57:50 +00:00
newval = va_arg ( aq , const char * ) ;
2007-07-11 18:35:36 +00:00
op = ! strchr ( newparam , ' ' ) ? " = " : " " ;
2007-11-25 17:50:07 +00:00
snprintf ( sql , sizeof ( sql ) , " SELECT * FROM %s WHERE %s%s ?%s " , table , newparam , op ,
strcasestr ( newparam , " LIKE " ) & & ! ast_odbc_backslash_is_escape ( obj ) ? " ESCAPE ' \\ ' " : " " ) ;
2004-10-07 19:57:50 +00:00
while ( ( newparam = va_arg ( aq , const char * ) ) ) {
2007-07-11 18:35:36 +00:00
op = ! strchr ( newparam , ' ' ) ? " = " : " " ;
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " AND %s%s ?%s " , newparam , op ,
2007-11-25 17:50:07 +00:00
strcasestr ( newparam , " LIKE " ) & & ! ast_odbc_backslash_is_escape ( obj ) ? " ESCAPE ' \\ ' " : " " ) ;
2004-10-07 19:57:50 +00:00
newval = va_arg ( aq , const char * ) ;
}
va_end ( aq ) ;
2007-07-06 16:14:39 +00:00
2007-08-07 19:14:45 +00:00
stmt = ast_odbc_prepare_and_execute ( obj , custom_prepare , & cps ) ;
2004-10-05 06:46:11 +00:00
2007-08-07 19:14:45 +00:00
if ( ! stmt ) {
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
return NULL ;
}
2005-10-31 21:31:25 +00:00
res = SQLNumResultCols ( stmt , & colcount ) ;
2004-10-05 06:46:11 +00:00
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
2005-10-31 21:31:25 +00:00
ast_log ( LOG_WARNING , " SQL Column Count error! \n [%s] \n \n " , sql ) ;
2004-10-05 06:46:11 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
return NULL ;
}
2005-10-31 21:31:25 +00:00
res = SQLFetch ( stmt ) ;
if ( res = = SQL_NO_DATA ) {
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2007-08-07 19:14:45 +00:00
return NULL ;
2005-10-31 21:31:25 +00:00
}
2004-10-05 06:46:11 +00:00
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
2005-10-31 21:31:25 +00:00
ast_log ( LOG_WARNING , " SQL Fetch error! \n [%s] \n \n " , sql ) ;
2004-10-05 06:46:11 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
return NULL ;
}
2006-04-18 18:16:32 +00:00
for ( x = 0 ; x < colcount ; x + + ) {
2005-10-31 21:31:25 +00:00
rowdata [ 0 ] = ' \0 ' ;
collen = sizeof ( coltitle ) ;
2006-03-01 17:53:05 +00:00
res = SQLDescribeCol ( stmt , x + 1 , ( unsigned char * ) coltitle , sizeof ( coltitle ) , & collen ,
2005-10-31 21:31:25 +00:00
& datatype , & colsize , & decimaldigits , & nullable ) ;
2004-10-05 06:46:11 +00:00
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
2005-10-31 21:31:25 +00:00
ast_log ( LOG_WARNING , " SQL Describe Column error! \n [%s] \n \n " , sql ) ;
if ( var )
ast_variables_destroy ( var ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
return NULL ;
}
2005-04-22 01:59:53 +00:00
2005-10-31 21:31:25 +00:00
indicator = 0 ;
res = SQLGetData ( stmt , x + 1 , SQL_CHAR , rowdata , sizeof ( rowdata ) , & indicator ) ;
if ( indicator = = SQL_NULL_DATA )
2007-01-07 16:21:12 +00:00
rowdata [ 0 ] = ' \0 ' ;
else if ( ast_strlen_zero ( 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 ) ) ;
}
2005-04-22 01:59:53 +00:00
2005-10-31 21:31:25 +00:00
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Get Data error! \n [%s] \n \n " , sql ) ;
if ( var )
ast_variables_destroy ( var ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2005-10-31 21:31:25 +00:00
return NULL ;
}
stringp = rowdata ;
while ( stringp ) {
chunk = strsep ( & stringp , " ; " ) ;
2007-08-07 19:14:45 +00:00
if ( ! ast_strlen_zero ( ast_strip ( chunk ) ) ) {
if ( prev ) {
2007-08-29 20:55:40 +00:00
prev - > next = ast_variable_new ( coltitle , chunk , " " ) ;
2007-08-07 19:14:45 +00:00
if ( prev - > next )
prev = prev - > next ;
} else
2007-08-29 20:55:40 +00:00
prev = var = ast_variable_new ( coltitle , chunk , " " ) ;
2007-08-07 19:14:45 +00:00
}
2004-10-05 06:46:11 +00:00
}
}
2007-08-07 19:14:45 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
return var ;
}
2007-07-23 14:32:04 +00:00
/*!
* \ brief Excute an Select query and return ast_config list
* \ param database
* \ param table
2007-09-05 16:31:39 +00:00
* \ param ap list containing one or more field / operator / value set .
*
2007-07-23 14:32:04 +00:00
* Select database and preform query on table , prepare the sql statement
* Sub - in the values to the prepared statement and execute it .
* Execute this prepared query against several ODBC connected databases .
* Return results as an ast_config variable .
*
* \ retval var on success
* \ retval NULL on failure
*/
2004-11-23 17:58:59 +00:00
static struct ast_config * realtime_multi_odbc ( const char * database , const char * table , va_list ap )
{
2006-04-18 18:16:32 +00:00
struct odbc_obj * obj ;
2004-11-23 17:58:59 +00:00
SQLHSTMT stmt ;
char sql [ 1024 ] ;
char coltitle [ 256 ] ;
char rowdata [ 2048 ] ;
2004-11-24 03:07:08 +00:00
const char * initfield = NULL ;
2004-11-23 17:58:59 +00:00
char * op ;
const char * newparam , * newval ;
char * stringp ;
char * chunk ;
SQLSMALLINT collen ;
int res ;
int x ;
2005-01-25 06:10:20 +00:00
struct ast_variable * var = NULL ;
2004-11-23 17:58:59 +00:00
struct ast_config * cfg = NULL ;
struct ast_category * cat = NULL ;
SQLULEN colsize ;
SQLSMALLINT colcount = 0 ;
SQLSMALLINT datatype ;
SQLSMALLINT decimaldigits ;
SQLSMALLINT nullable ;
2006-12-19 14:57:45 +00:00
SQLLEN indicator ;
2007-08-07 21:00:10 +00:00
struct custom_prepare_struct cps = { . sql = sql } ;
2004-11-23 17:58:59 +00:00
va_list aq ;
2007-08-07 21:00:10 +00:00
va_copy ( cps . ap , ap ) ;
2004-11-23 17:58:59 +00:00
va_copy ( aq , ap ) ;
2007-06-28 19:41:18 +00:00
2004-11-23 17:58:59 +00:00
if ( ! table )
return NULL ;
2006-09-20 04:57:20 +00:00
obj = ast_odbc_request_obj ( database , 0 ) ;
2004-11-23 17:58:59 +00:00
if ( ! obj )
return NULL ;
newparam = va_arg ( aq , const char * ) ;
if ( ! newparam ) {
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-11-23 17:58:59 +00:00
return NULL ;
}
2004-11-24 03:07:08 +00:00
initfield = ast_strdupa ( newparam ) ;
2006-05-10 13:22:15 +00:00
if ( ( op = strchr ( initfield , ' ' ) ) )
2004-11-24 03:07:08 +00:00
* op = ' \0 ' ;
2004-11-23 17:58:59 +00:00
newval = va_arg ( aq , const char * ) ;
2007-07-11 18:35:36 +00:00
op = ! strchr ( newparam , ' ' ) ? " = " : " " ;
2007-11-23 17:09:06 +00:00
snprintf ( sql , sizeof ( sql ) , " SELECT * FROM %s WHERE %s%s ?%s " , table , newparam , op ,
2007-11-25 17:50:07 +00:00
strcasestr ( newparam , " LIKE " ) & & ! ast_odbc_backslash_is_escape ( obj ) ? " ESCAPE ' \\ ' " : " " ) ;
2004-11-23 17:58:59 +00:00
while ( ( newparam = va_arg ( aq , const char * ) ) ) {
2007-07-11 18:35:36 +00:00
op = ! strchr ( newparam , ' ' ) ? " = " : " " ;
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " AND %s%s ?%s " , newparam , op ,
2007-11-25 17:50:07 +00:00
strcasestr ( newparam , " LIKE " ) & & ! ast_odbc_backslash_is_escape ( obj ) ? " ESCAPE ' \\ ' " : " " ) ;
2004-11-23 17:58:59 +00:00
newval = va_arg ( aq , const char * ) ;
}
2004-11-24 03:07:08 +00:00
if ( initfield )
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " ORDER BY %s " , initfield ) ;
2004-11-23 17:58:59 +00:00
va_end ( aq ) ;
2007-07-06 16:14:39 +00:00
2007-08-07 19:14:45 +00:00
stmt = ast_odbc_prepare_and_execute ( obj , custom_prepare , & cps ) ;
2004-11-23 17:58:59 +00:00
2007-08-07 19:14:45 +00:00
if ( ! stmt ) {
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-11-23 17:58:59 +00:00
return NULL ;
}
res = SQLNumResultCols ( stmt , & colcount ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Column Count error! \n [%s] \n \n " , sql ) ;
2006-04-18 18:16:32 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-11-23 17:58:59 +00:00
return NULL ;
}
2005-01-25 06:10:20 +00:00
cfg = ast_config_new ( ) ;
if ( ! cfg ) {
ast_log ( LOG_WARNING , " Out of memory! \n " ) ;
2006-04-18 18:16:32 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2005-01-25 06:10:20 +00:00
return NULL ;
}
2005-10-31 21:31:25 +00:00
while ( ( res = SQLFetch ( stmt ) ) ! = SQL_NO_DATA ) {
2004-11-23 17:58:59 +00:00
var = NULL ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Fetch error! \n [%s] \n \n " , sql ) ;
continue ;
}
2007-08-29 20:55:40 +00:00
cat = ast_category_new ( " " , " " , 99999 ) ;
2005-01-25 06:10:20 +00:00
if ( ! cat ) {
ast_log ( LOG_WARNING , " Out of memory! \n " ) ;
continue ;
}
2004-11-23 17:58:59 +00:00
for ( x = 0 ; x < colcount ; x + + ) {
rowdata [ 0 ] = ' \0 ' ;
collen = sizeof ( coltitle ) ;
2006-03-01 17:53:05 +00:00
res = SQLDescribeCol ( stmt , x + 1 , ( unsigned char * ) coltitle , sizeof ( coltitle ) , & collen ,
2004-11-23 17:58:59 +00:00
& datatype , & colsize , & decimaldigits , & nullable ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Describe Column error! \n [%s] \n \n " , sql ) ;
2005-01-25 06:10:20 +00:00
ast_category_destroy ( cat ) ;
2004-11-23 17:58:59 +00:00
continue ;
}
2005-04-22 01:59:53 +00:00
indicator = 0 ;
res = SQLGetData ( stmt , x + 1 , SQL_CHAR , rowdata , sizeof ( rowdata ) , & indicator ) ;
if ( indicator = = SQL_NULL_DATA )
continue ;
2004-11-23 17:58:59 +00:00
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Get Data error! \n [%s] \n \n " , sql ) ;
2005-01-25 06:10:20 +00:00
ast_category_destroy ( cat ) ;
2004-11-23 17:58:59 +00:00
continue ;
}
stringp = rowdata ;
while ( stringp ) {
chunk = strsep ( & stringp , " ; " ) ;
2005-11-08 01:55:31 +00:00
if ( ! ast_strlen_zero ( ast_strip ( chunk ) ) ) {
2005-01-25 06:10:20 +00:00
if ( initfield & & ! strcmp ( initfield , coltitle ) )
ast_category_rename ( cat , chunk ) ;
2007-08-29 20:55:40 +00:00
var = ast_variable_new ( coltitle , chunk , " " ) ;
2005-01-25 06:10:20 +00:00
ast_variable_append ( cat , var ) ;
2004-11-23 17:58:59 +00:00
}
}
2004-11-24 03:07:08 +00:00
}
2005-01-25 06:10:20 +00:00
ast_category_append ( cfg , cat ) ;
2004-11-23 17:58:59 +00:00
}
2006-04-18 18:16:32 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-11-23 17:58:59 +00:00
return cfg ;
}
2007-07-23 14:32:04 +00:00
/*!
* \ brief Excute an UPDATE query
* \ param database
* \ param table
* \ param keyfield where clause field
* \ param lookup value of field for where clause
2007-09-05 16:31:39 +00:00
* \ param ap list containing one or more field / value set ( s ) .
*
2007-07-23 14:32:04 +00:00
* Update a database table , prepare the sql statement using keyfield and lookup
* control the number of records to change . All values to be changed are stored in ap list .
* Sub - in the values to the prepared statement and execute it .
*
* \ retval number of rows affected
* \ retval - 1 on failure
*/
2004-10-05 06:46:11 +00:00
static int update_odbc ( const char * database , const char * table , const char * keyfield , const char * lookup , va_list ap )
{
2006-04-18 18:16:32 +00:00
struct odbc_obj * obj ;
2004-10-05 06:46:11 +00:00
SQLHSTMT stmt ;
char sql [ 256 ] ;
SQLLEN rowcount = 0 ;
const char * newparam , * newval ;
2008-06-05 19:07:27 +00:00
int res , count = 0 ;
2004-10-05 06:46:11 +00:00
va_list aq ;
2007-08-07 21:00:10 +00:00
struct custom_prepare_struct cps = { . sql = sql , . extra = lookup } ;
2008-06-10 21:14:58 +00:00
struct odbc_cache_tables * tableptr = ast_odbc_find_table ( database , table ) ;
2008-06-05 19:07:27 +00:00
struct odbc_cache_columns * column ;
2007-08-07 21:00:10 +00:00
va_copy ( cps . ap , ap ) ;
2004-10-05 06:46:11 +00:00
va_copy ( aq , ap ) ;
2008-06-05 19:07:27 +00:00
if ( ! table ) {
2008-06-10 21:14:58 +00:00
ast_odbc_release_table ( tableptr ) ;
2004-10-05 06:46:11 +00:00
return - 1 ;
2008-06-05 19:07:27 +00:00
}
2004-10-05 06:46:11 +00:00
2006-09-20 04:57:20 +00:00
obj = ast_odbc_request_obj ( database , 0 ) ;
2008-06-05 19:07:27 +00:00
if ( ! obj ) {
2008-06-10 21:14:58 +00:00
ast_odbc_release_table ( tableptr ) ;
2004-10-05 06:46:11 +00:00
return - 1 ;
2008-06-05 19:07:27 +00:00
}
2004-10-05 06:46:11 +00:00
newparam = va_arg ( aq , const char * ) ;
if ( ! newparam ) {
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2008-06-10 21:14:58 +00:00
ast_odbc_release_table ( tableptr ) ;
2004-10-05 06:46:11 +00:00
return - 1 ;
}
newval = va_arg ( aq , const char * ) ;
2008-06-05 19:07:27 +00:00
2008-06-10 21:14:58 +00:00
if ( tableptr & & ! ( column = ast_odbc_find_column ( tableptr , newparam ) ) ) {
2008-06-05 19:07:27 +00:00
ast_log ( LOG_WARNING , " Key field '%s' does not exist in table '%s@%s'. Update will fail \n " , newparam , table , database ) ;
}
2004-10-05 06:46:11 +00:00
snprintf ( sql , sizeof ( sql ) , " UPDATE %s SET %s=? " , table , newparam ) ;
while ( ( newparam = va_arg ( aq , const char * ) ) ) {
2008-06-10 21:14:58 +00:00
if ( ( tableptr & & ( column = ast_odbc_find_column ( tableptr , newparam ) ) ) | | count > 63 ) {
2008-06-05 19:07:27 +00:00
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " , %s=? " , newparam ) ;
newval = va_arg ( aq , const char * ) ;
} else { /* the column does not exist in the table OR we've exceeded the space in our flag field */
cps . skip | = ( ( ( long long ) 1 ) < < count ) ;
}
count + + ;
2004-10-05 06:46:11 +00:00
}
va_end ( aq ) ;
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " WHERE %s=? " , keyfield ) ;
2008-06-10 21:14:58 +00:00
ast_odbc_release_table ( tableptr ) ;
2004-10-05 06:46:11 +00:00
2007-08-07 19:14:45 +00:00
stmt = ast_odbc_prepare_and_execute ( obj , custom_prepare , & cps ) ;
2004-10-05 06:46:11 +00:00
2007-08-07 19:14:45 +00:00
if ( ! stmt ) {
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
return - 1 ;
}
res = SQLRowCount ( stmt , & rowcount ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Row Count error! \n [%s] \n \n " , sql ) ;
return - 1 ;
}
2006-04-18 18:16:32 +00:00
if ( rowcount > = 0 )
return ( int ) rowcount ;
2005-04-22 03:29:03 +00:00
2004-10-05 06:46:11 +00:00
return - 1 ;
}
2008-10-14 00:08:52 +00:00
struct update2_prepare_struct {
const char * database ;
const char * table ;
va_list ap ;
} ;
static SQLHSTMT update2_prepare ( struct odbc_obj * obj , void * data )
{
int res , x = 1 , first = 1 ;
struct update2_prepare_struct * ups = data ;
const char * newparam , * newval ;
struct ast_str * sql = ast_str_thread_get ( & sql_buf , 16 ) ;
SQLHSTMT stmt ;
va_list ap ;
struct odbc_cache_tables * tableptr = ast_odbc_find_table ( ups - > database , ups - > table ) ;
struct odbc_cache_columns * column ;
if ( ! sql ) {
if ( tableptr ) {
ast_odbc_release_table ( tableptr ) ;
}
return NULL ;
}
if ( ! tableptr ) {
ast_log ( LOG_ERROR , " Could not retrieve metadata for table '%s@%s'. Update will fail! \n " , ups - > table , ups - > database ) ;
return NULL ;
}
res = SQLAllocHandle ( SQL_HANDLE_STMT , obj - > con , & stmt ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Alloc Handle failed! \n " ) ;
ast_odbc_release_table ( tableptr ) ;
return NULL ;
}
ast_str_set ( & sql , 0 , " UPDATE %s SET " , ups - > table ) ;
/* Start by finding the second set of parameters */
va_copy ( ap , ups - > ap ) ;
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
}
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
if ( ( column = ast_odbc_find_column ( tableptr , newparam ) ) ) {
ast_str_append ( & sql , 0 , " %s%s=? " , first ? " " : " , " , newparam ) ;
SQLBindParameter ( stmt , x + + , SQL_PARAM_INPUT , SQL_C_CHAR , SQL_CHAR , strlen ( newval ) , 0 , ( void * ) newval , 0 , NULL ) ;
first = 0 ;
} else {
ast_log ( LOG_NOTICE , " Not updating column '%s' in '%s@%s' because that column does not exist! \n " , newparam , ups - > table , ups - > database ) ;
}
}
va_end ( ap ) ;
/* Restart search, because we need to add the search parameters */
va_copy ( ap , ups - > ap ) ;
ast_str_append ( & sql , 0 , " WHERE " ) ;
first = 1 ;
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
if ( ! ( column = ast_odbc_find_column ( tableptr , newparam ) ) ) {
ast_log ( LOG_ERROR , " One or more of the criteria columns '%s' on '%s@%s' for this update does not exist! \n " , newparam , ups - > table , ups - > database ) ;
ast_odbc_release_table ( tableptr ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
return NULL ;
}
ast_str_append ( & sql , 0 , " %s %s=? " , first ? " " : " AND " , newparam ) ;
SQLBindParameter ( stmt , x + + , SQL_PARAM_INPUT , SQL_C_CHAR , SQL_CHAR , strlen ( newval ) , 0 , ( void * ) newval , 0 , NULL ) ;
first = 0 ;
}
va_end ( ap ) ;
/* Done with the table metadata */
ast_odbc_release_table ( tableptr ) ;
res = SQLPrepare ( stmt , ( unsigned char * ) sql - > str , SQL_NTS ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Prepare failed![%s] \n " , sql - > str ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
return NULL ;
}
return stmt ;
}
/*!
* \ brief Execute an UPDATE query
* \ param database
* \ param table
* \ param ap list containing one or more field / value set ( s ) .
*
* Update a database table , preparing the sql statement from a list of
* key / value pairs specified in ap . The lookup pairs are specified first
* and are separated from the update pairs by a sentinel value .
* Sub - in the values to the prepared statement and execute it .
*
* \ retval number of rows affected
* \ retval - 1 on failure
*/
static int update2_odbc ( const char * database , const char * table , va_list ap )
{
struct odbc_obj * obj ;
SQLHSTMT stmt ;
struct update2_prepare_struct ups = { . database = database , . table = table , } ;
struct ast_str * sql ;
int res ;
SQLLEN rowcount = 0 ;
va_copy ( ups . ap , ap ) ;
if ( ! ( obj = ast_odbc_request_obj ( database , 0 ) ) ) {
return - 1 ;
}
if ( ! ( stmt = ast_odbc_prepare_and_execute ( obj , update2_prepare , & ups ) ) ) {
ast_odbc_release_obj ( obj ) ;
return - 1 ;
}
res = SQLRowCount ( stmt , & rowcount ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
ast_odbc_release_obj ( obj ) ;
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. */
sql = ast_str_thread_get ( & sql_buf , 16 ) ;
ast_log ( LOG_WARNING , " SQL Row Count error! \n [%s] \n " , sql - > str ) ;
return - 1 ;
}
if ( rowcount > = 0 ) {
return ( int ) rowcount ;
}
return - 1 ;
}
2007-08-17 13:45:44 +00:00
/*!
* \ brief Excute an INSERT query
* \ param database
* \ param table
* \ param ap list containing one or more field / value set ( s )
2007-09-05 16:31:39 +00:00
*
2007-08-17 13:45:44 +00:00
* Insert a new record into database table , prepare the sql statement .
* All values to be changed are stored in ap list .
* Sub - in the values to the prepared statement and execute it .
*
* \ retval number of rows affected
* \ retval - 1 on failure
*/
static int store_odbc ( const char * database , const char * table , va_list ap )
{
struct odbc_obj * obj ;
SQLHSTMT stmt ;
char sql [ 256 ] ;
char keys [ 256 ] ;
char vals [ 256 ] ;
SQLLEN rowcount = 0 ;
const char * newparam , * newval ;
int res ;
va_list aq ;
struct custom_prepare_struct cps = { . sql = sql , . extra = NULL } ;
va_copy ( cps . ap , ap ) ;
va_copy ( aq , ap ) ;
if ( ! table )
return - 1 ;
obj = ast_odbc_request_obj ( database , 0 ) ;
if ( ! obj )
return - 1 ;
newparam = va_arg ( aq , const char * ) ;
if ( ! newparam ) {
ast_odbc_release_obj ( obj ) ;
return - 1 ;
}
newval = va_arg ( aq , const char * ) ;
snprintf ( keys , sizeof ( keys ) , " %s " , newparam ) ;
2007-10-01 15:23:19 +00:00
ast_copy_string ( vals , " ? " , sizeof ( vals ) ) ;
2007-08-17 13:45:44 +00:00
while ( ( newparam = va_arg ( aq , const char * ) ) ) {
snprintf ( keys + strlen ( keys ) , sizeof ( keys ) - strlen ( keys ) , " , %s " , newparam ) ;
snprintf ( vals + strlen ( vals ) , sizeof ( vals ) - strlen ( vals ) , " , ? " ) ;
newval = va_arg ( aq , const char * ) ;
}
va_end ( aq ) ;
snprintf ( sql , sizeof ( sql ) , " INSERT INTO %s (%s) VALUES (%s) " , table , keys , vals ) ;
stmt = ast_odbc_prepare_and_execute ( obj , custom_prepare , & cps ) ;
if ( ! stmt ) {
ast_odbc_release_obj ( obj ) ;
return - 1 ;
}
res = SQLRowCount ( stmt , & rowcount ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
ast_odbc_release_obj ( obj ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Row Count error! \n [%s] \n \n " , sql ) ;
return - 1 ;
}
if ( rowcount > = 0 )
return ( int ) rowcount ;
return - 1 ;
}
/*!
* \ brief Excute an DELETE query
* \ param database
* \ param table
* \ param keyfield where clause field
* \ param lookup value of field for where clause
* \ param ap list containing one or more field / value set ( s )
2007-09-05 16:31:39 +00:00
*
* Delete a row from a database table , prepare the sql statement using keyfield and lookup
2007-08-17 13:45:44 +00:00
* control the number of records to change . Additional params to match rows are stored in ap list .
* Sub - in the values to the prepared statement and execute it .
*
* \ retval number of rows affected
* \ retval - 1 on failure
*/
static int destroy_odbc ( const char * database , const char * table , const char * keyfield , const char * lookup , va_list ap )
{
struct odbc_obj * obj ;
SQLHSTMT stmt ;
char sql [ 256 ] ;
SQLLEN rowcount = 0 ;
const char * newparam , * newval ;
int res ;
va_list aq ;
struct custom_prepare_struct cps = { . sql = sql , . extra = lookup } ;
va_copy ( cps . ap , ap ) ;
va_copy ( aq , ap ) ;
if ( ! table )
return - 1 ;
obj = ast_odbc_request_obj ( database , 0 ) ;
if ( ! obj )
return - 1 ;
snprintf ( sql , sizeof ( sql ) , " DELETE FROM %s WHERE " , table ) ;
while ( ( newparam = va_arg ( aq , const char * ) ) ) {
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " %s=? AND " , newparam ) ;
newval = va_arg ( aq , const char * ) ;
}
va_end ( aq ) ;
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " %s=? " , keyfield ) ;
stmt = ast_odbc_prepare_and_execute ( obj , custom_prepare , & cps ) ;
if ( ! stmt ) {
ast_odbc_release_obj ( obj ) ;
return - 1 ;
}
res = SQLRowCount ( stmt , & rowcount ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
ast_odbc_release_obj ( obj ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
ast_log ( LOG_WARNING , " SQL Row Count error! \n [%s] \n \n " , sql ) ;
return - 1 ;
}
if ( rowcount > = 0 )
return ( int ) rowcount ;
return - 1 ;
}
2006-04-18 18:16:32 +00:00
struct config_odbc_obj {
char * sql ;
unsigned long cat_metric ;
char category [ 128 ] ;
char var_name [ 128 ] ;
2006-11-01 19:48:40 +00:00
char var_val [ 1024 ] ; /* changed from 128 to 1024 via bug 8251 */
2006-12-19 14:57:45 +00:00
SQLLEN err ;
2006-04-18 18:16:32 +00:00
} ;
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 ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 4 , " Failure in AllocStatement %d \n " , res ) ;
2006-04-18 18:16:32 +00:00
return NULL ;
}
res = SQLPrepare ( sth , ( unsigned char * ) q - > sql , SQL_NTS ) ;
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 4 , " Error in PREPARE %d \n " , res ) ;
2006-04-18 18:16:32 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , sth ) ;
return NULL ;
}
2007-05-03 00:10:38 +00:00
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 ) ;
2006-04-18 18:16:32 +00:00
return sth ;
}
2008-03-11 22:55:16 +00:00
static struct ast_config * config_odbc ( const char * database , const char * table , const char * file , struct ast_config * cfg , struct ast_flags flags , const char * sugg_incl , const char * who_asked )
2004-10-05 06:46:11 +00:00
{
2005-01-25 06:10:20 +00:00
struct ast_variable * new_v ;
struct ast_category * cur_cat ;
2004-10-05 06:46:11 +00:00
int res = 0 ;
2006-04-18 18:16:32 +00:00
struct odbc_obj * obj ;
2007-05-03 00:10:38 +00:00
char sqlbuf [ 1024 ] = " " ;
2007-05-03 00:25:50 +00:00
char * sql = sqlbuf ;
2007-05-03 00:10:38 +00:00
size_t sqlleft = sizeof ( sqlbuf ) ;
2006-04-18 18:16:32 +00:00
unsigned int last_cat_metric = 0 ;
2007-05-03 00:10:38 +00:00
SQLSMALLINT rowcount = 0 ;
2004-07-08 20:16:28 +00:00
SQLHSTMT stmt ;
2005-01-25 06:10:20 +00:00
char last [ 128 ] = " " ;
2006-04-18 18:16:32 +00:00
struct config_odbc_obj q ;
2007-08-16 21:09:46 +00:00
struct ast_flags loader_flags = { 0 } ;
2006-04-18 18:16:32 +00:00
memset ( & q , 0 , sizeof ( q ) ) ;
2004-07-08 20:16:28 +00:00
if ( ! file | | ! strcmp ( file , " res_config_odbc.conf " ) )
2004-12-18 22:04:07 +00:00
return NULL ; /* cant configure myself with myself ! */
2004-07-08 20:16:28 +00:00
2006-09-20 04:57:20 +00:00
obj = ast_odbc_request_obj ( database , 0 ) ;
2004-07-08 20:16:28 +00:00
if ( ! obj )
return NULL ;
2007-05-03 00:10:38 +00:00
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 ;
2004-07-08 20:16:28 +00:00
2006-09-20 04:57:20 +00:00
stmt = ast_odbc_prepare_and_execute ( obj , config_odbc_prepare , & q ) ;
2006-04-18 18:16:32 +00:00
if ( ! stmt ) {
ast_log ( LOG_WARNING , " SQL select error! \n [%s] \n \n " , sql ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-07-08 20:16:28 +00:00
return NULL ;
2004-06-11 00:12:35 +00:00
}
2006-04-18 18:16:32 +00:00
res = SQLNumResultCols ( stmt , & rowcount ) ;
2004-06-11 00:12:35 +00:00
2004-07-08 20:16:28 +00:00
if ( ( res ! = SQL_SUCCESS ) & & ( res ! = SQL_SUCCESS_WITH_INFO ) ) {
2006-04-18 18:16:32 +00:00
ast_log ( LOG_WARNING , " SQL NumResultCols error! \n [%s] \n \n " , sql ) ;
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2004-10-05 06:46:11 +00:00
return NULL ;
}
2005-01-25 06:10:20 +00:00
if ( ! rowcount ) {
2006-04-18 18:16:32 +00:00
ast_log ( LOG_NOTICE , " found nothing \n " ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2005-01-25 06:10:20 +00:00
return cfg ;
}
2004-07-08 20:16:28 +00:00
2005-01-25 06:10:20 +00:00
cur_cat = ast_config_get_current_category ( cfg ) ;
2004-07-08 20:16:28 +00:00
2005-01-25 06:10:20 +00:00
while ( ( res = SQLFetch ( stmt ) ) ! = SQL_NO_DATA ) {
2006-04-18 18:16:32 +00:00
if ( ! strcmp ( q . var_name , " #include " ) ) {
2008-03-11 22:55:16 +00:00
if ( ! ast_config_internal_load ( q . var_val , cfg , loader_flags , " " , who_asked ) ) {
2006-04-18 18:16:32 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2005-01-25 06:10:20 +00:00
return NULL ;
2004-07-08 20:16:28 +00:00
}
2005-01-25 06:10:20 +00:00
continue ;
}
2006-04-18 18:16:32 +00:00
if ( strcmp ( last , q . category ) | | last_cat_metric ! = q . cat_metric ) {
2007-08-29 20:55:40 +00:00
cur_cat = ast_category_new ( q . category , " " , 99999 ) ;
2005-01-25 06:10:20 +00:00
if ( ! cur_cat ) {
ast_log ( LOG_WARNING , " Out of memory! \n " ) ;
break ;
}
2006-04-18 18:16:32 +00:00
strcpy ( last , q . category ) ;
last_cat_metric = q . cat_metric ;
2005-01-25 06:10:20 +00:00
ast_category_append ( cfg , cur_cat ) ;
2004-07-08 20:16:28 +00:00
}
2007-08-29 20:55:40 +00:00
new_v = ast_variable_new ( q . var_name , q . var_val , " " ) ;
2005-01-25 06:10:20 +00:00
ast_variable_append ( cur_cat , new_v ) ;
2004-07-08 20:16:28 +00:00
}
2004-06-11 00:12:35 +00:00
2006-04-18 18:16:32 +00:00
SQLFreeHandle ( SQL_HANDLE_STMT , stmt ) ;
2006-09-20 04:57:20 +00:00
ast_odbc_release_obj ( obj ) ;
2005-01-25 06:10:20 +00:00
return cfg ;
2004-07-08 20:16:28 +00:00
}
2004-06-11 00:12:35 +00:00
2008-06-09 22:51:59 +00:00
# define warn_length(col, size) ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is not long enough to contain realtime data (needs %d)\n", table, database, col->name, size)
# define warn_type(col, type) ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is of the incorrect type (%d) to contain the required realtime data\n", table, database, col->name, col->type)
2008-06-05 19:07:27 +00:00
static int require_odbc ( const char * database , const char * table , va_list ap )
{
2008-06-10 21:14:58 +00:00
struct odbc_cache_tables * tableptr = ast_odbc_find_table ( database , table ) ;
2008-06-05 19:07:27 +00:00
struct odbc_cache_columns * col ;
char * elm ;
int type , size ;
if ( ! tableptr ) {
return - 1 ;
}
while ( ( elm = va_arg ( ap , char * ) ) ) {
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 ) {
/* Type check, first. Some fields are more particular than others */
switch ( col - > type ) {
case SQL_CHAR :
case SQL_VARCHAR :
case SQL_LONGVARCHAR :
case SQL_BINARY :
case SQL_VARBINARY :
case SQL_LONGVARBINARY :
case SQL_GUID :
2008-06-09 22:51:59 +00:00
# define CHECK_SIZE(n) \
if ( col - > size < n ) { \
warn_length ( col , n ) ; \
} \
break ;
switch ( type ) {
case RQ_UINTEGER1 : CHECK_SIZE ( 3 ) /* 255 */
case RQ_INTEGER1 : CHECK_SIZE ( 4 ) /* -128 */
case RQ_UINTEGER2 : CHECK_SIZE ( 5 ) /* 65535 */
case RQ_INTEGER2 : CHECK_SIZE ( 6 ) /* -32768 */
case RQ_UINTEGER3 : /* 16777215 */
case RQ_INTEGER3 : CHECK_SIZE ( 8 ) /* -8388608 */
case RQ_DATE : /* 2008-06-09 */
case RQ_UINTEGER4 : CHECK_SIZE ( 10 ) /* 4200000000 */
case RQ_INTEGER4 : CHECK_SIZE ( 11 ) /* -2100000000 */
case RQ_DATETIME : /* 2008-06-09 16:03:47 */
case RQ_UINTEGER8 : CHECK_SIZE ( 19 ) /* trust me */
case RQ_INTEGER8 : CHECK_SIZE ( 20 ) /* ditto */
case RQ_FLOAT :
case RQ_CHAR : CHECK_SIZE ( size )
2008-06-05 19:07:27 +00:00
}
2008-06-09 22:51:59 +00:00
# undef CHECK_SIZE
2008-06-05 19:07:27 +00:00
break ;
case SQL_TYPE_DATE :
if ( type ! = RQ_DATE ) {
warn_type ( col , type ) ;
}
break ;
case SQL_TYPE_TIMESTAMP :
case SQL_TIMESTAMP :
if ( type ! = RQ_DATE & & type ! = RQ_DATETIME ) {
warn_type ( col , type ) ;
}
break ;
case SQL_BIT :
2008-06-09 22:51:59 +00:00
warn_length ( col , size ) ;
break ;
# define WARN_TYPE_OR_LENGTH(n) \
if ( ! ast_rq_is_int ( type ) ) { \
warn_type ( col , type ) ; \
} else { \
warn_length ( col , n ) ; \
}
case SQL_TINYINT :
if ( type ! = RQ_UINTEGER1 ) {
WARN_TYPE_OR_LENGTH ( size )
}
break ;
case SQL_C_STINYINT :
if ( type ! = RQ_INTEGER1 ) {
WARN_TYPE_OR_LENGTH ( size )
2008-06-05 19:07:27 +00:00
}
2008-06-09 22:51:59 +00:00
break ;
case SQL_C_USHORT :
if ( type ! = RQ_UINTEGER1 & & type ! = RQ_INTEGER1 & & type ! = RQ_UINTEGER2 ) {
WARN_TYPE_OR_LENGTH ( size )
}
break ;
case SQL_SMALLINT :
case SQL_C_SSHORT :
if ( type ! = RQ_UINTEGER1 & & type ! = RQ_INTEGER1 & & type ! = RQ_INTEGER2 ) {
WARN_TYPE_OR_LENGTH ( size )
}
break ;
case SQL_C_ULONG :
if ( type ! = RQ_UINTEGER1 & & type ! = RQ_INTEGER1 & &
type ! = RQ_UINTEGER2 & & type ! = RQ_INTEGER2 & &
type ! = RQ_UINTEGER3 & & type ! = RQ_INTEGER3 & &
type ! = RQ_INTEGER4 ) {
WARN_TYPE_OR_LENGTH ( size )
}
break ;
case SQL_INTEGER :
case SQL_C_SLONG :
if ( type ! = RQ_UINTEGER1 & & type ! = RQ_INTEGER1 & &
type ! = RQ_UINTEGER2 & & type ! = RQ_INTEGER2 & &
type ! = RQ_UINTEGER3 & & type ! = RQ_INTEGER3 & &
type ! = RQ_UINTEGER4 ) {
WARN_TYPE_OR_LENGTH ( size )
}
break ;
case SQL_C_UBIGINT :
if ( type ! = RQ_UINTEGER1 & & type ! = RQ_INTEGER1 & &
type ! = RQ_UINTEGER2 & & type ! = RQ_INTEGER2 & &
type ! = RQ_UINTEGER3 & & type ! = RQ_INTEGER3 & &
type ! = RQ_UINTEGER4 & & type ! = RQ_INTEGER4 & &
type ! = RQ_INTEGER8 ) {
WARN_TYPE_OR_LENGTH ( size )
}
break ;
case SQL_BIGINT :
case SQL_C_SBIGINT :
if ( type ! = RQ_UINTEGER1 & & type ! = RQ_INTEGER1 & &
type ! = RQ_UINTEGER2 & & type ! = RQ_INTEGER2 & &
type ! = RQ_UINTEGER3 & & type ! = RQ_INTEGER3 & &
type ! = RQ_UINTEGER4 & & type ! = RQ_INTEGER4 & &
type ! = RQ_UINTEGER8 ) {
WARN_TYPE_OR_LENGTH ( size )
2008-06-05 19:07:27 +00:00
}
break ;
2008-06-09 22:51:59 +00:00
# undef WARN_TYPE_OR_LENGTH
2008-06-05 19:07:27 +00:00
case SQL_NUMERIC :
case SQL_DECIMAL :
case SQL_FLOAT :
case SQL_REAL :
case SQL_DOUBLE :
2008-06-09 22:51:59 +00:00
if ( ! ast_rq_is_int ( type ) & & type ! = RQ_FLOAT ) {
2008-06-05 19:07:27 +00:00
warn_type ( col , type ) ;
}
break ;
default :
2008-06-09 22:51:59 +00:00
ast_log ( LOG_WARNING , " Realtime table %s@%s: column type (%d) unrecognized for column '%s' \n " , table , database , col - > type , elm ) ;
2008-06-05 19:07:27 +00:00
}
break ;
}
}
if ( ! col ) {
2008-06-09 22:51:59 +00:00
ast_log ( LOG_WARNING , " Realtime table %s@%s requires column '%s', but that column does not exist! \n " , table , database , elm ) ;
2008-06-05 19:07:27 +00:00
}
}
va_end ( ap ) ;
AST_RWLIST_UNLOCK ( & tableptr - > columns ) ;
return 0 ;
}
2008-06-09 22:51:59 +00:00
# undef warn_length
# undef warn_type
2008-06-05 19:07:27 +00:00
2005-01-25 06:10:20 +00:00
static struct ast_config_engine odbc_engine = {
. name = " odbc " ,
. load_func = config_odbc ,
. realtime_func = realtime_odbc ,
. realtime_multi_func = realtime_multi_odbc ,
2007-08-17 13:45:44 +00:00
. store_func = store_odbc ,
. destroy_func = destroy_odbc ,
2008-06-05 19:07:27 +00:00
. update_func = update_odbc ,
2008-10-14 00:08:52 +00:00
. update2_func = update2_odbc ,
2008-06-05 19:07:27 +00:00
. require_func = require_odbc ,
2008-06-10 21:14:58 +00:00
. unload_func = ast_odbc_clear_cache ,
2005-01-25 06:10:20 +00:00
} ;
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
2004-06-11 00:12:35 +00:00
{
2005-01-25 06:10:20 +00:00
ast_config_engine_deregister ( & odbc_engine ) ;
2008-06-05 19:07:27 +00:00
2007-07-26 15:49:18 +00:00
ast_verb ( 1 , " res_config_odbc unloaded. \n " ) ;
2004-06-11 00:12:35 +00:00
return 0 ;
}
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2004-06-11 00:12:35 +00:00
{
2005-01-25 06:10:20 +00:00
ast_config_engine_register ( & odbc_engine ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 1 , " res_config_odbc loaded. \n " ) ;
2004-06-11 00:12:35 +00:00
return 0 ;
}
2008-06-05 19:07:27 +00:00
static int reload_module ( void )
{
return 0 ;
}
2007-05-30 05:17:09 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_GLOBAL_SYMBOLS , " Realtime ODBC configuration " ,
2006-08-21 02:11:39 +00:00
. load = load_module ,
. unload = unload_module ,
2008-06-05 19:07:27 +00:00
. reload = reload_module ,
2006-08-21 02:11:39 +00:00
) ;