Wed Jan 8 2020 09:50:18

Asterisk developer's documentation


res_config_pgsql.c File Reference

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  tables::psql_columns
 
struct  psql_tables
 
struct  tables
 

Macros

#define ESCAPE_STRING(buffer, stringname)
 
#define has_schema_support   (version > 70300 ? 1 : 0)
 
#define MAX_DB_OPTION_SIZE   64
 
#define release_table(table)   ast_rwlock_unlock(&(table)->lock);
 
#define RES_CONFIG_PGSQL_CONF   "res_pgsql.conf"
 

Enumerations

enum  { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR }
 

Functions

static void __init_escapebuf_buf (void)
 
static void __init_findtable_buf (void)
 
static void __init_semibuf_buf (void)
 
static void __init_sql_buf (void)
 
static void __init_where_buf (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static struct ast_configconfig_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 columnsfind_column (struct tables *t, const char *colname)
 
static struct tablesfind_table (const char *database, const char *orig_tablename)
 
static char * handle_cli_realtime_pgsql_cache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_realtime_pgsql_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int load_module (void)
 
static int parse_config (int reload)
 
static int pgsql_reconnect (const char *database)
 
static struct ast_configrealtime_multi_pgsql (const char *database, const char *table, va_list ap)
 
static struct ast_variablerealtime_pgsql (const char *database, const char *tablename, va_list ap)
 
static int reload (void)
 
static int require_pgsql (const char *database, const char *tablename, va_list ap)
 
static int store_pgsql (const char *database, const char *table, va_list ap)
 
static int unload_module (void)
 
static int unload_pgsql (const char *database, const char *tablename)
 
static int update2_pgsql (const char *database, const char *tablename, va_list ap)
 
static int update_pgsql (const char *database, const char *tablename, const char *keyfield, const char *lookup, va_list ap)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PostgreSQL RealTime Configuration Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DRIVER, }
 
static struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_realtime []
 
static time_t connect_time = 0
 
static char dbhost [MAX_DB_OPTION_SIZE] = ""
 
static char dbname [MAX_DB_OPTION_SIZE] = ""
 
static char dbpass [MAX_DB_OPTION_SIZE] = ""
 
static int dbport = 5432
 
static char dbsock [MAX_DB_OPTION_SIZE] = ""
 
static char dbuser [MAX_DB_OPTION_SIZE] = ""
 
static struct ast_threadstorage escapebuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_escapebuf_buf , .custom_init = NULL , }
 
static struct ast_threadstorage findtable_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_findtable_buf , .custom_init = NULL , }
 
static struct ast_config_engine pgsql_engine
 
static ast_mutex_t pgsql_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
 
static PGconn * pgsqlConn = NULL
 
static struct psql_tables psql_tables = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } , }
 
static enum { ... }  requirements
 
static struct ast_threadstorage semibuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_semibuf_buf , .custom_init = NULL , }
 
static struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }
 
static int version
 
static struct ast_threadstorage where_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_where_buf , .custom_init = NULL , }
 

Detailed Description

PostgreSQL plugin for Asterisk RealTime Architecture.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Manuel Guesdon mgues.nosp@m.don@.nosp@m.oxymi.nosp@m.um.n.nosp@m.et - PostgreSQL RealTime Driver Author/Adaptor
ExtRef:
PostgreSQL http://www.postgresql.org

Definition in file res_config_pgsql.c.

Macro Definition Documentation

#define ESCAPE_STRING (   buffer,
  stringname 
)
#define has_schema_support   (version > 70300 ? 1 : 0)

Definition at line 56 of file res_config_pgsql.c.

Referenced by find_table().

#define MAX_DB_OPTION_SIZE   64

Definition at line 58 of file res_config_pgsql.c.

#define release_table (   table)    ast_rwlock_unlock(&(table)->lock);
#define RES_CONFIG_PGSQL_CONF   "res_pgsql.conf"

Definition at line 52 of file res_config_pgsql.c.

Referenced by config_pgsql(), and parse_config().

Enumeration Type Documentation

anonymous enum
Enumerator
RQ_WARN 
RQ_CREATECLOSE 
RQ_CREATECHAR 

Definition at line 91 of file res_config_pgsql.c.

Function Documentation

static void __init_escapebuf_buf ( void  )
static

Definition at line 49 of file res_config_pgsql.c.

56 : 0)
static void __init_findtable_buf ( void  )
static

Definition at line 47 of file res_config_pgsql.c.

56 : 0)
static void __init_semibuf_buf ( void  )
static

Definition at line 50 of file res_config_pgsql.c.

56 : 0)
static void __init_sql_buf ( void  )
static

Definition at line 46 of file res_config_pgsql.c.

56 : 0)
static void __init_where_buf ( void  )
static

Definition at line 48 of file res_config_pgsql.c.

56 : 0)
static void __reg_module ( void  )
static

Definition at line 1669 of file res_config_pgsql.c.

static void __unreg_module ( void  )
static

Definition at line 1669 of file res_config_pgsql.c.

static struct ast_config* config_pgsql ( const char *  database,
const char *  table,
const char *  file,
struct ast_config cfg,
struct ast_flags  flags,
const char *  suggested_incl,
const char *  who_asked 
)
static

Definition at line 1077 of file res_config_pgsql.c.

References ast_category_append(), ast_category_new(), ast_config_internal_load(), ast_copy_string(), ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_variable_append(), ast_variable_new(), dbname, last, LOG_WARNING, pgsql_lock, pgsql_reconnect(), RAII_VAR, RES_CONFIG_PGSQL_CONF, and sql_buf.

1080 {
1081  RAII_VAR(PGresult *, result, NULL, PQclear);
1082  long num_rows;
1083  struct ast_variable *new_v;
1084  struct ast_category *cur_cat = NULL;
1085  struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
1086  char last[80];
1087  int last_cat_metric = 0;
1088 
1089  last[0] = '\0';
1090 
1091  /*
1092  * Ignore database from the extconfig.conf since it is
1093  * configured by res_pgsql.conf.
1094  */
1095  database = dbname;
1096 
1097  if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
1098  ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n");
1099  return NULL;
1100  }
1101 
1102  ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s "
1103  "WHERE filename='%s' and commented=0"
1104  "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file);
1105 
1106  ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql));
1107 
1108  /* We now have our complete statement; Lets connect to the server and execute it. */
1110  if (!pgsql_reconnect(database)) {
1112  return NULL;
1113  }
1114 
1115  if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
1117  "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", table, database);
1118  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
1119  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
1121  return NULL;
1122  } else {
1123  ExecStatusType result_status = PQresultStatus(result);
1124  if (result_status != PGRES_COMMAND_OK
1125  && result_status != PGRES_TUPLES_OK
1126  && result_status != PGRES_NONFATAL_ERROR) {
1128  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
1129  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
1130  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
1131  PQresultErrorMessage(result), PQresStatus(result_status));
1133  return NULL;
1134  }
1135  }
1136 
1137  if ((num_rows = PQntuples(result)) > 0) {
1138  int rowIndex = 0;
1139 
1140  ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows);
1141 
1142  for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
1143  char *field_category = PQgetvalue(result, rowIndex, 0);
1144  char *field_var_name = PQgetvalue(result, rowIndex, 1);
1145  char *field_var_val = PQgetvalue(result, rowIndex, 2);
1146  char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
1147  if (!strcmp(field_var_name, "#include")) {
1148  if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) {
1150  return NULL;
1151  }
1152  continue;
1153  }
1154 
1155  if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
1156  cur_cat = ast_category_new(field_category, "", 99999);
1157  if (!cur_cat)
1158  break;
1159  ast_copy_string(last, field_category, sizeof(last));
1160  last_cat_metric = atoi(field_cat_metric);
1161  ast_category_append(cfg, cur_cat);
1162  }
1163  new_v = ast_variable_new(field_var_name, field_var_val, "");
1164  ast_variable_append(cur_cat, new_v);
1165  }
1166  } else {
1168  "PostgreSQL RealTime: Could not find config '%s' in database.\n", file);
1169  }
1170 
1172 
1173  return cfg;
1174 }
static PGconn * pgsqlConn
static char dbname[MAX_DB_OPTION_SIZE]
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category structure.
Definition: config.c:673
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RES_CONFIG_PGSQL_CONF
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
struct sla_ringing_trunk * last
Definition: app_meetme.c:965
static int pgsql_reconnect(const char *database)
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: config.c:483
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct ast_threadstorage sql_buf
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
void ast_category_append(struct ast_config *config, struct ast_category *cat)
Definition: config.c:719
struct ast_config * ast_config_internal_load(const char *configfile, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl_file, const char *who_asked)
Definition: config.c:2459
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int destroy_pgsql ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
va_list  ap 
)
static

