Thu Apr 28 2011 17:16: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"
Include dependency graph for res_config_pgsql.c:

Go to the source code of this file.

Data Structures

struct  columns
struct  tables::psql_columns
struct  psql_tables
struct  tables

Defines

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

Enumerations

enum  { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR }

Functions

static void __reg_module (void)
static void __unreg_module (void)
 AST_THREADSTORAGE_CUSTOM_SCOPE (findtable_buf, NULL, ast_free_ptr, static)
 AST_THREADSTORAGE_CUSTOM_SCOPE (escapebuf_buf, NULL, ast_free_ptr, static)
 AST_THREADSTORAGE_CUSTOM_SCOPE (semibuf_buf, NULL, ast_free_ptr, static)
 AST_THREADSTORAGE_CUSTOM_SCOPE (sql_buf, NULL, ast_free_ptr, static)
 AST_THREADSTORAGE_CUSTOM_SCOPE (where_buf, NULL, ast_free_ptr, static)
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 char * decode_chunk (char *chunk)
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 *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
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "PostgreSQL RealTime Configuration Driver" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload }
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_config_engine pgsql_engine
static ast_mutex_t pgsql_lock = AST_MUTEX_INIT_VALUE
PGconn * pgsqlConn = NULL
static struct psql_tables psql_tables
enum { ... }  requirements
static int version

Detailed Description

PostgreSQL plugin for Asterisk RealTime Architecture.

Author:
Mark Spencer <markster@digium.com>
Manuel Guesdon <mguesdon@oxymium.net> - PostgreSQL RealTime Driver Author/Adaptor

Definition in file res_config_pgsql.c.


Define Documentation

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

Definition at line 55 of file res_config_pgsql.c.

Referenced by find_table().

#define MAX_DB_OPTION_SIZE   64

Definition at line 57 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 51 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 90 of file res_config_pgsql.c.


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 1625 of file res_config_pgsql.c.

static void __unreg_module ( void  ) [static]

Definition at line 1625 of file res_config_pgsql.c.

AST_THREADSTORAGE_CUSTOM_SCOPE ( findtable_buf  ,
NULL  ,
ast_free_ptr  ,
static   
)
AST_THREADSTORAGE_CUSTOM_SCOPE ( escapebuf_buf  ,
NULL  ,
ast_free_ptr  ,
static   
)
AST_THREADSTORAGE_CUSTOM_SCOPE ( semibuf_buf  ,
NULL  ,
ast_free_ptr  ,
static   
)
AST_THREADSTORAGE_CUSTOM_SCOPE ( sql_buf  ,
NULL  ,
ast_free_ptr  ,
static   
)
AST_THREADSTORAGE_CUSTOM_SCOPE ( where_buf  ,
NULL  ,
ast_free_ptr  ,
static   
)
static struct ast_config* config_pgsql ( const char *  database,
const char *  table,
const char *  file,
struct ast_config cfg,
struct ast_flags  flags,
const char *  suggested_incl,
const char *  who_asked 
) [static, read]

Definition at line 1052 of file res_config_pgsql.c.

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

{
   PGresult *result = NULL;
   long num_rows;
   struct ast_variable *new_v;
   struct ast_category *cur_cat = NULL;
   struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
   char last[80] = "";
   int last_cat_metric = 0;

   last[0] = '\0';

   if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
      ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n");
      return NULL;
   }

   ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s "
         "WHERE filename='%s' and commented=0"
         "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file);

   ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql));

   /* We now have our complete statement; Lets connect to the server and execute it. */
   ast_mutex_lock(&pgsql_lock);
   if (!pgsql_reconnect(database)) {
      ast_mutex_unlock(&pgsql_lock);
      return NULL;
   }

   if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", table, database);
      ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
      ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
      ast_mutex_unlock(&pgsql_lock);
      return NULL;
   } else {
      ExecStatusType result_status = PQresultStatus(result);
      if (result_status != PGRES_COMMAND_OK
         && result_status != PGRES_TUPLES_OK
         && result_status != PGRES_NONFATAL_ERROR) {
         ast_log(LOG_WARNING,
               "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
         ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
         ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
                  PQresultErrorMessage(result), PQresStatus(result_status));
         ast_mutex_unlock(&pgsql_lock);
         return NULL;
      }
   }

   if ((num_rows = PQntuples(result)) > 0) {
      int rowIndex = 0;

      ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows);

      for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
         char *field_category = PQgetvalue(result, rowIndex, 0);
         char *field_var_name = PQgetvalue(result, rowIndex, 1);
         char *field_var_val = PQgetvalue(result, rowIndex, 2);
         char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
         if (!strcmp(field_var_name, "#include")) {
            if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) {
               PQclear(result);
               ast_mutex_unlock(&pgsql_lock);
               return NULL;
            }
            continue;
         }

         if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
            cur_cat = ast_category_new(field_category, "", 99999);
            if (!cur_cat)
               break;
            strcpy(last, field_category);
            last_cat_metric = atoi(field_cat_metric);
            ast_category_append(cfg, cur_cat);
         }
         new_v = ast_variable_new(field_var_name, field_var_val, "");
         ast_variable_append(cur_cat, new_v);
      }
   } else {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Could not find config '%s' in database.\n", file);
   }

   PQclear(result);
   ast_mutex_unlock(&pgsql_lock);

   return cfg;
}
static char* decode_chunk ( char *  chunk) [static]

Definition at line 294 of file res_config_pgsql.c.

