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