Fri Nov 12 12:07:58 2010

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

Defines

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

Enumerations

enum  { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR }

Functions

static void __init_escapebuf_buf (void)
static void __init_findtable_buf (void)
static void __init_sql_buf (void)
static void __init_where_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
static struct ast_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 *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_GLOBAL_SYMBOLS , .description = "PostgreSQL RealTime Configuration Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload }
static struct ast_module_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 = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
PGconn * pgsqlConn = NULL
enum { ... }  requirements
static struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }
static int version
static struct ast_threadstorage where_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_where_buf , .custom_init = NULL , }

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 54 of file res_config_pgsql.c.

Referenced by find_table().

#define MAX_DB_OPTION_SIZE   64

Definition at line 56 of file res_config_pgsql.c.

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

Definition at line 50 of file res_config_pgsql.c.

Referenced by config_pgsql(), and parse_config().


Enumeration Type Documentation

anonymous enum
Enumerator:
RQ_WARN 
RQ_CREATECLOSE 
RQ_CREATECHAR 

Definition at line 89 of file res_config_pgsql.c.


Function Documentation

static void __init_escapebuf_buf ( void   )  [static]

Definition at line 48 of file res_config_pgsql.c.

00054 : 0)

static void __init_findtable_buf ( void   )  [static]

Definition at line 46 of file res_config_pgsql.c.

00054 : 0)

static void __init_sql_buf ( void   )  [static]

Definition at line 45 of file res_config_pgsql.c.

00054 : 0)

static void __init_where_buf ( void   )  [static]

Definition at line 47 of file res_config_pgsql.c.

00054 : 0)

static void __reg_module ( void   )  [static]

Definition at line 1596 of file res_config_pgsql.c.

static void __unreg_module ( void   )  [static]

Definition at line 1596 of file res_config_pgsql.c.

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

Definition at line 1030 of file res_config_pgsql.c.

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

01033 {
01034    PGresult *result = NULL;
01035    long num_rows;
01036    struct ast_variable *new_v;
01037    struct ast_category *cur_cat = NULL;
01038    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
01039    char last[80] = "";
01040    int last_cat_metric = 0;
01041 
01042    last[0] = '\0';
01043 
01044    if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
01045       ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n");
01046       return NULL;
01047    }
01048 
01049    ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s "
01050          "WHERE filename='%s' and commented=0"
01051          "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file);
01052 
01053    ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql));
01054 
01055    /* We now have our complete statement; Lets connect to the server and execute it. */
01056    ast_mutex_lock(&pgsql_lock);
01057    if (!pgsql_reconnect(database)) {
01058       ast_mutex_unlock(&pgsql_lock);
01059       return NULL;
01060    }
01061 
01062    if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
01063       ast_log(LOG_WARNING,
01064             "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", table, database);
01065       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
01066       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
01067       ast_mutex_unlock(&pgsql_lock);
01068       return NULL;
01069    } else {
01070       ExecStatusType result_status = PQresultStatus(result);
01071       if (result_status != PGRES_COMMAND_OK
01072          && result_status != PGRES_TUPLES_OK
01073          && result_status != PGRES_NONFATAL_ERROR) {
01074          ast_log(LOG_WARNING,
01075                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
01076          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
01077          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
01078                   PQresultErrorMessage(result), PQresStatus(result_status));
01079          ast_mutex_unlock(&pgsql_lock);
01080          return NULL;
01081       }
01082    }
01083 
01084    if ((num_rows = PQntuples(result)) > 0) {
01085       int rowIndex = 0;
01086 
01087       ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows);
01088 
01089       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
01090          char *field_category = PQgetvalue(result, rowIndex, 0);
01091          char *field_var_name = PQgetvalue(result, rowIndex, 1);
01092          char *field_var_val = PQgetvalue(result, rowIndex, 2);
01093          char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
01094          if (!strcmp(field_var_name, "#include")) {
01095             if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) {
01096                PQclear(result);
01097                ast_mutex_unlock(&pgsql_lock);
01098                return NULL;
01099             }
01100             continue;
01101          }
01102 
01103          if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
01104             cur_cat = ast_category_new(field_category, "", 99999);
01105             if (!cur_cat)
01106                break;
01107             strcpy(last, field_category);
01108             last_cat_metric = atoi(field_cat_metric);
01109             ast_category_append(cfg, cur_cat);
01110          }
01111          new_v = ast_variable_new(field_var_name, field_var_val, "");
01112          ast_variable_append(cur_cat, new_v);
01113       }
01114    } else {
01115       ast_log(LOG_WARNING,
01116             "PostgreSQL RealTime: Could not find config '%s' in database.\n", file);
01117    }
01118 
01119    PQclear(result);
01120    ast_mutex_unlock(&pgsql_lock);
01121 
01122    return cfg;
01123 }

static int destroy_pgsql ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
va_list  ap 
) [static]

Definition at line 938 of file res_config_pgsql.c.

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

00939 {
00940    PGresult *result = NULL;
00941    int numrows = 0;
00942    int pgresult;
00943    struct ast_str *sql = ast_str_thread_get(&sql_buf, 256);
00944    struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60);
00945    const char *newparam, *newval;
00946 
00947    if (!table) {
00948       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00949       return -1;
00950    }
00951 
00952    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00953    /*newparam = va_arg(ap, const char *);
00954    newval = va_arg(ap, const char *);
00955    if (!newparam || !newval) {*/
00956    if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
00957       ast_log(LOG_WARNING,
00958             "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n");
00959       if (pgsqlConn) {
00960          PQfinish(pgsqlConn);
00961          pgsqlConn = NULL;
00962       };
00963       return -1;
00964    }
00965 
00966    /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
00967    ast_mutex_lock(&pgsql_lock);
00968    if (!pgsql_reconnect(database)) {
00969       ast_mutex_unlock(&pgsql_lock);
00970       return -1;
00971    }
00972 
00973 
00974    /* Create the first part of the query using the first parameter/value pairs we just extracted
00975       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00976 
00977    ESCAPE_STRING(buf1, keyfield);
00978    ESCAPE_STRING(buf2, lookup);
00979    ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
00980    while ((newparam = va_arg(ap, const char *))) {
00981       newval = va_arg(ap, const char *);
00982       ESCAPE_STRING(buf1, newparam);
00983       ESCAPE_STRING(buf2, newval);
00984       ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
00985    }
00986    va_end(ap);
00987 
00988    ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
00989 
00990    if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
00991       ast_log(LOG_WARNING,
00992             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00993       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00994       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00995       ast_mutex_unlock(&pgsql_lock);
00996       return -1;
00997    } else {
00998       ExecStatusType result_status = PQresultStatus(result);
00999       if (result_status != PGRES_COMMAND_OK
01000          && result_status != PGRES_TUPLES_OK
01001          && result_status != PGRES_NONFATAL_ERROR) {
01002          ast_log(LOG_WARNING,
01003                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
01004          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
01005          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
01006                   PQresultErrorMessage(result), PQresStatus(result_status));
01007          ast_mutex_unlock(&pgsql_lock);
01008          return -1;
01009       }
01010    }
01011 
01012    numrows = atoi(PQcmdTuples(result));
01013    ast_mutex_unlock(&pgsql_lock);
01014 
01015    ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table);
01016 
01017    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
01018     * An integer greater than zero indicates the number of rows affected
01019     * Zero indicates that no records were updated
01020     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
01021     */
01022 
01023    if (numrows >= 0)
01024       return (int) numrows;
01025 
01026    return -1;
01027 }

