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