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_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_GLOBAL_SYMBOLS , .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 = "0901e4e500243c855563a2d78b0c03e4" , .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_RECURSIVE_MUTEX_INITIALIZER_NP ) |
| PGconn * | pgsqlConn = NULL |
| 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 , } |
PostgreSQL plugin for Asterisk RealTime Architecture.
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) |
Definition at line 54 of file res_config_pgsql.c.
Referenced by find_table().
| #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" |
Definition at line 50 of file res_config_pgsql.c.
Referenced by config_pgsql(), and parse_config().
| 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] |
Definition at line 48 of file res_config_pgsql.c.
| static void __init_findtable_buf | ( | void | ) | [static] |
Definition at line 46 of file res_config_pgsql.c.
| static void __init_sql_buf | ( | void | ) | [static] |
Definition at line 45 of file res_config_pgsql.c.
| static void __init_where_buf | ( | void | ) | [static] |
Definition at line 47 of file res_config_pgsql.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1596 of file res_config_pgsql.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1596 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 1030 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.
01033 { 01034 PGresult *result = NULL; 01035 long num_rows; 01036 struct ast_variable *new_v; 01037 struct ast_category *cur_cat = NULL; 01038 struct ast_str *sql = ast_str_thread_get(&sql_buf, 100); 01039 char last[80] = ""; 01040 int last_cat_metric = 0; 01041 01042 last[0] = '\0'; 01043 01044 if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) { 01045 ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n"); 01046 return NULL; 01047 } 01048 01049 ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s " 01050 "WHERE filename='%s' and commented=0" 01051 "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file); 01052 01053 ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql)); 01054 01055 /* We now have our complete statement; Lets connect to the server and execute it. */ 01056 ast_mutex_lock(&pgsql_lock); 01057 if (!pgsql_reconnect(database)) { 01058 ast_mutex_unlock(&pgsql_lock); 01059 return NULL; 01060 } 01061 01062 if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) { 01063 ast_log(LOG_WARNING, 01064 "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", table, database); 01065 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 01066 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn)); 01067 ast_mutex_unlock(&pgsql_lock); 01068 return NULL; 01069 } else { 01070 ExecStatusType result_status = PQresultStatus(result); 01071 if (result_status != PGRES_COMMAND_OK 01072 && result_status != PGRES_TUPLES_OK 01073 && result_status != PGRES_NONFATAL_ERROR) { 01074 ast_log(LOG_WARNING, 01075 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 01076 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 01077 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 01078 PQresultErrorMessage(result), PQresStatus(result_status)); 01079 ast_mutex_unlock(&pgsql_lock); 01080 return NULL; 01081 } 01082 } 01083 01084 if ((num_rows = PQntuples(result)) > 0) { 01085 int rowIndex = 0; 01086 01087 ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows); 01088 01089 for (rowIndex = 0; rowIndex < num_rows; rowIndex++) { 01090 char *field_category = PQgetvalue(result, rowIndex, 0); 01091 char *field_var_name = PQgetvalue(result, rowIndex, 1); 01092 char *field_var_val = PQgetvalue(result, rowIndex, 2); 01093 char *field_cat_metric = PQgetvalue(result, rowIndex, 3); 01094 if (!strcmp(field_var_name, "#include")) { 01095 if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) { 01096 PQclear(result); 01097 ast_mutex_unlock(&pgsql_lock); 01098 return NULL; 01099 } 01100 continue; 01101 } 01102 01103 if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) { 01104 cur_cat = ast_category_new(field_category, "", 99999); 01105 if (!cur_cat) 01106 break; 01107 strcpy(last, field_category); 01108 last_cat_metric = atoi(field_cat_metric); 01109 ast_category_append(cfg, cur_cat); 01110 } 01111 new_v = ast_variable_new(field_var_name, field_var_val, ""); 01112 ast_variable_append(cur_cat, new_v); 01113 } 01114 } else { 01115 ast_log(LOG_WARNING, 01116 "PostgreSQL RealTime: Could not find config '%s' in database.\n", file); 01117 } 01118 01119 PQclear(result); 01120 ast_mutex_unlock(&pgsql_lock); 01121 01122 return cfg; 01123 }
| static int destroy_pgsql | ( | const char * | database, | |
| const char * | table, | |||
| const char * | keyfield, | |||
| const char * | lookup, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 938 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.
00939 { 00940 PGresult *result = NULL; 00941 int numrows = 0; 00942 int pgresult; 00943 struct ast_str *sql = ast_str_thread_get(&sql_buf, 256); 00944 struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60); 00945 const char *newparam, *newval; 00946 00947 if (!table) { 00948 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00949 return -1; 00950 } 00951 00952 /* Get the first parameter and first value in our list of passed paramater/value pairs */ 00953 /*newparam = va_arg(ap, const char *); 00954 newval = va_arg(ap, const char *); 00955 if (!newparam || !newval) {*/ 00956 if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup)) { 00957 ast_log(LOG_WARNING, 00958 "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n"); 00959 if (pgsqlConn) { 00960 PQfinish(pgsqlConn); 00961 pgsqlConn = NULL; 00962 }; 00963 return -1; 00964 } 00965 00966 /* Must connect to the server before anything else, as the escape function requires the connection handle.. */ 00967 ast_mutex_lock(&pgsql_lock); 00968 if (!pgsql_reconnect(database)) { 00969 ast_mutex_unlock(&pgsql_lock); 00970 return -1; 00971 } 00972 00973 00974 /* Create the first part of the query using the first parameter/value pairs we just extracted 00975 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ 00976 00977 ESCAPE_STRING(buf1, keyfield); 00978 ESCAPE_STRING(buf2, lookup); 00979 ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2)); 00980 while ((newparam = va_arg(ap, const char *))) { 00981 newval = va_arg(ap, const char *); 00982 ESCAPE_STRING(buf1, newparam); 00983 ESCAPE_STRING(buf2, newval); 00984 ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2)); 00985 } 00986 va_end(ap); 00987 00988 ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql)); 00989 00990 if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) { 00991 ast_log(LOG_WARNING, 00992 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 00993 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 00994 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn)); 00995 ast_mutex_unlock(&pgsql_lock); 00996 return -1; 00997 } else { 00998 ExecStatusType result_status = PQresultStatus(result); 00999 if (result_status != PGRES_COMMAND_OK 01000 && result_status != PGRES_TUPLES_OK 01001 && result_status != PGRES_NONFATAL_ERROR) { 01002 ast_log(LOG_WARNING, 01003 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 01004 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 01005 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 01006 PQresultErrorMessage(result), PQresStatus(result_status)); 01007 ast_mutex_unlock(&pgsql_lock); 01008 return -1; 01009 } 01010 } 01011 01012 numrows = atoi(PQcmdTuples(result)); 01013 ast_mutex_unlock(&pgsql_lock); 01014 01015 ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table); 01016 01017 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 01018 * An integer greater than zero indicates the number of rows affected 01019 * Zero indicates that no records were updated 01020 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 01021 */ 01022 01023 if (numrows >= 0) 01024 return (int) numrows; 01025 01026 return -1; 01027 }
| 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_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 handle_cli_realtime_pgsql_cache(), 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 1484 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.
01485 { 01486 struct tables *cur; 01487 int l, which; 01488 char *ret = NULL; 01489 01490 switch (cmd) { 01491 case CLI_INIT: 01492 e->command = "realtime show pgsql cache"; 01493 e->usage = 01494 "Usage: realtime show pgsql cache [<table>]\n" 01495 " Shows table cache for the PostgreSQL RealTime driver\n"; 01496 return NULL; 01497 case CLI_GENERATE: 01498 if (a->argc != 4) { 01499 return NULL; 01500 } 01501 l = strlen(a->word); 01502 which = 0; 01503 AST_LIST_LOCK(&psql_tables); 01504 AST_LIST_TRAVERSE(&psql_tables, cur, list) { 01505 if (!strncasecmp(a->word, cur->name, l) && ++which > a->n) { 01506 ret = ast_strdup(cur->name); 01507 break; 01508 } 01509 } 01510 AST_LIST_UNLOCK(&psql_tables); 01511 return ret; 01512 } 01513 01514 if (a->argc == 4) { 01515 /* List of tables */ 01516 AST_LIST_LOCK(&psql_tables); 01517 AST_LIST_TRAVERSE(&psql_tables, cur, list) { 01518 ast_cli(a->fd, "%s\n", cur->name); 01519 } 01520 AST_LIST_UNLOCK(&psql_tables); 01521 } else if (a->argc == 5) { 01522 /* List of columns */ 01523 if ((cur = find_table(a->argv[4]))) { 01524 struct columns *col; 01525 ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[4]); 01526 ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable"); 01527 AST_LIST_TRAVERSE(&cur->columns, col, list) { 01528 ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : ""); 01529 } 01530 release_table(cur); 01531 } else { 01532 ast_cli(a->fd, "No such table '%s'\n", a->argv[4]); 01533 } 01534 } 01535 return 0; 01536 }
| static char * handle_cli_realtime_pgsql_status | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1538 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.
01539 { 01540 char status[256], credentials[100] = ""; 01541 int ctimesec = time(NULL) - connect_time; 01542 01543 switch (cmd) { 01544 case CLI_INIT: 01545 e->command = "realtime show pgsql status"; 01546 e->usage = 01547 "Usage: realtime show pgsql status\n" 01548 " Shows connection information for the PostgreSQL RealTime driver\n"; 01549 return NULL; 01550 case CLI_GENERATE: 01551 return NULL; 01552 } 01553 01554 if (a->argc != 4) 01555 return CLI_SHOWUSAGE; 01556 01557 if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { 01558 if (!ast_strlen_zero(dbhost)) 01559 snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport); 01560 else if (!ast_strlen_zero(dbsock)) 01561 snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock); 01562 else 01563 snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost); 01564 01565 if (!ast_strlen_zero(dbuser)) 01566 snprintf(credentials, sizeof(credentials), " with username %s", dbuser); 01567 01568 if (ctimesec > 31536000) 01569 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", 01570 status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400, 01571 (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60); 01572 else if (ctimesec > 86400) 01573 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, 01574 credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, 01575 ctimesec % 60); 01576 else if (ctimesec > 3600) 01577 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials, 01578 ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60); 01579 else if (ctimesec > 60) 01580 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60, 01581 ctimesec % 60); 01582 else 01583 ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec); 01584 01585 return CLI_SUCCESS; 01586 } else { 01587 return CLI_FAILURE; 01588 } 01589 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1281 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.
01282 { 01283 if(!parse_config(0)) 01284 return AST_MODULE_LOAD_DECLINE; 01285 01286 ast_config_engine_register(&pgsql_engine); 01287 ast_verb(1, "PostgreSQL RealTime driver loaded.\n"); 01288 ast_cli_register_multiple(cli_realtime, ARRAY_LEN(cli_realtime)); 01289 01290 return 0; 01291 }
| static int parse_config | ( | int | reload | ) | [static] |
Definition at line 1327 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.
Referenced by load_module(), and reload().
01328 { 01329 struct ast_config *config; 01330 const char *s; 01331 struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01332 01333 config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags); 01334 if (config == CONFIG_STATUS_FILEUNCHANGED) { 01335 return 0; 01336 } 01337 01338 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) { 01339 ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF); 01340 return 0; 01341 } 01342 01343 ast_mutex_lock(&pgsql_lock); 01344 01345 if (pgsqlConn) { 01346 PQfinish(pgsqlConn); 01347 pgsqlConn = NULL; 01348 } 01349 01350 if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) { 01351 ast_log(LOG_WARNING, 01352 "PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n"); 01353 strcpy(dbuser, "asterisk"); 01354 } else { 01355 ast_copy_string(dbuser, s, sizeof(dbuser)); 01356 } 01357 01358 if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) { 01359 ast_log(LOG_WARNING, 01360 "PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n"); 01361 strcpy(dbpass, "asterisk"); 01362 } else { 01363 ast_copy_string(dbpass, s, sizeof(dbpass)); 01364 } 01365 01366 if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) { 01367 ast_log(LOG_WARNING, 01368 "PostgreSQL RealTime: No database host found, using localhost via socket.\n"); 01369 dbhost[0] = '\0'; 01370 } else { 01371 ast_copy_string(dbhost, s, sizeof(dbhost)); 01372 } 01373 01374 if (!(s = ast_variable_retrieve(config, "general", "dbname"))) { 01375 ast_log(LOG_WARNING, 01376 "PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n"); 01377 strcpy(dbname, "asterisk"); 01378 } else { 01379 ast_copy_string(dbname, s, sizeof(dbname)); 01380 } 01381 01382 if (!(s = ast_variable_retrieve(config, "general", "dbport"))) { 01383 ast_log(LOG_WARNING, 01384 "PostgreSQL RealTime: No database port found, using 5432 as default.\n"); 01385 dbport = 5432; 01386 } else { 01387 dbport = atoi(s); 01388 } 01389 01390 if (!ast_strlen_zero(dbhost)) { 01391 /* No socket needed */ 01392 } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) { 01393 ast_log(LOG_WARNING, 01394 "PostgreSQL RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n"); 01395 strcpy(dbsock, "/tmp/pgsql.sock"); 01396 } else { 01397 ast_copy_string(dbsock, s, sizeof(dbsock)); 01398 } 01399 01400 if (!(s = ast_variable_retrieve(config, "general", "requirements"))) { 01401 ast_log(LOG_WARNING, 01402 "PostgreSQL RealTime: no requirements setting found, using 'warn' as default.\n"); 01403 requirements = RQ_WARN; 01404 } else if (!strcasecmp(s, "createclose")) { 01405 requirements = RQ_CREATECLOSE; 01406 } else if (!strcasecmp(s, "createchar")) { 01407 requirements = RQ_CREATECHAR; 01408 } 01409 01410 ast_config_destroy(config); 01411 01412 if (option_debug) { 01413 if (!ast_strlen_zero(dbhost)) { 01414 ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost); 01415 ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport); 01416 } else { 01417 ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock); 01418 } 01419 ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser); 01420 ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass); 01421 ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname); 01422 } 01423 01424 if (!pgsql_reconnect(NULL)) { 01425 ast_log(LOG_WARNING, 01426 "PostgreSQL RealTime: Couldn't establish connection. Check debug.\n"); 01427 ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn)); 01428 } 01429 01430 ast_verb(2, "PostgreSQL RealTime reloaded.\n"); 01431 01432 /* Done reloading. Release lock so others can now use driver. */ 01433 ast_mutex_unlock(&pgsql_lock); 01434 01435 return 1; 01436 }
| static int pgsql_reconnect | ( | const char * | database | ) | [static] |
Definition at line 1438 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().
01439 { 01440 char my_database[50]; 01441 01442 ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database)); 01443 01444 /* mutex lock should have been locked before calling this function. */ 01445 01446 if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) { 01447 PQfinish(pgsqlConn); 01448 pgsqlConn = NULL; 01449 } 01450 01451 /* DB password can legitimately be 0-length */ 01452 if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) { 01453 struct ast_str *connInfo = ast_str_create(32); 01454 01455 ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s", 01456 dbhost, dbport, my_database, dbuser); 01457 if (!ast_strlen_zero(dbpass)) 01458 ast_str_append(&connInfo, 0, " password=%s", dbpass); 01459 01460 ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo)); 01461 pgsqlConn = PQconnectdb(ast_str_buffer(connInfo)); 01462 ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo)); 01463 ast_free(connInfo); 01464 connInfo = NULL; 01465 01466 ast_debug(1, "pgsqlConn=%p\n", pgsqlConn); 01467 if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { 01468 ast_debug(1, "PostgreSQL RealTime: Successfully connected to database.\n"); 01469 connect_time = time(NULL); 01470 version = PQserverVersion(pgsqlConn); 01471 return 1; 01472 } else { 01473 ast_log(LOG_ERROR, 01474 "PostgreSQL RealTime: Failed to connect database %s on %s: %s\n", 01475 dbname, dbhost, PQresultErrorMessage(NULL)); 01476 return 0; 01477 } 01478 } else { 01479 ast_debug(1, "PostgreSQL RealTime: One or more of the parameters in the config does not pass our validity checks.\n"); 01480 return 1; 01481 } 01482 }
| 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_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new(), ESCAPE_STRING, escapebuf_buf, LOG_ERROR, LOG_WARNING, pgsql_lock, pgsql_reconnect(), sql_buf, 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, 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 1320 of file res_config_pgsql.c.
References parse_config().
01321 { 01322 parse_config(1); 01323 01324 return 0; 01325 }
| static int require_pgsql | ( | const char * | database, | |
| const char * | tablename, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 1125 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.
01126 { 01127 struct columns *column; 01128 struct tables *table = find_table(tablename); 01129 char *elm; 01130 int type, size, res = 0; 01131 01132 if (!table) { 01133 ast_log(LOG_WARNING, "Table %s not found in database. This table should exist if you're using realtime.\n", tablename); 01134 return -1; 01135 } 01136 01137 while ((elm = va_arg(ap, char *))) { 01138 type = va_arg(ap, require_type); 01139 size = va_arg(ap, int); 01140 AST_LIST_TRAVERSE(&table->columns, column, list) { 01141 if (strcmp(column->name, elm) == 0) { 01142 /* Char can hold anything, as long as it is large enough */ 01143 if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0 || strcmp(column->type, "bpchar") == 0)) { 01144 if ((size > column->len) && column->len != -1) { 01145 ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len); 01146 res = -1; 01147 } 01148 } else if (strncmp(column->type, "int", 3) == 0) { 01149 int typesize = atoi(column->type + 3); 01150 /* Integers can hold only other integers */ 01151 if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 || 01152 type == RQ_INTEGER4 || type == RQ_UINTEGER4 || 01153 type == RQ_INTEGER3 || type == RQ_UINTEGER3 || 01154 type == RQ_UINTEGER2) && typesize == 2) { 01155 ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size); 01156 res = -1; 01157 } else if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 || 01158 type == RQ_UINTEGER4) && typesize == 4) { 01159 ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size); 01160 res = -1; 01161 } else if (type == RQ_CHAR || type == RQ_DATETIME || type == RQ_FLOAT || type == RQ_DATE) { 01162 ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n", 01163 column->name, 01164 type == RQ_CHAR ? "char" : 01165 type == RQ_DATETIME ? "datetime" : 01166 type == RQ_DATE ? "date" : 01167 type == RQ_FLOAT ? "float" : 01168 "a rather stiff drink ", 01169 size, column->type); 01170 res = -1; 01171 } 01172 } else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) { 01173 ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type); 01174 res = -1; 01175 } else { /* There are other types that no module implements yet */ 01176 ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name); 01177 res = -1; 01178 } 01179 break; 01180 } 01181 } 01182 01183 if (!column) { 01184 if (requirements == RQ_WARN) { 01185 ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size); 01186 } else { 01187 struct ast_str *sql = ast_str_create(100); 01188 char fieldtype[15]; 01189 PGresult *result; 01190 01191 if (requirements == RQ_CREATECHAR || type == RQ_CHAR) { 01192 /* Size is minimum length; make it at least 50% greater, 01193 * just to be sure, because PostgreSQL doesn't support 01194 * resizing columns. */ 01195 snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)", 01196 size < 15 ? size * 2 : 01197 (size * 3 / 2 > 255) ? 255 : size * 3 / 2); 01198 } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) { 01199 snprintf(fieldtype, sizeof(fieldtype), "INT2"); 01200 } else if (type == RQ_UINTEGER2 || type == RQ_INTEGER3 || type == RQ_UINTEGER3 || type == RQ_INTEGER4) { 01201 snprintf(fieldtype, sizeof(fieldtype), "INT4"); 01202 } else if (type == RQ_UINTEGER4 || type == RQ_INTEGER8) { 01203 snprintf(fieldtype, sizeof(fieldtype), "INT8"); 01204 } else if (type == RQ_UINTEGER8) { 01205 /* No such type on PostgreSQL */ 01206 snprintf(fieldtype, sizeof(fieldtype), "CHAR(20)"); 01207 } else if (type == RQ_FLOAT) { 01208 snprintf(fieldtype, sizeof(fieldtype), "FLOAT8"); 01209 } else if (type == RQ_DATE) { 01210 snprintf(fieldtype, sizeof(fieldtype), "DATE"); 01211 } else if (type == RQ_DATETIME) { 01212 snprintf(fieldtype, sizeof(fieldtype), "TIMESTAMP"); 01213 } else { 01214 ast_log(LOG_ERROR, "Unrecognized request type %d\n", type); 01215 ast_free(sql); 01216 continue; 01217 } 01218 ast_str_set(&sql, 0, "ALTER TABLE %s ADD COLUMN %s %s", tablename, elm, fieldtype); 01219 ast_debug(1, "About to lock pgsql_lock (running alter on table '%s' to add column '%s')\n", tablename, elm); 01220 01221 ast_mutex_lock(&pgsql_lock); 01222 if (!pgsql_reconnect(database)) { 01223 ast_mutex_unlock(&pgsql_lock); 01224 ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql)); 01225 ast_free(sql); 01226 continue; 01227 } 01228 01229 ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm); 01230 result = PQexec(pgsqlConn, ast_str_buffer(sql)); 01231 ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename); 01232 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 01233 ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql)); 01234 } 01235 PQclear(result); 01236 ast_mutex_unlock(&pgsql_lock); 01237 01238 ast_free(sql); 01239 } 01240 } 01241 } 01242 release_table(table); 01243 return res; 01244 }
| static int store_pgsql | ( | const char * | database, | |
| const char * | table, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 846 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.
00847 { 00848 PGresult *result = NULL; 00849 Oid insertid; 00850 struct ast_str *buf = ast_str_thread_get(&escapebuf_buf, 256); 00851 struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256); 00852 struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256); 00853 int pgresult; 00854 const char *newparam, *newval; 00855 00856 if (!table) { 00857 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00858 return -1; 00859 } 00860 00861 /* Get the first parameter and first value in our list of passed paramater/value pairs */ 00862 newparam = va_arg(ap, const char *); 00863 newval = va_arg(ap, const char *); 00864 if (!newparam || !newval) { 00865 ast_log(LOG_WARNING, 00866 "PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n"); 00867 if (pgsqlConn) { 00868 PQfinish(pgsqlConn); 00869 pgsqlConn = NULL; 00870 } 00871 return -1; 00872 } 00873 00874 /* Must connect to the server before anything else, as the escape function requires the connection handle.. */ 00875 ast_mutex_lock(&pgsql_lock); 00876 if (!pgsql_reconnect(database)) { 00877 ast_mutex_unlock(&pgsql_lock); 00878 return -1; 00879 } 00880 00881 /* Create the first part of the query using the first parameter/value pairs we just extracted 00882 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ 00883 ESCAPE_STRING(buf, newparam); 00884 ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf)); 00885 ESCAPE_STRING(buf, newval); 00886 ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf)); 00887 while ((newparam = va_arg(ap, const char *))) { 00888 newval = va_arg(ap, const char *); 00889 ESCAPE_STRING(buf, newparam); 00890 ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf)); 00891 ESCAPE_STRING(buf, newval); 00892 ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf)); 00893 } 00894 va_end(ap); 00895 ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2)); 00896 00897 ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1)); 00898 00899 if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql1)))) { 00900 ast_log(LOG_WARNING, 00901 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 00902 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1)); 00903 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn)); 00904 ast_mutex_unlock(&pgsql_lock); 00905 return -1; 00906 } else { 00907 ExecStatusType result_status = PQresultStatus(result); 00908 if (result_status != PGRES_COMMAND_OK 00909 && result_status != PGRES_TUPLES_OK 00910 && result_status != PGRES_NONFATAL_ERROR) { 00911 ast_log(LOG_WARNING, 00912 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 00913 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1)); 00914 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 00915 PQresultErrorMessage(result), PQresStatus(result_status)); 00916 ast_mutex_unlock(&pgsql_lock); 00917 return -1; 00918 } 00919 } 00920 00921 insertid = PQoidValue(result); 00922 ast_mutex_unlock(&pgsql_lock); 00923 00924 ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid); 00925 00926 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 00927 * An integer greater than zero indicates the number of rows affected 00928 * Zero indicates that no records were updated 00929 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 00930 */ 00931 00932 if (insertid >= 0) 00933 return (int) insertid; 00934 00935 return -1; 00936 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1293 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.
01294 { 01295 struct tables *table; 01296 /* Acquire control before doing anything to the module itself. */ 01297 ast_mutex_lock(&pgsql_lock); 01298 01299 if (pgsqlConn) { 01300 PQfinish(pgsqlConn); 01301 pgsqlConn = NULL; 01302 } 01303 ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime)); 01304 ast_config_engine_deregister(&pgsql_engine); 01305 ast_verb(1, "PostgreSQL RealTime unloaded.\n"); 01306 01307 /* Destroy cached table info */ 01308 AST_LIST_LOCK(&psql_tables); 01309 while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) { 01310 destroy_table(table); 01311 } 01312 AST_LIST_UNLOCK(&psql_tables); 01313 01314 /* Unlock so something else can destroy the lock. */ 01315 ast_mutex_unlock(&pgsql_lock); 01316 01317 return 0; 01318 }
| static int unload_pgsql | ( | const char * | database, | |
| const char * | tablename | |||
| ) | [static] |
Definition at line 1246 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.
01247 { 01248 struct tables *cur; 01249 ast_debug(2, "About to lock table cache list\n"); 01250 AST_LIST_LOCK(&psql_tables); 01251 ast_debug(2, "About to traverse table cache list\n"); 01252 AST_LIST_TRAVERSE_SAFE_BEGIN(&psql_tables, cur, list) { 01253 if (strcmp(cur->name, tablename) == 0) { 01254 ast_debug(2, "About to remove matching cache entry\n"); 01255 AST_LIST_REMOVE_CURRENT(list); 01256 ast_debug(2, "About to destroy matching cache entry\n"); 01257 destroy_table(cur); 01258 ast_debug(1, "Cache entry '%s@%s' destroyed\n", tablename, database); 01259 break; 01260 } 01261 } 01262 AST_LIST_TRAVERSE_SAFE_END 01263 AST_LIST_UNLOCK(&psql_tables); 01264 ast_debug(2, "About to return\n"); 01265 return cur ? 0 : -1; 01266 }
| static int update2_pgsql | ( | const char * | database, | |
| const char * | tablename, | |||
| va_list | ap | |||
| ) | [static] |
Definition at line 714 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.
00715 { 00716 PGresult *result = NULL; 00717 int numrows = 0, pgresult, first = 1; 00718 struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16); 00719 const char *newparam, *newval; 00720 struct ast_str *sql = ast_str_thread_get(&sql_buf, 100); 00721 struct ast_str *where = ast_str_thread_get(&where_buf, 100); 00722 struct tables *table; 00723 00724 if (!tablename) { 00725 ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n"); 00726 return -1; 00727 } 00728 00729 if (!escapebuf || !sql || !where) { 00730 /* Memory error, already handled */ 00731 return -1; 00732 } 00733 00734 if (!(table = find_table(tablename))) { 00735 ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename); 00736 return -1; 00737 } 00738 00739 ast_str_set(&sql, 0, "UPDATE %s SET ", tablename); 00740 ast_str_set(&where, 0, "WHERE"); 00741 00742 while ((newparam = va_arg(ap, const char *))) { 00743 if (!find_column(table, newparam)) { 00744 ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database); 00745 release_table(table); 00746 return -1; 00747 } 00748 00749 newval = va_arg(ap, const char *); 00750 ESCAPE_STRING(escapebuf, newval); 00751 if (pgresult) { 00752 ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval); 00753 release_table(table); 00754 ast_free(sql); 00755 return -1; 00756 } 00757 ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf)); 00758 first = 0; 00759 } 00760 00761 if (first) { 00762 ast_log(LOG_WARNING, 00763 "PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on.\n"); 00764 if (pgsqlConn) { 00765 PQfinish(pgsqlConn); 00766 pgsqlConn = NULL; 00767 } 00768 release_table(table); 00769 return -1; 00770 } 00771 00772 /* Now retrieve the columns to update */ 00773 first = 1; 00774 while ((newparam = va_arg(ap, const char *))) { 00775 newval = va_arg(ap, const char *); 00776 00777 /* If the column is not within the table, then skip it */ 00778 if (!find_column(table, newparam)) { 00779 ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database); 00780 continue; 00781 } 00782 00783 ESCAPE_STRING(escapebuf, newval); 00784 if (pgresult) { 00785 ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval); 00786 release_table(table); 00787 ast_free(sql); 00788 return -1; 00789 } 00790 00791 ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf)); 00792 } 00793 release_table(table); 00794 00795 ast_str_append(&sql, 0, " %s", ast_str_buffer(where)); 00796 00797 ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql)); 00798 00799 /* We now have our complete statement; connect to the server and execute it. */ 00800 ast_mutex_lock(&pgsql_lock); 00801 if (!pgsql_reconnect(database)) { 00802 ast_mutex_unlock(&pgsql_lock); 00803 return -1; 00804 } 00805 00806 if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) { 00807 ast_log(LOG_WARNING, 00808 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 00809 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 00810 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn)); 00811 ast_mutex_unlock(&pgsql_lock); 00812 return -1; 00813 } else { 00814 ExecStatusType result_status = PQresultStatus(result); 00815 if (result_status != PGRES_COMMAND_OK 00816 && result_status != PGRES_TUPLES_OK 00817 && result_status != PGRES_NONFATAL_ERROR) { 00818 ast_log(LOG_WARNING, 00819 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 00820 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 00821 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 00822 PQresultErrorMessage(result), PQresStatus(result_status)); 00823 ast_mutex_unlock(&pgsql_lock); 00824 return -1; 00825 } 00826 } 00827 00828 numrows = atoi(PQcmdTuples(result)); 00829 ast_mutex_unlock(&pgsql_lock); 00830 00831 ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename); 00832 00833 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 00834 * An integer greater than zero indicates the number of rows affected 00835 * Zero indicates that no records were updated 00836 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 00837 */ 00838 00839 if (numrows >= 0) { 00840 return (int) numrows; 00841 } 00842 00843 return -1; 00844 }
| 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_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 return -1; 00682 } else { 00683 ExecStatusType result_status = PQresultStatus(result); 00684 if (result_status != PGRES_COMMAND_OK 00685 && result_status != PGRES_TUPLES_OK 00686 && result_status != PGRES_NONFATAL_ERROR) { 00687 ast_log(LOG_WARNING, 00688 "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n"); 00689 ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql)); 00690 ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n", 00691 PQresultErrorMessage(result), PQresStatus(result_status)); 00692 ast_mutex_unlock(&pgsql_lock); 00693 return -1; 00694 } 00695 } 00696 00697 numrows = atoi(PQcmdTuples(result)); 00698 ast_mutex_unlock(&pgsql_lock); 00699 00700 ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename); 00701 00702 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html 00703 * An integer greater than zero indicates the number of rows affected 00704 * Zero indicates that no records were updated 00705 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.) 00706 */ 00707 00708 if (numrows >= 0) 00709 return (int) numrows; 00710 00711 return -1; 00712 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload } [static] |
Definition at line 1596 of file res_config_pgsql.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1596 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 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.
Referenced by handle_cli_realtime_pgsql_status(), and pgsql_reconnect().
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] |
Definition at line 46 of file res_config_pgsql.c.
Referenced by find_table().
struct ast_config_engine pgsql_engine [static] |
Definition at line 1268 of file res_config_pgsql.c.
Referenced by load_module(), and unload_module().
ast_mutex_t pgsql_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static] |
Definition at line 44 of file res_config_pgsql.c.
Referenced by config_pgsql(), destroy_pgsql(), parse_config(), realtime_multi_pgsql(), realtime_pgsql(), require_pgsql(), store_pgsql(), unload_module(), update2_pgsql(), and update_pgsql().
| PGconn* pgsqlConn = NULL |
Definition at line 52 of file res_config_pgsql.c.
| enum { ... } requirements |
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.
Referenced by config_pgsql(), destroy_pgsql(), realtime_multi_pgsql(), realtime_pgsql(), store_pgsql(), update2_pgsql(), and update_pgsql().
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(), store_pgsql(), and update2_pgsql().
1.6.2