Referenced by realtime_multi_pgsql(), and realtime_pgsql().

{
   char *orig = chunk;
   for (; *chunk; chunk++) {
      if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
         sscanf(chunk + 1, "%02hhX", chunk);
         memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
      }
   }
   return orig;
}
static int destroy_pgsql ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
va_list  ap 
) [static]

Definition at line 960 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(), ESCAPE_STRING, LOG_WARNING, pgsql_lock, and pgsql_reconnect().

{
   PGresult *result = NULL;
   int numrows = 0;
   int pgresult;
   struct ast_str *sql = ast_str_thread_get(&sql_buf, 256);
   struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60);
   const char *newparam, *newval;

   if (!table) {
      ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
      return -1;
   }

   /* Get the first parameter and first value in our list of passed paramater/value pairs */
   /*newparam = va_arg(ap, const char *);
   newval = va_arg(ap, const char *);
   if (!newparam || !newval) {*/
   if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n");
      if (pgsqlConn) {
         PQfinish(pgsqlConn);
         pgsqlConn = NULL;
      };
      return -1;
   }

   /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
   ast_mutex_lock(&pgsql_lock);
   if (!pgsql_reconnect(database)) {
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   }


   /* Create the first part of the query using the first parameter/value pairs we just extracted
      If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */

   ESCAPE_STRING(buf1, keyfield);
   ESCAPE_STRING(buf2, lookup);
   ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
      ESCAPE_STRING(buf1, newparam);
      ESCAPE_STRING(buf2, newval);
      ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
   }
   va_end(ap);

   ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));

   if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
      ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
      ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   } else {
      ExecStatusType result_status = PQresultStatus(result);
      if (result_status != PGRES_COMMAND_OK
         && result_status != PGRES_TUPLES_OK
         && result_status != PGRES_NONFATAL_ERROR) {
         ast_log(LOG_WARNING,
               "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
         ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
         ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
                  PQresultErrorMessage(result), PQresStatus(result_status));
         ast_mutex_unlock(&pgsql_lock);
         return -1;
      }
   }

   numrows = atoi(PQcmdTuples(result));
   ast_mutex_unlock(&pgsql_lock);

   ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table);

   /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
    * An integer greater than zero indicates the number of rows affected
    * Zero indicates that no records were updated
    * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
    */

   if (numrows >= 0)
      return (int) numrows;

   return -1;
}
static void destroy_table ( struct tables table) [static]
static struct columns* find_column ( struct tables t,
const char *  colname 
) [static, read]

Definition at line 281 of file res_config_pgsql.c.

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

Referenced by update2_pgsql(), and update_pgsql().

{
   struct columns *column;

   /* Check that the column exists in the table */
   AST_LIST_TRAVERSE(&t->columns, column, list) {
      if (strcmp(column->name, colname) == 0) {
         return column;
      }
   }
   return NULL;
}
static struct tables* find_table ( const char *  orig_tablename) [static, read]

Definition at line 128 of file res_config_pgsql.c.

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

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

{
   struct columns *column;
   struct tables *table;
   struct ast_str *sql = ast_str_thread_get(&findtable_buf, 330);
   char *pgerror;
   PGresult *result;
   char *fname, *ftype, *flen, *fnotnull, *fdef;
   int i, rows;

   AST_LIST_LOCK(&psql_tables);
   AST_LIST_TRAVERSE(&psql_tables, table, list) {
      if (!strcasecmp(table->name, orig_tablename)) {
         ast_debug(1, "Found table in cache; now locking\n");
         ast_rwlock_rdlock(&table->lock);
         ast_debug(1, "Lock cached table; now returning\n");
         AST_LIST_UNLOCK(&psql_tables);
         return table;
      }
   }

   ast_debug(1, "Table '%s' not found in cache, querying now\n", orig_tablename);

   /* Not found, scan the table */
   if (has_schema_support) {
      char *schemaname, *tablename;
      if (strchr(orig_tablename, '.')) {
         schemaname = ast_strdupa(orig_tablename);
         tablename = strchr(schemaname, '.');
         *tablename++ = '\0';
      } else {
         schemaname = "";
         tablename = ast_strdupa(orig_tablename);
      }

      /* Escape special characters in schemaname */
      if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
         char *tmp = schemaname, *ptr;

         ptr = schemaname = alloca(strlen(tmp) * 2 + 1);
         for (; *tmp; tmp++) {
            if (strchr("\\'", *tmp)) {
               *ptr++ = *tmp;
            }
            *ptr++ = *tmp;
         }
         *ptr = '\0';
      }
      /* Escape special characters in tablename */
      if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
         char *tmp = tablename, *ptr;

         ptr = tablename = alloca(strlen(tmp) * 2 + 1);
         for (; *tmp; tmp++) {
            if (strchr("\\'", *tmp)) {
               *ptr++ = *tmp;
            }
            *ptr++ = *tmp;
         }
         *ptr = '\0';
      }

      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",
         tablename,
         ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'");
   } else {
      /* Escape special characters in tablename */
      if (strchr(orig_tablename, '\\') || strchr(orig_tablename, '\'')) {
         const char *tmp = orig_tablename;
         char *ptr;

         orig_tablename = ptr = alloca(strlen(tmp) * 2 + 1);
         for (; *tmp; tmp++) {
            if (strchr("\\'", *tmp)) {
               *ptr++ = *tmp;
            }
            *ptr++ = *tmp;
         }
         *ptr = '\0';
      }

      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);
   }

   result = PQexec(pgsqlConn, ast_str_buffer(sql));
   ast_debug(1, "Query of table structure complete.  Now retrieving results.\n");
   if (PQresultStatus(result) != PGRES_TUPLES_OK) {
      pgerror = PQresultErrorMessage(result);
      ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
      PQclear(result);
      AST_LIST_UNLOCK(&psql_tables);
      return NULL;
   }

   if (!(table = ast_calloc(1, sizeof(*table) + strlen(orig_tablename) + 1))) {
      ast_log(LOG_ERROR, "Unable to allocate memory for new table structure\n");
      AST_LIST_UNLOCK(&psql_tables);
      return NULL;
   }
   strcpy(table->name, orig_tablename); /* SAFE */
   ast_rwlock_init(&table->lock);
   AST_LIST_HEAD_INIT_NOLOCK(&table->columns);

   rows = PQntuples(result);
   for (i = 0; i < rows; i++) {
      fname = PQgetvalue(result, i, 0);
      ftype = PQgetvalue(result, i, 1);
      flen = PQgetvalue(result, i, 2);
      fnotnull = PQgetvalue(result, i, 3);
      fdef = PQgetvalue(result, i, 4);
      ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);

      if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + 2))) {
         ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", orig_tablename, fname);
         destroy_table(table);
         AST_LIST_UNLOCK(&psql_tables);
         return NULL;
      }

      if (strcmp(flen, "-1") == 0) {
         /* Some types, like chars, have the length stored in a different field */
         flen = PQgetvalue(result, i, 5);
         sscanf(flen, "%30d", &column->len);
         column->len -= 4;
      } else {
         sscanf(flen, "%30d", &column->len);
      }
      column->name = (char *)column + sizeof(*column);
      column->type = (char *)column + sizeof(*column) + strlen(fname) + 1;
      strcpy(column->name, fname);
      strcpy(column->type, ftype);
      if (*fnotnull == 't') {
         column->notnull = 1;
      } else {
         column->notnull = 0;
      }
      if (!ast_strlen_zero(fdef)) {
         column->hasdefault = 1;
      } else {
         column->hasdefault = 0;
      }
      AST_LIST_INSERT_TAIL(&table->columns, column, list);
   }
   PQclear(result);

   AST_LIST_INSERT_TAIL(&psql_tables, table, list);
   ast_rwlock_rdlock(&table->lock);
   AST_LIST_UNLOCK(&psql_tables);
   return table;
}
static char * handle_cli_realtime_pgsql_cache ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1513 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.