static void destroy_table ( struct tables table  )  [static]

Definition at line 105 of file res_config_pgsql.c.

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

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

00106 {
00107    struct columns *column;
00108    ast_rwlock_wrlock(&table->lock);
00109    while ((column = AST_LIST_REMOVE_HEAD(&table->columns, list))) {
00110       ast_free(column);
00111    }
00112    ast_rwlock_unlock(&table->lock);
00113    ast_rwlock_destroy(&table->lock);
00114    ast_free(table);
00115 }

static struct columns* find_column ( struct tables t,
const char *  colname 
) [static, read]

Definition at line 270 of file res_config_pgsql.c.

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

Referenced by update2_pgsql(), and update_pgsql().

00271 {
00272    struct columns *column;
00273 
00274    /* Check that the column exists in the table */
00275    AST_LIST_TRAVERSE(&t->columns, column, list) {
00276       if (strcmp(column->name, colname) == 0) {
00277          return column;
00278       }
00279    }
00280    return NULL;
00281 }

static struct tables* find_table ( const char *  orig_tablename  )  [static, read]

Definition at line 117 of file res_config_pgsql.c.

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

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

00118 {
00119    struct columns *column;
00120    struct tables *table;
00121    struct ast_str *sql = ast_str_thread_get(&findtable_buf, 330);
00122    char *pgerror;
00123    PGresult *result;
00124    char *fname, *ftype, *flen, *fnotnull, *fdef;
00125    int i, rows;
00126 
00127    AST_LIST_LOCK(&psql_tables);
00128    AST_LIST_TRAVERSE(&psql_tables, table, list) {
00129       if (!strcasecmp(table->name, orig_tablename)) {
00130          ast_debug(1, "Found table in cache; now locking\n");
00131          ast_rwlock_rdlock(&table->lock);
00132          ast_debug(1, "Lock cached table; now returning\n");
00133          AST_LIST_UNLOCK(&psql_tables);
00134          return table;
00135       }
00136    }
00137 
00138    ast_debug(1, "Table '%s' not found in cache, querying now\n", orig_tablename);
00139 
00140    /* Not found, scan the table */
00141    if (has_schema_support) {
00142       char *schemaname, *tablename;
00143       if (strchr(orig_tablename, '.')) {
00144          schemaname = ast_strdupa(orig_tablename);
00145          tablename = strchr(schemaname, '.');
00146          *tablename++ = '\0';
00147       } else {
00148          schemaname = "";
00149          tablename = ast_strdupa(orig_tablename);
00150       }
00151 
00152       /* Escape special characters in schemaname */
00153       if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
00154          char *tmp = schemaname, *ptr;
00155 
00156          ptr = schemaname = alloca(strlen(tmp) * 2 + 1);
00157          for (; *tmp; tmp++) {
00158             if (strchr("\\'", *tmp)) {
00159                *ptr++ = *tmp;
00160             }
00161             *ptr++ = *tmp;
00162          }
00163          *ptr = '\0';
00164       }
00165       /* Escape special characters in tablename */
00166       if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
00167          char *tmp = tablename, *ptr;
00168 
00169          ptr = tablename = alloca(strlen(tmp) * 2 + 1);
00170          for (; *tmp; tmp++) {
00171             if (strchr("\\'", *tmp)) {
00172                *ptr++ = *tmp;
00173             }
00174             *ptr++ = *tmp;
00175          }
00176          *ptr = '\0';
00177       }
00178 
00179       ast_str_set(&sql, 0, "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM (((pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND c.relname = '%s' AND n.nspname = %s%s%s) INNER JOIN pg_catalog.pg_attribute a ON (NOT a.attisdropped) AND a.attnum > 0 AND a.attrelid = c.oid) INNER JOIN pg_catalog.pg_type t ON t.oid = a.atttypid) LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum ORDER BY n.nspname, c.relname, attnum",
00180          tablename,
00181          ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'");
00182    } else {
00183       /* Escape special characters in tablename */
00184       if (strchr(orig_tablename, '\\') || strchr(orig_tablename, '\'')) {
00185          const char *tmp = orig_tablename;
00186          char *ptr;
00187 
00188          orig_tablename = ptr = alloca(strlen(tmp) * 2 + 1);
00189          for (; *tmp; tmp++) {
00190             if (strchr("\\'", *tmp)) {
00191                *ptr++ = *tmp;
00192             }
00193             *ptr++ = *tmp;
00194          }
00195          *ptr = '\0';
00196       }
00197 
00198       ast_str_set(&sql, 0, "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM pg_class c, pg_type t, pg_attribute a LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum WHERE c.oid = a.attrelid AND a.atttypid = t.oid AND (a.attnum > 0) AND c.relname = '%s' ORDER BY c.relname, attnum", orig_tablename);
00199    }
00200 
00201    result = PQexec(pgsqlConn, ast_str_buffer(sql));
00202    ast_debug(1, "Query of table structure complete.  Now retrieving results.\n");
00203    if (PQresultStatus(result) != PGRES_TUPLES_OK) {
00204       pgerror = PQresultErrorMessage(result);
00205       ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
00206       PQclear(result);
00207       AST_LIST_UNLOCK(&psql_tables);
00208       return NULL;
00209    }
00210 
00211    if (!(table = ast_calloc(1, sizeof(*table) + strlen(orig_tablename) + 1))) {
00212       ast_log(LOG_ERROR, "Unable to allocate memory for new table structure\n");
00213       AST_LIST_UNLOCK(&psql_tables);
00214       return NULL;
00215    }
00216    strcpy(table->name, orig_tablename); /* SAFE */
00217    ast_rwlock_init(&table->lock);
00218    AST_LIST_HEAD_INIT_NOLOCK(&table->columns);
00219 
00220    rows = PQntuples(result);
00221    for (i = 0; i < rows; i++) {
00222       fname = PQgetvalue(result, i, 0);
00223       ftype = PQgetvalue(result, i, 1);
00224       flen = PQgetvalue(result, i, 2);
00225       fnotnull = PQgetvalue(result, i, 3);
00226       fdef = PQgetvalue(result, i, 4);
00227       ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
00228 
00229       if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + 2))) {
00230          ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", orig_tablename, fname);
00231          destroy_table(table);
00232          AST_LIST_UNLOCK(&psql_tables);
00233          return NULL;
00234       }
00235 
00236       if (strcmp(flen, "-1") == 0) {
00237          /* Some types, like chars, have the length stored in a different field */
00238          flen = PQgetvalue(result, i, 5);
00239          sscanf(flen, "%30d", &column->len);
00240          column->len -= 4;
00241       } else {
00242          sscanf(flen, "%30d", &column->len);
00243       }
00244       column->name = (char *)column + sizeof(*column);
00245       column->type = (char *)column + sizeof(*column) + strlen(fname) + 1;
00246       strcpy(column->name, fname);
00247       strcpy(column->type, ftype);
00248       if (*fnotnull == 't') {
00249          column->notnull = 1;
00250       } else {
00251          column->notnull = 0;
00252       }
00253       if (!ast_strlen_zero(fdef)) {
00254          column->hasdefault = 1;
00255       } else {
00256          column->hasdefault = 0;
00257       }
00258       AST_LIST_INSERT_TAIL(&table->columns, column, list);
00259    }
00260    PQclear(result);
00261 
00262    AST_LIST_INSERT_TAIL(&psql_tables, table, list);
00263    ast_rwlock_rdlock(&table->lock);
00264    AST_LIST_UNLOCK(&psql_tables);
00265    return table;
00266 }