Definition at line 980 of file res_config_pgsql.c.

References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strlen_zero(), buf1, buf2, dbname, ESCAPE_STRING, escapebuf_buf, LOG_WARNING, pgsql_lock, pgsql_reconnect(), RAII_VAR, sql_buf, and where_buf.

981 {
982  RAII_VAR(PGresult *, result, NULL, PQclear);
983  int numrows = 0;
984  int pgresult;
985  struct ast_str *sql = ast_str_thread_get(&sql_buf, 256);
987  const char *newparam, *newval;
988 
989  /*
990  * Ignore database from the extconfig.conf since it was
991  * configured by res_pgsql.conf.
992  */
993  database = dbname;
994 
995  if (!table) {
996  ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
997  return -1;
998  }
999 
1000  /* Get the first parameter and first value in our list of passed paramater/value pairs */
1001  /*newparam = va_arg(ap, const char *);
1002  newval = va_arg(ap, const char *);
1003  if (!newparam || !newval) {*/
1004  if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup)) {
1006  "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n");
1007  if (pgsqlConn) {
1008  PQfinish(pgsqlConn);
1009  pgsqlConn = NULL;
1010  };
1011  return -1;
1012  }
1013 
1014  /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
1016  if (!pgsql_reconnect(database)) {
1018  return -1;
1019  }
1020 
1021 
1022  /* Create the first part of the query using the first parameter/value pairs we just extracted
1023  If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
1024 
1025  ESCAPE_STRING(buf1, keyfield);
1026  ESCAPE_STRING(buf2, lookup);
1027  ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
1028  while ((newparam = va_arg(ap, const char *))) {
1029  newval = va_arg(ap, const char *);
1030  ESCAPE_STRING(buf1, newparam);
1031  ESCAPE_STRING(buf2, newval);
1032  ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
1033  }
1034 
1035  ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
1036 
1037  if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
1039  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
1040  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
1041  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
1043  return -1;
1044  } else {
1045  ExecStatusType result_status = PQresultStatus(result);
1046  if (result_status != PGRES_COMMAND_OK
1047  && result_status != PGRES_TUPLES_OK
1048  && result_status != PGRES_NONFATAL_ERROR) {
1050  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
1051  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
1052  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
1053  PQresultErrorMessage(result), PQresStatus(result_status));
1055  return -1;
1056  }
1057  }
1058 
1059  numrows = atoi(PQcmdTuples(result));
1061 
1062  ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table);
1063 
1064  /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
1065  * An integer greater than zero indicates the number of rows affected
1066  * Zero indicates that no records were updated
1067  * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
1068  */
1069 
1070  if (numrows >= 0)
1071  return (int) numrows;
1072 
1073  return -1;
1074 }
static PGconn * pgsqlConn
static struct ast_threadstorage escapebuf_buf
static char dbname[MAX_DB_OPTION_SIZE]
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
static struct ast_threadstorage buf2
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
#define ESCAPE_STRING(buffer, stringname)
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
static struct ast_threadstorage where_buf
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static int pgsql_reconnect(const char *database)
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct ast_threadstorage buf1
static struct ast_threadstorage sql_buf
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define ast_mutex_unlock(a)
Definition: lock.h:156
static void destroy_table ( struct tables table)
static

Definition at line 117 of file res_config_pgsql.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_rwlock_destroy, ast_rwlock_unlock, ast_rwlock_wrlock, tables::columns, tables::list, and tables::lock.

Referenced by find_table(), unload_module(), and unload_pgsql().

118 {
119  struct columns *column;
120  ast_rwlock_wrlock(&table->lock);
121  while ((column = AST_LIST_REMOVE_HEAD(&table->columns, list))) {
122  ast_free(column);
123  }
124  ast_rwlock_unlock(&table->lock);
125  ast_rwlock_destroy(&table->lock);
126  ast_free(table);
127 }
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:199
#define ast_rwlock_unlock(a)
Definition: lock.h:200
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
struct tables::odbc_columns columns
struct columns::@71 list
ast_rwlock_t lock
#define ast_free(a)
Definition: astmm.h:97
#define ast_rwlock_wrlock(a)
Definition: lock.h:202
static struct columns* find_column ( struct tables t,
const char *  colname 
)
static

Definition at line 291 of file res_config_pgsql.c.

References AST_LIST_TRAVERSE, tables::columns, tables::list, and columns::name.

Referenced by update2_pgsql(), and update_pgsql().

292 {
293  struct columns *column;
294 
295  /* Check that the column exists in the table */
296  AST_LIST_TRAVERSE(&t->columns, column, list) {
297  if (strcmp(column->name, colname) == 0) {
298  return column;
299  }
300  }
301  return NULL;
302 }
struct tables::odbc_columns columns
struct columns::@71 list
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static struct tables* find_table ( const char *  database,
const char *  orig_tablename 
)
static

Definition at line 129 of file res_config_pgsql.c.

References ast_alloca, ast_calloc, ast_debug, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rwlock_init, ast_rwlock_rdlock, ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strdupa, ast_strlen_zero(), ast_verb, tables::columns, destroy_table(), findtable_buf, has_schema_support, columns::hasdefault, columns::len, tables::list, tables::lock, LOG_ERROR, columns::name, tables::name, columns::notnull, pgsql_lock, pgsql_reconnect(), RAII_VAR, tables::table, and columns::type.

Referenced by handle_cli_realtime_pgsql_cache(), require_pgsql(), update2_pgsql(), and update_pgsql().