{
   struct tables *cur;
   int l, which;
   char *ret = NULL;

   switch (cmd) {
   case CLI_INIT:
      e->command = "realtime show pgsql cache";
      e->usage =
         "Usage: realtime show pgsql cache [<table>]\n"
         "       Shows table cache for the PostgreSQL RealTime driver\n";
      return NULL;
   case CLI_GENERATE:
      if (a->argc != 4) {
         return NULL;
      }
      l = strlen(a->word);
      which = 0;
      AST_LIST_LOCK(&psql_tables);
      AST_LIST_TRAVERSE(&psql_tables, cur, list) {
         if (!strncasecmp(a->word, cur->name, l) && ++which > a->n) {
            ret = ast_strdup(cur->name);
            break;
         }
      }
      AST_LIST_UNLOCK(&psql_tables);
      return ret;
   }

   if (a->argc == 4) {
      /* List of tables */
      AST_LIST_LOCK(&psql_tables);
      AST_LIST_TRAVERSE(&psql_tables, cur, list) {
         ast_cli(a->fd, "%s\n", cur->name);
      }
      AST_LIST_UNLOCK(&psql_tables);
   } else if (a->argc == 5) {
      /* List of columns */
      if ((cur = find_table(a->argv[4]))) {
         struct columns *col;
         ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[4]);
         ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable");
         AST_LIST_TRAVERSE(&cur->columns, col, list) {
            ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : "");
         }
         release_table(cur);
      } else {
         ast_cli(a->fd, "No such table '%s'\n", a->argv[4]);
      }
   }
   return 0;
}
static char * handle_cli_realtime_pgsql_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1567 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.

{
   char status[256], credentials[100] = "";
   int ctimesec = time(NULL) - connect_time;

   switch (cmd) {
   case CLI_INIT:
      e->command = "realtime show pgsql status";
      e->usage =
         "Usage: realtime show pgsql status\n"
         "       Shows connection information for the PostgreSQL RealTime driver\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4)
      return CLI_SHOWUSAGE;

   if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
      if (!ast_strlen_zero(dbhost))
         snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport);
      else if (!ast_strlen_zero(dbsock))
         snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock);
      else
         snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost);

      if (!ast_strlen_zero(dbuser))
         snprintf(credentials, sizeof(credentials), " with username %s", dbuser);

      if (ctimesec > 31536000)
         ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
               status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400,
               (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
      else if (ctimesec > 86400)
         ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
               credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60,
               ctimesec % 60);
      else if (ctimesec > 3600)
         ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials,
               ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
      else if (ctimesec > 60)
         ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60,
               ctimesec % 60);
      else
         ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);

      return CLI_SUCCESS;
   } else {
      return CLI_FAILURE;
   }
}
static int parse_config ( int  reload) [static]

Definition at line 1356 of file res_config_pgsql.c.

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

Referenced by load_module(), and reload().