static char * handle_cli_realtime_pgsql_cache ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1484 of file res_config_pgsql.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, CLI_GENERATE, CLI_INIT, tables::columns, ast_cli_entry::command, ast_cli_args::fd, find_table(), columns::len, tables::list, ast_cli_args::n, columns::name, tables::name, columns::notnull, release_table, columns::type, ast_cli_entry::usage, and ast_cli_args::word.

01485 {
01486    struct tables *cur;
01487    int l, which;
01488    char *ret = NULL;
01489 
01490    switch (cmd) {
01491    case CLI_INIT:
01492       e->command = "realtime show pgsql cache";
01493       e->usage =
01494          "Usage: realtime show pgsql cache [<table>]\n"
01495          "       Shows table cache for the PostgreSQL RealTime driver\n";
01496       return NULL;
01497    case CLI_GENERATE:
01498       if (a->argc != 4) {
01499          return NULL;
01500       }
01501       l = strlen(a->word);
01502       which = 0;
01503       AST_LIST_LOCK(&psql_tables);
01504       AST_LIST_TRAVERSE(&psql_tables, cur, list) {
01505          if (!strncasecmp(a->word, cur->name, l) && ++which > a->n) {
01506             ret = ast_strdup(cur->name);
01507             break;
01508          }
01509       }
01510       AST_LIST_UNLOCK(&psql_tables);
01511       return ret;
01512    }
01513 
01514    if (a->argc == 4) {
01515       /* List of tables */
01516       AST_LIST_LOCK(&psql_tables);
01517       AST_LIST_TRAVERSE(&psql_tables, cur, list) {
01518          ast_cli(a->fd, "%s\n", cur->name);
01519       }
01520       AST_LIST_UNLOCK(&psql_tables);
01521    } else if (a->argc == 5) {
01522       /* List of columns */
01523       if ((cur = find_table(a->argv[4]))) {
01524          struct columns *col;
01525          ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[4]);
01526          ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable");
01527          AST_LIST_TRAVERSE(&cur->columns, col, list) {
01528             ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : "");
01529          }
01530          release_table(cur);
01531       } else {
01532          ast_cli(a->fd, "No such table '%s'\n", a->argv[4]);
01533       }
01534    }
01535    return 0;
01536 }

static char * handle_cli_realtime_pgsql_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1538 of file res_config_pgsql.c.

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

01539 {
01540    char status[256], credentials[100] = "";
01541    int ctimesec = time(NULL) - connect_time;
01542 
01543    switch (cmd) {
01544    case CLI_INIT:
01545       e->command = "realtime show pgsql status";
01546       e->usage =
01547          "Usage: realtime show pgsql status\n"
01548          "       Shows connection information for the PostgreSQL RealTime driver\n";
01549       return NULL;
01550    case CLI_GENERATE:
01551       return NULL;
01552    }
01553 
01554    if (a->argc != 4)
01555       return CLI_SHOWUSAGE;
01556 
01557    if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
01558       if (!ast_strlen_zero(dbhost))
01559          snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport);
01560       else if (!ast_strlen_zero(dbsock))
01561          snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock);
01562       else
01563          snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost);
01564 
01565       if (!ast_strlen_zero(dbuser))
01566          snprintf(credentials, sizeof(credentials), " with username %s", dbuser);
01567 
01568       if (ctimesec > 31536000)
01569          ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01570                status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400,
01571                (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
01572       else if (ctimesec > 86400)
01573          ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
01574                credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60,
01575                ctimesec % 60);
01576       else if (ctimesec > 3600)
01577          ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials,
01578                ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
01579       else if (ctimesec > 60)
01580          ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60,
01581                ctimesec % 60);
01582       else
01583          ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
01584 
01585       return CLI_SUCCESS;
01586    } else {
01587       return CLI_FAILURE;
01588    }
01589 }

static int load_module ( void   )  [static]

Definition at line 1281 of file res_config_pgsql.c.

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

01282 {
01283    if(!parse_config(0))
01284       return AST_MODULE_LOAD_DECLINE;
01285 
01286    ast_config_engine_register(&pgsql_engine);
01287    ast_verb(1, "PostgreSQL RealTime driver loaded.\n");
01288    ast_cli_register_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
01289 
01290    return 0;
01291 }

static int parse_config ( int  reload  )  [static]

Definition at line 1327 of file res_config_pgsql.c.

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

Referenced by load_module(), and reload().