130 {
131  struct columns *column;
132  struct tables *table;
133  struct ast_str *sql = ast_str_thread_get(&findtable_buf, 330);
134  char *pgerror;
135  RAII_VAR(PGresult *, result, NULL, PQclear);
136  char *fname, *ftype, *flen, *fnotnull, *fdef;
137  int i, rows;
138 
140  AST_LIST_TRAVERSE(&psql_tables, table, list) {
141  if (!strcasecmp(table->name, orig_tablename)) {
142  ast_debug(1, "Found table in cache; now locking\n");
143  ast_rwlock_rdlock(&table->lock);
144  ast_debug(1, "Lock cached table; now returning\n");
146  return table;
147  }
148  }
149 
150  ast_debug(1, "Table '%s' not found in cache, querying now\n", orig_tablename);
151 
152  /* Not found, scan the table */
153  if (has_schema_support) {
154  char *schemaname, *tablename;
155  if (strchr(orig_tablename, '.')) {
156  schemaname = ast_strdupa(orig_tablename);
157  tablename = strchr(schemaname, '.');
158  *tablename++ = '\0';
159  } else {
160  schemaname = "";
161  tablename = ast_strdupa(orig_tablename);
162  }
163 
164  /* Escape special characters in schemaname */
165  if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
166  char *tmp = schemaname, *ptr;
167 
168  ptr = schemaname = ast_alloca(strlen(tmp) * 2 + 1);
169  for (; *tmp; tmp++) {
170  if (strchr("\\'", *tmp)) {
171  *ptr++ = *tmp;
172  }
173  *ptr++ = *tmp;
174  }
175  *ptr = '\0';
176  }
177  /* Escape special characters in tablename */
178  if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
179  char *tmp = tablename, *ptr;
180 
181  ptr = tablename = ast_alloca(strlen(tmp) * 2 + 1);
182  for (; *tmp; tmp++) {
183  if (strchr("\\'", *tmp)) {
184  *ptr++ = *tmp;
185  }
186  *ptr++ = *tmp;
187  }
188  *ptr = '\0';
189  }
190 
191  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",
192  tablename,
193  ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'");
194  } else {
195  /* Escape special characters in tablename */
196  if (strchr(orig_tablename, '\\') || strchr(orig_tablename, '\'')) {
197  const char *tmp = orig_tablename;
198  char *ptr;
199 
200  orig_tablename = ptr = ast_alloca(strlen(tmp) * 2 + 1);
201  for (; *tmp; tmp++) {
202  if (strchr("\\'", *tmp)) {
203  *ptr++ = *tmp;
204  }
205  *ptr++ = *tmp;
206  }
207  *ptr = '\0';
208  }
209 
210  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);
211  }
212 
214  if (!pgsql_reconnect(database)) {
217  return NULL;
218  }
219 
220  result = PQexec(pgsqlConn, ast_str_buffer(sql));
221  ast_debug(1, "Query of table structure complete. Now retrieving results.\n");
222  if (PQresultStatus(result) != PGRES_TUPLES_OK) {
223  pgerror = PQresultErrorMessage(result);
224  ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
227  return NULL;
228  }
229 
230  if (!(table = ast_calloc(1, sizeof(*table) + strlen(orig_tablename) + 1))) {
231  ast_log(LOG_ERROR, "Unable to allocate memory for new table structure\n");
234  return NULL;
235  }
236  strcpy(table->name, orig_tablename); /* SAFE */
237  ast_rwlock_init(&table->lock);
239 
240  rows = PQntuples(result);
241  for (i = 0; i < rows; i++) {
242  fname = PQgetvalue(result, i, 0);
243  ftype = PQgetvalue(result, i, 1);
244  flen = PQgetvalue(result, i, 2);
245  fnotnull = PQgetvalue(result, i, 3);
246  fdef = PQgetvalue(result, i, 4);
247  ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
248 
249  if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + 2))) {
250  ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", orig_tablename, fname);
251  destroy_table(table);
254  return NULL;
255  }
256 
257  if (strcmp(flen, "-1") == 0) {
258  /* Some types, like chars, have the length stored in a different field */
259  flen = PQgetvalue(result, i, 5);
260  sscanf(flen, "%30d", &column->len);
261  column->len -= 4;
262  } else {
263  sscanf(flen, "%30d", &column->len);
264  }
265  column->name = (char *)column + sizeof(*column);
266  column->type = (char *)column + sizeof(*column) + strlen(fname) + 1;
267  strcpy(column->name, fname);
268  strcpy(column->type, ftype);
269  if (*fnotnull == 't') {
270  column->notnull = 1;
271  } else {
272  column->notnull = 0;
273  }
274  if (!ast_strlen_zero(fdef)) {
275  column->hasdefault = 1;
276  } else {
277  column->hasdefault = 0;
278  }
279  AST_LIST_INSERT_TAIL(&table->columns, column, list);
280  }
281 
282  AST_LIST_INSERT_TAIL(&psql_tables, table, list);
283  ast_rwlock_rdlock(&table->lock);
286  return table;
287 }
unsigned int hasdefault
Definition: cdr_pgsql.c:69
#define has_schema_support
#define ast_rwlock_rdlock(a)
Definition: lock.h:201
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static void destroy_table(struct tables *table)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
static PGconn * pgsqlConn
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
char name[0]
#define ast_verb(level,...)
Definition: logger.h:243
SQLSMALLINT type
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static int pgsql_reconnect(const char *database)
struct tables::odbc_columns columns
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:190
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
ast_rwlock_t lock
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static struct ast_threadstorage findtable_buf
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
unsigned int notnull
Definition: cdr_pgsql.c:68
int len
Definition: cdr_pgsql.c:67
#define ast_calloc(a, b)
Definition: astmm.h:82
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define ast_mutex_unlock(a)
Definition: lock.h:156
static char * handle_cli_realtime_pgsql_cache ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1556 of file res_config_pgsql.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, CLI_GENERATE, CLI_INIT, tables::columns, ast_cli_entry::command, ast_cli_args::fd, find_table(), columns::len, 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.

1557 {
1558  struct tables *cur;
1559  int l, which;
1560  char *ret = NULL;
1561 
1562  switch (cmd) {
1563  case CLI_INIT:
1564  e->command = "realtime show pgsql cache";
1565  e->usage =
1566  "Usage: realtime show pgsql cache [<table>]\n"
1567  " Shows table cache for the PostgreSQL RealTime driver\n";
1568  return NULL;
1569  case CLI_GENERATE:
1570  if (a->argc != 4) {
1571  return NULL;
1572  }
1573  l = strlen(a->word);
1574  which = 0;
1577  if (!strncasecmp(a->word, cur->name, l) && ++which > a->n) {
1578  ret = ast_strdup(cur->name);
1579  break;
1580  }
1581  }
1583  return ret;
1584  }
1585 
1586  if (a->argc == 4) {
1587  /* List of tables */
1590  ast_cli(a->fd, "%s\n", cur->name);
1591  }
1593  } else if (a->argc == 5) {
1594  /* List of columns */
1595  if ((cur = find_table(NULL, a->argv[4]))) {
1596  struct columns *col;
1597  ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[4]);
1598  ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable");
1599  AST_LIST_TRAVERSE(&cur->columns, col, list) {
1600  ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : "");
1601  }
1602  release_table(cur);
1603  } else {
1604  ast_cli(a->fd, "No such table '%s'\n", a->argv[4]);
1605  }
1606  }
1607  return 0;
1608 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define ast_strdup(a)
Definition: astmm.h:109
#define release_table(table)
const int argc
Definition: cli.h:154
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Definition: cli.h:146
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
static struct tables * find_table(const char *database, const char *orig_tablename)
char name[0]
SQLSMALLINT type
struct tables::@329 list
const int fd
Definition: cli.h:153
const int n
Definition: cli.h:159
struct tables::odbc_columns columns
const char *const * argv
Definition: cli.h:155
struct columns::@71 list
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
char * command
Definition: cli.h:180
const char * word
Definition: cli.h:157
const char * usage
Definition: cli.h:171
unsigned int notnull
Definition: cdr_pgsql.c:68
int len
Definition: cdr_pgsql.c:67
static char * handle_cli_realtime_pgsql_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1610 of file res_config_pgsql.c.

References ast_cli_args::argc, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, connect_time, dbhost, dbname, dbport, dbsock, dbuser, ast_cli_args::fd, status, and ast_cli_entry::usage.

1611 {
1612  char status[256], credentials[100] = "";
1613  int ctimesec = time(NULL) - connect_time;
1614 
1615  switch (cmd) {
1616  case CLI_INIT:
1617  e->command = "realtime show pgsql status";
1618  e->usage =
1619  "Usage: realtime show pgsql status\n"
1620  " Shows connection information for the PostgreSQL RealTime driver\n";
1621  return NULL;
1622  case CLI_GENERATE:
1623  return NULL;
1624  }
1625 
1626  if (a->argc != 4)
1627  return CLI_SHOWUSAGE;
1628 
1629  if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
1630  if (!ast_strlen_zero(dbhost))
1631  snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport);
1632  else if (!ast_strlen_zero(dbsock))
1633  snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock);
1634  else
1635  snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost);
1636 
1637  if (!ast_strlen_zero(dbuser))
1638  snprintf(credentials, sizeof(credentials), " with username %s", dbuser);
1639 
1640  if (ctimesec > 31536000)
1641  ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
1642  status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400,
1643  (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
1644  else if (ctimesec > 86400)
1645  ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
1646  credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60,
1647  ctimesec % 60);
1648  else if (ctimesec > 3600)
1649  ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials,
1650  ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
1651  else if (ctimesec > 60)
1652  ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60,
1653  ctimesec % 60);
1654  else
1655  ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
1656 
1657  return CLI_SUCCESS;
1658  } else {
1659  return CLI_FAILURE;
1660  }
1661 }
static int dbport
static PGconn * pgsqlConn
static char dbname[MAX_DB_OPTION_SIZE]
const int argc
Definition: cli.h:154
Definition: cli.h:146
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
const int fd
Definition: cli.h:153
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define CLI_SHOWUSAGE
Definition: cli.h:44
#define CLI_FAILURE
Definition: cli.h:45
char * command
Definition: cli.h:180
static char dbuser[MAX_DB_OPTION_SIZE]
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
static char dbsock[MAX_DB_OPTION_SIZE]
static time_t connect_time
static char dbhost[MAX_DB_OPTION_SIZE]
jack_status_t status
Definition: app_jack.c:143
static int load_module ( void  )
static

