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