{
   struct ast_config *config;
   const char *s;
   struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

   config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags);
   if (config == CONFIG_STATUS_FILEUNCHANGED) {
      return 0;
   }

   if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF);
      return 0;
   }

   ast_mutex_lock(&pgsql_lock);

   if (pgsqlConn) {
      PQfinish(pgsqlConn);
      pgsqlConn = NULL;
   }

   if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n");
      strcpy(dbuser, "asterisk");
   } else {
      ast_copy_string(dbuser, s, sizeof(dbuser));
   }

   if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n");
      strcpy(dbpass, "asterisk");
   } else {
      ast_copy_string(dbpass, s, sizeof(dbpass));
   }

   if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: No database host found, using localhost via socket.\n");
      dbhost[0] = '\0';
   } else {
      ast_copy_string(dbhost, s, sizeof(dbhost));
   }

   if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n");
      strcpy(dbname, "asterisk");
   } else {
      ast_copy_string(dbname, s, sizeof(dbname));
   }

   if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: No database port found, using 5432 as default.\n");
      dbport = 5432;
   } else {
      dbport = atoi(s);
   }

   if (!ast_strlen_zero(dbhost)) {
      /* No socket needed */
   } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: No database socket found, using '/tmp/.s.PGSQL.%d' as default.\n", dbport);
      strcpy(dbsock, "/tmp");
   } else {
      ast_copy_string(dbsock, s, sizeof(dbsock));
   }

   if (!(s = ast_variable_retrieve(config, "general", "requirements"))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: no requirements setting found, using 'warn' as default.\n");
      requirements = RQ_WARN;
   } else if (!strcasecmp(s, "createclose")) {
      requirements = RQ_CREATECLOSE;
   } else if (!strcasecmp(s, "createchar")) {
      requirements = RQ_CREATECHAR;
   }

   ast_config_destroy(config);

   if (option_debug) {
      if (!ast_strlen_zero(dbhost)) {
         ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost);
         ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport);
      } else {
         ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock);
      }
      ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser);
      ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass);
      ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname);
   }

   if (!pgsql_reconnect(NULL)) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Couldn't establish connection. Check debug.\n");
      ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn));
   }

   ast_verb(2, "PostgreSQL RealTime reloaded.\n");

   /* Done reloading. Release lock so others can now use driver. */
   ast_mutex_unlock(&pgsql_lock);

   return 1;
}
static int pgsql_reconnect ( const char *  database) [static]

Definition at line 1467 of file res_config_pgsql.c.

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

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

{
   char my_database[50];

   ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));

   /* mutex lock should have been locked before calling this function. */

   if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
      PQfinish(pgsqlConn);
      pgsqlConn = NULL;
   }

   /* DB password can legitimately be 0-length */
   if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) {
      struct ast_str *connInfo = ast_str_create(32);

      ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s",
         S_OR(dbhost, dbsock), dbport, my_database, dbuser);
      if (!ast_strlen_zero(dbpass))
         ast_str_append(&connInfo, 0, " password=%s", dbpass);

      ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
      pgsqlConn = PQconnectdb(ast_str_buffer(connInfo));
      ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
      ast_free(connInfo);
      connInfo = NULL;

      ast_debug(1, "pgsqlConn=%p\n", pgsqlConn);
      if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
         ast_debug(1, "PostgreSQL RealTime: Successfully connected to database.\n");
         connect_time = time(NULL);
         version = PQserverVersion(pgsqlConn);
         return 1;
      } else {
         ast_log(LOG_ERROR,
               "PostgreSQL RealTime: Failed to connect database %s on %s: %s\n",
               dbname, dbhost, PQresultErrorMessage(NULL));
         return 0;
      }
   } else {
      ast_debug(1, "PostgreSQL RealTime: One or more of the parameters in the config does not pass our validity checks.\n");
      return 1;
   }
}
static struct ast_config* realtime_multi_pgsql ( const char *  database,
const char *  table,
va_list  ap 
) [static, read]

Definition at line 441 of file res_config_pgsql.c.

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