Definition at line 1353 of file res_config_pgsql.c.

References ARRAY_LEN, ast_cli_register_multiple(), ast_config_engine_register(), AST_MODULE_LOAD_DECLINE, ast_verb, cli_realtime, parse_config(), and pgsql_engine.

1354 {
1355  if(!parse_config(0))
1356  return AST_MODULE_LOAD_DECLINE;
1357 
1359  ast_verb(1, "PostgreSQL RealTime driver loaded.\n");
1361 
1362  return 0;
1363 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ast_verb(level,...)
Definition: logger.h:243
static struct ast_cli_entry cli_realtime[]
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
Definition: config.c:2378
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
static int parse_config(int reload)
static struct ast_config_engine pgsql_engine
static int parse_config ( int  reload)
static

Definition at line 1399 of file res_config_pgsql.c.

References ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), ast_variable_retrieve(), ast_verb, config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, dbhost, dbname, dbpass, dbport, dbsock, dbuser, LOG_WARNING, option_debug, pgsql_lock, pgsql_reconnect(), requirements, RES_CONFIG_PGSQL_CONF, RQ_CREATECHAR, RQ_CREATECLOSE, and RQ_WARN.

Referenced by load_module(), and reload().

1400 {
1401  struct ast_config *config;
1402  const char *s;
1403  struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1404 
1405  config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags);
1406  if (config == CONFIG_STATUS_FILEUNCHANGED) {
1407  return 0;
1408  }
1409 
1410  if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
1411  ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF);
1412  return 0;
1413  }
1414 
1416 
1417  if (pgsqlConn) {
1418  PQfinish(pgsqlConn);
1419  pgsqlConn = NULL;
1420  }
1421 
1422  if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
1424  "PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n");
1425  strcpy(dbuser, "asterisk");
1426  } else {
1427  ast_copy_string(dbuser, s, sizeof(dbuser));
1428  }
1429 
1430  if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
1432  "PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n");
1433  strcpy(dbpass, "asterisk");
1434  } else {
1435  ast_copy_string(dbpass, s, sizeof(dbpass));
1436  }
1437 
1438  if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
1440  "PostgreSQL RealTime: No database host found, using localhost via socket.\n");
1441  dbhost[0] = '\0';
1442  } else {
1443  ast_copy_string(dbhost, s, sizeof(dbhost));
1444  }
1445 
1446  if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
1448  "PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n");
1449  strcpy(dbname, "asterisk");
1450  } else {
1451  ast_copy_string(dbname, s, sizeof(dbname));
1452  }
1453 
1454  if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
1456  "PostgreSQL RealTime: No database port found, using 5432 as default.\n");
1457  dbport = 5432;
1458  } else {
1459  dbport = atoi(s);
1460  }
1461 
1462  if (!ast_strlen_zero(dbhost)) {
1463  /* No socket needed */
1464  } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
1466  "PostgreSQL RealTime: No database socket found, using '/tmp/.s.PGSQL.%d' as default.\n", dbport);
1467  strcpy(dbsock, "/tmp");
1468  } else {
1469  ast_copy_string(dbsock, s, sizeof(dbsock));
1470  }
1471 
1472  if (!(s = ast_variable_retrieve(config, "general", "requirements"))) {
1474  "PostgreSQL RealTime: no requirements setting found, using 'warn' as default.\n");
1476  } else if (!strcasecmp(s, "createclose")) {
1478  } else if (!strcasecmp(s, "createchar")) {
1480  }
1481 
1482  ast_config_destroy(config);
1483 
1484  if (option_debug) {
1485  if (!ast_strlen_zero(dbhost)) {
1486  ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost);
1487  ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport);
1488  } else {
1489  ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock);
1490  }
1491  ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser);
1492  ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass);
1493  ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname);
1494  }
1495 
1496  if (!pgsql_reconnect(NULL)) {
1498  "PostgreSQL RealTime: Couldn't establish connection. Check debug.\n");
1499  ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn));
1500  }
1501 
1502  ast_verb(2, "PostgreSQL RealTime reloaded.\n");
1503 
1504  /* Done reloading. Release lock so others can now use driver. */
1506 
1507  return 1;
1508 }
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
static const char config[]
Definition: cdr_csv.c:57
static int dbport
int option_debug
Definition: asterisk.c:182
static PGconn * pgsqlConn
static char dbname[MAX_DB_OPTION_SIZE]
#define LOG_WARNING
Definition: logger.h:144
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
static char dbpass[MAX_DB_OPTION_SIZE]
#define ast_verb(level,...)
Definition: logger.h:243
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
#define CONFIG_STATUS_FILEMISSING
Definition: config.h:50
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RES_CONFIG_PGSQL_CONF
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static int pgsql_reconnect(const char *database)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static enum @327 requirements
Structure used to handle boolean flags.
Definition: utils.h:200
static char dbuser[MAX_DB_OPTION_SIZE]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static char dbsock[MAX_DB_OPTION_SIZE]
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static char dbhost[MAX_DB_OPTION_SIZE]
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int pgsql_reconnect ( const char *  database)
static

Definition at line 1510 of file res_config_pgsql.c.

References ast_copy_string(), ast_debug, ast_free, ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_str_size(), ast_strlen_zero(), connect_time, dbhost, dbname, dbpass, dbport, dbsock, dbuser, LOG_ERROR, and S_OR.

Referenced by config_pgsql(), destroy_pgsql(), find_table(), parse_config(), realtime_multi_pgsql(), realtime_pgsql(), require_pgsql(), store_pgsql(), update2_pgsql(), and update_pgsql().

1511 {
1512  char my_database[50];
1513 
1514  ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
1515 
1516  /* mutex lock should have been locked before calling this function. */
1517 
1518  if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
1519  PQfinish(pgsqlConn);
1520  pgsqlConn = NULL;
1521  }
1522 
1523  /* DB password can legitimately be 0-length */
1524  if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) {
1525  struct ast_str *connInfo = ast_str_create(128);
1526 
1527  ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s",
1528  S_OR(dbhost, dbsock), dbport, my_database, dbuser);
1529  if (!ast_strlen_zero(dbpass))
1530  ast_str_append(&connInfo, 0, " password=%s", dbpass);
1531 
1532  ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
1533  pgsqlConn = PQconnectdb(ast_str_buffer(connInfo));
1534  ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
1535  ast_free(connInfo);
1536  connInfo = NULL;
1537 
1538  ast_debug(1, "pgsqlConn=%p\n", pgsqlConn);
1539  if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
1540  ast_debug(1, "PostgreSQL RealTime: Successfully connected to database.\n");
1541  connect_time = time(NULL);
1542  version = PQserverVersion(pgsqlConn);
1543  return 1;
1544  } else {
1546  "PostgreSQL RealTime: Failed to connect database %s on %s: %s\n",
1547  my_database, dbhost, PQresultErrorMessage(NULL));
1548  return 0;
1549  }
1550  } else {
1551  ast_debug(1, "PostgreSQL RealTime: One or more of the parameters in the config does not pass our validity checks.\n");
1552  return 1;
1553  }
1554 }
uint32_t version
static int dbport
static PGconn * pgsqlConn
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:482
static char dbname[MAX_DB_OPTION_SIZE]
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
static char dbpass[MAX_DB_OPTION_SIZE]
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
static char dbuser[MAX_DB_OPTION_SIZE]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
static char dbsock[MAX_DB_OPTION_SIZE]
static time_t connect_time
static char dbhost[MAX_DB_OPTION_SIZE]
static struct ast_config* realtime_multi_pgsql ( const char *  database,
const char *  table,
va_list  ap 
)
static

