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