01328 {
01329    struct ast_config *config;
01330    const char *s;
01331    struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01332 
01333    config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags);
01334    if (config == CONFIG_STATUS_FILEUNCHANGED) {
01335       return 0;
01336    }
01337 
01338    if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
01339       ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF);
01340       return 0;
01341    }
01342 
01343    ast_mutex_lock(&pgsql_lock);
01344 
01345    if (pgsqlConn) {
01346       PQfinish(pgsqlConn);
01347       pgsqlConn = NULL;
01348    }
01349 
01350    if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
01351       ast_log(LOG_WARNING,
01352             "PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n");
01353       strcpy(dbuser, "asterisk");
01354    } else {
01355       ast_copy_string(dbuser, s, sizeof(dbuser));
01356    }
01357 
01358    if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
01359       ast_log(LOG_WARNING,
01360             "PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n");
01361       strcpy(dbpass, "asterisk");
01362    } else {
01363       ast_copy_string(dbpass, s, sizeof(dbpass));
01364    }
01365 
01366    if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
01367       ast_log(LOG_WARNING,
01368             "PostgreSQL RealTime: No database host found, using localhost via socket.\n");
01369       dbhost[0] = '\0';
01370    } else {
01371       ast_copy_string(dbhost, s, sizeof(dbhost));
01372    }
01373 
01374    if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
01375       ast_log(LOG_WARNING,
01376             "PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n");
01377       strcpy(dbname, "asterisk");
01378    } else {
01379       ast_copy_string(dbname, s, sizeof(dbname));
01380    }
01381 
01382    if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
01383       ast_log(LOG_WARNING,
01384             "PostgreSQL RealTime: No database port found, using 5432 as default.\n");
01385       dbport = 5432;
01386    } else {
01387       dbport = atoi(s);
01388    }
01389 
01390    if (!ast_strlen_zero(dbhost)) {
01391       /* No socket needed */
01392    } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
01393       ast_log(LOG_WARNING,
01394             "PostgreSQL RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
01395       strcpy(dbsock, "/tmp/pgsql.sock");
01396    } else {
01397       ast_copy_string(dbsock, s, sizeof(dbsock));
01398    }
01399 
01400    if (!(s = ast_variable_retrieve(config, "general", "requirements"))) {
01401       ast_log(LOG_WARNING,
01402             "PostgreSQL RealTime: no requirements setting found, using 'warn' as default.\n");
01403       requirements = RQ_WARN;
01404    } else if (!strcasecmp(s, "createclose")) {
01405       requirements = RQ_CREATECLOSE;
01406    } else if (!strcasecmp(s, "createchar")) {
01407       requirements = RQ_CREATECHAR;
01408    }
01409 
01410    ast_config_destroy(config);
01411 
01412    if (option_debug) {
01413       if (!ast_strlen_zero(dbhost)) {
01414          ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost);
01415          ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport);
01416       } else {
01417          ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock);
01418       }
01419       ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser);
01420       ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass);
01421       ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname);
01422    }
01423 
01424    if (!pgsql_reconnect(NULL)) {
01425       ast_log(LOG_WARNING,
01426             "PostgreSQL RealTime: Couldn't establish connection. Check debug.\n");
01427       ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn));
01428    }
01429 
01430    ast_verb(2, "PostgreSQL RealTime reloaded.\n");
01431 
01432    /* Done reloading. Release lock so others can now use driver. */
01433    ast_mutex_unlock(&pgsql_lock);
01434 
01435    return 1;
01436 }

static int pgsql_reconnect ( const char *  database  )  [static]

Definition at line 1438 of file res_config_pgsql.c.

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

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

01439 {
01440    char my_database[50];
01441 
01442    ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
01443 
01444    /* mutex lock should have been locked before calling this function. */
01445 
01446    if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
01447       PQfinish(pgsqlConn);
01448       pgsqlConn = NULL;
01449    }
01450 
01451    /* DB password can legitimately be 0-length */
01452    if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) {
01453       struct ast_str *connInfo = ast_str_create(32);
01454 
01455       ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s",
01456          dbhost, dbport, my_database, dbuser);
01457       if (!ast_strlen_zero(dbpass))
01458          ast_str_append(&connInfo, 0, " password=%s", dbpass);
01459 
01460       ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
01461       pgsqlConn = PQconnectdb(ast_str_buffer(connInfo));
01462       ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
01463       ast_free(connInfo);
01464       connInfo = NULL;
01465 
01466       ast_debug(1, "pgsqlConn=%p\n", pgsqlConn);
01467       if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
01468          ast_debug(1, "PostgreSQL RealTime: Successfully connected to database.\n");
01469          connect_time = time(NULL);
01470          version = PQserverVersion(pgsqlConn);
01471          return 1;
01472       } else {
01473          ast_log(LOG_ERROR,
01474                "PostgreSQL RealTime: Failed to connect database %s on %s: %s\n",
01475                dbname, dbhost, PQresultErrorMessage(NULL));
01476          return 0;
01477       }
01478    } else {
01479       ast_debug(1, "PostgreSQL RealTime: One or more of the parameters in the config does not pass our validity checks.\n");
01480       return 1;
01481    }
01482 }

static struct ast_config* realtime_multi_pgsql ( const char *  database,
const char *  table,
va_list  ap 
) [static, read]

Definition at line 418 of file res_config_pgsql.c.

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

