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