{
   PGresult *result = NULL;
   int num_rows = 0, pgresult;
   struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
   struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
   const char *initfield = NULL;
   char *stringp;
   char *chunk;
   char *op;
   const char *newparam, *newval;
   struct ast_variable *var = NULL;
   struct ast_config *cfg = NULL;
   struct ast_category *cat = NULL;

   if (!table) {
      ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
      return NULL;
   }

   if (!(cfg = ast_config_new()))
      return NULL;

   /* Get the first parameter and first value in our list of passed paramater/value pairs */
   newparam = va_arg(ap, const char *);
   newval = va_arg(ap, const char *);
   if (!newparam || !newval) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
      if (pgsqlConn) {
         PQfinish(pgsqlConn);
         pgsqlConn = NULL;
      }
      return NULL;
   }

   initfield = ast_strdupa(newparam);
   if ((op = strchr(initfield, ' '))) {
      *op = '\0';
   }

   /* Create the first part of the query using the first parameter/value pairs we just extracted
      If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */

   if (!strchr(newparam, ' '))
      op = " =";
   else
      op = "";

   ESCAPE_STRING(escapebuf, newval);
   if (pgresult) {
      ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
      va_end(ap);
      return NULL;
   }

   ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
      if (!strchr(newparam, ' '))
         op = " =";
      else
         op = "";

      ESCAPE_STRING(escapebuf, newval);
      if (pgresult) {
         ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
         va_end(ap);
         return NULL;
      }

      ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
   }

   if (initfield) {
      ast_str_append(&sql, 0, " ORDER BY %s", initfield);
   }

   va_end(ap);

   /* We now have our complete statement; Lets connect to the server and execute it. */
   ast_mutex_lock(&pgsql_lock);
   if (!pgsql_reconnect(database)) {
      ast_mutex_unlock(&pgsql_lock);
      return NULL;
   }

   if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
      ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
      ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
      ast_mutex_unlock(&pgsql_lock);
      return NULL;
   } else {
      ExecStatusType result_status = PQresultStatus(result);
      if (result_status != PGRES_COMMAND_OK
         && result_status != PGRES_TUPLES_OK
         && result_status != PGRES_NONFATAL_ERROR) {
         ast_log(LOG_WARNING,
               "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
         ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
         ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
                  PQresultErrorMessage(result), PQresStatus(result_status));
         ast_mutex_unlock(&pgsql_lock);
         return NULL;
      }
   }

   ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));

   if ((num_rows = PQntuples(result)) > 0) {
      int numFields = PQnfields(result);
      int i = 0;
      int rowIndex = 0;
      char **fieldnames = NULL;

      ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);

      if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
         ast_mutex_unlock(&pgsql_lock);
         PQclear(result);
         return NULL;
      }
      for (i = 0; i < numFields; i++)
         fieldnames[i] = PQfname(result, i);

      for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
         var = NULL;
         if (!(cat = ast_category_new("","",99999)))
            continue;
         for (i = 0; i < numFields; i++) {
            stringp = PQgetvalue(result, rowIndex, i);
            while (stringp) {
               chunk = strsep(&stringp, ";");
               if (chunk && !ast_strlen_zero(decode_chunk(ast_strip(chunk)))) {
                  if (initfield && !strcmp(initfield, fieldnames[i])) {
                     ast_category_rename(cat, chunk);
                  }
                  var = ast_variable_new(fieldnames[i], chunk, "");
                  ast_variable_append(cat, var);
               }
            }
         }
         ast_category_append(cfg, cat);
      }
      ast_free(fieldnames);
   } else {
      ast_debug(1, "PostgreSQL RealTime: Could not find any rows in table %s.\n", table);
   }

   ast_mutex_unlock(&pgsql_lock);
   PQclear(result);

   return cfg;
}
static struct ast_variable* realtime_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
) [static, read]

Definition at line 306 of file res_config_pgsql.c.

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

{
   PGresult *result = NULL;
   int num_rows = 0, pgresult;
   struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
   struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
   char *stringp;
   char *chunk;
   char *op;
   const char *newparam, *newval;
   struct ast_variable *var = NULL, *prev = NULL;

   if (!tablename) {
      ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
      return NULL;
   }

   /* Get the first parameter and first value in our list of passed paramater/value pairs */
   newparam = va_arg(ap, const char *);
   newval = va_arg(ap, const char *);
   if (!newparam || !newval) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
      if (pgsqlConn) {
         PQfinish(pgsqlConn);
         pgsqlConn = NULL;
      }
      return NULL;
   }

   /* Create the first part of the query using the first parameter/value pairs we just extracted
      If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
   op = strchr(newparam, ' ') ? "" : " =";

   ESCAPE_STRING(escapebuf, newval);
   if (pgresult) {
      ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
      va_end(ap);
      return NULL;
   }

   ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
      if (!strchr(newparam, ' '))
         op = " =";
      else
         op = "";

      ESCAPE_STRING(escapebuf, newval);
      if (pgresult) {
         ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
         va_end(ap);
         return NULL;
      }

      ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
   }
   va_end(ap);

   /* We now have our complete statement; Lets connect to the server and execute it. */
   ast_mutex_lock(&pgsql_lock);
   if (!pgsql_reconnect(database)) {
      ast_mutex_unlock(&pgsql_lock);
      return NULL;
   }

   if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
      ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
      ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
      ast_mutex_unlock(&pgsql_lock);
      return NULL;
   } else {
      ExecStatusType result_status = PQresultStatus(result);
      if (result_status != PGRES_COMMAND_OK
         && result_status != PGRES_TUPLES_OK
         && result_status != PGRES_NONFATAL_ERROR) {
         ast_log(LOG_WARNING,
               "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
         ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
         ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
                  PQresultErrorMessage(result), PQresStatus(result_status));
         ast_mutex_unlock(&pgsql_lock);
         return NULL;
      }
   }

   ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));

   if ((num_rows = PQntuples(result)) > 0) {
      int i = 0;
      int rowIndex = 0;
      int numFields = PQnfields(result);
      char **fieldnames = NULL;

      ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);

      if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
         ast_mutex_unlock(&pgsql_lock);
         PQclear(result);
         return NULL;
      }
      for (i = 0; i < numFields; i++)
         fieldnames[i] = PQfname(result, i);
      for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
         for (i = 0; i < numFields; i++) {
            stringp = PQgetvalue(result, rowIndex, i);
            while (stringp) {
               chunk = strsep(&stringp, ";");
               if (chunk && !ast_strlen_zero(decode_chunk(ast_strip(chunk)))) {
                  if (prev) {
                     prev->next = ast_variable_new(fieldnames[i], chunk, "");
                     if (prev->next) {
                        prev = prev->next;
                     }
                  } else {
                     prev = var = ast_variable_new(fieldnames[i], chunk, "");
                  }
               }
            }
         }
      }
      ast_free(fieldnames);
   } else {
      ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s@%s.\n", tablename, database);
   }

   ast_mutex_unlock(&pgsql_lock);
   PQclear(result);

   return var;
}
static int reload ( void  ) [static]