Definition at line 440 of file res_config_pgsql.c.

References ast_calloc, ast_category_append(), ast_category_new(), ast_category_rename(), ast_config_destroy(), ast_config_new(), ast_debug, ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_realtime_decode_chunk(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strdupa, ast_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new(), dbname, ESCAPE_STRING, escapebuf_buf, LOG_ERROR, LOG_WARNING, pgsql_lock, pgsql_reconnect(), RAII_VAR, sql_buf, strsep(), and var.

441 {
442  RAII_VAR(PGresult *, result, NULL, PQclear);
443  int num_rows = 0, pgresult;
444  struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
445  struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
446  const char *initfield = NULL;
447  char *stringp;
448  char *chunk;
449  char *op;
450  const char *newparam, *newval;
451  struct ast_variable *var = NULL;
452  struct ast_config *cfg = NULL;
453  struct ast_category *cat = NULL;
454 
455  /*
456  * Ignore database from the extconfig.conf since it was
457  * configured by res_pgsql.conf.
458  */
459  database = dbname;
460 
461  if (!table) {
462  ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
463  return NULL;
464  }
465 
466  if (!(cfg = ast_config_new()))
467  return NULL;
468 
469  /* Get the first parameter and first value in our list of passed paramater/value pairs */
470  newparam = va_arg(ap, const char *);
471  newval = va_arg(ap, const char *);
472  if (!newparam || !newval) {
474  "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
475  if (pgsqlConn) {
476  PQfinish(pgsqlConn);
477  pgsqlConn = NULL;
478  }
479  ast_config_destroy(cfg);
480  return NULL;
481  }
482 
483  initfield = ast_strdupa(newparam);
484  if ((op = strchr(initfield, ' '))) {
485  *op = '\0';
486  }
487 
488  /* Create the first part of the query using the first parameter/value pairs we just extracted
489  If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
490 
491  if (!strchr(newparam, ' '))
492  op = " =";
493  else
494  op = "";
495 
496  ESCAPE_STRING(escapebuf, newval);
497  if (pgresult) {
498  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
499  ast_config_destroy(cfg);
500  return NULL;
501  }
502 
503  ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
504  while ((newparam = va_arg(ap, const char *))) {
505  newval = va_arg(ap, const char *);
506  if (!strchr(newparam, ' '))
507  op = " =";
508  else
509  op = "";
510 
511  ESCAPE_STRING(escapebuf, newval);
512  if (pgresult) {
513  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
514  ast_config_destroy(cfg);
515  return NULL;
516  }
517 
518  ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
519  }
520 
521  if (initfield) {
522  ast_str_append(&sql, 0, " ORDER BY %s", initfield);
523  }
524 
525 
526  /* We now have our complete statement; Lets connect to the server and execute it. */
528  if (!pgsql_reconnect(database)) {
530  ast_config_destroy(cfg);
531  return NULL;
532  }
533 
534  if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
536  "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
537  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
538  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
540  ast_config_destroy(cfg);
541  return NULL;
542  } else {
543  ExecStatusType result_status = PQresultStatus(result);
544  if (result_status != PGRES_COMMAND_OK
545  && result_status != PGRES_TUPLES_OK
546  && result_status != PGRES_NONFATAL_ERROR) {
548  "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
549  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
550  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
551  PQresultErrorMessage(result), PQresStatus(result_status));
553  ast_config_destroy(cfg);
554  return NULL;
555  }
556  }
557 
558  ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
559 
560  if ((num_rows = PQntuples(result)) > 0) {
561  int numFields = PQnfields(result);
562  int i = 0;
563  int rowIndex = 0;
564  char **fieldnames = NULL;
565 
566  ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
567 
568  if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
570  ast_config_destroy(cfg);
571  return NULL;
572  }
573  for (i = 0; i < numFields; i++)
574  fieldnames[i] = PQfname(result, i);
575 
576  for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
577  var = NULL;
578  if (!(cat = ast_category_new("","",99999)))
579  continue;
580  for (i = 0; i < numFields; i++) {
581  stringp = PQgetvalue(result, rowIndex, i);
582  while (stringp) {
583  chunk = strsep(&stringp, ";");
584  if (chunk && !ast_strlen_zero(ast_realtime_decode_chunk(ast_strip(chunk)))) {
585  if (initfield && !strcmp(initfield, fieldnames[i])) {
586  ast_category_rename(cat, chunk);
587  }
588  var = ast_variable_new(fieldnames[i], chunk, "");
589  ast_variable_append(cat, var);
590  }
591  }
592  }
593  ast_category_append(cfg, cat);
594  }
595  ast_free(fieldnames);
596  } else {
597  ast_debug(1, "PostgreSQL RealTime: Could not find any rows in table %s.\n", table);
598  }
599 
601 
602  return cfg;
603 }
char * strsep(char **str, const char *delims)
static PGconn * pgsqlConn
static struct ast_threadstorage escapebuf_buf
static char dbname[MAX_DB_OPTION_SIZE]
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
#define ESCAPE_STRING(buffer, stringname)
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category structure.
Definition: config.c:673
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
char * ast_realtime_decode_chunk(char *chunk)
Remove standard encoding from realtime values, which ensures that a semicolon embedded within a singl...
Definition: config.c:2773
static int pgsql_reconnect(const char *database)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: config.c:483
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: config.c:888
static struct ast_threadstorage sql_buf
#define ast_calloc(a, b)
Definition: astmm.h:82
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
void ast_category_append(struct ast_config *config, struct ast_category *cat)
Definition: config.c:719
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: config.c:867
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
#define ast_mutex_unlock(a)
Definition: lock.h:156
static struct ast_variable* realtime_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
)
static

Definition at line 304 of file res_config_pgsql.c.