00419 {
00420    PGresult *result = NULL;
00421    int num_rows = 0, pgresult;
00422    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00423    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
00424    const char *initfield = NULL;
00425    char *stringp;
00426    char *chunk;
00427    char *op;
00428    const char *newparam, *newval;
00429    struct ast_variable *var = NULL;
00430    struct ast_config *cfg = NULL;
00431    struct ast_category *cat = NULL;
00432 
00433    if (!table) {
00434       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00435       return NULL;
00436    }
00437 
00438    if (!(cfg = ast_config_new()))
00439       return NULL;
00440 
00441    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00442    newparam = va_arg(ap, const char *);
00443    newval = va_arg(ap, const char *);
00444    if (!newparam || !newval) {
00445       ast_log(LOG_WARNING,
00446             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00447       if (pgsqlConn) {
00448          PQfinish(pgsqlConn);
00449          pgsqlConn = NULL;
00450       }
00451       return NULL;
00452    }
00453 
00454    initfield = ast_strdupa(newparam);
00455    if ((op = strchr(initfield, ' '))) {
00456       *op = '\0';
00457    }
00458 
00459    /* Create the first part of the query using the first parameter/value pairs we just extracted
00460       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00461 
00462    if (!strchr(newparam, ' '))
00463       op = " =";
00464    else
00465       op = "";
00466 
00467    ESCAPE_STRING(escapebuf, newval);
00468    if (pgresult) {
00469       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00470       va_end(ap);
00471       return NULL;
00472    }
00473 
00474    ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
00475    while ((newparam = va_arg(ap, const char *))) {
00476       newval = va_arg(ap, const char *);
00477       if (!strchr(newparam, ' '))
00478          op = " =";
00479       else
00480          op = "";
00481 
00482       ESCAPE_STRING(escapebuf, newval);
00483       if (pgresult) {
00484          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00485          va_end(ap);
00486          return NULL;
00487       }
00488 
00489       ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
00490    }
00491 
00492    if (initfield) {
00493       ast_str_append(&sql, 0, " ORDER BY %s", initfield);
00494    }
00495 
00496    va_end(ap);
00497 
00498    /* We now have our complete statement; Lets connect to the server and execute it. */
00499    ast_mutex_lock(&pgsql_lock);
00500    if (!pgsql_reconnect(database)) {
00501       ast_mutex_unlock(&pgsql_lock);
00502       return NULL;
00503    }
00504 
00505    if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
00506       ast_log(LOG_WARNING,
00507             "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
00508       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00509       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00510       ast_mutex_unlock(&pgsql_lock);
00511       return NULL;
00512    } else {
00513       ExecStatusType result_status = PQresultStatus(result);
00514       if (result_status != PGRES_COMMAND_OK
00515          && result_status != PGRES_TUPLES_OK
00516          && result_status != PGRES_NONFATAL_ERROR) {
00517          ast_log(LOG_WARNING,
00518                "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
00519          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00520          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00521                   PQresultErrorMessage(result), PQresStatus(result_status));
00522          ast_mutex_unlock(&pgsql_lock);
00523          return NULL;
00524       }
00525    }
00526 
00527    ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
00528 
00529    if ((num_rows = PQntuples(result)) > 0) {
00530       int numFields = PQnfields(result);
00531       int i = 0;
00532       int rowIndex = 0;
00533       char **fieldnames = NULL;
00534 
00535       ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
00536 
00537       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00538          ast_mutex_unlock(&pgsql_lock);
00539          PQclear(result);
00540          return NULL;
00541       }
00542       for (i = 0; i < numFields; i++)
00543          fieldnames[i] = PQfname(result, i);
00544 
00545       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00546          var = NULL;
00547          if (!(cat = ast_category_new("","",99999)))
00548             continue;
00549          for (i = 0; i < numFields; i++) {
00550             stringp = PQgetvalue(result, rowIndex, i);
00551             while (stringp) {
00552                chunk = strsep(&stringp, ";");
00553                if (!ast_strlen_zero(ast_strip(chunk))) {
00554                   if (initfield && !strcmp(initfield, fieldnames[i])) {
00555                      ast_category_rename(cat, chunk);
00556                   }
00557                   var = ast_variable_new(fieldnames[i], chunk, "");
00558                   ast_variable_append(cat, var);
00559                }
00560             }
00561          }
00562          ast_category_append(cfg, cat);
00563       }
00564       ast_free(fieldnames);
00565    } else {
00566       ast_log(LOG_WARNING,
00567             "PostgreSQL RealTime: Could not find any rows in table %s.\n", table);
00568    }
00569 
00570    ast_mutex_unlock(&pgsql_lock);
00571    PQclear(result);
00572 
00573    return cfg;
00574 }

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

Definition at line 283 of file res_config_pgsql.c.

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

00284 {
00285    PGresult *result = NULL;
00286    int num_rows = 0, pgresult;
00287    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00288    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
00289    char *stringp;
00290    char *chunk;
00291    char *op;
00292    const char *newparam, *newval;
00293    struct ast_variable *var = NULL, *prev = NULL;
00294 
00295    if (!tablename) {
00296       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00297       return NULL;
00298    }
00299 
00300    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00301    newparam = va_arg(ap, const char *);
00302    newval = va_arg(ap, const char *);
00303    if (!newparam || !newval) {
00304       ast_log(LOG_WARNING,
00305             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00306       if (pgsqlConn) {
00307          PQfinish(pgsqlConn);
00308          pgsqlConn = NULL;
00309       }
00310       return NULL;
00311    }
00312 
00313    /* Create the first part of the query using the first parameter/value pairs we just extracted
00314       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00315    op = strchr(newparam, ' ') ? "" : " =";
00316 
00317    ESCAPE_STRING(escapebuf, newval);
00318    if (pgresult) {
00319       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00320       va_end(ap);
00321       return NULL;
00322    }
00323 
00324    ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
00325    while ((newparam = va_arg(ap, const char *))) {
00326       newval = va_arg(ap, const char *);
00327       if (!strchr(newparam, ' '))
00328          op = " =";
00329       else
00330          op = "";
00331 
00332       ESCAPE_STRING(escapebuf, newval);
00333       if (pgresult) {
00334          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00335          va_end(ap);
00336          return NULL;
00337       }
00338 
00339       ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
00340    }
00341    va_end(ap);
00342 
00343    /* We now have our complete statement; Lets connect to the server and execute it. */
00344    ast_mutex_lock(&pgsql_lock);
00345    if (!pgsql_reconnect(database)) {
00346       ast_mutex_unlock(&pgsql_lock);
00347       return NULL;
00348    }
00349 
00350    if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
00351       ast_log(LOG_WARNING,
00352             "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
00353       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00354       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00355       ast_mutex_unlock(&pgsql_lock);
00356       return NULL;
00357    } else {
00358       ExecStatusType result_status = PQresultStatus(result);
00359       if (result_status != PGRES_COMMAND_OK
00360          && result_status != PGRES_TUPLES_OK
00361          && result_status != PGRES_NONFATAL_ERROR) {
00362          ast_log(LOG_WARNING,
00363                "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
00364          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00365          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00366                   PQresultErrorMessage(result), PQresStatus(result_status));
00367          ast_mutex_unlock(&pgsql_lock);
00368          return NULL;
00369       }
00370    }
00371 
00372    ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
00373 
00374    if ((num_rows = PQntuples(result)) > 0) {
00375       int i = 0;
00376       int rowIndex = 0;
00377       int numFields = PQnfields(result);
00378       char **fieldnames = NULL;
00379 
00380       ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
00381 
00382       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00383          ast_mutex_unlock(&pgsql_lock);
00384          PQclear(result);
00385          return NULL;
00386       }
00387       for (i = 0; i < numFields; i++)
00388          fieldnames[i] = PQfname(result, i);
00389       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00390          for (i = 0; i < numFields; i++) {
00391             stringp = PQgetvalue(result, rowIndex, i);
00392             while (stringp) {
00393                chunk = strsep(&stringp, ";");
00394                if (!ast_strlen_zero(ast_strip(chunk))) {
00395                   if (prev) {
00396                      prev->next = ast_variable_new(fieldnames[i], chunk, "");
00397                      if (prev->next) {
00398                         prev = prev->next;
00399                      }
00400                   } else {
00401                      prev = var = ast_variable_new(fieldnames[i], chunk, "");
00402                   }
00403                }
00404             }
00405          }
00406       }
00407       ast_free(fieldnames);
00408    } else {
00409       ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s@%s.\n", tablename, database);
00410    }
00411 
00412    ast_mutex_unlock(&pgsql_lock);
00413    PQclear(result);
00414 
00415    return var;
00416 }

