odbc+odbc plugin for portable configuration engine More...
#include "asterisk.h"
#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"
#include "asterisk/stringfields.h"
Go to the source code of this file.
Data Structures | |
struct | config_odbc_obj |
struct | custom_prepare_struct |
struct | update2_prepare_struct |
Defines | |
#define | CHECK_SIZE(n) |
#define | ENCODE_CHUNK(buffer, s) |
#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) |
#define | WARN_TYPE_OR_LENGTH(n) |
Functions | |
static void | __init_rowdata_buf (void) |
static void | __init_sql_buf (void) |
static void | __reg_module (void) |
static void | __unreg_module (void) |
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) |
static SQLHSTMT | config_odbc_prepare (struct odbc_obj *obj, void *data) |
static SQLHSTMT | custom_prepare (struct odbc_obj *obj, void *data) |
static void | decode_chunk (char *chunk) |
static int | destroy_odbc (const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap) |
Excute an DELETE query. | |
static int | is_text (const struct odbc_cache_columns *column) |
static SQLHSTMT | length_determination_odbc_prepare (struct odbc_obj *obj, void *data) |
static int | load_module (void) |
static struct ast_config * | realtime_multi_odbc (const char *database, const char *table, va_list ap) |
Excute an Select query and return ast_config list. | |
static struct ast_variable * | realtime_odbc (const char *database, const char *table, va_list ap) |
Excute an SQL query and return ast_variable list. | |
static int | reload_module (void) |
static int | require_odbc (const char *database, const char *table, va_list ap) |
static int | store_odbc (const char *database, const char *table, va_list ap) |
Excute an INSERT query. | |
static int | unload_module (void) |
static int | unload_odbc (const char *a, const char *b) |
static int | update2_odbc (const char *database, const char *table, va_list ap) |
Execute an UPDATE query. | |
static SQLHSTMT | update2_prepare (struct odbc_obj *obj, void *data) |
static int | update_odbc (const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap) |
Excute an UPDATE query. | |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime ODBC configuration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_config_engine | odbc_engine |
static struct ast_threadstorage | rowdata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_rowdata_buf , .custom_init = NULL , } |
static struct ast_threadstorage | sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , } |
odbc+odbc plugin for portable configuration engine
Definition in file res_config_odbc.c.
#define CHECK_SIZE | ( | n | ) |
if (col->size < n) { \ warn_length(col, n); \ } \ break;
Referenced by require_odbc().
#define ENCODE_CHUNK | ( | buffer, | |||
s | ) |
Definition at line 63 of file res_config_odbc.c.
Referenced by custom_prepare().
#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) |
Definition at line 1099 of file res_config_odbc.c.
Referenced by require_odbc().
#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) |
Definition at line 1100 of file res_config_odbc.c.
Referenced by require_odbc().
#define WARN_TYPE_OR_LENGTH | ( | n | ) |
if (!ast_rq_is_int(type)) { \ warn_type(col, type); \ } else { \ warn_length(col, n); \ }
Referenced by require_odbc().
static void __init_rowdata_buf | ( | void | ) | [static] |
Definition at line 51 of file res_config_odbc.c.
static void __init_sql_buf | ( | void | ) | [static] |
Definition at line 50 of file res_config_odbc.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 1302 of file res_config_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1302 of file res_config_odbc.c.
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 | |||
) | [static, read] |
Definition at line 962 of file res_config_odbc.c.
References ast_build_string(), ast_category_append(), ast_category_new(), ast_config_get_current_category(), ast_config_internal_load(), ast_free, ast_log(), ast_malloc, ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_variable_append(), ast_variable_new(), config_odbc_obj::cat_metric, config_odbc_obj::category, config_odbc_prepare(), last, length_determination_odbc_prepare(), LOG_NOTICE, LOG_WARNING, RES_ODBC_CONNECTED, config_odbc_obj::sql, config_odbc_obj::var_name, config_odbc_obj::var_val, and config_odbc_obj::var_val_size.
00963 { 00964 struct ast_variable *new_v; 00965 struct ast_category *cur_cat; 00966 int res = 0; 00967 struct odbc_obj *obj; 00968 char sqlbuf[1024] = ""; 00969 char *sql = sqlbuf; 00970 size_t sqlleft = sizeof(sqlbuf); 00971 unsigned int last_cat_metric = 0; 00972 SQLSMALLINT rowcount = 0; 00973 SQLHSTMT stmt; 00974 char last[128] = ""; 00975 struct config_odbc_obj q; 00976 struct ast_flags loader_flags = { 0 }; 00977 struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; 00978 00979 memset(&q, 0, sizeof(q)); 00980 00981 if (!file || !strcmp (file, "res_config_odbc.conf")) 00982 return NULL; /* cant configure myself with myself ! */ 00983 00984 obj = ast_odbc_request_obj2(database, connected_flag); 00985 if (!obj) 00986 return NULL; 00987 00988 q.sql = sqlbuf; 00989 00990 ast_build_string(&sql, &sqlleft, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", table, file); 00991 00992 stmt = ast_odbc_prepare_and_execute(obj, length_determination_odbc_prepare, &q); 00993 00994 if (!stmt) { 00995 ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql); 00996 ast_odbc_release_obj(obj); 00997 return NULL; 00998 } 00999 01000 res = SQLNumResultCols(stmt, &rowcount); 01001 01002 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01003 ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql); 01004 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01005 ast_odbc_release_obj(obj); 01006 return NULL; 01007 } 01008 01009 if (!rowcount) { 01010 ast_log(LOG_NOTICE, "found nothing\n"); 01011 ast_odbc_release_obj(obj); 01012 return cfg; 01013 } 01014 01015 /* There will be only one result for this, the maximum length of a variable value */ 01016 if (SQLFetch(stmt) == SQL_NO_DATA) { 01017 ast_log(LOG_NOTICE, "Failed to determine maximum length of a configuration value\n"); 01018 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01019 ast_odbc_release_obj(obj); 01020 return NULL; 01021 } 01022 01023 /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */ 01024 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01025 sql = sqlbuf; 01026 sqlleft = sizeof(sqlbuf); 01027 01028 ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table); 01029 ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file); 01030 ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name "); 01031 01032 q.var_val_size += 1; 01033 q.var_val = ast_malloc(q.var_val_size); 01034 if (!q.var_val) { 01035 ast_log(LOG_WARNING, "Could not create buffer for reading in configuration values for '%s'\n", file); 01036 ast_odbc_release_obj(obj); 01037 return NULL; 01038 } 01039 01040 stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q); 01041 01042 if (!stmt) { 01043 ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql); 01044 ast_odbc_release_obj(obj); 01045 ast_free(q.var_val); 01046 return NULL; 01047 } 01048 01049 res = SQLNumResultCols(stmt, &rowcount); 01050 01051 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01052 ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql); 01053 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01054 ast_odbc_release_obj(obj); 01055 ast_free(q.var_val); 01056 return NULL; 01057 } 01058 01059 if (!rowcount) { 01060 ast_log(LOG_NOTICE, "found nothing\n"); 01061 ast_odbc_release_obj(obj); 01062 ast_free(q.var_val); 01063 return cfg; 01064 } 01065 01066 cur_cat = ast_config_get_current_category(cfg); 01067 01068 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) { 01069 if (!strcmp (q.var_name, "#include")) { 01070 if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) { 01071 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01072 ast_odbc_release_obj(obj); 01073 ast_free(q.var_val); 01074 return NULL; 01075 } 01076 continue; 01077 } 01078 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) { 01079 cur_cat = ast_category_new(q.category, "", 99999); 01080 if (!cur_cat) { 01081 ast_log(LOG_WARNING, "Out of memory!\n"); 01082 break; 01083 } 01084 strcpy(last, q.category); 01085 last_cat_metric = q.cat_metric; 01086 ast_category_append(cfg, cur_cat); 01087 } 01088 01089 new_v = ast_variable_new(q.var_name, q.var_val, ""); 01090 ast_variable_append(cur_cat, new_v); 01091 } 01092 01093 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01094 ast_odbc_release_obj(obj); 01095 ast_free(q.var_val); 01096 return cfg; 01097 }
static SQLHSTMT config_odbc_prepare | ( | struct odbc_obj * | obj, | |
void * | data | |||
) | [static] |
Definition at line 935 of file res_config_odbc.c.
References ast_verb, config_odbc_obj::cat_metric, config_odbc_obj::category, odbc_obj::con, config_odbc_obj::err, config_odbc_obj::sql, config_odbc_obj::var_name, config_odbc_obj::var_val, and config_odbc_obj::var_val_size.
Referenced by config_odbc().
00936 { 00937 struct config_odbc_obj *q = data; 00938 SQLHSTMT sth; 00939 int res; 00940 00941 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth); 00942 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00943 ast_verb(4, "Failure in AllocStatement %d\n", res); 00944 return NULL; 00945 } 00946 00947 res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS); 00948 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00949 ast_verb(4, "Error in PREPARE %d\n", res); 00950 SQLFreeHandle(SQL_HANDLE_STMT, sth); 00951 return NULL; 00952 } 00953 00954 SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err); 00955 SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err); 00956 SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err); 00957 SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err); 00958 00959 return sth; 00960 }
static SQLHSTMT custom_prepare | ( | struct odbc_obj * | obj, | |
void * | data | |||
) | [static] |
Definition at line 99 of file res_config_odbc.c.
References custom_prepare_struct::ap, ast_debug, ast_log(), ast_string_field_set, ast_strlen_zero(), odbc_obj::con, ENCODE_CHUNK, custom_prepare_struct::encoding, encoding, custom_prepare_struct::extra, LOG_WARNING, custom_prepare_struct::skip, and custom_prepare_struct::sql.
Referenced by destroy_odbc(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().
00100 { 00101 int res, x = 1, count = 0; 00102 struct custom_prepare_struct *cps = data; 00103 const char *newparam, *newval; 00104 char encodebuf[1024]; 00105 SQLHSTMT stmt; 00106 va_list ap; 00107 00108 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00109 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00110 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00111 return NULL; 00112 } 00113 00114 ast_debug(1, "Skip: %llu; SQL: %s\n", cps->skip, cps->sql); 00115 00116 res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS); 00117 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00118 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql); 00119 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00120 return NULL; 00121 } 00122 00123 va_copy(ap, cps->ap); 00124 while ((newparam = va_arg(ap, const char *))) { 00125 newval = va_arg(ap, const char *); 00126 if ((1LL << count++) & cps->skip) { 00127 ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1ULL << (count - 1), cps->skip); 00128 continue; 00129 } 00130 ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, newparam, newval); 00131 if (strchr(newval, ';') || strchr(newval, '^')) { 00132 ENCODE_CHUNK(encodebuf, newval); 00133 ast_string_field_set(cps, encoding[x], encodebuf); 00134 newval = cps->encoding[x]; 00135 } 00136 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); 00137 } 00138 va_end(ap); 00139 00140 if (!ast_strlen_zero(cps->extra)) { 00141 const char *newval = cps->extra; 00142 if (strchr(newval, ';') || strchr(newval, '^')) { 00143 ENCODE_CHUNK(encodebuf, newval); 00144 ast_string_field_set(cps, encoding[x], encodebuf); 00145 newval = cps->encoding[x]; 00146 } 00147 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); 00148 } 00149 00150 return stmt; 00151 }
static void decode_chunk | ( | char * | chunk | ) | [static] |
Definition at line 83 of file res_config_odbc.c.
Referenced by realtime_multi_odbc(), and realtime_odbc().
static int destroy_odbc | ( | const char * | database, | |
const char * | table, | |||
const char * | keyfield, | |||
const char * | lookup, | |||
va_list | ap | |||
) | [static] |
Excute an DELETE query.
database | ||
table | ||
keyfield | where clause field | |
lookup | value of field for where clause | |
ap | list containing one or more field/value set(s) |
Delete a row from a database table, prepare the sql statement using keyfield and lookup 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.
number | of rows affected | |
-1 | on failure |
Definition at line 840 of file res_config_odbc.c.
References custom_prepare_struct::ap, ast_log(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_string_field_free_memory, ast_string_field_init, custom_prepare(), LOG_WARNING, RES_ODBC_CONNECTED, and custom_prepare_struct::sql.
00841 { 00842 struct odbc_obj *obj; 00843 SQLHSTMT stmt; 00844 char sql[256]; 00845 SQLLEN rowcount=0; 00846 const char *newparam; 00847 int res; 00848 va_list aq; 00849 struct custom_prepare_struct cps = { .sql = sql, .extra = lookup }; 00850 struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; 00851 00852 if (!table) { 00853 return -1; 00854 } 00855 00856 obj = ast_odbc_request_obj2(database, connected_flag); 00857 if (!obj) { 00858 return -1; 00859 } 00860 00861 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table); 00862 00863 va_copy(aq, ap); 00864 while((newparam = va_arg(aq, const char *))) { 00865 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam); 00866 va_arg(aq, const char *); 00867 } 00868 va_end(aq); 00869 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield); 00870 00871 if (ast_string_field_init(&cps, 256)) { 00872 ast_odbc_release_obj(obj); 00873 return -1; 00874 } 00875 va_copy(cps.ap, ap); 00876 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps); 00877 va_end(cps.ap); 00878 ast_string_field_free_memory(&cps); 00879 00880 if (!stmt) { 00881 ast_odbc_release_obj(obj); 00882 return -1; 00883 } 00884 00885 res = SQLRowCount(stmt, &rowcount); 00886 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00887 ast_odbc_release_obj(obj); 00888 00889 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00890 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); 00891 return -1; 00892 } 00893 00894 if (rowcount >= 0) 00895 return (int)rowcount; 00896 00897 return -1; 00898 }
static int is_text | ( | const struct odbc_cache_columns * | column | ) | [inline, static] |
Definition at line 93 of file res_config_odbc.c.
References odbc_cache_columns::type.
Referenced by update_odbc().
static SQLHSTMT length_determination_odbc_prepare | ( | struct odbc_obj * | obj, | |
void * | data | |||
) | [static] |
Definition at line 911 of file res_config_odbc.c.
References ast_verb, odbc_obj::con, config_odbc_obj::err, config_odbc_obj::sql, and config_odbc_obj::var_val_size.
Referenced by config_odbc().
00912 { 00913 struct config_odbc_obj *q = data; 00914 SQLHSTMT sth; 00915 int res; 00916 00917 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth); 00918 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00919 ast_verb(4, "Failure in AllocStatement %d\n", res); 00920 return NULL; 00921 } 00922 00923 res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS); 00924 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00925 ast_verb(4, "Error in PREPARE %d\n", res); 00926 SQLFreeHandle(SQL_HANDLE_STMT, sth); 00927 return NULL; 00928 } 00929 00930 SQLBindCol(sth, 1, SQL_C_ULONG, &q->var_val_size, sizeof(q->var_val_size), &q->err); 00931 00932 return sth; 00933 }
static int load_module | ( | void | ) | [static] |
Definition at line 1285 of file res_config_odbc.c.
References ast_config_engine_register(), and ast_verb.
01286 { 01287 ast_config_engine_register(&odbc_engine); 01288 ast_verb(1, "res_config_odbc loaded.\n"); 01289 return 0; 01290 }
static struct ast_config* realtime_multi_odbc | ( | const char * | database, | |
const char * | table, | |||
va_list | ap | |||
) | [static, read] |
Excute an Select query and return ast_config list.
database | ||
table | ||
ap | list containing one or more field/operator/value set. |
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.
var | on success | |
NULL | on failure |
Definition at line 335 of file res_config_odbc.c.
References custom_prepare_struct::ap, ast_category_append(), ast_category_destroy(), ast_category_new(), ast_category_rename(), ast_config_new(), ast_log(), ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_size(), ast_str_strlen(), ast_str_thread_get(), ast_str_update(), ast_strdupa, ast_string_field_free_memory, ast_string_field_init, ast_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new(), custom_prepare(), decode_chunk(), LOG_WARNING, RES_ODBC_CONNECTED, rowdata_buf, custom_prepare_struct::sql, and var.
00336 { 00337 struct odbc_obj *obj; 00338 SQLHSTMT stmt; 00339 char sql[1024]; 00340 char coltitle[256]; 00341 struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128); 00342 const char *initfield; 00343 char *op; 00344 const char *newparam; 00345 char *stringp; 00346 char *chunk; 00347 SQLSMALLINT collen; 00348 int res; 00349 int x; 00350 struct ast_variable *var=NULL; 00351 struct ast_config *cfg=NULL; 00352 struct ast_category *cat=NULL; 00353 struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; 00354 SQLULEN colsize; 00355 SQLSMALLINT colcount=0; 00356 SQLSMALLINT datatype; 00357 SQLSMALLINT decimaldigits; 00358 SQLSMALLINT nullable; 00359 SQLLEN indicator; 00360 struct custom_prepare_struct cps = { .sql = sql }; 00361 va_list aq; 00362 00363 if (!table) { 00364 return NULL; 00365 } 00366 00367 obj = ast_odbc_request_obj2(database, connected_flag); 00368 if (!obj) { 00369 return NULL; 00370 } 00371 00372 va_copy(aq, ap); 00373 newparam = va_arg(aq, const char *); 00374 if (!newparam) { 00375 va_end(aq); 00376 ast_odbc_release_obj(obj); 00377 return NULL; 00378 } 00379 00380 initfield = ast_strdupa(newparam); 00381 if ((op = strchr(initfield, ' '))) { 00382 *op = '\0'; 00383 } 00384 00385 va_arg(aq, const char *); 00386 op = !strchr(newparam, ' ') ? " =" : ""; 00387 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op, 00388 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : ""); 00389 while((newparam = va_arg(aq, const char *))) { 00390 op = !strchr(newparam, ' ') ? " =" : ""; 00391 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op, 00392 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : ""); 00393 va_arg(aq, const char *); 00394 } 00395 va_end(aq); 00396 00397 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield); 00398 00399 if (ast_string_field_init(&cps, 256)) { 00400 ast_odbc_release_obj(obj); 00401 return NULL; 00402 } 00403 va_copy(cps.ap, ap); 00404 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps); 00405 va_end(cps.ap); 00406 ast_string_field_free_memory(&cps); 00407 00408 if (!stmt) { 00409 ast_odbc_release_obj(obj); 00410 return NULL; 00411 } 00412 00413 res = SQLNumResultCols(stmt, &colcount); 00414 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00415 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); 00416 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00417 ast_odbc_release_obj(obj); 00418 return NULL; 00419 } 00420 00421 cfg = ast_config_new(); 00422 if (!cfg) { 00423 ast_log(LOG_WARNING, "Out of memory!\n"); 00424 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00425 ast_odbc_release_obj(obj); 00426 return NULL; 00427 } 00428 00429 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) { 00430 var = NULL; 00431 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00432 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); 00433 continue; 00434 } 00435 cat = ast_category_new("","",99999); 00436 if (!cat) { 00437 ast_log(LOG_WARNING, "Out of memory!\n"); 00438 continue; 00439 } 00440 for (x=0;x<colcount;x++) { 00441 colsize = 0; 00442 collen = sizeof(coltitle); 00443 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 00444 &datatype, &colsize, &decimaldigits, &nullable); 00445 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00446 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); 00447 ast_category_destroy(cat); 00448 goto next_sql_fetch; 00449 } 00450 00451 ast_str_reset(rowdata); 00452 indicator = 0; 00453 00454 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator); 00455 ast_str_update(rowdata); 00456 if (indicator == SQL_NULL_DATA) { 00457 continue; 00458 } 00459 00460 if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) { 00461 if (indicator != ast_str_strlen(rowdata)) { 00462 /* If the available space was not enough to contain the row data enlarge and read in the rest */ 00463 ast_str_make_space(&rowdata, indicator + 1); 00464 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata), 00465 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator); 00466 ast_str_update(rowdata); 00467 } 00468 } 00469 00470 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00471 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); 00472 ast_category_destroy(cat); 00473 goto next_sql_fetch; 00474 } 00475 stringp = ast_str_buffer(rowdata); 00476 while (stringp) { 00477 chunk = strsep(&stringp, ";"); 00478 if (!ast_strlen_zero(ast_strip(chunk))) { 00479 if (strchr(chunk, '^')) { 00480 decode_chunk(chunk); 00481 } 00482 if (!strcmp(initfield, coltitle)) { 00483 ast_category_rename(cat, chunk); 00484 } 00485 var = ast_variable_new(coltitle, chunk, ""); 00486 ast_variable_append(cat, var); 00487 } 00488 } 00489 } 00490 ast_category_append(cfg, cat); 00491 next_sql_fetch:; 00492 } 00493 00494 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00495 ast_odbc_release_obj(obj); 00496 return cfg; 00497 }
static struct ast_variable* realtime_odbc | ( | const char * | database, | |
const char * | table, | |||
va_list | ap | |||
) | [static, read] |
Excute an SQL query and return ast_variable list.
database | ||
table | ||
ap | list containing one or more field/operator/value set. |
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.
var | on success | |
NULL | on failure |
Definition at line 166 of file res_config_odbc.c.
References custom_prepare_struct::ap, ast_log(), ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_set(), ast_str_size(), ast_str_strlen(), ast_str_thread_get(), ast_str_update(), ast_string_field_free_memory, ast_string_field_init, ast_strip(), ast_strlen_zero(), ast_variable_new(), ast_variables_destroy(), custom_prepare(), decode_chunk(), LOG_ERROR, LOG_WARNING, RES_ODBC_CONNECTED, rowdata_buf, custom_prepare_struct::sql, and var.
00167 { 00168 struct odbc_obj *obj; 00169 SQLHSTMT stmt; 00170 char sql[1024]; 00171 char coltitle[256]; 00172 struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128); 00173 char *op; 00174 const char *newparam; 00175 char *stringp; 00176 char *chunk; 00177 SQLSMALLINT collen; 00178 int res; 00179 int x; 00180 struct ast_variable *var=NULL, *prev=NULL; 00181 SQLULEN colsize; 00182 SQLSMALLINT colcount=0; 00183 SQLSMALLINT datatype; 00184 SQLSMALLINT decimaldigits; 00185 SQLSMALLINT nullable; 00186 SQLLEN indicator; 00187 va_list aq; 00188 struct custom_prepare_struct cps = { .sql = sql }; 00189 struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; 00190 00191 if (!table) { 00192 return NULL; 00193 } 00194 00195 obj = ast_odbc_request_obj2(database, connected_flag); 00196 00197 if (!obj) { 00198 ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database); 00199 return NULL; 00200 } 00201 00202 va_copy(aq, ap); 00203 newparam = va_arg(aq, const char *); 00204 if (!newparam) { 00205 va_end(aq); 00206 ast_odbc_release_obj(obj); 00207 return NULL; 00208 } 00209 va_arg(aq, const char *); 00210 op = !strchr(newparam, ' ') ? " =" : ""; 00211 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op, 00212 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : ""); 00213 while((newparam = va_arg(aq, const char *))) { 00214 op = !strchr(newparam, ' ') ? " =" : ""; 00215 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op, 00216 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : ""); 00217 va_arg(aq, const char *); 00218 } 00219 va_end(aq); 00220 00221 if (ast_string_field_init(&cps, 256)) { 00222 ast_odbc_release_obj(obj); 00223 return NULL; 00224 } 00225 va_copy(cps.ap, ap); 00226 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps); 00227 va_end(cps.ap); 00228 ast_string_field_free_memory(&cps); 00229 00230 if (!stmt) { 00231 ast_odbc_release_obj(obj); 00232 return NULL; 00233 } 00234 00235 res = SQLNumResultCols(stmt, &colcount); 00236 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00237 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); 00238 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00239 ast_odbc_release_obj(obj); 00240 return NULL; 00241 } 00242 00243 res = SQLFetch(stmt); 00244 if (res == SQL_NO_DATA) { 00245 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00246 ast_odbc_release_obj(obj); 00247 return NULL; 00248 } 00249 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00250 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); 00251 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00252 ast_odbc_release_obj(obj); 00253 return NULL; 00254 } 00255 for (x = 0; x < colcount; x++) { 00256 colsize = 0; 00257 collen = sizeof(coltitle); 00258 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 00259 &datatype, &colsize, &decimaldigits, &nullable); 00260 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00261 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); 00262 if (var) 00263 ast_variables_destroy(var); 00264 ast_odbc_release_obj(obj); 00265 return NULL; 00266 } 00267 00268 ast_str_reset(rowdata); 00269 indicator = 0; 00270 00271 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator); 00272 ast_str_update(rowdata); 00273 if (indicator == SQL_NULL_DATA) { 00274 ast_str_reset(rowdata); 00275 } else if (!ast_str_strlen(rowdata)) { 00276 /* Because we encode the empty string for a NULL, we will encode 00277 * actual empty strings as a string containing a single whitespace. */ 00278 ast_str_set(&rowdata, -1, "%s", " "); 00279 } else if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) { 00280 if (indicator != ast_str_strlen(rowdata)) { 00281 /* If the available space was not enough to contain the row data enlarge and read in the rest */ 00282 ast_str_make_space(&rowdata, indicator + 1); 00283 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata), 00284 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator); 00285 ast_str_update(rowdata); 00286 } 00287 } 00288 00289 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00290 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); 00291 if (var) 00292 ast_variables_destroy(var); 00293 ast_odbc_release_obj(obj); 00294 return NULL; 00295 } 00296 00297 stringp = ast_str_buffer(rowdata); 00298 while (stringp) { 00299 chunk = strsep(&stringp, ";"); 00300 if (!ast_strlen_zero(ast_strip(chunk))) { 00301 if (strchr(chunk, '^')) { 00302 decode_chunk(chunk); 00303 } 00304 if (prev) { 00305 prev->next = ast_variable_new(coltitle, chunk, ""); 00306 if (prev->next) { 00307 prev = prev->next; 00308 } 00309 } else { 00310 prev = var = ast_variable_new(coltitle, chunk, ""); 00311 } 00312 } 00313 } 00314 } 00315 00316 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00317 ast_odbc_release_obj(obj); 00318 return var; 00319 }
static int reload_module | ( | void | ) | [static] |
Definition at line 1292 of file res_config_odbc.c.
static int require_odbc | ( | const char * | database, | |
const char * | table, | |||
va_list | ap | |||
) | [static] |
Definition at line 1102 of file res_config_odbc.c.
References ast_log(), ast_odbc_find_table(), AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CHECK_SIZE, odbc_cache_tables::columns, odbc_cache_columns::list, LOG_WARNING, odbc_cache_columns::name, RQ_CHAR, RQ_DATE, RQ_DATETIME, RQ_FLOAT, RQ_INTEGER1, RQ_INTEGER2, RQ_INTEGER3, RQ_INTEGER4, RQ_INTEGER8, RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, RQ_UINTEGER8, odbc_cache_columns::size, odbc_cache_columns::type, type, warn_length, warn_type, and WARN_TYPE_OR_LENGTH.
01103 { 01104 struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table); 01105 struct odbc_cache_columns *col; 01106 char *elm; 01107 int type, size; 01108 01109 if (!tableptr) { 01110 return -1; 01111 } 01112 01113 while ((elm = va_arg(ap, char *))) { 01114 type = va_arg(ap, require_type); 01115 size = va_arg(ap, int); 01116 /* Check if the field matches the criteria */ 01117 AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) { 01118 if (strcmp(col->name, elm) == 0) { 01119 /* Type check, first. Some fields are more particular than others */ 01120 switch (col->type) { 01121 case SQL_CHAR: 01122 case SQL_VARCHAR: 01123 case SQL_LONGVARCHAR: 01124 #ifdef HAVE_ODBC_WCHAR 01125 case SQL_WCHAR: 01126 case SQL_WVARCHAR: 01127 case SQL_WLONGVARCHAR: 01128 #endif 01129 case SQL_BINARY: 01130 case SQL_VARBINARY: 01131 case SQL_LONGVARBINARY: 01132 case SQL_GUID: 01133 #define CHECK_SIZE(n) \ 01134 if (col->size < n) { \ 01135 warn_length(col, n); \ 01136 } \ 01137 break; 01138 switch (type) { 01139 case RQ_UINTEGER1: CHECK_SIZE(3) /* 255 */ 01140 case RQ_INTEGER1: CHECK_SIZE(4) /* -128 */ 01141 case RQ_UINTEGER2: CHECK_SIZE(5) /* 65535 */ 01142 case RQ_INTEGER2: CHECK_SIZE(6) /* -32768 */ 01143 case RQ_UINTEGER3: /* 16777215 */ 01144 case RQ_INTEGER3: CHECK_SIZE(8) /* -8388608 */ 01145 case RQ_DATE: /* 2008-06-09 */ 01146 case RQ_UINTEGER4: CHECK_SIZE(10) /* 4200000000 */ 01147 case RQ_INTEGER4: CHECK_SIZE(11) /* -2100000000 */ 01148 case RQ_DATETIME: /* 2008-06-09 16:03:47 */ 01149 case RQ_UINTEGER8: CHECK_SIZE(19) /* trust me */ 01150 case RQ_INTEGER8: CHECK_SIZE(20) /* ditto */ 01151 case RQ_FLOAT: 01152 case RQ_CHAR: CHECK_SIZE(size) 01153 } 01154 #undef CHECK_SIZE 01155 break; 01156 case SQL_TYPE_DATE: 01157 if (type != RQ_DATE) { 01158 warn_type(col, type); 01159 } 01160 break; 01161 case SQL_TYPE_TIMESTAMP: 01162 case SQL_TIMESTAMP: 01163 if (type != RQ_DATE && type != RQ_DATETIME) { 01164 warn_type(col, type); 01165 } 01166 break; 01167 case SQL_BIT: 01168 warn_length(col, size); 01169 break; 01170 #define WARN_TYPE_OR_LENGTH(n) \ 01171 if (!ast_rq_is_int(type)) { \ 01172 warn_type(col, type); \ 01173 } else { \ 01174 warn_length(col, n); \ 01175 } 01176 case SQL_TINYINT: 01177 if (type != RQ_UINTEGER1) { 01178 WARN_TYPE_OR_LENGTH(size) 01179 } 01180 break; 01181 case SQL_C_STINYINT: 01182 if (type != RQ_INTEGER1) { 01183 WARN_TYPE_OR_LENGTH(size) 01184 } 01185 break; 01186 case SQL_C_USHORT: 01187 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) { 01188 WARN_TYPE_OR_LENGTH(size) 01189 } 01190 break; 01191 case SQL_SMALLINT: 01192 case SQL_C_SSHORT: 01193 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) { 01194 WARN_TYPE_OR_LENGTH(size) 01195 } 01196 break; 01197 case SQL_C_ULONG: 01198 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && 01199 type != RQ_UINTEGER2 && type != RQ_INTEGER2 && 01200 type != RQ_UINTEGER3 && type != RQ_INTEGER3 && 01201 type != RQ_INTEGER4) { 01202 WARN_TYPE_OR_LENGTH(size) 01203 } 01204 break; 01205 case SQL_INTEGER: 01206 case SQL_C_SLONG: 01207 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && 01208 type != RQ_UINTEGER2 && type != RQ_INTEGER2 && 01209 type != RQ_UINTEGER3 && type != RQ_INTEGER3 && 01210 type != RQ_INTEGER4) { 01211 WARN_TYPE_OR_LENGTH(size) 01212 } 01213 break; 01214 case SQL_C_UBIGINT: 01215 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && 01216 type != RQ_UINTEGER2 && type != RQ_INTEGER2 && 01217 type != RQ_UINTEGER3 && type != RQ_INTEGER3 && 01218 type != RQ_UINTEGER4 && type != RQ_INTEGER4 && 01219 type != RQ_INTEGER8) { 01220 WARN_TYPE_OR_LENGTH(size) 01221 } 01222 break; 01223 case SQL_BIGINT: 01224 case SQL_C_SBIGINT: 01225 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && 01226 type != RQ_UINTEGER2 && type != RQ_INTEGER2 && 01227 type != RQ_UINTEGER3 && type != RQ_INTEGER3 && 01228 type != RQ_UINTEGER4 && type != RQ_INTEGER4 && 01229 type != RQ_INTEGER8) { 01230 WARN_TYPE_OR_LENGTH(size) 01231 } 01232 break; 01233 #undef WARN_TYPE_OR_LENGTH 01234 case SQL_NUMERIC: 01235 case SQL_DECIMAL: 01236 case SQL_FLOAT: 01237 case SQL_REAL: 01238 case SQL_DOUBLE: 01239 if (!ast_rq_is_int(type) && type != RQ_FLOAT) { 01240 warn_type(col, type); 01241 } 01242 break; 01243 default: 01244 ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm); 01245 } 01246 break; 01247 } 01248 } 01249 if (!col) { 01250 ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm); 01251 } 01252 } 01253 AST_RWLIST_UNLOCK(&tableptr->columns); 01254 return 0; 01255 }
static int store_odbc | ( | const char * | database, | |
const char * | table, | |||
va_list | ap | |||
) | [static] |
Excute an INSERT query.
database | ||
table | ||
ap | list containing one or more field/value set(s) |
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.
number | of rows affected | |
-1 | on failure |
Definition at line 754 of file res_config_odbc.c.
References custom_prepare_struct::ap, ast_copy_string(), ast_log(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_string_field_free_memory, ast_string_field_init, custom_prepare(), LOG_WARNING, RES_ODBC_CONNECTED, and custom_prepare_struct::sql.
00755 { 00756 struct odbc_obj *obj; 00757 SQLHSTMT stmt; 00758 char sql[256]; 00759 char keys[256]; 00760 char vals[256]; 00761 SQLLEN rowcount=0; 00762 const char *newparam; 00763 int res; 00764 va_list aq; 00765 struct custom_prepare_struct cps = { .sql = sql, .extra = NULL }; 00766 struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; 00767 00768 if (!table) { 00769 return -1; 00770 } 00771 00772 obj = ast_odbc_request_obj2(database, connected_flag); 00773 if (!obj) { 00774 return -1; 00775 } 00776 00777 va_copy(aq, ap); 00778 00779 newparam = va_arg(aq, const char *); 00780 if (!newparam) { 00781 va_end(aq); 00782 ast_odbc_release_obj(obj); 00783 return -1; 00784 } 00785 va_arg(aq, const char *); 00786 snprintf(keys, sizeof(keys), "%s", newparam); 00787 ast_copy_string(vals, "?", sizeof(vals)); 00788 while ((newparam = va_arg(aq, const char *))) { 00789 snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam); 00790 snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?"); 00791 va_arg(aq, const char *); 00792 } 00793 va_end(aq); 00794 snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals); 00795 00796 if (ast_string_field_init(&cps, 256)) { 00797 ast_odbc_release_obj(obj); 00798 return -1; 00799 } 00800 va_copy(cps.ap, ap); 00801 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps); 00802 va_end(cps.ap); 00803 ast_string_field_free_memory(&cps); 00804 00805 if (!stmt) { 00806 ast_odbc_release_obj(obj); 00807 return -1; 00808 } 00809 00810 res = SQLRowCount(stmt, &rowcount); 00811 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00812 ast_odbc_release_obj(obj); 00813 00814 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00815 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); 00816 return -1; 00817 } 00818 00819 if (rowcount >= 0) 00820 return (int)rowcount; 00821 00822 return -1; 00823 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1277 of file res_config_odbc.c.
References ast_config_engine_deregister(), and ast_verb.
01278 { 01279 ast_config_engine_deregister(&odbc_engine); 01280 01281 ast_verb(1, "res_config_odbc unloaded.\n"); 01282 return 0; 01283 }
static int unload_odbc | ( | const char * | a, | |
const char * | b | |||
) | [static] |
Definition at line 1259 of file res_config_odbc.c.
References ast_odbc_clear_cache().
01260 { 01261 return ast_odbc_clear_cache(a, b); 01262 }
static int update2_odbc | ( | const char * | database, | |
const char * | table, | |||
va_list | ap | |||
) | [static] |
Execute an UPDATE query.
database | ||
table | ||
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.
number | of rows affected | |
-1 | on failure |
Definition at line 702 of file res_config_odbc.c.
References update2_prepare_struct::ap, ast_log(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj, ast_str_buffer(), ast_str_thread_get(), update2_prepare_struct::database, LOG_WARNING, sql_buf, and update2_prepare().
00703 { 00704 struct odbc_obj *obj; 00705 SQLHSTMT stmt; 00706 struct update2_prepare_struct ups = { .database = database, .table = table, }; 00707 struct ast_str *sql; 00708 int res; 00709 SQLLEN rowcount = 0; 00710 00711 if (!(obj = ast_odbc_request_obj(database, 0))) { 00712 return -1; 00713 } 00714 00715 va_copy(ups.ap, ap); 00716 if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) { 00717 va_end(ups.ap); 00718 ast_odbc_release_obj(obj); 00719 return -1; 00720 } 00721 va_end(ups.ap); 00722 00723 res = SQLRowCount(stmt, &rowcount); 00724 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00725 ast_odbc_release_obj(obj); 00726 00727 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00728 /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */ 00729 sql = ast_str_thread_get(&sql_buf, 16); 00730 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql)); 00731 return -1; 00732 } 00733 00734 if (rowcount >= 0) { 00735 return (int)rowcount; 00736 } 00737 00738 return -1; 00739 }
static SQLHSTMT update2_prepare | ( | struct odbc_obj * | obj, | |
void * | data | |||
) | [static] |
Definition at line 604 of file res_config_odbc.c.
References update2_prepare_struct::ap, ast_log(), ast_odbc_find_column(), ast_odbc_find_table(), ast_odbc_release_table, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), odbc_obj::con, update2_prepare_struct::database, first, LOG_ERROR, LOG_NOTICE, LOG_WARNING, sql_buf, and update2_prepare_struct::table.
Referenced by update2_odbc().
00605 { 00606 int res, x = 1, first = 1; 00607 struct update2_prepare_struct *ups = data; 00608 const char *newparam, *newval; 00609 struct ast_str *sql = ast_str_thread_get(&sql_buf, 16); 00610 SQLHSTMT stmt; 00611 va_list ap; 00612 struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table); 00613 00614 if (!sql) { 00615 if (tableptr) { 00616 ast_odbc_release_table(tableptr); 00617 } 00618 return NULL; 00619 } 00620 00621 if (!tableptr) { 00622 ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", ups->table, ups->database); 00623 return NULL; 00624 } 00625 00626 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00627 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00628 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00629 ast_odbc_release_table(tableptr); 00630 return NULL; 00631 } 00632 00633 ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table); 00634 00635 /* Start by finding the second set of parameters */ 00636 va_copy(ap, ups->ap); 00637 00638 while ((newparam = va_arg(ap, const char *))) { 00639 newval = va_arg(ap, const char *); 00640 } 00641 00642 while ((newparam = va_arg(ap, const char *))) { 00643 newval = va_arg(ap, const char *); 00644 if (ast_odbc_find_column(tableptr, newparam)) { 00645 ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam); 00646 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); 00647 first = 0; 00648 } else { 00649 ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database); 00650 } 00651 } 00652 va_end(ap); 00653 00654 ast_str_append(&sql, 0, "WHERE"); 00655 first = 1; 00656 00657 /* Restart search, because we need to add the search parameters */ 00658 va_copy(ap, ups->ap); 00659 00660 while ((newparam = va_arg(ap, const char *))) { 00661 newval = va_arg(ap, const char *); 00662 if (!ast_odbc_find_column(tableptr, newparam)) { 00663 va_end(ap); 00664 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); 00665 ast_odbc_release_table(tableptr); 00666 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00667 return NULL; 00668 } 00669 ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam); 00670 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); 00671 first = 0; 00672 } 00673 va_end(ap); 00674 00675 /* Done with the table metadata */ 00676 ast_odbc_release_table(tableptr); 00677 00678 res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS); 00679 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00680 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql)); 00681 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00682 return NULL; 00683 } 00684 00685 return stmt; 00686 }
static int update_odbc | ( | const char * | database, | |
const char * | table, | |||
const char * | keyfield, | |||
const char * | lookup, | |||
va_list | ap | |||
) | [static] |
Excute an UPDATE query.
database | ||
table | ||
keyfield | where clause field | |
lookup | value of field for where clause | |
ap | list containing one or more field/value set(s). |
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.
number | of rows affected | |
-1 | on failure |
Definition at line 514 of file res_config_odbc.c.
References custom_prepare_struct::ap, ast_log(), ast_odbc_allow_empty_string_in_nontext(), ast_odbc_find_column(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_release_table, ast_odbc_request_obj2, ast_string_field_free_memory, ast_string_field_init, ast_strlen_zero(), custom_prepare(), is_text(), LOG_WARNING, odbc_cache_columns::nullable, RES_ODBC_CONNECTED, custom_prepare_struct::skip, and custom_prepare_struct::sql.
00515 { 00516 struct odbc_obj *obj; 00517 SQLHSTMT stmt; 00518 char sql[256]; 00519 SQLLEN rowcount=0; 00520 const char *newparam, *newval; 00521 int res, count = 0, paramcount = 0; 00522 va_list aq; 00523 struct custom_prepare_struct cps = { .sql = sql, .extra = lookup }; 00524 struct odbc_cache_tables *tableptr; 00525 struct odbc_cache_columns *column = NULL; 00526 struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; 00527 00528 if (!table || !keyfield) { 00529 return -1; 00530 } 00531 00532 tableptr = ast_odbc_find_table(database, table); 00533 if (!(obj = ast_odbc_request_obj2(database, connected_flag))) { 00534 ast_odbc_release_table(tableptr); 00535 return -1; 00536 } 00537 00538 if (tableptr && !ast_odbc_find_column(tableptr, keyfield)) { 00539 ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database); 00540 } 00541 00542 va_copy(aq, ap); 00543 00544 snprintf(sql, sizeof(sql), "UPDATE %s SET ", table); 00545 while((newparam = va_arg(aq, const char *))) { 00546 newval = va_arg(aq, const char *); 00547 if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count >= 64) { 00548 if (paramcount++) { 00549 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", "); 00550 } 00551 /* NULL test for non-text columns */ 00552 if (count < 64 && ast_strlen_zero(newval) && column->nullable && !is_text(column) && !ast_odbc_allow_empty_string_in_nontext(obj)) { 00553 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", newparam); 00554 cps.skip |= (1LL << count); 00555 } else { 00556 /* Value is not an empty string, or column accepts empty strings, or we couldn't fit any more into cps.skip (count >= 64 ?!). */ 00557 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", newparam); 00558 } 00559 } else { /* the column does not exist in the table */ 00560 cps.skip |= (1LL << count); 00561 } 00562 ++count; 00563 } 00564 va_end(aq); 00565 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield); 00566 ast_odbc_release_table(tableptr); 00567 00568 if (ast_string_field_init(&cps, 256)) { 00569 ast_odbc_release_obj(obj); 00570 return -1; 00571 } 00572 va_copy(cps.ap, ap); 00573 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps); 00574 va_end(cps.ap); 00575 ast_string_field_free_memory(&cps); 00576 00577 if (!stmt) { 00578 ast_odbc_release_obj(obj); 00579 return -1; 00580 } 00581 00582 res = SQLRowCount(stmt, &rowcount); 00583 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00584 ast_odbc_release_obj(obj); 00585 00586 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00587 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); 00588 return -1; 00589 } 00590 00591 if (rowcount >= 0) { 00592 return (int) rowcount; 00593 } 00594 00595 return -1; 00596 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime ODBC configuration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, } [static] |
Definition at line 1302 of file res_config_odbc.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1302 of file res_config_odbc.c.
struct ast_config_engine odbc_engine [static] |
Definition at line 1264 of file res_config_odbc.c.
struct ast_threadstorage rowdata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_rowdata_buf , .custom_init = NULL , } [static] |
Definition at line 51 of file res_config_odbc.c.
Referenced by realtime_multi_odbc(), and realtime_odbc().
struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , } [static] |
Definition at line 50 of file res_config_odbc.c.
Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), cli_odbc_write(), update2_odbc(), and update2_prepare().