References ast_calloc, ast_debug, ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_realtime_decode_chunk(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strip(), ast_strlen_zero(), ast_variable_new(), dbname, ESCAPE_STRING, escapebuf_buf, LOG_ERROR, LOG_WARNING, pgsql_lock, pgsql_reconnect(), RAII_VAR, sql_buf, strsep(), and var.

305 {
306  RAII_VAR(PGresult *, result, NULL, PQclear);
307  int num_rows = 0, pgresult;
308  struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
309  struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
310  char *stringp;
311  char *chunk;
312  char *op;
313  const char *newparam, *newval;
314  struct ast_variable *var = NULL, *prev = NULL;
315 
316  /*
317  * Ignore database from the extconfig.conf since it was
318  * configured by res_pgsql.conf.
319  */
320  database = dbname;
321 
322  if (!tablename) {
323  ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
324  return NULL;
325  }
326 
327  /* Get the first parameter and first value in our list of passed paramater/value pairs */
328  newparam = va_arg(ap, const char *);
329  newval = va_arg(ap, const char *);
330  if (!newparam || !newval) {
332  "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
333  if (pgsqlConn) {
334  PQfinish(pgsqlConn);
335  pgsqlConn = NULL;
336  }
337  return NULL;
338  }
339 
340  /* Create the first part of the query using the first parameter/value pairs we just extracted
341  If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
342  op = strchr(newparam, ' ') ? "" : " =";
343 
344  ESCAPE_STRING(escapebuf, newval);
345  if (pgresult) {
346  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
347  return NULL;
348  }
349 
350  ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
351  while ((newparam = va_arg(ap, const char *))) {
352  newval = va_arg(ap, const char *);
353  if (!strchr(newparam, ' '))
354  op = " =";
355  else
356  op = "";
357 
358  ESCAPE_STRING(escapebuf, newval);
359  if (pgresult) {
360  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
361  return NULL;
362  }
363 
364  ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
365  }
366 
367  /* We now have our complete statement; Lets connect to the server and execute it. */
369  if (!pgsql_reconnect(database)) {
371  return NULL;
372  }
373 
374  if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
376  "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
377  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
378  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
380  return NULL;
381  } else {
382  ExecStatusType result_status = PQresultStatus(result);
383  if (result_status != PGRES_COMMAND_OK
384  && result_status != PGRES_TUPLES_OK
385  && result_status != PGRES_NONFATAL_ERROR) {
387  "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
388  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
389  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
390  PQresultErrorMessage(result), PQresStatus(result_status));
392  return NULL;
393  }
394  }
395 
396  ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
397 
398  if ((num_rows = PQntuples(result)) > 0) {
399  int i = 0;
400  int rowIndex = 0;
401  int numFields = PQnfields(result);
402  char **fieldnames = NULL;
403 
404  ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
405 
406  if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
408  return NULL;
409  }
410  for (i = 0; i < numFields; i++)
411  fieldnames[i] = PQfname(result, i);
412  for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
413  for (i = 0; i < numFields; i++) {
414  stringp = PQgetvalue(result, rowIndex, i);
415  while (stringp) {
416  chunk = strsep(&stringp, ";");
417  if (chunk && !ast_strlen_zero(ast_realtime_decode_chunk(ast_strip(chunk)))) {
418  if (prev) {
419  prev->next = ast_variable_new(fieldnames[i], chunk, "");
420  if (prev->next) {
421  prev = prev->next;
422  }
423  } else {
424  prev = var = ast_variable_new(fieldnames[i], chunk, "");
425  }
426  }
427  }
428  }
429  }
430  ast_free(fieldnames);
431  } else {
432  ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s@%s.\n", tablename, database);
433  }
434 
436 
437  return var;
438 }
char * strsep(char **str, const char *delims)
static PGconn * pgsqlConn
static struct ast_threadstorage escapebuf_buf
static char dbname[MAX_DB_OPTION_SIZE]
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
#define ESCAPE_STRING(buffer, stringname)
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
char * ast_realtime_decode_chunk(char *chunk)
Remove standard encoding from realtime values, which ensures that a semicolon embedded within a singl...
Definition: config.c:2773
static int pgsql_reconnect(const char *database)
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
static struct ast_threadstorage sql_buf
#define ast_calloc(a, b)
Definition: astmm.h:82
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int reload ( void  )
static

Definition at line 1392 of file res_config_pgsql.c.

References parse_config().

1393 {
1394  parse_config(1);
1395 
1396  return 0;
1397 }
static int parse_config(int reload)
static int require_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
)
static

Definition at line 1176 of file res_config_pgsql.c.

References ast_debug, ast_free, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rq_is_int(), ast_str_buffer(), ast_str_create(), ast_str_set(), tables::columns, dbname, 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, type, and columns::type.

1177 {
1178  struct columns *column;
1179  struct tables *table;
1180  char *elm;
1181  int type, size, res = 0;
1182 
1183  /*
1184  * Ignore database from the extconfig.conf since it was
1185  * configured by res_pgsql.conf.
1186  */
1187  database = dbname;
1188 
1189  table = find_table(database, tablename);
1190  if (!table) {
1191  ast_log(LOG_WARNING, "Table %s not found in database. This table should exist if you're using realtime.\n", tablename);
1192  return -1;
1193  }
1194 
1195  while ((elm = va_arg(ap, char *))) {
1196  type = va_arg(ap, require_type);
1197  size = va_arg(ap, int);
1198  AST_LIST_TRAVERSE(&table->columns, column, list) {
1199  if (strcmp(column->name, elm) == 0) {
1200  /* Char can hold anything, as long as it is large enough */
1201  if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0 || strcmp(column->type, "bpchar") == 0)) {
1202  if ((size > column->len) && column->len != -1) {
1203  ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len);
1204  res = -1;
1205  }
1206  } else if (strncmp(column->type, "int", 3) == 0) {
1207  int typesize = atoi(column->type + 3);
1208  /* Integers can hold only other integers */
1209  if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
1210  type == RQ_INTEGER4 || type == RQ_UINTEGER4 ||
1211  type == RQ_INTEGER3 || type == RQ_UINTEGER3 ||
1212  type == RQ_UINTEGER2) && typesize == 2) {
1213  ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
1214  res = -1;
1215  } else if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
1216  type == RQ_UINTEGER4) && typesize == 4) {
1217  ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
1218  res = -1;
1219  } else if (type == RQ_CHAR || type == RQ_DATETIME || type == RQ_FLOAT || type == RQ_DATE) {
1220  ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n",
1221  column->name,
1222  type == RQ_CHAR ? "char" :
1223  type == RQ_DATETIME ? "datetime" :
1224  type == RQ_DATE ? "date" :
1225  type == RQ_FLOAT ? "float" :
1226  "a rather stiff drink ",
1227  size, column->type);
1228  res = -1;
1229  }
1230  } else if (strncmp(column->type, "float", 5) == 0) {
1231  if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
1232  ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
1233  res = -1;
1234  }
1235  } else if (strncmp(column->type, "timestamp", 9) == 0) {
1236  if (type != RQ_DATETIME && type != RQ_DATE) {
1237  ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
1238  res = -1;
1239  }
1240  } else { /* There are other types that no module implements yet */
1241  ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
1242  res = -1;
1243  }
1244  break;
1245  }
1246  }
1247 
1248  if (!column) {
1249  if (requirements == RQ_WARN) {
1250  ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size);
1251  } else {
1252  struct ast_str *sql = ast_str_create(100);
1253  char fieldtype[15];
1254  PGresult *result;
1255 
1256  if (requirements == RQ_CREATECHAR || type == RQ_CHAR) {
1257  /* Size is minimum length; make it at least 50% greater,
1258  * just to be sure, because PostgreSQL doesn't support
1259  * resizing columns. */
1260  snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)",
1261  size < 15 ? size * 2 :
1262  (size * 3 / 2 > 255) ? 255 : size * 3 / 2);
1263  } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) {
1264  snprintf(fieldtype, sizeof(fieldtype), "INT2");
1265  } else if (type == RQ_UINTEGER2 || type == RQ_INTEGER3 || type == RQ_UINTEGER3 || type == RQ_INTEGER4) {
1266  snprintf(fieldtype, sizeof(fieldtype), "INT4");
1267  } else if (type == RQ_UINTEGER4 || type == RQ_INTEGER8) {
1268  snprintf(fieldtype, sizeof(fieldtype), "INT8");
1269  } else if (type == RQ_UINTEGER8) {
1270  /* No such type on PostgreSQL */
1271  snprintf(fieldtype, sizeof(fieldtype), "CHAR(20)");
1272  } else if (type == RQ_FLOAT) {
1273  snprintf(fieldtype, sizeof(fieldtype), "FLOAT8");
1274  } else if (type == RQ_DATE) {
1275  snprintf(fieldtype, sizeof(fieldtype), "DATE");
1276  } else if (type == RQ_DATETIME) {
1277  snprintf(fieldtype, sizeof(fieldtype), "TIMESTAMP");
1278  } else {
1279  ast_log(LOG_ERROR, "Unrecognized request type %d\n", type);
1280  ast_free(sql);
1281  continue;
1282  }
1283  ast_str_set(&sql, 0, "ALTER TABLE %s ADD COLUMN %s %s", tablename, elm, fieldtype);
1284  ast_debug(1, "About to lock pgsql_lock (running alter on table '%s' to add column '%s')\n", tablename, elm);
1285 
1287  if (!pgsql_reconnect(database)) {
1289  ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
1290  ast_free(sql);
1291  continue;
1292  }
1293 
1294  ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm);
1295  result = PQexec(pgsqlConn, ast_str_buffer(sql));
1296  ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename);
1297  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
1298  ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
1299  }
1300  PQclear(result);
1302 
1303  ast_free(sql);
1304  }
1305  }
1306  }
1307  release_table(table);
1308  return res;
1309 }
static PGconn * pgsqlConn
static char dbname[MAX_DB_OPTION_SIZE]
#define release_table(table)
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
static struct tables * find_table(const char *database, const char *orig_tablename)
SQLSMALLINT type
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
struct tables::@329 list
Definition: config.h:68
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static int pgsql_reconnect(const char *database)
struct tables::odbc_columns columns
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_free(a)
Definition: astmm.h:97
static enum @327 requirements
static const char type[]
Definition: chan_nbs.c:57
int len
Definition: cdr_pgsql.c:67
int ast_rq_is_int(require_type type)
Check if require type is an integer type.
Definition: config.h:768
require_type
Types used in ast_realtime_require_field.
Definition: config.h:57
Definition: config.h:70
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int store_pgsql ( const char *  database,
const char *  table,
va_list  ap 
)
static