Definition at line 1349 of file res_config_pgsql.c.

References parse_config().

{
   parse_config(1);

   return 0;
}
static int require_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
) [static]

Definition at line 1147 of file res_config_pgsql.c.

References ast_debug, ast_free, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rq_is_int(), ast_str_buffer(), ast_str_create(), ast_str_set(), tables::columns, find_table(), columns::len, tables::list, LOG_ERROR, LOG_WARNING, columns::name, pgsql_lock, pgsql_reconnect(), release_table, requirements, RQ_CHAR, RQ_CREATECHAR, RQ_DATE, RQ_DATETIME, RQ_FLOAT, RQ_INTEGER1, RQ_INTEGER2, RQ_INTEGER3, RQ_INTEGER4, RQ_INTEGER8, RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, RQ_UINTEGER8, RQ_WARN, tables::table, columns::type, and type.

{
   struct columns *column;
   struct tables *table = find_table(tablename);
   char *elm;
   int type, size, res = 0;

   if (!table) {
      ast_log(LOG_WARNING, "Table %s not found in database.  This table should exist if you're using realtime.\n", tablename);
      return -1;
   }

   while ((elm = va_arg(ap, char *))) {
      type = va_arg(ap, require_type);
      size = va_arg(ap, int);
      AST_LIST_TRAVERSE(&table->columns, column, list) {
         if (strcmp(column->name, elm) == 0) {
            /* Char can hold anything, as long as it is large enough */
            if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0 || strcmp(column->type, "bpchar") == 0)) {
               if ((size > column->len) && column->len != -1) {
                  ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len);
                  res = -1;
               }
            } else if (strncmp(column->type, "int", 3) == 0) {
               int typesize = atoi(column->type + 3);
               /* Integers can hold only other integers */
               if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
                  type == RQ_INTEGER4 || type == RQ_UINTEGER4 ||
                  type == RQ_INTEGER3 || type == RQ_UINTEGER3 ||
                  type == RQ_UINTEGER2) && typesize == 2) {
                  ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
                  res = -1;
               } else if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
                  type == RQ_UINTEGER4) && typesize == 4) {
                  ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
                  res = -1;
               } else if (type == RQ_CHAR || type == RQ_DATETIME || type == RQ_FLOAT || type == RQ_DATE) {
                  ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n",
                     column->name,
                        type == RQ_CHAR ? "char" :
                        type == RQ_DATETIME ? "datetime" :
                        type == RQ_DATE ? "date" :
                        type == RQ_FLOAT ? "float" :
                        "a rather stiff drink ",
                     size, column->type);
                  res = -1;
               }
            } else if (strncmp(column->type, "float", 5) == 0) {
               if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
                  ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
                  res = -1;
               }
            } else if (strncmp(column->type, "timestamp", 9) == 0) {
               if (type != RQ_DATETIME && type != RQ_DATE) {
                  ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
                  res = -1;
               }
            } else { /* There are other types that no module implements yet */
               ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
               res = -1;
            }
            break;
         }
      }

      if (!column) {
         if (requirements == RQ_WARN) {
            ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size);
         } else {
            struct ast_str *sql = ast_str_create(100);
            char fieldtype[15];
            PGresult *result;

            if (requirements == RQ_CREATECHAR || type == RQ_CHAR) {
               /* Size is minimum length; make it at least 50% greater,
                * just to be sure, because PostgreSQL doesn't support
                * resizing columns. */
               snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)",
                  size < 15 ? size * 2 :
                  (size * 3 / 2 > 255) ? 255 : size * 3 / 2);
            } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) {
               snprintf(fieldtype, sizeof(fieldtype), "INT2");
            } else if (type == RQ_UINTEGER2 || type == RQ_INTEGER3 || type == RQ_UINTEGER3 || type == RQ_INTEGER4) {
               snprintf(fieldtype, sizeof(fieldtype), "INT4");
            } else if (type == RQ_UINTEGER4 || type == RQ_INTEGER8) {
               snprintf(fieldtype, sizeof(fieldtype), "INT8");
            } else if (type == RQ_UINTEGER8) {
               /* No such type on PostgreSQL */
               snprintf(fieldtype, sizeof(fieldtype), "CHAR(20)");
            } else if (type == RQ_FLOAT) {
               snprintf(fieldtype, sizeof(fieldtype), "FLOAT8");
            } else if (type == RQ_DATE) {
               snprintf(fieldtype, sizeof(fieldtype), "DATE");
            } else if (type == RQ_DATETIME) {
               snprintf(fieldtype, sizeof(fieldtype), "TIMESTAMP");
            } else {
               ast_log(LOG_ERROR, "Unrecognized request type %d\n", type);
               ast_free(sql);
               continue;
            }
            ast_str_set(&sql, 0, "ALTER TABLE %s ADD COLUMN %s %s", tablename, elm, fieldtype);
            ast_debug(1, "About to lock pgsql_lock (running alter on table '%s' to add column '%s')\n", tablename, elm);

            ast_mutex_lock(&pgsql_lock);
            if (!pgsql_reconnect(database)) {
               ast_mutex_unlock(&pgsql_lock);
               ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
               ast_free(sql);
               continue;
            }

            ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm);
            result = PQexec(pgsqlConn, ast_str_buffer(sql));
            ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename);
            if (PQresultStatus(result) != PGRES_COMMAND_OK) {
               ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
            }
            PQclear(result);
            ast_mutex_unlock(&pgsql_lock);

            ast_free(sql);
         }
      }
   }
   release_table(table);
   return res;
}
static int store_pgsql ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Definition at line 868 of file res_config_pgsql.c.