static int reload ( void   )  [static]

Definition at line 1320 of file res_config_pgsql.c.

References parse_config().

01321 {
01322    parse_config(1);
01323 
01324    return 0;
01325 }

static int require_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
) [static]

Definition at line 1125 of file res_config_pgsql.c.

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

01126 {
01127    struct columns *column;
01128    struct tables *table = find_table(tablename);
01129    char *elm;
01130    int type, size, res = 0;
01131 
01132    if (!table) {
01133       ast_log(LOG_WARNING, "Table %s not found in database.  This table should exist if you're using realtime.\n", tablename);
01134       return -1;
01135    }
01136 
01137    while ((elm = va_arg(ap, char *))) {
01138       type = va_arg(ap, require_type);
01139       size = va_arg(ap, int);
01140       AST_LIST_TRAVERSE(&table->columns, column, list) {
01141          if (strcmp(column->name, elm) == 0) {
01142             /* Char can hold anything, as long as it is large enough */
01143             if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0 || strcmp(column->type, "bpchar") == 0)) {
01144                if ((size > column->len) && column->len != -1) {
01145                   ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len);
01146                   res = -1;
01147                }
01148             } else if (strncmp(column->type, "int", 3) == 0) {
01149                int typesize = atoi(column->type + 3);
01150                /* Integers can hold only other integers */
01151                if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
01152                   type == RQ_INTEGER4 || type == RQ_UINTEGER4 ||
01153                   type == RQ_INTEGER3 || type == RQ_UINTEGER3 ||
01154                   type == RQ_UINTEGER2) && typesize == 2) {
01155                   ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
01156                   res = -1;
01157                } else if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
01158                   type == RQ_UINTEGER4) && typesize == 4) {
01159                   ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
01160                   res = -1;
01161                } else if (type == RQ_CHAR || type == RQ_DATETIME || type == RQ_FLOAT || type == RQ_DATE) {
01162                   ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n",
01163                      column->name,
01164                         type == RQ_CHAR ? "char" :
01165                         type == RQ_DATETIME ? "datetime" :
01166                         type == RQ_DATE ? "date" :
01167                         type == RQ_FLOAT ? "float" :
01168                         "a rather stiff drink ",
01169                      size, column->type);
01170                   res = -1;
01171                }
01172             } else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
01173                ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
01174                res = -1;
01175             } else { /* There are other types that no module implements yet */
01176                ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
01177                res = -1;
01178             }
01179             break;
01180          }
01181       }
01182 
01183       if (!column) {
01184          if (requirements == RQ_WARN) {
01185             ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size);
01186          } else {
01187             struct ast_str *sql = ast_str_create(100);
01188             char fieldtype[15];
01189             PGresult *result;
01190 
01191             if (requirements == RQ_CREATECHAR || type == RQ_CHAR) {
01192                /* Size is minimum length; make it at least 50% greater,
01193                 * just to be sure, because PostgreSQL doesn't support
01194                 * resizing columns. */
01195                snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)",
01196                   size < 15 ? size * 2 :
01197                   (size * 3 / 2 > 255) ? 255 : size * 3 / 2);
01198             } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) {
01199                snprintf(fieldtype, sizeof(fieldtype), "INT2");
01200             } else if (type == RQ_UINTEGER2 || type == RQ_INTEGER3 || type == RQ_UINTEGER3 || type == RQ_INTEGER4) {
01201                snprintf(fieldtype, sizeof(fieldtype), "INT4");
01202             } else if (type == RQ_UINTEGER4 || type == RQ_INTEGER8) {
01203                snprintf(fieldtype, sizeof(fieldtype), "INT8");
01204             } else if (type == RQ_UINTEGER8) {
01205                /* No such type on PostgreSQL */
01206                snprintf(fieldtype, sizeof(fieldtype), "CHAR(20)");
01207             } else if (type == RQ_FLOAT) {
01208                snprintf(fieldtype, sizeof(fieldtype), "FLOAT8");
01209             } else if (type == RQ_DATE) {
01210                snprintf(fieldtype, sizeof(fieldtype), "DATE");
01211             } else if (type == RQ_DATETIME) {
01212                snprintf(fieldtype, sizeof(fieldtype), "TIMESTAMP");
01213             } else {
01214                ast_log(LOG_ERROR, "Unrecognized request type %d\n", type);
01215                ast_free(sql);
01216                continue;
01217             }
01218             ast_str_set(&sql, 0, "ALTER TABLE %s ADD COLUMN %s %s", tablename, elm, fieldtype);
01219             ast_debug(1, "About to lock pgsql_lock (running alter on table '%s' to add column '%s')\n", tablename, elm);
01220 
01221             ast_mutex_lock(&pgsql_lock);
01222             if (!pgsql_reconnect(database)) {
01223                ast_mutex_unlock(&pgsql_lock);
01224                ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
01225                ast_free(sql);
01226                continue;
01227             }
01228 
01229             ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm);
01230             result = PQexec(pgsqlConn, ast_str_buffer(sql));
01231             ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename);
01232             if (PQresultStatus(result) != PGRES_COMMAND_OK) {
01233                ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
01234             }
01235             PQclear(result);
01236             ast_mutex_unlock(&pgsql_lock);
01237 
01238             ast_free(sql);
01239          }
01240       }
01241    }
01242    release_table(table);
01243    return res;
01244 }

static int store_pgsql ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Definition at line 846 of file res_config_pgsql.c.

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