Definition at line 882 of file res_config_pgsql.c.

References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), dbname, ESCAPE_STRING, escapebuf_buf, LOG_WARNING, pgsql_lock, pgsql_reconnect(), RAII_VAR, sql_buf, and where_buf.

883 {
884  RAII_VAR(PGresult *, result, NULL, PQclear);
885  int numrows;
886  struct ast_str *buf = ast_str_thread_get(&escapebuf_buf, 256);
887  struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256);
888  struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256);
889  int pgresult;
890  const char *newparam, *newval;
891 
892  /*
893  * Ignore database from the extconfig.conf since it was
894  * configured by res_pgsql.conf.
895  */
896  database = dbname;
897 
898  if (!table) {
899  ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
900  return -1;
901  }
902 
903  /* Get the first parameter and first value in our list of passed paramater/value pairs */
904  newparam = va_arg(ap, const char *);
905  newval = va_arg(ap, const char *);
906  if (!newparam || !newval) {
908  "PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
909  if (pgsqlConn) {
910  PQfinish(pgsqlConn);
911  pgsqlConn = NULL;
912  }
913  return -1;
914  }
915 
916  /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
918  if (!pgsql_reconnect(database)) {
920  return -1;
921  }
922 
923  /* Create the first part of the query using the first parameter/value pairs we just extracted
924  If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
925  ESCAPE_STRING(buf, newparam);
926  ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
927  ESCAPE_STRING(buf, newval);
928  ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
929  while ((newparam = va_arg(ap, const char *))) {
930  newval = va_arg(ap, const char *);
931  ESCAPE_STRING(buf, newparam);
932  ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
933  ESCAPE_STRING(buf, newval);
934  ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
935  }
936  ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
937 
938  ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1));
939 
940  if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql1)))) {
942  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
943  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
944  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
946  return -1;
947  } else {
948  ExecStatusType result_status = PQresultStatus(result);
949  if (result_status != PGRES_COMMAND_OK
950  && result_status != PGRES_TUPLES_OK
951  && result_status != PGRES_NONFATAL_ERROR) {
953  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
954  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
955  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
956  PQresultErrorMessage(result), PQresStatus(result_status));
958  return -1;
959  }
960  }
961 
962  numrows = atoi(PQcmdTuples(result));
964 
965  ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s.", table);
966 
967  /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
968  * An integer greater than zero indicates the number of rows affected
969  * Zero indicates that no records were updated
970  * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
971  */
972 
973  if (numrows >= 0) {
974  return numrows;
975  }
976 
977  return -1;
978 }
static PGconn * pgsqlConn
static struct ast_threadstorage escapebuf_buf
static char dbname[MAX_DB_OPTION_SIZE]
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
#define ESCAPE_STRING(buffer, stringname)
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
static struct ast_threadstorage where_buf
static int pgsql_reconnect(const char *database)
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct ast_threadstorage sql_buf
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int unload_module ( void  )
static

Definition at line 1365 of file res_config_pgsql.c.

References ARRAY_LEN, ast_cli_unregister_multiple(), ast_config_engine_deregister(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_verb, cli_realtime, destroy_table(), tables::list, pgsql_engine, pgsql_lock, and tables::table.

1366 {
1367  struct tables *table;
1368  /* Acquire control before doing anything to the module itself. */
1370 
1371  if (pgsqlConn) {
1372  PQfinish(pgsqlConn);
1373  pgsqlConn = NULL;
1374  }
1377  ast_verb(1, "PostgreSQL RealTime unloaded.\n");
1378 
1379  /* Destroy cached table info */
1381  while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) {
1382  destroy_table(table);
1383  }
1385 
1386  /* Unlock so something else can destroy the lock. */
1388 
1389  return 0;
1390 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static void destroy_table(struct tables *table)
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
static PGconn * pgsqlConn
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
#define ast_verb(level,...)
Definition: logger.h:243
static char * table
Definition: cdr_odbc.c:50
struct tables::@329 list
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
static struct ast_cli_entry cli_realtime[]
static struct ast_config_engine pgsql_engine
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
Definition: config.c:2397
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int unload_pgsql ( const char *  database,
const char *  tablename 
)
static

Definition at line 1311 of file res_config_pgsql.c.

References ast_debug, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dbname, destroy_table(), tables::list, and tables::name.

1312 {
1313  struct tables *cur;
1314 
1315  /*
1316  * Ignore database from the extconfig.conf since it was
1317  * configured by res_pgsql.conf.
1318  */
1319  database = dbname;
1320 
1321  ast_debug(2, "About to lock table cache list\n");
1323  ast_debug(2, "About to traverse table cache list\n");
1325  if (strcmp(cur->name, tablename) == 0) {
1326  ast_debug(2, "About to remove matching cache entry\n");
1328  ast_debug(2, "About to destroy matching cache entry\n");
1329  destroy_table(cur);
1330  ast_debug(1, "Cache entry '%s@%s' destroyed\n", tablename, database);
1331  break;
1332  }
1333  }
1336  ast_debug(2, "About to return\n");
1337  return cur ? 0 : -1;
1338 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static void destroy_table(struct tables *table)
static char dbname[MAX_DB_OPTION_SIZE]
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
char name[0]
struct tables::@329 list
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
static int update2_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
)
static

Definition at line 745 of file res_config_pgsql.c.

References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), dbname, ESCAPE_STRING, escapebuf_buf, find_column(), find_table(), first, LOG_ERROR, LOG_NOTICE, LOG_WARNING, pgsql_lock, pgsql_reconnect(), RAII_VAR, release_table, sql_buf, tables::table, and where_buf.