References ast_debug, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), buf, ESCAPE_STRING, LOG_WARNING, pgsql_lock, and pgsql_reconnect().

{
   PGresult *result = NULL;
   Oid insertid;
   struct ast_str *buf = ast_str_thread_get(&escapebuf_buf, 256);
   struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256);
   struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256);
   int pgresult;
   const char *newparam, *newval;

   if (!table) {
      ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
      return -1;
   }

   /* Get the first parameter and first value in our list of passed paramater/value pairs */
   newparam = va_arg(ap, const char *);
   newval = va_arg(ap, const char *);
   if (!newparam || !newval) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
      if (pgsqlConn) {
         PQfinish(pgsqlConn);
         pgsqlConn = NULL;
      }
      return -1;
   }

   /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
   ast_mutex_lock(&pgsql_lock);
   if (!pgsql_reconnect(database)) {
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   }

   /* Create the first part of the query using the first parameter/value pairs we just extracted
      If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
   ESCAPE_STRING(buf, newparam);
   ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
   ESCAPE_STRING(buf, newval);
   ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
      ESCAPE_STRING(buf, newparam);
      ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
      ESCAPE_STRING(buf, newval);
      ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
   }
   va_end(ap);
   ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));

   ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1));

   if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql1)))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
      ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
      ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   } else {
      ExecStatusType result_status = PQresultStatus(result);
      if (result_status != PGRES_COMMAND_OK
         && result_status != PGRES_TUPLES_OK
         && result_status != PGRES_NONFATAL_ERROR) {
         ast_log(LOG_WARNING,
               "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
         ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
         ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
                  PQresultErrorMessage(result), PQresStatus(result_status));
         ast_mutex_unlock(&pgsql_lock);
         return -1;
      }
   }

   insertid = PQoidValue(result);
   ast_mutex_unlock(&pgsql_lock);

   ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid);

   /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
    * An integer greater than zero indicates the number of rows affected
    * Zero indicates that no records were updated
    * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
    */

   if (insertid >= 0)
      return (int) insertid;

   return -1;
}
static int unload_module ( void  ) [static]

Definition at line 1322 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.

{
   struct tables *table;
   /* Acquire control before doing anything to the module itself. */
   ast_mutex_lock(&pgsql_lock);

   if (pgsqlConn) {
      PQfinish(pgsqlConn);
      pgsqlConn = NULL;
   }
   ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
   ast_config_engine_deregister(&pgsql_engine);
   ast_verb(1, "PostgreSQL RealTime unloaded.\n");

   /* Destroy cached table info */
   AST_LIST_LOCK(&psql_tables);
   while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) {
      destroy_table(table);
   }
   AST_LIST_UNLOCK(&psql_tables);

   /* Unlock so something else can destroy the lock. */
   ast_mutex_unlock(&pgsql_lock);

   return 0;
}
static int unload_pgsql ( const char *  database,
const char *  tablename 
) [static]

Definition at line 1275 of file res_config_pgsql.c.

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

{
   struct tables *cur;
   ast_debug(2, "About to lock table cache list\n");
   AST_LIST_LOCK(&psql_tables);
   ast_debug(2, "About to traverse table cache list\n");
   AST_LIST_TRAVERSE_SAFE_BEGIN(&psql_tables, cur, list) {
      if (strcmp(cur->name, tablename) == 0) {
         ast_debug(2, "About to remove matching cache entry\n");
         AST_LIST_REMOVE_CURRENT(list);
         ast_debug(2, "About to destroy matching cache entry\n");
         destroy_table(cur);
         ast_debug(1, "Cache entry '%s@%s' destroyed\n", tablename, database);
         break;
      }
   }
   AST_LIST_TRAVERSE_SAFE_END
   AST_LIST_UNLOCK(&psql_tables);
   ast_debug(2, "About to return\n");
   return cur ? 0 : -1;
}
static int update2_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
) [static]

Definition at line 736 of file res_config_pgsql.c.

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

{
   PGresult *result = NULL;
   int numrows = 0, pgresult, first = 1;
   struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16);
   const char *newparam, *newval;
   struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
   struct ast_str *where = ast_str_thread_get(&where_buf, 100);
   struct tables *table;

   if (!tablename) {
      ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
      return -1;
   }

   if (!escapebuf || !sql || !where) {
      /* Memory error, already handled */
      return -1;
   }

   if (!(table = find_table(tablename))) {
      ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
      return -1;
   }

   ast_str_set(&sql, 0, "UPDATE %s SET ", tablename);
   ast_str_set(&where, 0, "WHERE");

   while ((newparam = va_arg(ap, const char *))) {
      if (!find_column(table, newparam)) {
         ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database);
         release_table(table);
         return -1;
      }

      newval = va_arg(ap, const char *);
      ESCAPE_STRING(escapebuf, newval);
      if (pgresult) {
         ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
         release_table(table);
         ast_free(sql);
         return -1;
      }
      ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
      first = 0;
   }

   if (first) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on.\n");
      if (pgsqlConn) {
         PQfinish(pgsqlConn);
         pgsqlConn = NULL;
      }
      release_table(table);
      return -1;
   }

   /* Now retrieve the columns to update */
   first = 1;
   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);

      /* If the column is not within the table, then skip it */
      if (!find_column(table, newparam)) {
         ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database);
         continue;
      }

      ESCAPE_STRING(escapebuf, newval);
      if (pgresult) {
         ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
         release_table(table);
         ast_free(sql);
         return -1;
      }

      ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
   }
   release_table(table);

   ast_str_append(&sql, 0, " %s", ast_str_buffer(where));

   ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));

   /* We now have our complete statement; connect to the server and execute it. */
   ast_mutex_lock(&pgsql_lock);
   if (!pgsql_reconnect(database)) {
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   }

   if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
      ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
      ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   } else {
      ExecStatusType result_status = PQresultStatus(result);
      if (result_status != PGRES_COMMAND_OK
         && result_status != PGRES_TUPLES_OK
         && result_status != PGRES_NONFATAL_ERROR) {
         ast_log(LOG_WARNING,
               "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
         ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
         ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
                  PQresultErrorMessage(result), PQresStatus(result_status));
         ast_mutex_unlock(&pgsql_lock);
         return -1;
      }
   }

   numrows = atoi(PQcmdTuples(result));
   ast_mutex_unlock(&pgsql_lock);

   ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);

   /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
    * An integer greater than zero indicates the number of rows affected
    * Zero indicates that no records were updated
    * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
    */

   if (numrows >= 0) {
      return (int) numrows;
   }

   return -1;
}
static int update_pgsql ( const char *  database,
const char *  tablename,
const char *  keyfield,
const char *  lookup,
va_list  ap 
) [static]