00847 {
00848    PGresult *result = NULL;
00849    Oid insertid;
00850    struct ast_str *buf = ast_str_thread_get(&escapebuf_buf, 256);
00851    struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256);
00852    struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256);
00853    int pgresult;
00854    const char *newparam, *newval;
00855 
00856    if (!table) {
00857       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00858       return -1;
00859    }
00860 
00861    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00862    newparam = va_arg(ap, const char *);
00863    newval = va_arg(ap, const char *);
00864    if (!newparam || !newval) {
00865       ast_log(LOG_WARNING,
00866             "PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
00867       if (pgsqlConn) {
00868          PQfinish(pgsqlConn);
00869          pgsqlConn = NULL;
00870       }
00871       return -1;
00872    }
00873 
00874    /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
00875    ast_mutex_lock(&pgsql_lock);
00876    if (!pgsql_reconnect(database)) {
00877       ast_mutex_unlock(&pgsql_lock);
00878       return -1;
00879    }
00880 
00881    /* Create the first part of the query using the first parameter/value pairs we just extracted
00882       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00883    ESCAPE_STRING(buf, newparam);
00884    ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
00885    ESCAPE_STRING(buf, newval);
00886    ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
00887    while ((newparam = va_arg(ap, const char *))) {
00888       newval = va_arg(ap, const char *);
00889       ESCAPE_STRING(buf, newparam);
00890       ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
00891       ESCAPE_STRING(buf, newval);
00892       ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
00893    }
00894    va_end(ap);
00895    ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
00896 
00897    ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1));
00898 
00899    if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql1)))) {
00900       ast_log(LOG_WARNING,
00901             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00902       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
00903       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00904       ast_mutex_unlock(&pgsql_lock);
00905       return -1;
00906    } else {
00907       ExecStatusType result_status = PQresultStatus(result);
00908       if (result_status != PGRES_COMMAND_OK
00909          && result_status != PGRES_TUPLES_OK
00910          && result_status != PGRES_NONFATAL_ERROR) {
00911          ast_log(LOG_WARNING,
00912                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00913          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
00914          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00915                   PQresultErrorMessage(result), PQresStatus(result_status));
00916          ast_mutex_unlock(&pgsql_lock);
00917          return -1;
00918       }
00919    }
00920 
00921    insertid = PQoidValue(result);
00922    ast_mutex_unlock(&pgsql_lock);
00923 
00924    ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid);
00925 
00926    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00927     * An integer greater than zero indicates the number of rows affected
00928     * Zero indicates that no records were updated
00929     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00930     */
00931 
00932    if (insertid >= 0)
00933       return (int) insertid;
00934 
00935    return -1;
00936 }

static int unload_module ( void   )  [static]

Definition at line 1293 of file res_config_pgsql.c.

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

01294 {
01295    struct tables *table;
01296    /* Acquire control before doing anything to the module itself. */
01297    ast_mutex_lock(&pgsql_lock);
01298 
01299    if (pgsqlConn) {
01300       PQfinish(pgsqlConn);
01301       pgsqlConn = NULL;
01302    }
01303    ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
01304    ast_config_engine_deregister(&pgsql_engine);
01305    ast_verb(1, "PostgreSQL RealTime unloaded.\n");
01306 
01307    /* Destroy cached table info */
01308    AST_LIST_LOCK(&psql_tables);
01309    while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) {
01310       destroy_table(table);
01311    }
01312    AST_LIST_UNLOCK(&psql_tables);
01313 
01314    /* Unlock so something else can destroy the lock. */
01315    ast_mutex_unlock(&pgsql_lock);
01316 
01317    return 0;
01318 }

static int unload_pgsql ( const char *  database,
const char *  tablename 
) [static]

Definition at line 1246 of file res_config_pgsql.c.

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

01247 {
01248    struct tables *cur;
01249    ast_debug(2, "About to lock table cache list\n");
01250    AST_LIST_LOCK(&psql_tables);
01251    ast_debug(2, "About to traverse table cache list\n");
01252    AST_LIST_TRAVERSE_SAFE_BEGIN(&psql_tables, cur, list) {
01253       if (strcmp(cur->name, tablename) == 0) {
01254          ast_debug(2, "About to remove matching cache entry\n");
01255          AST_LIST_REMOVE_CURRENT(list);
01256          ast_debug(2, "About to destroy matching cache entry\n");
01257          destroy_table(cur);
01258          ast_debug(1, "Cache entry '%s@%s' destroyed\n", tablename, database);
01259          break;
01260       }
01261    }
01262    AST_LIST_TRAVERSE_SAFE_END
01263    AST_LIST_UNLOCK(&psql_tables);
01264    ast_debug(2, "About to return\n");
01265    return cur ? 0 : -1;
01266 }

static int update2_pgsql ( const char *  database,
const char *  tablename,
va_list  ap 
) [static]

Definition at line 714 of file res_config_pgsql.c.

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

