#include "asterisk.h"
#include <libpq-fe.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/utils.h"
#include "asterisk/cli.h"

Go to the source code of this file.
Data Structures | |
| struct | columns |
| struct | psql_tables |
| struct | tables |
| struct | tables::psql_columns |
Defines | |
| #define | ESCAPE_STRING(buffer, stringname) |
| #define | has_schema_support (version > 70300 ? 1 : 0) |
| #define | MAX_DB_OPTION_SIZE 64 |
| #define | release_table(table) ast_rwlock_unlock(&(table)->lock); |
| #define | RES_CONFIG_PGSQL_CONF "res_pgsql.conf" |
Enumerations | |
| enum | { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR } |
Functions | |
| static void | __init_escapebuf_buf (void) |
| static void | __init_findtable_buf (void) |
| static void | __init_semibuf_buf (void) |
| static void | __init_sql_buf (void) |
| static void | __init_where_buf (void) |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | _pgsql_exec (const char *database, const char *tablename, const char *sql, PGresult **result) |
| static struct ast_config * | config_pgsql (const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl, const char *who_asked) |
| static int | destroy_pgsql (const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap) |
| static void | destroy_table (struct tables *table) |
| static struct columns * | find_column (struct tables *t, const char *colname) |
| static struct tables * | find_table (const char *database, const char *orig_tablename) |
| static char * | handle_cli_realtime_pgsql_cache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_cli_realtime_pgsql_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | load_module (void) |
| static int | parse_config (int reload) |
| static int | pgsql_exec (const char *database, const char *tablename, const char *sql, PGresult **result) |
| static int | pgsql_reconnect (const char *database) |
| static struct ast_config * | realtime_multi_pgsql (const char *database, const char *table, va_list ap) |
| static struct ast_variable * | realtime_pgsql (const char *database, const char *tablename, va_list ap) |
| static int | reload (void) |
| static int | require_pgsql (const char *database, const char *tablename, va_list ap) |
| static int | store_pgsql (const char *database, const char *table, va_list ap) |
| static int | unload_module (void) |
| static int | unload_pgsql (const char *database, const char *tablename) |
| static int | update2_pgsql (const char *database, const char *tablename, va_list ap) |
| static int | update_pgsql (const char *database, const char *tablename, const char *keyfield, const char *lookup, va_list ap) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PostgreSQL RealTime Configuration Driver" , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DRIVER, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_realtime [] |
| static time_t | connect_time = 0 |
| static char | dbhost [MAX_DB_OPTION_SIZE] = "" |
| static char | dbname [MAX_DB_OPTION_SIZE] = "" |
| static char | dbpass [MAX_DB_OPTION_SIZE] = "" |
| static int | dbport = 5432 |
| static char | dbsock [MAX_DB_OPTION_SIZE] = "" |
| static char | dbuser [MAX_DB_OPTION_SIZE] = "" |
| static struct ast_threadstorage | escapebuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_escapebuf_buf , .custom_init = NULL , } |
| static struct ast_threadstorage | findtable_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_findtable_buf , .custom_init = NULL , } |
| static struct ast_config_engine | pgsql_engine |
| static ast_mutex_t | pgsql_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } |
| static PGconn * | pgsqlConn = NULL |
| static enum { ... } | requirements |
| static struct ast_threadstorage | semibuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_semibuf_buf , .custom_init = NULL , } |
| static struct ast_threadstorage | sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , } |
| static int | version |
| static struct ast_threadstorage | where_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_where_buf , .custom_init = NULL , } |
Definition in file res_config_pgsql.c.
| #define ESCAPE_STRING | ( | buffer, | |||
| stringname | ) |
Definition at line 98 of file res_config_pgsql.c.
Referenced by destroy_pgsql(), realtime_multi_pgsql(), realtime_pgsql(), store_pgsql(), update2_pgsql(), and update_pgsql().
| #define has_schema_support (version > 70300 ? 1 : 0) |
| #define MAX_DB_OPTION_SIZE 64 |
Definition at line 58 of file res_config_pgsql.c.
Definition at line 406 of file res_config_pgsql.c.
Referenced by cdr_handler(), handle_cli_realtime_pgsql_cache(), require_pgsql(), update2_pgsql(), and update_pgsql().
| #define RES_CONFIG_PGSQL_CONF "res_pgsql.conf" |
| anonymous enum |
Definition at line 91 of file res_config_pgsql.c.
00091 { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR } requirements;
| static void __init_escapebuf_buf | ( | void | ) | [static] |
| static void __init_findtable_buf | ( | void | ) | [static] |
| static void __init_semibuf_buf | ( | void | ) | [static] |
| static void __init_sql_buf | ( | void | ) | [static] |
| static void __init_where_buf | ( | void | ) | [static] |
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1634 of file res_config_pgsql.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1634 of file res_config_pgsql.c.
| static int _pgsql_exec | ( | const char * | database, | |
| const char * | tablename, | |||
| const char * | sql, | |||
| PGresult ** | result | |||
| ) | [static] |
Definition at line 144 of file res_config_pgsql.c.
References ast_debug, ast_log(), LOG_ERROR, LOG_NOTICE, and pgsql_reconnect().
Referenced by pgsql_exec().
00145 { 00146 ExecStatusType result_status; 00147 00148 if (!pgsqlConn) { 00149 ast_debug(1, "PostgreSQL connection not defined, connecting\n"); 00150 00151 if (pgsql_reconnect(database) != 1) { 00152 ast_log(LOG_NOTICE, "reconnect failed\n"); 00153 *result = NULL; 00154 return -1; 00155 } 00156 00157 ast_debug(1, "PostgreSQL connection successful\n"); 00158 } 00159 00160 *result = PQexec(pgsqlConn, sql); 00161 result_status = PQresultStatus(*result); 00162 if (result_status != PGRES_COMMAND_OK 00163 && result_status != PGRES_TUPLES_OK 00164 && result_status != PGRES_NONFATAL_ERROR) { 00165 00166 ast_log(LOG_ERROR, "PostgreSQL RealTime: Failed to query '%s@%s'.\n", tablename, database); 00167 ast_log(LOG_ERROR, "PostgreSQL RealTime: Query Failed: %s\n", sql); 00168 ast_log(LOG_ERROR, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 00169 PQresultErrorMessage(*result), 00170 PQresStatus(result_status)); 00171 00172 /* we may have tried to run a command on a disconnected/disconnecting handle */ 00173 /* are we no longer connected to the database... if not try again */ 00174 if (PQstatus(pgsqlConn) != CONNECTION_OK) { 00175 PQfinish(pgsqlConn); 00176 pgsqlConn = NULL; 00177 return -2; 00178 } 00179 00180 /* connection still okay, which means the query is just plain bad */ 00181 return -1; 00182 } 00183 00184 ast_debug(1, "PostgreSQL query successful: %s\n", sql); 00185 return 0; 00186 }
| static struct ast_config* config_pgsql | ( | const char * | database, | |
| const char * | table, | |||
| const char * | file, | |||
| struct ast_config * | cfg, | |||
| struct ast_flags | flags, | |||
| const char * | suggested_incl, | |||
| const char * | who_asked | |||
| ) | [static, read] |
Definition at line 1083 of file res_config_pgsql.c.
References ast_category_append(), ast_category_new(), ast_config_internal_load(), ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_variable_append(), ast_variable_new(), last, LOG_WARNING, pgsql_exec(), pgsql_lock, RES_CONFIG_PGSQL_CONF, and sql_buf.
01086 { 01087 PGresult *result = NULL; 01088 long num_rows; 01089 struct ast_variable *new_v; 01090 struct ast_category *cur_cat = NULL; 01091 struct ast_str *sql = ast_str_thread_get(&sql_buf, 100); 01092 char last[80] = ""; 01093 int last_cat_metric = 0; 01094 01095 last[0] = '\0'; 01096 01097 if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) { 01098 ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n"); 01099 return NULL; 01100 } 01101 01102 ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s " 01103 "WHERE filename='%s' and commented=0 " 01104 "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file); 01105 01106 ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql)); 01107 01108 ast_mutex_lock(&pgsql_lock); 01109 01110 /* We now have our complete statement; Lets connect to the server and execute it. */ 01111 if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) { 01112 ast_mutex_unlock(&pgsql_lock); 01113 return NULL; 01114 } 01115 01116 if ((num_rows = PQntuples(result)) > 0) { 01117 int rowIndex = 0; 01118 01119 ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows); 01120 01121 for (rowIndex = 0; rowIndex < num_rows; rowIndex++) { 01122 char *field_category = PQgetvalue(result, rowIndex, 0); 01123 char *field_var_name = PQgetvalue(result, rowIndex, 1); 01124 char *field_var_val = PQgetvalue(result, rowIndex, 2); 01125 char *field_cat_metric = PQgetvalue(result, rowIndex, 3); 01126 if (!strcmp(field_var_name, "#include")) { 01127 if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) { 01128 PQclear(result); 01129 ast_mutex_unlock(&pgsql_lock); 01130 return NULL; 01131 } 01132 continue; 01133 } 01134 01135 if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) { 01136 cur_cat = ast_category_new(field_category, "", 99999); 01137 if (!cur_cat) 01138 break; 01139 strcpy(last, field_category); 01140 last_cat_metric = atoi(field_cat_metric); 01141 ast_category_append(cfg, cur_cat); 01142 } 01143 new_v = ast_variable_new(field_var_name, field_var_val, ""); 01144 ast_variable_append(cur_cat, new_v); 01145 } 01146 } else { 01147 ast_log(LOG_WARNING, 01148 "PostgreSQL RealTime: Could not find config '%s' in database.\n", file); 01149 } 01150 01151 PQclear(result); 01152 ast_mutex_unlock(&pgsql_lock); 01153 01154 return cfg; 01155 }
| static int destroy_pgsql | ( | const char * | database, | |
| const char * | table, | |||
| const char * | keyfield, | |||
| const char * | lookup, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 1008 of file res_config_pgsql.c.
References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strlen_zero(), buf1, buf2, ESCAPE_STRING, escapebuf_buf, LOG_WARNING, pgsql_exec(), pgsql_lock, pgsql_reconnect(), sql_buf, and where_buf.
01009 { 01010 PGresult *result = NULL; 01011 int numrows = 0; 01012 int pgresult; 01013 struct ast_str *sql = ast_str_thread_get(&sql_buf, 256); 01014 struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60); 01015 const char *newparam, *newval; 01016 01017 if (!table) { 01018 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 01019 return -1; 01020 } 01021 01022 /* Get the first parameter and first value in our list of passed paramater/value pairs */ 01023 /*newparam = va_arg(ap, const char *); 01024 newval = va_arg(ap, const char *); 01025 if (!newparam || !newval) {*/ 01026 if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup)) { 01027 ast_log(LOG_WARNING, 01028 "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n"); 01029 if (pgsqlConn) { 01030 PQfinish(pgsqlConn); 01031 pgsqlConn = NULL; 01032 }; 01033 return -1; 01034 } 01035 01036 /* Must connect to the server before anything else, as the escape function requires the connection handle.. */ 01037 ast_mutex_lock(&pgsql_lock); 01038 if (!pgsql_reconnect(database)) { 01039 ast_mutex_unlock(&pgsql_lock); 01040 return -1; 01041 } 01042 01043 01044 /* Create the first part of the query using the first parameter/value pairs we just extracted 01045 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ 01046 01047 ESCAPE_STRING(buf1, keyfield); 01048 ESCAPE_STRING(buf2, lookup); 01049 ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2)); 01050 while ((newparam = va_arg(ap, const char *))) { 01051 newval = va_arg(ap, const char *); 01052 ESCAPE_STRING(buf1, newparam); 01053 ESCAPE_STRING(buf2, newval); 01054 ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2)); 01055 } 01056 va_end(ap); 01057 01058 ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql)); 01059 01060 if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) { 01061 ast_mutex_unlock(&pgsql_lock); 01062 return -1; 01063 } 01064 01065 numrows = atoi(PQcmdTuples(result)); 01066 ast_mutex_unlock(&pgsql_lock); 01067 01068 ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table); 01069 01070 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 01071 * An integer greater than zero indicates the number of rows affected 01072 * Zero indicates that no records were updated 01073 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 01074 */ 01075 01076 if (numrows >= 0) 01077 return (int) numrows; 01078 01079 return -1; 01080 }
| static void destroy_table | ( | struct tables * | table | ) | [static] |
Definition at line 117 of file res_config_pgsql.c.
References ast_free, AST_LIST_REMOVE_HEAD, ast_rwlock_destroy, ast_rwlock_unlock, ast_rwlock_wrlock, tables::columns, tables::list, and tables::lock.
Referenced by find_table(), unload_module(), and unload_pgsql().
00118 { 00119 struct columns *column; 00120 ast_rwlock_wrlock(&table->lock); 00121 while ((column = AST_LIST_REMOVE_HEAD(&table->columns, list))) { 00122 ast_free(column); 00123 } 00124 ast_rwlock_unlock(&table->lock); 00125 ast_rwlock_destroy(&table->lock); 00126 ast_free(table); 00127 }
Definition at line 408 of file res_config_pgsql.c.
References AST_LIST_TRAVERSE, tables::columns, tables::list, and columns::name.
Referenced by update2_pgsql(), and update_pgsql().
00409 { 00410 struct columns *column; 00411 00412 /* Check that the column exists in the table */ 00413 AST_LIST_TRAVERSE(&t->columns, column, list) { 00414 if (strcmp(column->name, colname) == 0) { 00415 return column; 00416 } 00417 } 00418 return NULL; 00419 }
| static struct tables* find_table | ( | const char * | database, | |
| const char * | orig_tablename | |||
| ) | [static, read] |
Definition at line 250 of file res_config_pgsql.c.
References ast_calloc, ast_debug, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_rwlock_init, ast_rwlock_rdlock, ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strdupa, ast_strlen_zero(), ast_verb, tables::columns, destroy_table(), findtable_buf, has_schema_support, columns::hasdefault, columns::len, tables::list, tables::lock, LOG_ERROR, columns::name, tables::name, columns::notnull, pgsql_exec(), tables::table, and columns::type.
Referenced by cdr_handler(), handle_cli_realtime_pgsql_cache(), realtime_require_handler(), require_pgsql(), update2_pgsql(), and update_pgsql().
00251 { 00252 struct columns *column; 00253 struct tables *table; 00254 struct ast_str *sql = ast_str_thread_get(&findtable_buf, 330); 00255 PGresult *result; 00256 int exec_result; 00257 char *fname, *ftype, *flen, *fnotnull, *fdef; 00258 int i, rows; 00259 00260 AST_LIST_LOCK(&psql_tables); 00261 AST_LIST_TRAVERSE(&psql_tables, table, list) { 00262 if (!strcasecmp(table->name, orig_tablename)) { 00263 ast_debug(1, "Found table in cache; now locking\n"); 00264 ast_rwlock_rdlock(&table->lock); 00265 ast_debug(1, "Lock cached table; now returning\n"); 00266 AST_LIST_UNLOCK(&psql_tables); 00267 return table; 00268 } 00269 } 00270 00271 if (database == NULL) { 00272 return NULL; 00273 } 00274 00275 ast_debug(1, "Table '%s' not found in cache, querying now\n", orig_tablename); 00276 00277 /* Not found, scan the table */ 00278 if (has_schema_support) { 00279 char *schemaname, *tablename; 00280 if (strchr(orig_tablename, '.')) { 00281 schemaname = ast_strdupa(orig_tablename); 00282 tablename = strchr(schemaname, '.'); 00283 *tablename++ = '\0'; 00284 } else { 00285 schemaname = ""; 00286 tablename = ast_strdupa(orig_tablename); 00287 } 00288 00289 /* Escape special characters in schemaname */ 00290 if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) { 00291 char *tmp = schemaname, *ptr; 00292 00293 ptr = schemaname = alloca(strlen(tmp) * 2 + 1); 00294 for (; *tmp; tmp++) { 00295 if (strchr("\\'", *tmp)) { 00296 *ptr++ = *tmp; 00297 } 00298 *ptr++ = *tmp; 00299 } 00300 *ptr = '\0'; 00301 } 00302 /* Escape special characters in tablename */ 00303 if (strchr(tablename, '\\') || strchr(tablename, '\'')) { 00304 char *tmp = tablename, *ptr; 00305 00306 ptr = tablename = alloca(strlen(tmp) * 2 + 1); 00307 for (; *tmp; tmp++) { 00308 if (strchr("\\'", *tmp)) { 00309 *ptr++ = *tmp; 00310 } 00311 *ptr++ = *tmp; 00312 } 00313 *ptr = '\0'; 00314 } 00315 00316 ast_str_set(&sql, 0, "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM (((pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND c.relname = '%s' AND n.nspname = %s%s%s) INNER JOIN pg_catalog.pg_attribute a ON (NOT a.attisdropped) AND a.attnum > 0 AND a.attrelid = c.oid) INNER JOIN pg_catalog.pg_type t ON t.oid = a.atttypid) LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum ORDER BY n.nspname, c.relname, attnum", 00317 tablename, 00318 ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'"); 00319 } else { 00320 /* Escape special characters in tablename */ 00321 if (strchr(orig_tablename, '\\') || strchr(orig_tablename, '\'')) { 00322 const char *tmp = orig_tablename; 00323 char *ptr; 00324 00325 orig_tablename = ptr = alloca(strlen(tmp) * 2 + 1); 00326 for (; *tmp; tmp++) { 00327 if (strchr("\\'", *tmp)) { 00328 *ptr++ = *tmp; 00329 } 00330 *ptr++ = *tmp; 00331 } 00332 *ptr = '\0'; 00333 } 00334 00335 ast_str_set(&sql, 0, "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM pg_class c, pg_type t, pg_attribute a LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum WHERE c.oid = a.attrelid AND a.atttypid = t.oid AND (a.attnum > 0) AND c.relname = '%s' ORDER BY c.relname, attnum", orig_tablename); 00336 } 00337 00338 exec_result = pgsql_exec(database, orig_tablename, ast_str_buffer(sql), &result); 00339 ast_debug(1, "Query of table structure complete. Now retrieving results.\n"); 00340 if (exec_result != 0) { 00341 ast_log(LOG_ERROR, "Failed to query database columns for table %s\n", orig_tablename); 00342 PQclear(result); 00343 AST_LIST_UNLOCK(&psql_tables); 00344 return NULL; 00345 } 00346 00347 if (!(table = ast_calloc(1, sizeof(*table) + strlen(orig_tablename) + 1))) { 00348 ast_log(LOG_ERROR, "Unable to allocate memory for new table structure\n"); 00349 PQclear(result); 00350 AST_LIST_UNLOCK(&psql_tables); 00351 return NULL; 00352 } 00353 strcpy(table->name, orig_tablename); /* SAFE */ 00354 ast_rwlock_init(&table->lock); 00355 AST_LIST_HEAD_INIT_NOLOCK(&table->columns); 00356 00357 rows = PQntuples(result); 00358 for (i = 0; i < rows; i++) { 00359 fname = PQgetvalue(result, i, 0); 00360 ftype = PQgetvalue(result, i, 1); 00361 flen = PQgetvalue(result, i, 2); 00362 fnotnull = PQgetvalue(result, i, 3); 00363 fdef = PQgetvalue(result, i, 4); 00364 ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype); 00365 00366 if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + 2))) { 00367 ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", orig_tablename, fname); 00368 PQclear(result); 00369 destroy_table(table); 00370 AST_LIST_UNLOCK(&psql_tables); 00371 return NULL; 00372 } 00373 00374 if (strcmp(flen, "-1") == 0) { 00375 /* Some types, like chars, have the length stored in a different field */ 00376 flen = PQgetvalue(result, i, 5); 00377 sscanf(flen, "%30d", &column->len); 00378 column->len -= 4; 00379 } else { 00380 sscanf(flen, "%30d", &column->len); 00381 } 00382 column->name = (char *)column + sizeof(*column); 00383 column->type = (char *)column + sizeof(*column) + strlen(fname) + 1; 00384 strcpy(column->name, fname); 00385 strcpy(column->type, ftype); 00386 if (*fnotnull == 't') { 00387 column->notnull = 1; 00388 } else { 00389 column->notnull = 0; 00390 } 00391 if (!ast_strlen_zero(fdef)) { 00392 column->hasdefault = 1; 00393 } else { 00394 column->hasdefault = 0; 00395 } 00396 AST_LIST_INSERT_TAIL(&table->columns, column, list); 00397 } 00398 PQclear(result); 00399 00400 AST_LIST_INSERT_TAIL(&psql_tables, table, list); 00401 ast_rwlock_rdlock(&table->lock); 00402 AST_LIST_UNLOCK(&psql_tables); 00403 return table; 00404 }
| static char * handle_cli_realtime_pgsql_cache | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1521 of file res_config_pgsql.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, CLI_GENERATE, CLI_INIT, tables::columns, ast_cli_entry::command, ast_cli_args::fd, find_table(), columns::len, tables::list, ast_cli_args::n, columns::name, tables::name, columns::notnull, release_table, columns::type, ast_cli_entry::usage, and ast_cli_args::word.
01522 { 01523 struct tables *cur; 01524 int l, which; 01525 char *ret = NULL; 01526 01527 switch (cmd) { 01528 case CLI_INIT: 01529 e->command = "realtime show pgsql cache"; 01530 e->usage = 01531 "Usage: realtime show pgsql cache [<table>]\n" 01532 " Shows table cache for the PostgreSQL RealTime driver\n"; 01533 return NULL; 01534 case CLI_GENERATE: 01535 if (a->argc != 4) { 01536 return NULL; 01537 } 01538 l = strlen(a->word); 01539 which = 0; 01540 AST_LIST_LOCK(&psql_tables); 01541 AST_LIST_TRAVERSE(&psql_tables, cur, list) { 01542 if (!strncasecmp(a->word, cur->name, l) && ++which > a->n) { 01543 ret = ast_strdup(cur->name); 01544 break; 01545 } 01546 } 01547 AST_LIST_UNLOCK(&psql_tables); 01548 return ret; 01549 } 01550 01551 if (a->argc == 4) { 01552 /* List of tables */ 01553 AST_LIST_LOCK(&psql_tables); 01554 AST_LIST_TRAVERSE(&psql_tables, cur, list) { 01555 ast_cli(a->fd, "%s\n", cur->name); 01556 } 01557 AST_LIST_UNLOCK(&psql_tables); 01558 } else if (a->argc == 5) { 01559 /* List of columns */ 01560 if ((cur = find_table(NULL, a->argv[4]))) { 01561 struct columns *col; 01562 ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[4]); 01563 ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable"); 01564 AST_LIST_TRAVERSE(&cur->columns, col, list) { 01565 ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : ""); 01566 } 01567 release_table(cur); 01568 } else { 01569 ast_cli(a->fd, "No such table '%s'\n", a->argv[4]); 01570 } 01571 } 01572 return 0; 01573 }
| static char * handle_cli_realtime_pgsql_status | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1575 of file res_config_pgsql.c.
References ast_cli_args::argc, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, connect_time, dbhost, dbname, dbport, dbsock, dbuser, ast_cli_args::fd, status, and ast_cli_entry::usage.
01576 { 01577 char status[256], credentials[100] = ""; 01578 int ctimesec = time(NULL) - connect_time; 01579 01580 switch (cmd) { 01581 case CLI_INIT: 01582 e->command = "realtime show pgsql status"; 01583 e->usage = 01584 "Usage: realtime show pgsql status\n" 01585 " Shows connection information for the PostgreSQL RealTime driver\n"; 01586 return NULL; 01587 case CLI_GENERATE: 01588 return NULL; 01589 } 01590 01591 if (a->argc != 4) 01592 return CLI_SHOWUSAGE; 01593 01594 if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { 01595 if (!ast_strlen_zero(dbhost)) 01596 snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport); 01597 else if (!ast_strlen_zero(dbsock)) 01598 snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock); 01599 else 01600 snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost); 01601 01602 if (!ast_strlen_zero(dbuser)) 01603 snprintf(credentials, sizeof(credentials), " with username %s", dbuser); 01604 01605 if (ctimesec > 31536000) 01606 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", 01607 status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400, 01608 (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60); 01609 else if (ctimesec > 86400) 01610 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, 01611 credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, 01612 ctimesec % 60); 01613 else if (ctimesec > 3600) 01614 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials, 01615 ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60); 01616 else if (ctimesec > 60) 01617 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60, 01618 ctimesec % 60); 01619 else 01620 ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec); 01621 01622 return CLI_SUCCESS; 01623 } else { 01624 return CLI_FAILURE; 01625 } 01626 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1318 of file res_config_pgsql.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_config_engine_register(), AST_MODULE_LOAD_DECLINE, ast_verb, cli_realtime, parse_config(), and pgsql_engine.
01319 { 01320 if(!parse_config(0)) 01321 return AST_MODULE_LOAD_DECLINE; 01322 01323 ast_config_engine_register(&pgsql_engine); 01324 ast_verb(1, "PostgreSQL RealTime driver loaded.\n"); 01325 ast_cli_register_multiple(cli_realtime, ARRAY_LEN(cli_realtime)); 01326 01327 return 0; 01328 }
| static int parse_config | ( | int | reload | ) | [static] |
Definition at line 1364 of file res_config_pgsql.c.
References ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), ast_variable_retrieve(), ast_verb, config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, dbhost, dbname, dbpass, dbport, dbsock, dbuser, LOG_WARNING, option_debug, pgsql_lock, pgsql_reconnect(), requirements, RES_CONFIG_PGSQL_CONF, RQ_CREATECHAR, RQ_CREATECLOSE, and RQ_WARN.
01365 { 01366 struct ast_config *config; 01367 const char *s; 01368 struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01369 01370 config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags); 01371 if (config == CONFIG_STATUS_FILEUNCHANGED) { 01372 return 0; 01373 } 01374 01375 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) { 01376 ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF); 01377 return 0; 01378 } 01379 01380 ast_mutex_lock(&pgsql_lock); 01381 01382 if (pgsqlConn) { 01383 PQfinish(pgsqlConn); 01384 pgsqlConn = NULL; 01385 } 01386 01387 if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) { 01388 ast_log(LOG_WARNING, 01389 "PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n"); 01390 strcpy(dbuser, "asterisk"); 01391 } else { 01392 ast_copy_string(dbuser, s, sizeof(dbuser)); 01393 } 01394 01395 if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) { 01396 ast_log(LOG_WARNING, 01397 "PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n"); 01398 strcpy(dbpass, "asterisk"); 01399 } else { 01400 ast_copy_string(dbpass, s, sizeof(dbpass)); 01401 } 01402 01403 if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) { 01404 ast_log(LOG_WARNING, 01405 "PostgreSQL RealTime: No database host found, using localhost via socket.\n"); 01406 dbhost[0] = '\0'; 01407 } else { 01408 ast_copy_string(dbhost, s, sizeof(dbhost)); 01409 } 01410 01411 if (!(s = ast_variable_retrieve(config, "general", "dbname"))) { 01412 ast_log(LOG_WARNING, 01413 "PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n"); 01414 strcpy(dbname, "asterisk"); 01415 } else { 01416 ast_copy_string(dbname, s, sizeof(dbname)); 01417 } 01418 01419 if (!(s = ast_variable_retrieve(config, "general", "dbport"))) { 01420 ast_log(LOG_WARNING, 01421 "PostgreSQL RealTime: No database port found, using 5432 as default.\n"); 01422 dbport = 5432; 01423 } else { 01424 dbport = atoi(s); 01425 } 01426 01427 if (!ast_strlen_zero(dbhost)) { 01428 /* No socket needed */ 01429 } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) { 01430 ast_log(LOG_WARNING, 01431 "PostgreSQL RealTime: No database socket found, using '/tmp/.s.PGSQL.%d' as default.\n", dbport); 01432 strcpy(dbsock, "/tmp"); 01433 } else { 01434 ast_copy_string(dbsock, s, sizeof(dbsock)); 01435 } 01436 01437 if (!(s = ast_variable_retrieve(config, "general", "requirements"))) { 01438 ast_log(LOG_WARNING, 01439 "PostgreSQL RealTime: no requirements setting found, using 'warn' as default.\n"); 01440 requirements = RQ_WARN; 01441 } else if (!strcasecmp(s, "createclose")) { 01442 requirements = RQ_CREATECLOSE; 01443 } else if (!strcasecmp(s, "createchar")) { 01444 requirements = RQ_CREATECHAR; 01445 } 01446 01447 ast_config_destroy(config); 01448 01449 if (option_debug) { 01450 if (!ast_strlen_zero(dbhost)) { 01451 ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost); 01452 ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport); 01453 } else { 01454 ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock); 01455 } 01456 ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser); 01457 ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass); 01458 ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname); 01459 } 01460 01461 if (!pgsql_reconnect(NULL)) { 01462 ast_log(LOG_WARNING, 01463 "PostgreSQL RealTime: Couldn't establish connection. Check debug.\n"); 01464 ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn)); 01465 } 01466 01467 ast_verb(2, "PostgreSQL RealTime reloaded.\n"); 01468 01469 /* Done reloading. Release lock so others can now use driver. */ 01470 ast_mutex_unlock(&pgsql_lock); 01471 01472 return 1; 01473 }
| static int pgsql_exec | ( | const char * | database, | |
| const char * | tablename, | |||
| const char * | sql, | |||
| PGresult ** | result | |||
| ) | [static] |
Definition at line 218 of file res_config_pgsql.c.
References _pgsql_exec(), ast_debug, ast_log(), and LOG_NOTICE.
Referenced by config_pgsql(), destroy_pgsql(), find_table(), realtime_multi_pgsql(), realtime_pgsql(), require_pgsql(), store_pgsql(), update2_pgsql(), and update_pgsql().
00219 { 00220 int attempts = 0; 00221 int res; 00222 00223 /* Try the query, note failure if any */ 00224 /* On first failure, reconnect and try again (_pgsql_exec handles reconnect) */ 00225 /* On second failure, treat as fatal query error */ 00226 00227 while (attempts++ < 2) { 00228 ast_debug(1, "PostgreSQL query attempt %d\n", attempts); 00229 res = _pgsql_exec(database, tablename, sql, result); 00230 00231 if (res == 0) { 00232 if (attempts > 1) { 00233 ast_log(LOG_NOTICE, "PostgreSQL RealTime: Query finally succeeded: %s\n", sql); 00234 } 00235 00236 return 0; 00237 } 00238 00239 if (res == -1) { 00240 return -1; /* Still connected to db, but could not process query (fatal error) */ 00241 } 00242 00243 /* res == -2 (query on a disconnected handle) */ 00244 ast_debug(1, "PostgreSQL query attempt %d failed, trying again\n", attempts); 00245 } 00246 00247 return -1; 00248 }
| static int pgsql_reconnect | ( | const char * | database | ) | [static] |
Definition at line 1475 of file res_config_pgsql.c.
References ast_copy_string(), ast_debug, ast_free, ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_str_size(), ast_strlen_zero(), connect_time, dbhost, dbname, dbpass, dbport, dbsock, dbuser, LOG_ERROR, and S_OR.
Referenced by _pgsql_exec(), destroy_pgsql(), parse_config(), and store_pgsql().
01476 { 01477 char my_database[50]; 01478 01479 ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database)); 01480 01481 /* mutex lock should have been locked before calling this function. */ 01482 01483 if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) { 01484 PQfinish(pgsqlConn); 01485 pgsqlConn = NULL; 01486 } 01487 01488 /* DB password can legitimately be 0-length */ 01489 if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) { 01490 struct ast_str *connInfo = ast_str_create(32); 01491 01492 ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s", 01493 S_OR(dbhost, dbsock), dbport, my_database, dbuser); 01494 if (!ast_strlen_zero(dbpass)) 01495 ast_str_append(&connInfo, 0, " password=%s", dbpass); 01496 01497 ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo)); 01498 pgsqlConn = PQconnectdb(ast_str_buffer(connInfo)); 01499 ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo)); 01500 ast_free(connInfo); 01501 connInfo = NULL; 01502 01503 ast_debug(1, "pgsqlConn=%p\n", pgsqlConn); 01504 if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { 01505 ast_debug(1, "PostgreSQL RealTime: Successfully connected to database.\n"); 01506 connect_time = time(NULL); 01507 version = PQserverVersion(pgsqlConn); 01508 return 1; 01509 } else { 01510 ast_log(LOG_ERROR, 01511 "PostgreSQL RealTime: Failed to connect database %s on %s: %s\n", 01512 dbname, dbhost, PQresultErrorMessage(NULL)); 01513 return 0; 01514 } 01515 } else { 01516 ast_debug(1, "PostgreSQL RealTime: One or more of the parameters in the config does not pass our validity checks.\n"); 01517 return 1; 01518 } 01519 }
| static struct ast_config* realtime_multi_pgsql | ( | const char * | database, | |
| const char * | table, | |||
| va_list | ap | |||
| ) | [static, read] |
Definition at line 536 of file res_config_pgsql.c.
References ast_calloc, ast_category_append(), ast_category_new(), ast_category_rename(), ast_config_destroy(), ast_config_new(), ast_debug, ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_realtime_decode_chunk(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strdupa, ast_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new(), ESCAPE_STRING, escapebuf_buf, LOG_ERROR, LOG_WARNING, pgsql_exec(), pgsql_lock, sql_buf, strsep(), and var.
00537 { 00538 PGresult *result = NULL; 00539 int num_rows = 0, pgresult; 00540 struct ast_str *sql = ast_str_thread_get(&sql_buf, 100); 00541 struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100); 00542 const char *initfield = NULL; 00543 char *stringp; 00544 char *chunk; 00545 char *op; 00546 const char *newparam, *newval; 00547 struct ast_variable *var = NULL; 00548 struct ast_config *cfg = NULL; 00549 struct ast_category *cat = NULL; 00550 00551 if (!table) { 00552 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00553 return NULL; 00554 } 00555 00556 if (!(cfg = ast_config_new())) 00557 return NULL; 00558 00559 /* Get the first parameter and first value in our list of passed paramater/value pairs */ 00560 newparam = va_arg(ap, const char *); 00561 newval = va_arg(ap, const char *); 00562 if (!newparam || !newval) { 00563 ast_log(LOG_WARNING, 00564 "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n"); 00565 if (pgsqlConn) { 00566 PQfinish(pgsqlConn); 00567 pgsqlConn = NULL; 00568 } 00569 ast_config_destroy(cfg); 00570 return NULL; 00571 } 00572 00573 initfield = ast_strdupa(newparam); 00574 if ((op = strchr(initfield, ' '))) { 00575 *op = '\0'; 00576 } 00577 00578 /* Create the first part of the query using the first parameter/value pairs we just extracted 00579 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ 00580 00581 if (!strchr(newparam, ' ')) 00582 op = " ="; 00583 else 00584 op = ""; 00585 00586 ESCAPE_STRING(escapebuf, newval); 00587 if (pgresult) { 00588 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00589 va_end(ap); 00590 ast_config_destroy(cfg); 00591 return NULL; 00592 } 00593 00594 ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf)); 00595 while ((newparam = va_arg(ap, const char *))) { 00596 newval = va_arg(ap, const char *); 00597 if (!strchr(newparam, ' ')) 00598 op = " ="; 00599 else 00600 op = ""; 00601 00602 ESCAPE_STRING(escapebuf, newval); 00603 if (pgresult) { 00604 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00605 va_end(ap); 00606 ast_config_destroy(cfg); 00607 return NULL; 00608 } 00609 00610 ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf)); 00611 } 00612 00613 if (initfield) { 00614 ast_str_append(&sql, 0, " ORDER BY %s", initfield); 00615 } 00616 00617 va_end(ap); 00618 00619 /* We now have our complete statement; Lets connect to the server and execute it. */ 00620 ast_mutex_lock(&pgsql_lock); 00621 00622 if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) { 00623 ast_mutex_unlock(&pgsql_lock); 00624 ast_config_destroy(cfg); 00625 return NULL; 00626 } else { 00627 ExecStatusType result_status = PQresultStatus(result); 00628 if (result_status != PGRES_COMMAND_OK 00629 && result_status != PGRES_TUPLES_OK 00630 && result_status != PGRES_NONFATAL_ERROR) { 00631 ast_log(LOG_WARNING, 00632 "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database); 00633 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 00634 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 00635 PQresultErrorMessage(result), PQresStatus(result_status)); 00636 PQclear(result); 00637 ast_mutex_unlock(&pgsql_lock); 00638 ast_config_destroy(cfg); 00639 return NULL; 00640 } 00641 } 00642 00643 ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql)); 00644 00645 if ((num_rows = PQntuples(result)) > 0) { 00646 int numFields = PQnfields(result); 00647 int i = 0; 00648 int rowIndex = 0; 00649 char **fieldnames = NULL; 00650 00651 ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows); 00652 00653 if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) { 00654 PQclear(result); 00655 ast_mutex_unlock(&pgsql_lock); 00656 ast_config_destroy(cfg); 00657 return NULL; 00658 } 00659 for (i = 0; i < numFields; i++) 00660 fieldnames[i] = PQfname(result, i); 00661 00662 for (rowIndex = 0; rowIndex < num_rows; rowIndex++) { 00663 var = NULL; 00664 if (!(cat = ast_category_new("","",99999))) 00665 continue; 00666 for (i = 0; i < numFields; i++) { 00667 stringp = PQgetvalue(result, rowIndex, i); 00668 while (stringp) { 00669 chunk = strsep(&stringp, ";"); 00670 if (chunk && !ast_strlen_zero(ast_realtime_decode_chunk(ast_strip(chunk)))) { 00671 if (initfield && !strcmp(initfield, fieldnames[i])) { 00672 ast_category_rename(cat, chunk); 00673 } 00674 var = ast_variable_new(fieldnames[i], chunk, ""); 00675 ast_variable_append(cat, var); 00676 } 00677 } 00678 } 00679 ast_category_append(cfg, cat); 00680 } 00681 ast_free(fieldnames); 00682 } else { 00683 ast_debug(1, "PostgreSQL RealTime: Could not find any rows in table %s.\n", table); 00684 } 00685 00686 PQclear(result); 00687 ast_mutex_unlock(&pgsql_lock); 00688 00689 return cfg; 00690 }
| static struct ast_variable* realtime_pgsql | ( | const char * | database, | |
| const char * | tablename, | |||
| va_list | ap | |||
| ) | [static, read] |
Definition at line 421 of file res_config_pgsql.c.
References ast_calloc, ast_debug, ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_realtime_decode_chunk(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strip(), ast_strlen_zero(), ast_variable_new(), ESCAPE_STRING, escapebuf_buf, LOG_ERROR, LOG_WARNING, pgsql_exec(), pgsql_lock, sql_buf, strsep(), and var.
00422 { 00423 PGresult *result = NULL; 00424 int num_rows = 0, pgresult; 00425 struct ast_str *sql = ast_str_thread_get(&sql_buf, 100); 00426 struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100); 00427 char *stringp; 00428 char *chunk; 00429 char *op; 00430 const char *newparam, *newval; 00431 struct ast_variable *var = NULL, *prev = NULL; 00432 00433 if (!tablename) { 00434 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00435 return NULL; 00436 } 00437 00438 /* Get the first parameter and first value in our list of passed paramater/value pairs */ 00439 newparam = va_arg(ap, const char *); 00440 newval = va_arg(ap, const char *); 00441 if (!newparam || !newval) { 00442 ast_log(LOG_WARNING, 00443 "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n"); 00444 if (pgsqlConn) { 00445 PQfinish(pgsqlConn); 00446 pgsqlConn = NULL; 00447 } 00448 return NULL; 00449 } 00450 00451 /* Create the first part of the query using the first parameter/value pairs we just extracted 00452 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ 00453 op = strchr(newparam, ' ') ? "" : " ="; 00454 00455 ESCAPE_STRING(escapebuf, newval); 00456 if (pgresult) { 00457 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00458 va_end(ap); 00459 return NULL; 00460 } 00461 00462 ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf)); 00463 while ((newparam = va_arg(ap, const char *))) { 00464 newval = va_arg(ap, const char *); 00465 if (!strchr(newparam, ' ')) 00466 op = " ="; 00467 else 00468 op = ""; 00469 00470 ESCAPE_STRING(escapebuf, newval); 00471 if (pgresult) { 00472 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00473 va_end(ap); 00474 return NULL; 00475 } 00476 00477 ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf)); 00478 } 00479 va_end(ap); 00480 00481 /* We now have our complete statement; Lets connect to the server and execute it. */ 00482 ast_mutex_lock(&pgsql_lock); 00483 00484 if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { 00485 PQclear(result); 00486 ast_mutex_unlock(&pgsql_lock); 00487 return NULL; 00488 } 00489 00490 ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql)); 00491 00492 if ((num_rows = PQntuples(result)) > 0) { 00493 int i = 0; 00494 int rowIndex = 0; 00495 int numFields = PQnfields(result); 00496 char **fieldnames = NULL; 00497 00498 ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows); 00499 00500 if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) { 00501 PQclear(result); 00502 ast_mutex_unlock(&pgsql_lock); 00503 return NULL; 00504 } 00505 for (i = 0; i < numFields; i++) 00506 fieldnames[i] = PQfname(result, i); 00507 for (rowIndex = 0; rowIndex < num_rows; rowIndex++) { 00508 for (i = 0; i < numFields; i++) { 00509 stringp = PQgetvalue(result, rowIndex, i); 00510 while (stringp) { 00511 chunk = strsep(&stringp, ";"); 00512 if (chunk && !ast_strlen_zero(ast_realtime_decode_chunk(ast_strip(chunk)))) { 00513 if (prev) { 00514 prev->next = ast_variable_new(fieldnames[i], chunk, ""); 00515 if (prev->next) { 00516 prev = prev->next; 00517 } 00518 } else { 00519 prev = var = ast_variable_new(fieldnames[i], chunk, ""); 00520 } 00521 } 00522 } 00523 } 00524 } 00525 ast_free(fieldnames); 00526 } else { 00527 ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s@%s.\n", tablename, database); 00528 } 00529 00530 PQclear(result); 00531 ast_mutex_unlock(&pgsql_lock); 00532 00533 return var; 00534 }
| static int reload | ( | void | ) | [static] |
Definition at line 1357 of file res_config_pgsql.c.
References parse_config().
01358 { 01359 parse_config(1); 01360 01361 return 0; 01362 }
| static int require_pgsql | ( | const char * | database, | |
| const char * | tablename, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 1157 of file res_config_pgsql.c.
References ast_debug, ast_free, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rq_is_int(), ast_str_buffer(), ast_str_create(), ast_str_set(), tables::columns, find_table(), columns::len, tables::list, LOG_ERROR, LOG_WARNING, columns::name, pgsql_exec(), pgsql_lock, release_table, requirements, RQ_CHAR, RQ_CREATECHAR, 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, RQ_WARN, tables::table, columns::type, and type.
01158 { 01159 struct columns *column; 01160 struct tables *table = find_table(database, tablename); 01161 char *elm; 01162 int type, size, res = 0; 01163 01164 if (!table) { 01165 ast_log(LOG_WARNING, "Table %s not found in database. This table should exist if you're using realtime.\n", tablename); 01166 return -1; 01167 } 01168 01169 while ((elm = va_arg(ap, char *))) { 01170 type = va_arg(ap, require_type); 01171 size = va_arg(ap, int); 01172 AST_LIST_TRAVERSE(&table->columns, column, list) { 01173 if (strcmp(column->name, elm) == 0) { 01174 /* Char can hold anything, as long as it is large enough */ 01175 if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0 || strcmp(column->type, "bpchar") == 0)) { 01176 if ((size > column->len) && column->len != -1) { 01177 ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len); 01178 res = -1; 01179 } 01180 } else if (strncmp(column->type, "int", 3) == 0) { 01181 int typesize = atoi(column->type + 3); 01182 /* Integers can hold only other integers */ 01183 if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 || 01184 type == RQ_INTEGER4 || type == RQ_UINTEGER4 || 01185 type == RQ_INTEGER3 || type == RQ_UINTEGER3 || 01186 type == RQ_UINTEGER2) && typesize == 2) { 01187 ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size); 01188 res = -1; 01189 } else if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 || 01190 type == RQ_UINTEGER4) && typesize == 4) { 01191 ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size); 01192 res = -1; 01193 } else if (type == RQ_CHAR || type == RQ_DATETIME || type == RQ_FLOAT || type == RQ_DATE) { 01194 ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n", 01195 column->name, 01196 type == RQ_CHAR ? "char" : 01197 type == RQ_DATETIME ? "datetime" : 01198 type == RQ_DATE ? "date" : 01199 type == RQ_FLOAT ? "float" : 01200 "a rather stiff drink ", 01201 size, column->type); 01202 res = -1; 01203 } 01204 } else if (strncmp(column->type, "float", 5) == 0) { 01205 if (!ast_rq_is_int(type) && type != RQ_FLOAT) { 01206 ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type); 01207 res = -1; 01208 } 01209 } else if (strncmp(column->type, "timestamp", 9) == 0) { 01210 if (type != RQ_DATETIME && type != RQ_DATE) { 01211 ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type); 01212 res = -1; 01213 } 01214 } else { /* There are other types that no module implements yet */ 01215 ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name); 01216 res = -1; 01217 } 01218 break; 01219 } 01220 } 01221 01222 if (!column) { 01223 if (requirements == RQ_WARN) { 01224 ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size); 01225 } else { 01226 struct ast_str *sql = ast_str_create(100); 01227 char fieldtype[15]; 01228 PGresult *result; 01229 01230 if (requirements == RQ_CREATECHAR || type == RQ_CHAR) { 01231 /* Size is minimum length; make it at least 50% greater, 01232 * just to be sure, because PostgreSQL doesn't support 01233 * resizing columns. */ 01234 snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)", 01235 size < 15 ? size * 2 : 01236 (size * 3 / 2 > 255) ? 255 : size * 3 / 2); 01237 } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) { 01238 snprintf(fieldtype, sizeof(fieldtype), "INT2"); 01239 } else if (type == RQ_UINTEGER2 || type == RQ_INTEGER3 || type == RQ_UINTEGER3 || type == RQ_INTEGER4) { 01240 snprintf(fieldtype, sizeof(fieldtype), "INT4"); 01241 } else if (type == RQ_UINTEGER4 || type == RQ_INTEGER8) { 01242 snprintf(fieldtype, sizeof(fieldtype), "INT8"); 01243 } else if (type == RQ_UINTEGER8) { 01244 /* No such type on PostgreSQL */ 01245 snprintf(fieldtype, sizeof(fieldtype), "CHAR(20)"); 01246 } else if (type == RQ_FLOAT) { 01247 snprintf(fieldtype, sizeof(fieldtype), "FLOAT8"); 01248 } else if (type == RQ_DATE) { 01249 snprintf(fieldtype, sizeof(fieldtype), "DATE"); 01250 } else if (type == RQ_DATETIME) { 01251 snprintf(fieldtype, sizeof(fieldtype), "TIMESTAMP"); 01252 } else { 01253 ast_log(LOG_ERROR, "Unrecognized request type %d\n", type); 01254 ast_free(sql); 01255 continue; 01256 } 01257 ast_str_set(&sql, 0, "ALTER TABLE %s ADD COLUMN %s %s", tablename, elm, fieldtype); 01258 ast_debug(1, "About to lock pgsql_lock (running alter on table '%s' to add column '%s')\n", tablename, elm); 01259 01260 ast_mutex_lock(&pgsql_lock); 01261 ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm); 01262 01263 if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { 01264 ast_mutex_unlock(&pgsql_lock); 01265 return -1; 01266 } 01267 01268 ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename); 01269 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 01270 ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql)); 01271 } 01272 PQclear(result); 01273 ast_mutex_unlock(&pgsql_lock); 01274 01275 ast_free(sql); 01276 } 01277 } 01278 } 01279 release_table(table); 01280 return res; 01281 }
| static int store_pgsql | ( | const char * | database, | |
| const char * | table, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 932 of file res_config_pgsql.c.
References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ESCAPE_STRING, escapebuf_buf, LOG_WARNING, pgsql_exec(), pgsql_lock, pgsql_reconnect(), sql_buf, and where_buf.
00933 { 00934 PGresult *result = NULL; 00935 Oid insertid; 00936 struct ast_str *buf = ast_str_thread_get(&escapebuf_buf, 256); 00937 struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256); 00938 struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256); 00939 int pgresult; 00940 const char *newparam, *newval; 00941 00942 if (!table) { 00943 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00944 return -1; 00945 } 00946 00947 /* Get the first parameter and first value in our list of passed paramater/value pairs */ 00948 newparam = va_arg(ap, const char *); 00949 newval = va_arg(ap, const char *); 00950 if (!newparam || !newval) { 00951 ast_log(LOG_WARNING, 00952 "PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n"); 00953 if (pgsqlConn) { 00954 PQfinish(pgsqlConn); 00955 pgsqlConn = NULL; 00956 } 00957 return -1; 00958 } 00959 00960 /* Must connect to the server before anything else, as the escape function requires the connection handle.. */ 00961 ast_mutex_lock(&pgsql_lock); 00962 if (!pgsql_reconnect(database)) { 00963 ast_mutex_unlock(&pgsql_lock); 00964 return -1; 00965 } 00966 00967 /* Create the first part of the query using the first parameter/value pairs we just extracted 00968 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ 00969 ESCAPE_STRING(buf, newparam); 00970 ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf)); 00971 ESCAPE_STRING(buf, newval); 00972 ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf)); 00973 while ((newparam = va_arg(ap, const char *))) { 00974 newval = va_arg(ap, const char *); 00975 ESCAPE_STRING(buf, newparam); 00976 ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf)); 00977 ESCAPE_STRING(buf, newval); 00978 ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf)); 00979 } 00980 va_end(ap); 00981 ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2)); 00982 00983 ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1)); 00984 00985 if (pgsql_exec(database, table, ast_str_buffer(sql1), &result) != 0) { 00986 ast_mutex_unlock(&pgsql_lock); 00987 return -1; 00988 } 00989 00990 insertid = PQoidValue(result); 00991 PQclear(result); 00992 ast_mutex_unlock(&pgsql_lock); 00993 00994 ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid); 00995 00996 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 00997 * An integer greater than zero indicates the number of rows affected 00998 * Zero indicates that no records were updated 00999 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 01000 */ 01001 01002 if (insertid >= 0) 01003 return (int) insertid; 01004 01005 return -1; 01006 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1330 of file res_config_pgsql.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_config_engine_deregister(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_verb, cli_realtime, destroy_table(), tables::list, pgsql_engine, pgsql_lock, and tables::table.
01331 { 01332 struct tables *table; 01333 /* Acquire control before doing anything to the module itself. */ 01334 ast_mutex_lock(&pgsql_lock); 01335 01336 if (pgsqlConn) { 01337 PQfinish(pgsqlConn); 01338 pgsqlConn = NULL; 01339 } 01340 ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime)); 01341 ast_config_engine_deregister(&pgsql_engine); 01342 ast_verb(1, "PostgreSQL RealTime unloaded.\n"); 01343 01344 /* Destroy cached table info */ 01345 AST_LIST_LOCK(&psql_tables); 01346 while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) { 01347 destroy_table(table); 01348 } 01349 AST_LIST_UNLOCK(&psql_tables); 01350 01351 /* Unlock so something else can destroy the lock. */ 01352 ast_mutex_unlock(&pgsql_lock); 01353 01354 return 0; 01355 }
| static int unload_pgsql | ( | const char * | database, | |
| const char * | tablename | |||
| ) | [static] |
Definition at line 1283 of file res_config_pgsql.c.
References ast_debug, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, destroy_table(), tables::list, and tables::name.
01284 { 01285 struct tables *cur; 01286 ast_debug(2, "About to lock table cache list\n"); 01287 AST_LIST_LOCK(&psql_tables); 01288 ast_debug(2, "About to traverse table cache list\n"); 01289 AST_LIST_TRAVERSE_SAFE_BEGIN(&psql_tables, cur, list) { 01290 if (strcmp(cur->name, tablename) == 0) { 01291 ast_debug(2, "About to remove matching cache entry\n"); 01292 AST_LIST_REMOVE_CURRENT(list); 01293 ast_debug(2, "About to destroy matching cache entry\n"); 01294 destroy_table(cur); 01295 ast_debug(1, "Cache entry '%s@%s' destroyed\n", tablename, database); 01296 break; 01297 } 01298 } 01299 AST_LIST_TRAVERSE_SAFE_END 01300 AST_LIST_UNLOCK(&psql_tables); 01301 ast_debug(2, "About to return\n"); 01302 return cur ? 0 : -1; 01303 }
| static int update2_pgsql | ( | const char * | database, | |
| const char * | tablename, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 823 of file res_config_pgsql.c.
References ast_debug, ast_free, ast_log(), ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ESCAPE_STRING, escapebuf_buf, find_column(), find_table(), first, LOG_ERROR, LOG_NOTICE, LOG_WARNING, pgsql_exec(), pgsql_lock, release_table, sql_buf, tables::table, and where_buf.
00824 { 00825 PGresult *result = NULL; 00826 int numrows = 0, pgresult, first = 1; 00827 struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16); 00828 const char *newparam, *newval; 00829 struct ast_str *sql = ast_str_thread_get(&sql_buf, 100); 00830 struct ast_str *where = ast_str_thread_get(&where_buf, 100); 00831 struct tables *table; 00832 00833 if (!tablename) { 00834 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00835 return -1; 00836 } 00837 00838 if (!escapebuf || !sql || !where) { 00839 /* Memory error, already handled */ 00840 return -1; 00841 } 00842 00843 if (!(table = find_table(database, tablename))) { 00844 ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename); 00845 return -1; 00846 } 00847 00848 ast_str_set(&sql, 0, "UPDATE %s SET ", tablename); 00849 ast_str_set(&where, 0, "WHERE"); 00850 00851 while ((newparam = va_arg(ap, const char *))) { 00852 if (!find_column(table, newparam)) { 00853 ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database); 00854 release_table(table); 00855 return -1; 00856 } 00857 00858 newval = va_arg(ap, const char *); 00859 ESCAPE_STRING(escapebuf, newval); 00860 if (pgresult) { 00861 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00862 release_table(table); 00863 ast_free(sql); 00864 return -1; 00865 } 00866 ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf)); 00867 first = 0; 00868 } 00869 00870 if (first) { 00871 ast_log(LOG_WARNING, 00872 "PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on.\n"); 00873 if (pgsqlConn) { 00874 PQfinish(pgsqlConn); 00875 pgsqlConn = NULL; 00876 } 00877 release_table(table); 00878 return -1; 00879 } 00880 00881 /* Now retrieve the columns to update */ 00882 first = 1; 00883 while ((newparam = va_arg(ap, const char *))) { 00884 newval = va_arg(ap, const char *); 00885 00886 /* If the column is not within the table, then skip it */ 00887 if (!find_column(table, newparam)) { 00888 ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database); 00889 continue; 00890 } 00891 00892 ESCAPE_STRING(escapebuf, newval); 00893 if (pgresult) { 00894 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00895 release_table(table); 00896 ast_free(sql); 00897 return -1; 00898 } 00899 00900 ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf)); 00901 } 00902 release_table(table); 00903 00904 ast_str_append(&sql, 0, " %s", ast_str_buffer(where)); 00905 00906 ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql)); 00907 00908 /* We now have our complete statement; connect to the server and execute it. */ 00909 if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { 00910 ast_mutex_unlock(&pgsql_lock); 00911 return -1; 00912 } 00913 00914 numrows = atoi(PQcmdTuples(result)); 00915 ast_mutex_unlock(&pgsql_lock); 00916 00917 ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename); 00918 00919 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 00920 * An integer greater than zero indicates the number of rows affected 00921 * Zero indicates that no records were updated 00922 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 00923 */ 00924 00925 if (numrows >= 0) { 00926 return (int) numrows; 00927 } 00928 00929 return -1; 00930 }
| static int update_pgsql | ( | const char * | database, | |
| const char * | tablename, | |||
| const char * | keyfield, | |||
| const char * | lookup, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 692 of file res_config_pgsql.c.
References ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), tables::columns, ESCAPE_STRING, escapebuf_buf, find_column(), find_table(), tables::list, LOG_ERROR, LOG_NOTICE, LOG_WARNING, columns::name, pgsql_exec(), pgsql_lock, release_table, sql_buf, and tables::table.
00694 { 00695 PGresult *result = NULL; 00696 int numrows = 0, pgresult; 00697 const char *newparam, *newval; 00698 struct ast_str *sql = ast_str_thread_get(&sql_buf, 100); 00699 struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100); 00700 struct tables *table; 00701 struct columns *column = NULL; 00702 00703 if (!tablename) { 00704 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00705 return -1; 00706 } 00707 00708 if (!(table = find_table(database, tablename))) { 00709 ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename); 00710 return -1; 00711 } 00712 00713 /* Get the first parameter and first value in our list of passed paramater/value pairs */ 00714 newparam = va_arg(ap, const char *); 00715 newval = va_arg(ap, const char *); 00716 if (!newparam || !newval) { 00717 ast_log(LOG_WARNING, 00718 "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n"); 00719 if (pgsqlConn) { 00720 PQfinish(pgsqlConn); 00721 pgsqlConn = NULL; 00722 } 00723 release_table(table); 00724 return -1; 00725 } 00726 00727 /* Check that the column exists in the table */ 00728 AST_LIST_TRAVERSE(&table->columns, column, list) { 00729 if (strcmp(column->name, newparam) == 0) { 00730 break; 00731 } 00732 } 00733 00734 if (!column) { 00735 ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename); 00736 release_table(table); 00737 return -1; 00738 } 00739 00740 /* Create the first part of the query using the first parameter/value pairs we just extracted 00741 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ 00742 00743 ESCAPE_STRING(escapebuf, newval); 00744 if (pgresult) { 00745 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00746 va_end(ap); 00747 release_table(table); 00748 return -1; 00749 } 00750 ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf)); 00751 00752 while ((newparam = va_arg(ap, const char *))) { 00753 newval = va_arg(ap, const char *); 00754 00755 if (!find_column(table, newparam)) { 00756 ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename); 00757 continue; 00758 } 00759 00760 ESCAPE_STRING(escapebuf, newval); 00761 if (pgresult) { 00762 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval); 00763 va_end(ap); 00764 release_table(table); 00765 return -1; 00766 } 00767 00768 ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf)); 00769 } 00770 va_end(ap); 00771 release_table(table); 00772 00773 ESCAPE_STRING(escapebuf, lookup); 00774 if (pgresult) { 00775 ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", lookup); 00776 va_end(ap); 00777 return -1; 00778 } 00779 00780 ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(escapebuf)); 00781 00782 ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql)); 00783 00784 /* We now have our complete statement; Lets connect to the server and execute it. */ 00785 ast_mutex_lock(&pgsql_lock); 00786 00787 if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { 00788 ast_mutex_unlock(&pgsql_lock); 00789 return -1; 00790 } else { 00791 ExecStatusType result_status = PQresultStatus(result); 00792 if (result_status != PGRES_COMMAND_OK 00793 && result_status != PGRES_TUPLES_OK 00794 && result_status != PGRES_NONFATAL_ERROR) { 00795 ast_log(LOG_WARNING, 00796 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 00797 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 00798 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 00799 PQresultErrorMessage(result), PQresStatus(result_status)); 00800 PQclear(result); 00801 ast_mutex_unlock(&pgsql_lock); 00802 return -1; 00803 } 00804 } 00805 00806 numrows = atoi(PQcmdTuples(result)); 00807 ast_mutex_unlock(&pgsql_lock); 00808 00809 ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename); 00810 00811 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 00812 * An integer greater than zero indicates the number of rows affected 00813 * Zero indicates that no records were updated 00814 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 00815 */ 00816 00817 if (numrows >= 0) 00818 return (int) numrows; 00819 00820 return -1; 00821 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PostgreSQL RealTime Configuration Driver" , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DRIVER, } [static] |
Definition at line 1634 of file res_config_pgsql.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1634 of file res_config_pgsql.c.
struct ast_cli_entry cli_realtime[] [static] |
Initial value:
{
AST_CLI_DEFINE(handle_cli_realtime_pgsql_status, "Shows connection information for the PostgreSQL RealTime driver"),
AST_CLI_DEFINE(handle_cli_realtime_pgsql_cache, "Shows cached tables within the PostgreSQL realtime driver"),
}
Definition at line 93 of file res_config_pgsql.c.
Referenced by load_module(), and unload_module().
time_t connect_time = 0 [static] |
Definition at line 84 of file res_config_pgsql.c.
char dbhost[MAX_DB_OPTION_SIZE] = "" [static] |
Definition at line 78 of file res_config_pgsql.c.
Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().
char dbname[MAX_DB_OPTION_SIZE] = "" [static] |
Definition at line 81 of file res_config_pgsql.c.
Referenced by db_open(), handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().
char dbpass[MAX_DB_OPTION_SIZE] = "" [static] |
Definition at line 80 of file res_config_pgsql.c.
Referenced by parse_config(), and pgsql_reconnect().
int dbport = 5432 [static] |
Definition at line 83 of file res_config_pgsql.c.
Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().
char dbsock[MAX_DB_OPTION_SIZE] = "" [static] |
Definition at line 82 of file res_config_pgsql.c.
Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().
char dbuser[MAX_DB_OPTION_SIZE] = "" [static] |
Definition at line 79 of file res_config_pgsql.c.
Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().
struct ast_threadstorage escapebuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_escapebuf_buf , .custom_init = NULL , } [static] |
Definition at line 49 of file res_config_pgsql.c.
Referenced by destroy_pgsql(), realtime_multi_pgsql(), realtime_pgsql(), store_pgsql(), update2_pgsql(), and update_pgsql().
struct ast_threadstorage findtable_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_findtable_buf , .custom_init = NULL , } [static] |
struct ast_config_engine pgsql_engine [static] |
Definition at line 1305 of file res_config_pgsql.c.
Referenced by load_module(), and unload_module().
ast_mutex_t pgsql_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static] |
Definition at line 45 of file res_config_pgsql.c.
PGconn* pgsqlConn = NULL [static] |
Definition at line 54 of file res_config_pgsql.c.
enum { ... } requirements [static] |
Referenced by parse_config(), and require_pgsql().
struct ast_threadstorage semibuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_semibuf_buf , .custom_init = NULL , } [static] |
Definition at line 50 of file res_config_pgsql.c.
struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , } [static] |
Definition at line 46 of file res_config_pgsql.c.
int version [static] |
Definition at line 55 of file res_config_pgsql.c.
struct ast_threadstorage where_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_where_buf , .custom_init = NULL , } [static] |
Definition at line 48 of file res_config_pgsql.c.
Referenced by destroy_pgsql(), realtime_update2_handler(), store_pgsql(), and update2_pgsql().
1.5.6