Definition at line 598 of file res_config_pgsql.c.

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

{
   PGresult *result = NULL;
   int numrows = 0, pgresult;
   const char *newparam, *newval;
   struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
   struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
   struct tables *table;
   struct columns *column = NULL;

   if (!tablename) {
      ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
      return -1;
   }

   if (!(table = find_table(tablename))) {
      ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
      return -1;
   }

   /* Get the first parameter and first value in our list of passed paramater/value pairs */
   newparam = va_arg(ap, const char *);
   newval = va_arg(ap, const char *);
   if (!newparam || !newval) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
      if (pgsqlConn) {
         PQfinish(pgsqlConn);
         pgsqlConn = NULL;
      }
      release_table(table);
      return -1;
   }

   /* Check that the column exists in the table */
   AST_LIST_TRAVERSE(&table->columns, column, list) {
      if (strcmp(column->name, newparam) == 0) {
         break;
      }
   }

   if (!column) {
      ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
      release_table(table);
      return -1;
   }

   /* Create the first part of the query using the first parameter/value pairs we just extracted
      If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */

   ESCAPE_STRING(escapebuf, newval);
   if (pgresult) {
      ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
      va_end(ap);
      release_table(table);
      return -1;
   }
   ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));

   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);

      if (!find_column(table, newparam)) {
         ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
         continue;
      }

      ESCAPE_STRING(escapebuf, newval);
      if (pgresult) {
         ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
         va_end(ap);
         release_table(table);
         return -1;
      }

      ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
   }
   va_end(ap);
   release_table(table);

   ESCAPE_STRING(escapebuf, lookup);
   if (pgresult) {
      ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
      va_end(ap);
      return -1;
   }

   ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(escapebuf));

   ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));

   /* We now have our complete statement; Lets connect to the server and execute it. */
   ast_mutex_lock(&pgsql_lock);
   if (!pgsql_reconnect(database)) {
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   }

   if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
      ast_log(LOG_WARNING,
            "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
      ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
      ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
      ast_mutex_unlock(&pgsql_lock);
      return -1;
   } else {
      ExecStatusType result_status = PQresultStatus(result);
      if (result_status != PGRES_COMMAND_OK
         && result_status != PGRES_TUPLES_OK
         && result_status != PGRES_NONFATAL_ERROR) {
         ast_log(LOG_WARNING,
               "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
         ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
         ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
                  PQresultErrorMessage(result), PQresStatus(result_status));
         ast_mutex_unlock(&pgsql_lock);
         return -1;
      }
   }

   numrows = atoi(PQcmdTuples(result));
   ast_mutex_unlock(&pgsql_lock);

   ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);

   /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
    * An integer greater than zero indicates the number of rows affected
    * Zero indicates that no records were updated
    * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
    */

   if (numrows >= 0)
      return (int) numrows;

   return -1;
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "PostgreSQL RealTime Configuration Driver" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload } [static]

Definition at line 1625 of file res_config_pgsql.c.

Definition at line 1625 of file res_config_pgsql.c.

struct ast_cli_entry cli_realtime[] [static]
Initial value:
 {
   AST_CLI_DEFINE(handle_cli_realtime_pgsql_status, "Shows connection information for the PostgreSQL RealTime driver"),
   AST_CLI_DEFINE(handle_cli_realtime_pgsql_cache, "Shows cached tables within the PostgreSQL realtime driver"),
}

Definition at line 92 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

time_t connect_time = 0 [static]

Definition at line 83 of file res_config_pgsql.c.

Referenced by handle_cli_realtime_pgsql_status(), and pgsql_reconnect().

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

Definition at line 79 of file res_config_pgsql.c.

Referenced by parse_config(), and pgsql_reconnect().

int dbport = 5432 [static]
char dbsock[MAX_DB_OPTION_SIZE] = "" [static]
char dbuser[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 1297 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

PGconn* pgsqlConn = NULL

Definition at line 53 of file res_config_pgsql.c.

struct psql_tables psql_tables [static]
enum { ... } requirements

Referenced by parse_config(), and require_pgsql().

int version [static]

Definition at line 54 of file res_config_pgsql.c.