00715 {
00716    PGresult *result = NULL;
00717    int numrows = 0, pgresult, first = 1;
00718    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16);
00719    const char *newparam, *newval;
00720    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00721    struct ast_str *where = ast_str_thread_get(&where_buf, 100);
00722    struct tables *table;
00723 
00724    if (!tablename) {
00725       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00726       return -1;
00727    }
00728 
00729    if (!escapebuf || !sql || !where) {
00730       /* Memory error, already handled */
00731       return -1;
00732    }
00733 
00734    if (!(table = find_table(tablename))) {
00735       ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
00736       return -1;
00737    }
00738 
00739    ast_str_set(&sql, 0, "UPDATE %s SET ", tablename);
00740    ast_str_set(&where, 0, "WHERE");
00741 
00742    while ((newparam = va_arg(ap, const char *))) {
00743       if (!find_column(table, newparam)) {
00744          ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database);
00745          release_table(table);
00746          return -1;
00747       }
00748          
00749       newval = va_arg(ap, const char *);
00750       ESCAPE_STRING(escapebuf, newval);
00751       if (pgresult) {
00752          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00753          release_table(table);
00754          ast_free(sql);
00755          return -1;
00756       }
00757       ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
00758       first = 0;
00759    }
00760 
00761    if (first) {
00762       ast_log(LOG_WARNING,
00763             "PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on.\n");
00764       if (pgsqlConn) {
00765          PQfinish(pgsqlConn);
00766          pgsqlConn = NULL;
00767       }
00768       release_table(table);
00769       return -1;
00770    }
00771 
00772    /* Now retrieve the columns to update */
00773    first = 1;
00774    while ((newparam = va_arg(ap, const char *))) {
00775       newval = va_arg(ap, const char *);
00776 
00777       /* If the column is not within the table, then skip it */
00778       if (!find_column(table, newparam)) {
00779          ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database);
00780          continue;
00781       }
00782 
00783       ESCAPE_STRING(escapebuf, newval);
00784       if (pgresult) {
00785          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00786          release_table(table);
00787          ast_free(sql);
00788          return -1;
00789       }
00790 
00791       ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
00792    }
00793    release_table(table);
00794 
00795    ast_str_append(&sql, 0, " %s", ast_str_buffer(where));
00796 
00797    ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
00798 
00799    /* We now have our complete statement; connect to the server and execute it. */
00800    ast_mutex_lock(&pgsql_lock);
00801    if (!pgsql_reconnect(database)) {
00802       ast_mutex_unlock(&pgsql_lock);
00803       return -1;
00804    }
00805 
00806    if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
00807       ast_log(LOG_WARNING,
00808             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00809       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00810       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00811       ast_mutex_unlock(&pgsql_lock);
00812       return -1;
00813    } else {
00814       ExecStatusType result_status = PQresultStatus(result);
00815       if (result_status != PGRES_COMMAND_OK
00816          && result_status != PGRES_TUPLES_OK
00817          && result_status != PGRES_NONFATAL_ERROR) {
00818          ast_log(LOG_WARNING,
00819                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00820          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00821          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00822                   PQresultErrorMessage(result), PQresStatus(result_status));
00823          ast_mutex_unlock(&pgsql_lock);
00824          return -1;
00825       }
00826    }
00827 
00828    numrows = atoi(PQcmdTuples(result));
00829    ast_mutex_unlock(&pgsql_lock);
00830 
00831    ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
00832 
00833    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00834     * An integer greater than zero indicates the number of rows affected
00835     * Zero indicates that no records were updated
00836     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00837     */
00838 
00839    if (numrows >= 0) {
00840       return (int) numrows;
00841    }
00842 
00843    return -1;
00844 }

static int update_pgsql ( const char *  database,
const char *  tablename,
const char *  keyfield,
const char *  lookup,
va_list  ap 
) [static]

Definition at line 576 of file res_config_pgsql.c.

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

00578 {
00579    PGresult *result = NULL;
00580    int numrows = 0, pgresult;
00581    const char *newparam, *newval;
00582    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00583    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
00584    struct tables *table;
00585    struct columns *column = NULL;
00586 
00587    if (!tablename) {
00588       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00589       return -1;
00590    }
00591 
00592    if (!(table = find_table(tablename))) {
00593       ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
00594       return -1;
00595    }
00596 
00597    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00598    newparam = va_arg(ap, const char *);
00599    newval = va_arg(ap, const char *);
00600    if (!newparam || !newval) {
00601       ast_log(LOG_WARNING,
00602             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00603       if (pgsqlConn) {
00604          PQfinish(pgsqlConn);
00605          pgsqlConn = NULL;
00606       }
00607       release_table(table);
00608       return -1;
00609    }
00610 
00611    /* Check that the column exists in the table */
00612    AST_LIST_TRAVERSE(&table->columns, column, list) {
00613       if (strcmp(column->name, newparam) == 0) {
00614          break;
00615       }
00616    }
00617 
00618    if (!column) {
00619       ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
00620       release_table(table);
00621       return -1;
00622    }
00623 
00624    /* Create the first part of the query using the first parameter/value pairs we just extracted
00625       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00626 
00627    ESCAPE_STRING(escapebuf, newval);
00628    if (pgresult) {
00629       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00630       va_end(ap);
00631       release_table(table);
00632       return -1;
00633    }
00634    ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));
00635 
00636    while ((newparam = va_arg(ap, const char *))) {
00637       newval = va_arg(ap, const char *);
00638 
00639       if (!find_column(table, newparam)) {
00640          ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
00641          continue;
00642       }
00643 
00644       ESCAPE_STRING(escapebuf, newval);
00645       if (pgresult) {
00646          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00647          va_end(ap);
00648          release_table(table);
00649          return -1;
00650       }
00651 
00652       ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
00653    }
00654    va_end(ap);
00655    release_table(table);
00656 
00657    ESCAPE_STRING(escapebuf, lookup);
00658    if (pgresult) {
00659       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
00660       va_end(ap);
00661       return -1;
00662    }
00663 
00664    ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(escapebuf));
00665 
00666    ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
00667 
00668    /* We now have our complete statement; Lets connect to the server and execute it. */
00669    ast_mutex_lock(&pgsql_lock);
00670    if (!pgsql_reconnect(database)) {
00671       ast_mutex_unlock(&pgsql_lock);
00672       return -1;
00673    }
00674 
00675    if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
00676       ast_log(LOG_WARNING,
00677             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00678       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00679       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00680       ast_mutex_unlock(&pgsql_lock);
00681       return -1;
00682    } else {
00683       ExecStatusType result_status = PQresultStatus(result);
00684       if (result_status != PGRES_COMMAND_OK
00685          && result_status != PGRES_TUPLES_OK
00686          && result_status != PGRES_NONFATAL_ERROR) {
00687          ast_log(LOG_WARNING,
00688                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00689          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00690          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00691                   PQresultErrorMessage(result), PQresStatus(result_status));
00692          ast_mutex_unlock(&pgsql_lock);
00693          return -1;
00694       }
00695    }
00696 
00697    numrows = atoi(PQcmdTuples(result));
00698    ast_mutex_unlock(&pgsql_lock);
00699 
00700    ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
00701 
00702    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00703     * An integer greater than zero indicates the number of rows affected
00704     * Zero indicates that no records were updated
00705     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00706     */
00707 
00708    if (numrows >= 0)
00709       return (int) numrows;
00710 
00711    return -1;
00712 }


Variable Documentation

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

Definition at line 1596 of file res_config_pgsql.c.

Definition at line 1596 of file res_config_pgsql.c.

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

Definition at line 91 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

time_t connect_time = 0 [static]

Definition at line 82 of file res_config_pgsql.c.

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 78 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 46 of file res_config_pgsql.c.

Referenced by find_table().

Definition at line 1268 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

ast_mutex_t pgsql_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]
PGconn* pgsqlConn = NULL

Definition at line 52 of file res_config_pgsql.c.

enum { ... } requirements

Referenced by parse_config(), and require_pgsql().

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

Definition at line 53 of file res_config_pgsql.c.

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

Definition at line 47 of file res_config_pgsql.c.

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


Generated by  doxygen 1.6.2