746 {
747  RAII_VAR(PGresult *, result, NULL, PQclear);
748  int numrows = 0, pgresult, first = 1;
749  struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16);
750  const char *newparam, *newval;
751  struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
752  struct ast_str *where = ast_str_thread_get(&where_buf, 100);
753  struct tables *table;
754 
755  /*
756  * Ignore database from the extconfig.conf since it was
757  * configured by res_pgsql.conf.
758  */
759  database = dbname;
760 
761  if (!tablename) {
762  ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
763  return -1;
764  }
765 
766  if (!escapebuf || !sql || !where) {
767  /* Memory error, already handled */
768  return -1;
769  }
770 
771  if (!(table = find_table(database, tablename))) {
772  ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
773  return -1;
774  }
775 
776  ast_str_set(&sql, 0, "UPDATE %s SET", tablename);
777  ast_str_set(&where, 0, " WHERE");
778 
779  while ((newparam = va_arg(ap, const char *))) {
780  if (!find_column(table, newparam)) {
781  ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database);
782  release_table(table);
783  return -1;
784  }
785 
786  newval = va_arg(ap, const char *);
787  ESCAPE_STRING(escapebuf, newval);
788  if (pgresult) {
789  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
790  release_table(table);
791  return -1;
792  }
793  ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
794  first = 0;
795  }
796 
797  if (first) {
799  "PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on.\n");
800  if (pgsqlConn) {
801  PQfinish(pgsqlConn);
802  pgsqlConn = NULL;
803  }
804  release_table(table);
805  return -1;
806  }
807 
808  /* Now retrieve the columns to update */
809  first = 1;
810  while ((newparam = va_arg(ap, const char *))) {
811  newval = va_arg(ap, const char *);
812 
813  /* If the column is not within the table, then skip it */
814  if (!find_column(table, newparam)) {
815  ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database);
816  continue;
817  }
818 
819  ESCAPE_STRING(escapebuf, newval);
820  if (pgresult) {
821  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
822  release_table(table);
823  return -1;
824  }
825 
826  ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
827  first = 0;
828  }
829  release_table(table);
830 
831  ast_str_append(&sql, 0, "%s", ast_str_buffer(where));
832 
833  ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
834 
835  /* We now have our complete statement; connect to the server and execute it. */
837  if (!pgsql_reconnect(database)) {
839  return -1;
840  }
841 
842  if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
844  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
845  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
846  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
848  return -1;
849  } else {
850  ExecStatusType result_status = PQresultStatus(result);
851  if (result_status != PGRES_COMMAND_OK
852  && result_status != PGRES_TUPLES_OK
853  && result_status != PGRES_NONFATAL_ERROR) {
855  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
856  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
857  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
858  PQresultErrorMessage(result), PQresStatus(result_status));
860  return -1;
861  }
862  }
863 
864  numrows = atoi(PQcmdTuples(result));
866 
867  ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
868 
869  /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
870  * An integer greater than zero indicates the number of rows affected
871  * Zero indicates that no records were updated
872  * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
873  */
874 
875  if (numrows >= 0) {
876  return (int) numrows;
877  }
878 
879  return -1;
880 }
static PGconn * pgsqlConn
static struct ast_threadstorage escapebuf_buf
static char dbname[MAX_DB_OPTION_SIZE]
#define release_table(table)
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
static struct tables * find_table(const char *database, const char *orig_tablename)
#define ESCAPE_STRING(buffer, stringname)
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
static struct ast_threadstorage where_buf
static int pgsql_reconnect(const char *database)
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
struct sla_ringing_trunk * first
Definition: app_meetme.c:965
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
static struct ast_threadstorage sql_buf
static struct columns * find_column(struct tables *t, const char *colname)
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int update_pgsql ( const char *  database,
const char *  tablename,
const char *  keyfield,
const char *  lookup,
va_list  ap 
)
static

Definition at line 605 of file res_config_pgsql.c.

References ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), tables::columns, dbname, ESCAPE_STRING, escapebuf_buf, find_column(), find_table(), tables::list, LOG_ERROR, LOG_NOTICE, LOG_WARNING, columns::name, pgsql_lock, pgsql_reconnect(), RAII_VAR, release_table, sql_buf, and tables::table.

607 {
608  RAII_VAR(PGresult *, result, NULL, PQclear);
609  int numrows = 0, pgresult;
610  const char *newparam, *newval;
611  struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
612  struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
613  struct tables *table;
614  struct columns *column = NULL;
615 
616  /*
617  * Ignore database from the extconfig.conf since it was
618  * configured by res_pgsql.conf.
619  */
620  database = dbname;
621 
622  if (!tablename) {
623  ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
624  return -1;
625  }
626 
627  if (!(table = find_table(database, tablename))) {
628  ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
629  return -1;
630  }
631 
632  /* Get the first parameter and first value in our list of passed paramater/value pairs */
633  newparam = va_arg(ap, const char *);
634  newval = va_arg(ap, const char *);
635  if (!newparam || !newval) {
637  "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
638  if (pgsqlConn) {
639  PQfinish(pgsqlConn);
640  pgsqlConn = NULL;
641  }
642  release_table(table);
643  return -1;
644  }
645 
646  /* Check that the column exists in the table */
647  AST_LIST_TRAVERSE(&table->columns, column, list) {
648  if (strcmp(column->name, newparam) == 0) {
649  break;
650  }
651  }
652 
653  if (!column) {
654  ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
655  release_table(table);
656  return -1;
657  }
658 
659  /* Create the first part of the query using the first parameter/value pairs we just extracted
660  If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
661 
662  ESCAPE_STRING(escapebuf, newval);
663  if (pgresult) {
664  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
665  release_table(table);
666  return -1;
667  }
668  ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));
669 
670  while ((newparam = va_arg(ap, const char *))) {
671  newval = va_arg(ap, const char *);
672 
673  if (!find_column(table, newparam)) {
674  ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
675  continue;
676  }
677 
678  ESCAPE_STRING(escapebuf, newval);
679  if (pgresult) {
680  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
681  release_table(table);
682  return -1;
683  }
684 
685  ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
686  }
687  release_table(table);
688 
689  ESCAPE_STRING(escapebuf, lookup);
690  if (pgresult) {
691  ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
692  return -1;
693  }
694 
695  ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(escapebuf));
696 
697  ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
698 
699  /* We now have our complete statement; Lets connect to the server and execute it. */
701  if (!pgsql_reconnect(database)) {
703  return -1;
704  }
705 
706  if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
708  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
709  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
710  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
712  return -1;
713  } else {
714  ExecStatusType result_status = PQresultStatus(result);
715  if (result_status != PGRES_COMMAND_OK
716  && result_status != PGRES_TUPLES_OK
717  && result_status != PGRES_NONFATAL_ERROR) {
719  "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
720  ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
721  ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
722  PQresultErrorMessage(result), PQresStatus(result_status));
724  return -1;
725  }
726  }
727 
728  numrows = atoi(PQcmdTuples(result));
730 
731  ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
732 
733  /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
734  * An integer greater than zero indicates the number of rows affected
735  * Zero indicates that no records were updated
736  * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
737  */
738 
739  if (numrows >= 0)
740  return (int) numrows;
741 
742  return -1;
743 }
static PGconn * pgsqlConn
static struct ast_threadstorage escapebuf_buf
static char dbname[MAX_DB_OPTION_SIZE]
#define release_table(table)
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t pgsql_lock
static struct tables * find_table(const char *database, const char *orig_tablename)
#define ESCAPE_STRING(buffer, stringname)
static char * table
Definition: cdr_odbc.c:50
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:915
static int pgsql_reconnect(const char *database)
struct tables::odbc_columns columns
struct columns::@71 list
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static struct ast_threadstorage sql_buf
static struct columns * find_column(struct tables *t, const char *colname)
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define ast_mutex_unlock(a)
Definition: lock.h:156

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PostgreSQL RealTime Configuration Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DRIVER, }
static

Definition at line 1669 of file res_config_pgsql.c.

Definition at line 1669 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"),
}
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static char * handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_realtime_pgsql_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 93 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

time_t connect_time = 0
static

Definition at line 84 of file res_config_pgsql.c.

Referenced by handle_cli_realtime_pgsql_status(), and pgsql_reconnect().

char dbhost[MAX_DB_OPTION_SIZE] = ""
static
char dbpass[MAX_DB_OPTION_SIZE] = ""
static

Definition at line 80 of file res_config_pgsql.c.

Referenced by parse_config(), and pgsql_reconnect().

int dbport = 5432
static
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

Definition at line 47 of file res_config_pgsql.c.

Referenced by find_table().

struct ast_config_engine pgsql_engine
static

Definition at line 1340 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

ast_mutex_t pgsql_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static
PGconn* pgsqlConn = NULL
static

Definition at line 54 of file res_config_pgsql.c.

struct psql_tables psql_tables = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } , }
static
enum { ... } requirements

Referenced by parse_config(), and require_pgsql().

struct ast_threadstorage semibuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_semibuf_buf , .custom_init = NULL , }
static

Definition at line 50 of file res_config_pgsql.c.

struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }
static
int version
static

Definition at line 55 of file res_config_pgsql.c.

struct ast_threadstorage where_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_where_buf , .custom_init = NULL , }
static

Definition at line 48 of file res_config_pgsql.c.

Referenced by destroy_pgsql(), store_pgsql(), and update2_pgsql().