Sat Feb 11 06:36:24 2012

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

Defines

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

Enumerations

enum  { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR }

Functions

static void __init_escapebuf_buf (void)
static void __init_findtable_buf (void)
static void __init_semibuf_buf (void)
static void __init_sql_buf (void)
static void __init_where_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
static int _pgsql_exec (const char *database, const char *tablename, const char *sql, PGresult **result)
static struct ast_configconfig_pgsql (const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl, const char *who_asked)
static int destroy_pgsql (const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
static void destroy_table (struct tables *table)
static struct columnsfind_column (struct tables *t, const char *colname)
static struct tablesfind_table (const char *database, const char *orig_tablename)
static char * handle_cli_realtime_pgsql_cache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_realtime_pgsql_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int load_module (void)
static int parse_config (int reload)
static int pgsql_exec (const char *database, const char *tablename, const char *sql, PGresult **result)
static int pgsql_reconnect (const char *database)
static struct ast_configrealtime_multi_pgsql (const char *database, const char *table, va_list ap)
static struct ast_variablerealtime_pgsql (const char *database, const char *tablename, va_list ap)
static int reload (void)
static int require_pgsql (const char *database, const char *tablename, va_list ap)
static int store_pgsql (const char *database, const char *table, va_list ap)
static int unload_module (void)
static int unload_pgsql (const char *database, const char *tablename)
static int update2_pgsql (const char *database, const char *tablename, va_list ap)
static int update_pgsql (const char *database, const char *tablename, const char *keyfield, const char *lookup, va_list ap)

Variables

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


Detailed Description

PostgreSQL plugin for Asterisk RealTime Architecture.

Author:
Mark Spencer <markster@digium.com>

Manuel Guesdon <mguesdon@oxymium.net> - PostgreSQL RealTime Driver Author/Adaptor

ExtRef:
PostgreSQL http://www.postgresql.org

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

Referenced by find_table().

#define MAX_DB_OPTION_SIZE   64

Definition at line 58 of file res_config_pgsql.c.

#define release_table ( table   )     ast_rwlock_unlock(&(table)->lock);

#define RES_CONFIG_PGSQL_CONF   "res_pgsql.conf"

Definition at line 52 of file res_config_pgsql.c.

Referenced by config_pgsql(), and parse_config().


Enumeration Type Documentation

anonymous enum

Enumerator:
RQ_WARN 
RQ_CREATECLOSE 
RQ_CREATECHAR 

Definition at line 91 of file res_config_pgsql.c.


Function Documentation

static void __init_escapebuf_buf ( void   )  [static]

Definition at line 49 of file res_config_pgsql.c.

00056 : 0)

static void __init_findtable_buf ( void   )  [static]

Definition at line 47 of file res_config_pgsql.c.

00056 : 0)

static void __init_semibuf_buf ( void   )  [static]

Definition at line 50 of file res_config_pgsql.c.

00056 : 0)

static void __init_sql_buf ( void   )  [static]

Definition at line 46 of file res_config_pgsql.c.

00056 : 0)

static void __init_where_buf ( void   )  [static]

Definition at line 48 of file res_config_pgsql.c.

00056 : 0)

static void __reg_module ( void   )  [static]

Definition at line 1634 of file res_config_pgsql.c.

static void __unreg_module ( void   )  [static]

Definition at line 1634 of file res_config_pgsql.c.

static int _pgsql_exec ( const char *  database,
const char *  tablename,
const char *  sql,
PGresult **  result 
) [static]

Definition at line 144 of file res_config_pgsql.c.

References ast_debug, ast_log(), LOG_ERROR, LOG_NOTICE, and pgsql_reconnect().

Referenced by pgsql_exec().

00145 {
00146    ExecStatusType result_status;
00147 
00148    if (!pgsqlConn) {
00149       ast_debug(1, "PostgreSQL connection not defined, connecting\n");
00150 
00151       if (pgsql_reconnect(database) != 1) {
00152          ast_log(LOG_NOTICE, "reconnect failed\n");
00153          *result = NULL;
00154          return -1;
00155       }
00156 
00157       ast_debug(1, "PostgreSQL connection successful\n");
00158    }
00159 
00160    *result = PQexec(pgsqlConn, sql);
00161    result_status = PQresultStatus(*result);
00162    if (result_status != PGRES_COMMAND_OK
00163       && result_status != PGRES_TUPLES_OK
00164       && result_status != PGRES_NONFATAL_ERROR) {
00165 
00166       ast_log(LOG_ERROR, "PostgreSQL RealTime: Failed to query '%s@%s'.\n", tablename, database);
00167       ast_log(LOG_ERROR, "PostgreSQL RealTime: Query Failed: %s\n", sql);
00168       ast_log(LOG_ERROR, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00169          PQresultErrorMessage(*result),
00170          PQresStatus(result_status));
00171 
00172       /* we may have tried to run a command on a disconnected/disconnecting handle */
00173       /* are we no longer connected to the database... if not try again */
00174       if (PQstatus(pgsqlConn) != CONNECTION_OK) {
00175          PQfinish(pgsqlConn);
00176          pgsqlConn = NULL;
00177          return -2;
00178       }
00179 
00180       /* connection still okay, which means the query is just plain bad */
00181       return -1;
00182    }
00183 
00184    ast_debug(1, "PostgreSQL query successful: %s\n", sql);
00185    return 0;
00186 }

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 1083 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_exec(), pgsql_lock, RES_CONFIG_PGSQL_CONF, and sql_buf.

01086 {
01087    PGresult *result = NULL;
01088    long num_rows;
01089    struct ast_variable *new_v;
01090    struct ast_category *cur_cat = NULL;
01091    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
01092    char last[80] = "";
01093    int last_cat_metric = 0;
01094 
01095    last[0] = '\0';
01096 
01097    if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
01098       ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n");
01099       return NULL;
01100    }
01101 
01102    ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s "
01103          "WHERE filename='%s' and commented=0 "
01104          "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file);
01105 
01106    ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql));
01107 
01108    ast_mutex_lock(&pgsql_lock);
01109 
01110    /* We now have our complete statement; Lets connect to the server and execute it. */
01111         if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) {
01112       ast_mutex_unlock(&pgsql_lock);
01113            return NULL;
01114         }
01115 
01116    if ((num_rows = PQntuples(result)) > 0) {
01117       int rowIndex = 0;
01118 
01119       ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows);
01120 
01121       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
01122          char *field_category = PQgetvalue(result, rowIndex, 0);
01123          char *field_var_name = PQgetvalue(result, rowIndex, 1);
01124          char *field_var_val = PQgetvalue(result, rowIndex, 2);
01125          char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
01126          if (!strcmp(field_var_name, "#include")) {
01127             if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) {
01128                PQclear(result);
01129                ast_mutex_unlock(&pgsql_lock);
01130                return NULL;
01131             }
01132             continue;
01133          }
01134 
01135          if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
01136             cur_cat = ast_category_new(field_category, "", 99999);
01137             if (!cur_cat)
01138                break;
01139             strcpy(last, field_category);
01140             last_cat_metric = atoi(field_cat_metric);
01141             ast_category_append(cfg, cur_cat);
01142          }
01143          new_v = ast_variable_new(field_var_name, field_var_val, "");
01144          ast_variable_append(cur_cat, new_v);
01145       }
01146    } else {
01147       ast_log(LOG_WARNING,
01148             "PostgreSQL RealTime: Could not find config '%s' in database.\n", file);
01149    }
01150 
01151    PQclear(result);
01152    ast_mutex_unlock(&pgsql_lock);
01153 
01154    return cfg;
01155 }

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

Definition at line 1008 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_exec(), pgsql_lock, pgsql_reconnect(), sql_buf, and where_buf.

01009 {
01010    PGresult *result = NULL;
01011    int numrows = 0;
01012    int pgresult;
01013    struct ast_str *sql = ast_str_thread_get(&sql_buf, 256);
01014    struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60);
01015    const char *newparam, *newval;
01016 
01017    if (!table) {
01018       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
01019       return -1;
01020    }
01021 
01022    /* Get the first parameter and first value in our list of passed paramater/value pairs */
01023    /*newparam = va_arg(ap, const char *);
01024    newval = va_arg(ap, const char *);
01025    if (!newparam || !newval) {*/
01026    if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
01027       ast_log(LOG_WARNING,
01028             "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n");
01029       if (pgsqlConn) {
01030          PQfinish(pgsqlConn);
01031          pgsqlConn = NULL;
01032       };
01033       return -1;
01034    }
01035 
01036    /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
01037    ast_mutex_lock(&pgsql_lock);
01038    if (!pgsql_reconnect(database)) {
01039       ast_mutex_unlock(&pgsql_lock);
01040       return -1;
01041    }
01042 
01043 
01044    /* Create the first part of the query using the first parameter/value pairs we just extracted
01045       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
01046 
01047    ESCAPE_STRING(buf1, keyfield);
01048    ESCAPE_STRING(buf2, lookup);
01049    ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
01050    while ((newparam = va_arg(ap, const char *))) {
01051       newval = va_arg(ap, const char *);
01052       ESCAPE_STRING(buf1, newparam);
01053       ESCAPE_STRING(buf2, newval);
01054       ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
01055    }
01056    va_end(ap);
01057 
01058    ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
01059 
01060         if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) {
01061       ast_mutex_unlock(&pgsql_lock);
01062            return -1;
01063         }
01064 
01065    numrows = atoi(PQcmdTuples(result));
01066    ast_mutex_unlock(&pgsql_lock);
01067 
01068    ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table);
01069 
01070    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
01071     * An integer greater than zero indicates the number of rows affected
01072     * Zero indicates that no records were updated
01073     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
01074     */
01075 
01076    if (numrows >= 0)
01077       return (int) numrows;
01078 
01079    return -1;
01080 }

static void destroy_table ( struct tables table  )  [static]

Definition at line 117 of file res_config_pgsql.c.

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

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

00118 {
00119    struct columns *column;
00120    ast_rwlock_wrlock(&table->lock);
00121    while ((column = AST_LIST_REMOVE_HEAD(&table->columns, list))) {
00122       ast_free(column);
00123    }
00124    ast_rwlock_unlock(&table->lock);
00125    ast_rwlock_destroy(&table->lock);
00126    ast_free(table);
00127 }

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

Definition at line 408 of file res_config_pgsql.c.

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

Referenced by update2_pgsql(), and update_pgsql().

00409 {
00410    struct columns *column;
00411 
00412    /* Check that the column exists in the table */
00413    AST_LIST_TRAVERSE(&t->columns, column, list) {
00414       if (strcmp(column->name, colname) == 0) {
00415          return column;
00416       }
00417    }
00418    return NULL;
00419 }

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

Definition at line 250 of file res_config_pgsql.c.

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

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

00251 {
00252    struct columns *column;
00253    struct tables *table;
00254    struct ast_str *sql = ast_str_thread_get(&findtable_buf, 330);
00255         PGresult *result;
00256         int exec_result;
00257    char *fname, *ftype, *flen, *fnotnull, *fdef;
00258    int i, rows;
00259 
00260    AST_LIST_LOCK(&psql_tables);
00261    AST_LIST_TRAVERSE(&psql_tables, table, list) {
00262       if (!strcasecmp(table->name, orig_tablename)) {
00263          ast_debug(1, "Found table in cache; now locking\n");
00264          ast_rwlock_rdlock(&table->lock);
00265          ast_debug(1, "Lock cached table; now returning\n");
00266          AST_LIST_UNLOCK(&psql_tables);
00267          return table;
00268       }
00269    }
00270 
00271    if (database == NULL) {
00272       return NULL;
00273    }
00274 
00275    ast_debug(1, "Table '%s' not found in cache, querying now\n", orig_tablename);
00276 
00277    /* Not found, scan the table */
00278    if (has_schema_support) {
00279       char *schemaname, *tablename;
00280       if (strchr(orig_tablename, '.')) {
00281          schemaname = ast_strdupa(orig_tablename);
00282          tablename = strchr(schemaname, '.');
00283          *tablename++ = '\0';
00284       } else {
00285          schemaname = "";
00286          tablename = ast_strdupa(orig_tablename);
00287       }
00288 
00289       /* Escape special characters in schemaname */
00290       if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
00291          char *tmp = schemaname, *ptr;
00292 
00293          ptr = schemaname = alloca(strlen(tmp) * 2 + 1);
00294          for (; *tmp; tmp++) {
00295             if (strchr("\\'", *tmp)) {
00296                *ptr++ = *tmp;
00297             }
00298             *ptr++ = *tmp;
00299          }
00300          *ptr = '\0';
00301       }
00302       /* Escape special characters in tablename */
00303       if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
00304          char *tmp = tablename, *ptr;
00305 
00306          ptr = tablename = alloca(strlen(tmp) * 2 + 1);
00307          for (; *tmp; tmp++) {
00308             if (strchr("\\'", *tmp)) {
00309                *ptr++ = *tmp;
00310             }
00311             *ptr++ = *tmp;
00312          }
00313          *ptr = '\0';
00314       }
00315 
00316       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",
00317          tablename,
00318          ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'");
00319    } else {
00320       /* Escape special characters in tablename */
00321       if (strchr(orig_tablename, '\\') || strchr(orig_tablename, '\'')) {
00322          const char *tmp = orig_tablename;
00323          char *ptr;
00324 
00325          orig_tablename = ptr = alloca(strlen(tmp) * 2 + 1);
00326          for (; *tmp; tmp++) {
00327             if (strchr("\\'", *tmp)) {
00328                *ptr++ = *tmp;
00329             }
00330             *ptr++ = *tmp;
00331          }
00332          *ptr = '\0';
00333       }
00334 
00335       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);
00336    }
00337 
00338    exec_result = pgsql_exec(database, orig_tablename, ast_str_buffer(sql), &result);
00339    ast_debug(1, "Query of table structure complete.  Now retrieving results.\n");
00340    if (exec_result != 0) {
00341       ast_log(LOG_ERROR, "Failed to query database columns for table %s\n", orig_tablename);
00342       PQclear(result);
00343       AST_LIST_UNLOCK(&psql_tables);
00344       return NULL;
00345    }
00346 
00347    if (!(table = ast_calloc(1, sizeof(*table) + strlen(orig_tablename) + 1))) {
00348       ast_log(LOG_ERROR, "Unable to allocate memory for new table structure\n");
00349       PQclear(result);
00350       AST_LIST_UNLOCK(&psql_tables);
00351       return NULL;
00352    }
00353    strcpy(table->name, orig_tablename); /* SAFE */
00354    ast_rwlock_init(&table->lock);
00355    AST_LIST_HEAD_INIT_NOLOCK(&table->columns);
00356 
00357    rows = PQntuples(result);
00358    for (i = 0; i < rows; i++) {
00359       fname = PQgetvalue(result, i, 0);
00360       ftype = PQgetvalue(result, i, 1);
00361       flen = PQgetvalue(result, i, 2);
00362       fnotnull = PQgetvalue(result, i, 3);
00363       fdef = PQgetvalue(result, i, 4);
00364       ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
00365 
00366       if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + 2))) {
00367          ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", orig_tablename, fname);
00368          PQclear(result);
00369          destroy_table(table);
00370          AST_LIST_UNLOCK(&psql_tables);
00371          return NULL;
00372       }
00373 
00374       if (strcmp(flen, "-1") == 0) {
00375          /* Some types, like chars, have the length stored in a different field */
00376          flen = PQgetvalue(result, i, 5);
00377          sscanf(flen, "%30d", &column->len);
00378          column->len -= 4;
00379       } else {
00380          sscanf(flen, "%30d", &column->len);
00381       }
00382       column->name = (char *)column + sizeof(*column);
00383       column->type = (char *)column + sizeof(*column) + strlen(fname) + 1;
00384       strcpy(column->name, fname);
00385       strcpy(column->type, ftype);
00386       if (*fnotnull == 't') {
00387          column->notnull = 1;
00388       } else {
00389          column->notnull = 0;
00390       }
00391       if (!ast_strlen_zero(fdef)) {
00392          column->hasdefault = 1;
00393       } else {
00394          column->hasdefault = 0;
00395       }
00396       AST_LIST_INSERT_TAIL(&table->columns, column, list);
00397    }
00398    PQclear(result);
00399 
00400    AST_LIST_INSERT_TAIL(&psql_tables, table, list);
00401    ast_rwlock_rdlock(&table->lock);
00402    AST_LIST_UNLOCK(&psql_tables);
00403    return table;
00404 }

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

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

01522 {
01523    struct tables *cur;
01524    int l, which;
01525    char *ret = NULL;
01526 
01527    switch (cmd) {
01528    case CLI_INIT:
01529       e->command = "realtime show pgsql cache";
01530       e->usage =
01531          "Usage: realtime show pgsql cache [<table>]\n"
01532          "       Shows table cache for the PostgreSQL RealTime driver\n";
01533       return NULL;
01534    case CLI_GENERATE:
01535       if (a->argc != 4) {
01536          return NULL;
01537       }
01538       l = strlen(a->word);
01539       which = 0;
01540       AST_LIST_LOCK(&psql_tables);
01541       AST_LIST_TRAVERSE(&psql_tables, cur, list) {
01542          if (!strncasecmp(a->word, cur->name, l) && ++which > a->n) {
01543             ret = ast_strdup(cur->name);
01544             break;
01545          }
01546       }
01547       AST_LIST_UNLOCK(&psql_tables);
01548       return ret;
01549    }
01550 
01551    if (a->argc == 4) {
01552       /* List of tables */
01553       AST_LIST_LOCK(&psql_tables);
01554       AST_LIST_TRAVERSE(&psql_tables, cur, list) {
01555          ast_cli(a->fd, "%s\n", cur->name);
01556       }
01557       AST_LIST_UNLOCK(&psql_tables);
01558    } else if (a->argc == 5) {
01559       /* List of columns */
01560       if ((cur = find_table(NULL, a->argv[4]))) {
01561          struct columns *col;
01562          ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[4]);
01563          ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable");
01564          AST_LIST_TRAVERSE(&cur->columns, col, list) {
01565             ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : "");
01566          }
01567          release_table(cur);
01568       } else {
01569          ast_cli(a->fd, "No such table '%s'\n", a->argv[4]);
01570       }
01571    }
01572    return 0;
01573 }

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

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

01576 {
01577    char status[256], credentials[100] = "";
01578    int ctimesec = time(NULL) - connect_time;
01579 
01580    switch (cmd) {
01581    case CLI_INIT:
01582       e->command = "realtime show pgsql status";
01583       e->usage =
01584          "Usage: realtime show pgsql status\n"
01585          "       Shows connection information for the PostgreSQL RealTime driver\n";
01586       return NULL;
01587    case CLI_GENERATE:
01588       return NULL;
01589    }
01590 
01591    if (a->argc != 4)
01592       return CLI_SHOWUSAGE;
01593 
01594    if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
01595       if (!ast_strlen_zero(dbhost))
01596          snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport);
01597       else if (!ast_strlen_zero(dbsock))
01598          snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock);
01599       else
01600          snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost);
01601 
01602       if (!ast_strlen_zero(dbuser))
01603          snprintf(credentials, sizeof(credentials), " with username %s", dbuser);
01604 
01605       if (ctimesec > 31536000)
01606          ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01607                status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400,
01608                (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
01609       else if (ctimesec > 86400)
01610          ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
01611                credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60,
01612                ctimesec % 60);
01613       else if (ctimesec > 3600)
01614          ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials,
01615                ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
01616       else if (ctimesec > 60)
01617          ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60,
01618                ctimesec % 60);
01619       else
01620          ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
01621 
01622       return CLI_SUCCESS;
01623    } else {
01624       return CLI_FAILURE;
01625    }
01626 }

static int load_module ( void   )  [static]

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

01319 {
01320    if(!parse_config(0))
01321       return AST_MODULE_LOAD_DECLINE;
01322 
01323    ast_config_engine_register(&pgsql_engine);
01324    ast_verb(1, "PostgreSQL RealTime driver loaded.\n");
01325    ast_cli_register_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
01326 
01327    return 0;
01328 }

static int parse_config ( int  reload  )  [static]

Definition at line 1364 of file res_config_pgsql.c.

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

01365 {
01366    struct ast_config *config;
01367    const char *s;
01368    struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01369 
01370    config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags);
01371    if (config == CONFIG_STATUS_FILEUNCHANGED) {
01372       return 0;
01373    }
01374 
01375    if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
01376       ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF);
01377       return 0;
01378    }
01379 
01380    ast_mutex_lock(&pgsql_lock);
01381 
01382    if (pgsqlConn) {
01383       PQfinish(pgsqlConn);
01384       pgsqlConn = NULL;
01385    }
01386 
01387    if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
01388       ast_log(LOG_WARNING,
01389             "PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n");
01390       strcpy(dbuser, "asterisk");
01391    } else {
01392       ast_copy_string(dbuser, s, sizeof(dbuser));
01393    }
01394 
01395    if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
01396       ast_log(LOG_WARNING,
01397             "PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n");
01398       strcpy(dbpass, "asterisk");
01399    } else {
01400       ast_copy_string(dbpass, s, sizeof(dbpass));
01401    }
01402 
01403    if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
01404       ast_log(LOG_WARNING,
01405             "PostgreSQL RealTime: No database host found, using localhost via socket.\n");
01406       dbhost[0] = '\0';
01407    } else {
01408       ast_copy_string(dbhost, s, sizeof(dbhost));
01409    }
01410 
01411    if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
01412       ast_log(LOG_WARNING,
01413             "PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n");
01414       strcpy(dbname, "asterisk");
01415    } else {
01416       ast_copy_string(dbname, s, sizeof(dbname));
01417    }
01418 
01419    if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
01420       ast_log(LOG_WARNING,
01421             "PostgreSQL RealTime: No database port found, using 5432 as default.\n");
01422       dbport = 5432;
01423    } else {
01424       dbport = atoi(s);
01425    }
01426 
01427    if (!ast_strlen_zero(dbhost)) {
01428       /* No socket needed */
01429    } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
01430       ast_log(LOG_WARNING,
01431             "PostgreSQL RealTime: No database socket found, using '/tmp/.s.PGSQL.%d' as default.\n", dbport);
01432       strcpy(dbsock, "/tmp");
01433    } else {
01434       ast_copy_string(dbsock, s, sizeof(dbsock));
01435    }
01436 
01437    if (!(s = ast_variable_retrieve(config, "general", "requirements"))) {
01438       ast_log(LOG_WARNING,
01439             "PostgreSQL RealTime: no requirements setting found, using 'warn' as default.\n");
01440       requirements = RQ_WARN;
01441    } else if (!strcasecmp(s, "createclose")) {
01442       requirements = RQ_CREATECLOSE;
01443    } else if (!strcasecmp(s, "createchar")) {
01444       requirements = RQ_CREATECHAR;
01445    }
01446 
01447    ast_config_destroy(config);
01448 
01449    if (option_debug) {
01450       if (!ast_strlen_zero(dbhost)) {
01451          ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost);
01452          ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport);
01453       } else {
01454          ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock);
01455       }
01456       ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser);
01457       ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass);
01458       ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname);
01459    }
01460 
01461    if (!pgsql_reconnect(NULL)) {
01462       ast_log(LOG_WARNING,
01463             "PostgreSQL RealTime: Couldn't establish connection. Check debug.\n");
01464       ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn));
01465    }
01466 
01467    ast_verb(2, "PostgreSQL RealTime reloaded.\n");
01468 
01469    /* Done reloading. Release lock so others can now use driver. */
01470    ast_mutex_unlock(&pgsql_lock);
01471 
01472    return 1;
01473 }

static int pgsql_exec ( const char *  database,
const char *  tablename,
const char *  sql,
PGresult **  result 
) [static]

Definition at line 218 of file res_config_pgsql.c.

References _pgsql_exec(), ast_debug, ast_log(), and LOG_NOTICE.

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

00219 {
00220    int attempts = 0;
00221    int res;
00222 
00223    /* Try the query, note failure if any */
00224    /* On first failure, reconnect and try again (_pgsql_exec handles reconnect) */
00225    /* On second failure, treat as fatal query error */
00226 
00227    while (attempts++ < 2) {
00228       ast_debug(1, "PostgreSQL query attempt %d\n", attempts);
00229       res = _pgsql_exec(database, tablename, sql, result);
00230 
00231       if (res == 0) {
00232          if (attempts > 1) {
00233             ast_log(LOG_NOTICE, "PostgreSQL RealTime: Query finally succeeded: %s\n", sql);
00234          }
00235 
00236          return 0;
00237       }
00238 
00239       if (res == -1) {
00240          return -1; /* Still connected to db, but could not process query (fatal error) */
00241       }
00242 
00243       /* res == -2 (query on a disconnected handle) */
00244       ast_debug(1, "PostgreSQL query attempt %d failed, trying again\n", attempts);
00245    }
00246 
00247    return -1;
00248 }

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

Definition at line 1475 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 _pgsql_exec(), destroy_pgsql(), parse_config(), and store_pgsql().

01476 {
01477    char my_database[50];
01478 
01479    ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
01480 
01481    /* mutex lock should have been locked before calling this function. */
01482 
01483    if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
01484       PQfinish(pgsqlConn);
01485       pgsqlConn = NULL;
01486    }
01487 
01488    /* DB password can legitimately be 0-length */
01489    if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) {
01490       struct ast_str *connInfo = ast_str_create(32);
01491 
01492       ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s",
01493          S_OR(dbhost, dbsock), dbport, my_database, dbuser);
01494       if (!ast_strlen_zero(dbpass))
01495          ast_str_append(&connInfo, 0, " password=%s", dbpass);
01496 
01497       ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
01498       pgsqlConn = PQconnectdb(ast_str_buffer(connInfo));
01499       ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
01500       ast_free(connInfo);
01501       connInfo = NULL;
01502 
01503       ast_debug(1, "pgsqlConn=%p\n", pgsqlConn);
01504       if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
01505          ast_debug(1, "PostgreSQL RealTime: Successfully connected to database.\n");
01506          connect_time = time(NULL);
01507          version = PQserverVersion(pgsqlConn);
01508          return 1;
01509       } else {
01510          ast_log(LOG_ERROR,
01511                "PostgreSQL RealTime: Failed to connect database %s on %s: %s\n",
01512                dbname, dbhost, PQresultErrorMessage(NULL));
01513          return 0;
01514       }
01515    } else {
01516       ast_debug(1, "PostgreSQL RealTime: One or more of the parameters in the config does not pass our validity checks.\n");
01517       return 1;
01518    }
01519 }

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

Definition at line 536 of file res_config_pgsql.c.

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

00537 {
00538    PGresult *result = NULL;
00539    int num_rows = 0, pgresult;
00540    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00541    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
00542    const char *initfield = NULL;
00543    char *stringp;
00544    char *chunk;
00545    char *op;
00546    const char *newparam, *newval;
00547    struct ast_variable *var = NULL;
00548    struct ast_config *cfg = NULL;
00549    struct ast_category *cat = NULL;
00550 
00551    if (!table) {
00552       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00553       return NULL;
00554    }
00555 
00556    if (!(cfg = ast_config_new()))
00557       return NULL;
00558 
00559    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00560    newparam = va_arg(ap, const char *);
00561    newval = va_arg(ap, const char *);
00562    if (!newparam || !newval) {
00563       ast_log(LOG_WARNING,
00564             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00565       if (pgsqlConn) {
00566          PQfinish(pgsqlConn);
00567          pgsqlConn = NULL;
00568       }
00569       ast_config_destroy(cfg);
00570       return NULL;
00571    }
00572 
00573    initfield = ast_strdupa(newparam);
00574    if ((op = strchr(initfield, ' '))) {
00575       *op = '\0';
00576    }
00577 
00578    /* Create the first part of the query using the first parameter/value pairs we just extracted
00579       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00580 
00581    if (!strchr(newparam, ' '))
00582       op = " =";
00583    else
00584       op = "";
00585 
00586    ESCAPE_STRING(escapebuf, newval);
00587    if (pgresult) {
00588       ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00589       va_end(ap);
00590       ast_config_destroy(cfg);
00591       return NULL;
00592    }
00593 
00594    ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
00595    while ((newparam = va_arg(ap, const char *))) {
00596       newval = va_arg(ap, const char *);
00597       if (!strchr(newparam, ' '))
00598          op = " =";
00599       else
00600          op = "";
00601 
00602       ESCAPE_STRING(escapebuf, newval);
00603       if (pgresult) {
00604          ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00605          va_end(ap);
00606          ast_config_destroy(cfg);
00607          return NULL;
00608       }
00609 
00610       ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
00611    }
00612 
00613    if (initfield) {
00614       ast_str_append(&sql, 0, " ORDER BY %s", initfield);
00615    }
00616 
00617    va_end(ap);
00618 
00619    /* We now have our complete statement; Lets connect to the server and execute it. */
00620    ast_mutex_lock(&pgsql_lock);
00621 
00622    if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) {
00623       ast_mutex_unlock(&pgsql_lock);
00624       ast_config_destroy(cfg);
00625       return NULL;
00626    } else {
00627       ExecStatusType result_status = PQresultStatus(result);
00628       if (result_status != PGRES_COMMAND_OK
00629          && result_status != PGRES_TUPLES_OK
00630          && result_status != PGRES_NONFATAL_ERROR) {
00631          ast_log(LOG_WARNING,
00632                "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
00633          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00634          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00635                   PQresultErrorMessage(result), PQresStatus(result_status));
00636          PQclear(result);
00637          ast_mutex_unlock(&pgsql_lock);
00638          ast_config_destroy(cfg);
00639          return NULL;
00640       }
00641    }
00642 
00643    ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
00644 
00645    if ((num_rows = PQntuples(result)) > 0) {
00646       int numFields = PQnfields(result);
00647       int i = 0;
00648       int rowIndex = 0;
00649       char **fieldnames = NULL;
00650 
00651       ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
00652 
00653       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00654          PQclear(result);
00655          ast_mutex_unlock(&pgsql_lock);
00656          ast_config_destroy(cfg);
00657          return NULL;
00658       }
00659       for (i = 0; i < numFields; i++)
00660          fieldnames[i] = PQfname(result, i);
00661 
00662       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00663          var = NULL;
00664          if (!(cat = ast_category_new("","",99999)))
00665             continue;
00666          for (i = 0; i < numFields; i++) {
00667             stringp = PQgetvalue(result, rowIndex, i);
00668             while (stringp) {
00669                chunk = strsep(&stringp, ";");
00670                if (chunk && !ast_strlen_zero(ast_realtime_decode_chunk(ast_strip(chunk)))) {
00671                   if (initfield && !strcmp(initfield, fieldnames[i])) {
00672                      ast_category_rename(cat, chunk);
00673                   }
00674                   var = ast_variable_new(fieldnames[i], chunk, "");
00675                   ast_variable_append(cat, var);
00676                }
00677             }
00678          }
00679          ast_category_append(cfg, cat);
00680       }
00681       ast_free(fieldnames);
00682    } else {
00683       ast_debug(1, "PostgreSQL RealTime: Could not find any rows in table %s.\n", table);
00684    }
00685 
00686    PQclear(result);
00687    ast_mutex_unlock(&pgsql_lock);
00688 
00689    return cfg;
00690 }

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

Definition at line 421 of file res_config_pgsql.c.

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

00422 {
00423    PGresult *result = NULL;
00424    int num_rows = 0, pgresult;
00425    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00426    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
00427    char *stringp;
00428    char *chunk;
00429    char *op;
00430    const char *newparam, *newval;
00431    struct ast_variable *var = NULL, *prev = NULL;
00432 
00433    if (!tablename) {
00434       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00435       return NULL;
00436    }
00437 
00438    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00439    newparam = va_arg(ap, const char *);
00440    newval = va_arg(ap, const char *);
00441    if (!newparam || !newval) {
00442       ast_log(LOG_WARNING,
00443             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00444       if (pgsqlConn) {
00445          PQfinish(pgsqlConn);
00446          pgsqlConn = NULL;
00447       }
00448       return NULL;
00449    }
00450 
00451    /* Create the first part of the query using the first parameter/value pairs we just extracted
00452       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00453    op = strchr(newparam, ' ') ? "" : " =";
00454 
00455    ESCAPE_STRING(escapebuf, newval);
00456    if (pgresult) {
00457       ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00458       va_end(ap);
00459       return NULL;
00460    }
00461 
00462    ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
00463    while ((newparam = va_arg(ap, const char *))) {
00464       newval = va_arg(ap, const char *);
00465       if (!strchr(newparam, ' '))
00466          op = " =";
00467       else
00468          op = "";
00469 
00470       ESCAPE_STRING(escapebuf, newval);
00471       if (pgresult) {
00472          ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00473          va_end(ap);
00474          return NULL;
00475       }
00476 
00477       ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
00478    }
00479    va_end(ap);
00480 
00481    /* We now have our complete statement; Lets connect to the server and execute it. */
00482    ast_mutex_lock(&pgsql_lock);
00483 
00484         if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) {
00485       PQclear(result);
00486       ast_mutex_unlock(&pgsql_lock);
00487       return NULL;
00488         }
00489 
00490    ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
00491 
00492    if ((num_rows = PQntuples(result)) > 0) {
00493       int i = 0;
00494       int rowIndex = 0;
00495       int numFields = PQnfields(result);
00496       char **fieldnames = NULL;
00497 
00498       ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
00499 
00500       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00501          PQclear(result);
00502          ast_mutex_unlock(&pgsql_lock);
00503          return NULL;
00504       }
00505       for (i = 0; i < numFields; i++)
00506          fieldnames[i] = PQfname(result, i);
00507       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00508          for (i = 0; i < numFields; i++) {
00509             stringp = PQgetvalue(result, rowIndex, i);
00510             while (stringp) {
00511                chunk = strsep(&stringp, ";");
00512                if (chunk && !ast_strlen_zero(ast_realtime_decode_chunk(ast_strip(chunk)))) {
00513                   if (prev) {
00514                      prev->next = ast_variable_new(fieldnames[i], chunk, "");
00515                      if (prev->next) {
00516                         prev = prev->next;
00517                      }
00518                   } else {
00519                      prev = var = ast_variable_new(fieldnames[i], chunk, "");
00520                   }
00521                }
00522             }
00523          }
00524       }
00525       ast_free(fieldnames);
00526    } else {
00527       ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s@%s.\n", tablename, database);
00528    }
00529 
00530    PQclear(result);
00531    ast_mutex_unlock(&pgsql_lock);
00532 
00533    return var;
00534 }

static int reload ( void   )  [static]

Definition at line 1357 of file res_config_pgsql.c.

References parse_config().

01358 {
01359    parse_config(1);
01360 
01361    return 0;
01362 }

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

Definition at line 1157 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_exec(), pgsql_lock, 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.

01158 {
01159    struct columns *column;
01160    struct tables *table = find_table(database, tablename);
01161    char *elm;
01162    int type, size, res = 0;
01163 
01164    if (!table) {
01165       ast_log(LOG_WARNING, "Table %s not found in database.  This table should exist if you're using realtime.\n", tablename);
01166       return -1;
01167    }
01168 
01169    while ((elm = va_arg(ap, char *))) {
01170       type = va_arg(ap, require_type);
01171       size = va_arg(ap, int);
01172       AST_LIST_TRAVERSE(&table->columns, column, list) {
01173          if (strcmp(column->name, elm) == 0) {
01174             /* Char can hold anything, as long as it is large enough */
01175             if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0 || strcmp(column->type, "bpchar") == 0)) {
01176                if ((size > column->len) && column->len != -1) {
01177                   ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len);
01178                   res = -1;
01179                }
01180             } else if (strncmp(column->type, "int", 3) == 0) {
01181                int typesize = atoi(column->type + 3);
01182                /* Integers can hold only other integers */
01183                if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
01184                   type == RQ_INTEGER4 || type == RQ_UINTEGER4 ||
01185                   type == RQ_INTEGER3 || type == RQ_UINTEGER3 ||
01186                   type == RQ_UINTEGER2) && typesize == 2) {
01187                   ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
01188                   res = -1;
01189                } else if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
01190                   type == RQ_UINTEGER4) && typesize == 4) {
01191                   ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
01192                   res = -1;
01193                } else if (type == RQ_CHAR || type == RQ_DATETIME || type == RQ_FLOAT || type == RQ_DATE) {
01194                   ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n",
01195                      column->name,
01196                         type == RQ_CHAR ? "char" :
01197                         type == RQ_DATETIME ? "datetime" :
01198                         type == RQ_DATE ? "date" :
01199                         type == RQ_FLOAT ? "float" :
01200                         "a rather stiff drink ",
01201                      size, column->type);
01202                   res = -1;
01203                }
01204             } else if (strncmp(column->type, "float", 5) == 0) {
01205                if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
01206                   ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
01207                   res = -1;
01208                }
01209             } else if (strncmp(column->type, "timestamp", 9) == 0) {
01210                if (type != RQ_DATETIME && type != RQ_DATE) {
01211                   ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
01212                   res = -1;
01213                }
01214             } else { /* There are other types that no module implements yet */
01215                ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
01216                res = -1;
01217             }
01218             break;
01219          }
01220       }
01221 
01222       if (!column) {
01223          if (requirements == RQ_WARN) {
01224             ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size);
01225          } else {
01226             struct ast_str *sql = ast_str_create(100);
01227             char fieldtype[15];
01228             PGresult *result;
01229 
01230             if (requirements == RQ_CREATECHAR || type == RQ_CHAR) {
01231                /* Size is minimum length; make it at least 50% greater,
01232                 * just to be sure, because PostgreSQL doesn't support
01233                 * resizing columns. */
01234                snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)",
01235                   size < 15 ? size * 2 :
01236                   (size * 3 / 2 > 255) ? 255 : size * 3 / 2);
01237             } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) {
01238                snprintf(fieldtype, sizeof(fieldtype), "INT2");
01239             } else if (type == RQ_UINTEGER2 || type == RQ_INTEGER3 || type == RQ_UINTEGER3 || type == RQ_INTEGER4) {
01240                snprintf(fieldtype, sizeof(fieldtype), "INT4");
01241             } else if (type == RQ_UINTEGER4 || type == RQ_INTEGER8) {
01242                snprintf(fieldtype, sizeof(fieldtype), "INT8");
01243             } else if (type == RQ_UINTEGER8) {
01244                /* No such type on PostgreSQL */
01245                snprintf(fieldtype, sizeof(fieldtype), "CHAR(20)");
01246             } else if (type == RQ_FLOAT) {
01247                snprintf(fieldtype, sizeof(fieldtype), "FLOAT8");
01248             } else if (type == RQ_DATE) {
01249                snprintf(fieldtype, sizeof(fieldtype), "DATE");
01250             } else if (type == RQ_DATETIME) {
01251                snprintf(fieldtype, sizeof(fieldtype), "TIMESTAMP");
01252             } else {
01253                ast_log(LOG_ERROR, "Unrecognized request type %d\n", type);
01254                ast_free(sql);
01255                continue;
01256             }
01257             ast_str_set(&sql, 0, "ALTER TABLE %s ADD COLUMN %s %s", tablename, elm, fieldtype);
01258             ast_debug(1, "About to lock pgsql_lock (running alter on table '%s' to add column '%s')\n", tablename, elm);
01259 
01260             ast_mutex_lock(&pgsql_lock);
01261             ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm);
01262 
01263                  if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) {
01264                ast_mutex_unlock(&pgsql_lock);
01265                     return -1;
01266                  }
01267 
01268             ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename);
01269             if (PQresultStatus(result) != PGRES_COMMAND_OK) {
01270                ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
01271             }
01272             PQclear(result);
01273             ast_mutex_unlock(&pgsql_lock);
01274 
01275             ast_free(sql);
01276          }
01277       }
01278    }
01279    release_table(table);
01280    return res;
01281 }

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

Definition at line 932 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(), ESCAPE_STRING, escapebuf_buf, LOG_WARNING, pgsql_exec(), pgsql_lock, pgsql_reconnect(), sql_buf, and where_buf.

00933 {
00934    PGresult *result = NULL;
00935    Oid insertid;
00936    struct ast_str *buf = ast_str_thread_get(&escapebuf_buf, 256);
00937    struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256);
00938    struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256);
00939    int pgresult;
00940    const char *newparam, *newval;
00941 
00942    if (!table) {
00943       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00944       return -1;
00945    }
00946 
00947    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00948    newparam = va_arg(ap, const char *);
00949    newval = va_arg(ap, const char *);
00950    if (!newparam || !newval) {
00951       ast_log(LOG_WARNING,
00952             "PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
00953       if (pgsqlConn) {
00954          PQfinish(pgsqlConn);
00955          pgsqlConn = NULL;
00956       }
00957       return -1;
00958    }
00959 
00960    /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
00961    ast_mutex_lock(&pgsql_lock);
00962    if (!pgsql_reconnect(database)) {
00963       ast_mutex_unlock(&pgsql_lock);
00964       return -1;
00965    }
00966 
00967    /* Create the first part of the query using the first parameter/value pairs we just extracted
00968       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00969    ESCAPE_STRING(buf, newparam);
00970    ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
00971    ESCAPE_STRING(buf, newval);
00972    ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
00973    while ((newparam = va_arg(ap, const char *))) {
00974       newval = va_arg(ap, const char *);
00975       ESCAPE_STRING(buf, newparam);
00976       ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
00977       ESCAPE_STRING(buf, newval);
00978       ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
00979    }
00980    va_end(ap);
00981    ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
00982 
00983    ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1));
00984 
00985         if (pgsql_exec(database, table, ast_str_buffer(sql1), &result) != 0) {
00986       ast_mutex_unlock(&pgsql_lock);
00987            return -1;
00988         }
00989 
00990    insertid = PQoidValue(result);
00991    PQclear(result);
00992    ast_mutex_unlock(&pgsql_lock);
00993 
00994    ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid);
00995 
00996    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00997     * An integer greater than zero indicates the number of rows affected
00998     * Zero indicates that no records were updated
00999     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
01000     */
01001 
01002    if (insertid >= 0)
01003       return (int) insertid;
01004 
01005    return -1;
01006 }

static int unload_module ( void   )  [static]

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

01331 {
01332    struct tables *table;
01333    /* Acquire control before doing anything to the module itself. */
01334    ast_mutex_lock(&pgsql_lock);
01335 
01336    if (pgsqlConn) {
01337       PQfinish(pgsqlConn);
01338       pgsqlConn = NULL;
01339    }
01340    ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
01341    ast_config_engine_deregister(&pgsql_engine);
01342    ast_verb(1, "PostgreSQL RealTime unloaded.\n");
01343 
01344    /* Destroy cached table info */
01345    AST_LIST_LOCK(&psql_tables);
01346    while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) {
01347       destroy_table(table);
01348    }
01349    AST_LIST_UNLOCK(&psql_tables);
01350 
01351    /* Unlock so something else can destroy the lock. */
01352    ast_mutex_unlock(&pgsql_lock);
01353 
01354    return 0;
01355 }

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

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

01284 {
01285    struct tables *cur;
01286    ast_debug(2, "About to lock table cache list\n");
01287    AST_LIST_LOCK(&psql_tables);
01288    ast_debug(2, "About to traverse table cache list\n");
01289    AST_LIST_TRAVERSE_SAFE_BEGIN(&psql_tables, cur, list) {
01290       if (strcmp(cur->name, tablename) == 0) {
01291          ast_debug(2, "About to remove matching cache entry\n");
01292          AST_LIST_REMOVE_CURRENT(list);
01293          ast_debug(2, "About to destroy matching cache entry\n");
01294          destroy_table(cur);
01295          ast_debug(1, "Cache entry '%s@%s' destroyed\n", tablename, database);
01296          break;
01297       }
01298    }
01299    AST_LIST_TRAVERSE_SAFE_END
01300    AST_LIST_UNLOCK(&psql_tables);
01301    ast_debug(2, "About to return\n");
01302    return cur ? 0 : -1;
01303 }

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

Definition at line 823 of file res_config_pgsql.c.

References ast_debug, ast_free, ast_log(), 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_exec(), pgsql_lock, release_table, sql_buf, tables::table, and where_buf.

00824 {
00825    PGresult *result = NULL;
00826    int numrows = 0, pgresult, first = 1;
00827    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16);
00828    const char *newparam, *newval;
00829    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00830    struct ast_str *where = ast_str_thread_get(&where_buf, 100);
00831    struct tables *table;
00832 
00833    if (!tablename) {
00834       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00835       return -1;
00836    }
00837 
00838    if (!escapebuf || !sql || !where) {
00839       /* Memory error, already handled */
00840       return -1;
00841    }
00842 
00843    if (!(table = find_table(database, tablename))) {
00844       ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
00845       return -1;
00846    }
00847 
00848    ast_str_set(&sql, 0, "UPDATE %s SET ", tablename);
00849    ast_str_set(&where, 0, "WHERE");
00850 
00851    while ((newparam = va_arg(ap, const char *))) {
00852       if (!find_column(table, newparam)) {
00853          ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database);
00854          release_table(table);
00855          return -1;
00856       }
00857 
00858       newval = va_arg(ap, const char *);
00859       ESCAPE_STRING(escapebuf, newval);
00860       if (pgresult) {
00861          ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00862          release_table(table);
00863          ast_free(sql);
00864          return -1;
00865       }
00866       ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
00867       first = 0;
00868    }
00869 
00870    if (first) {
00871       ast_log(LOG_WARNING,
00872             "PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on.\n");
00873       if (pgsqlConn) {
00874          PQfinish(pgsqlConn);
00875          pgsqlConn = NULL;
00876       }
00877       release_table(table);
00878       return -1;
00879    }
00880 
00881    /* Now retrieve the columns to update */
00882    first = 1;
00883    while ((newparam = va_arg(ap, const char *))) {
00884       newval = va_arg(ap, const char *);
00885 
00886       /* If the column is not within the table, then skip it */
00887       if (!find_column(table, newparam)) {
00888          ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database);
00889          continue;
00890       }
00891 
00892       ESCAPE_STRING(escapebuf, newval);
00893       if (pgresult) {
00894          ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00895          release_table(table);
00896          ast_free(sql);
00897          return -1;
00898       }
00899 
00900       ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
00901    }
00902    release_table(table);
00903 
00904    ast_str_append(&sql, 0, " %s", ast_str_buffer(where));
00905 
00906    ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
00907 
00908    /* We now have our complete statement; connect to the server and execute it. */
00909         if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) {
00910       ast_mutex_unlock(&pgsql_lock);
00911            return -1;
00912         }
00913 
00914    numrows = atoi(PQcmdTuples(result));
00915    ast_mutex_unlock(&pgsql_lock);
00916 
00917    ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
00918 
00919    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00920     * An integer greater than zero indicates the number of rows affected
00921     * Zero indicates that no records were updated
00922     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00923     */
00924 
00925    if (numrows >= 0) {
00926       return (int) numrows;
00927    }
00928 
00929    return -1;
00930 }

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

Definition at line 692 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_NOTICE, LOG_WARNING, columns::name, pgsql_exec(), pgsql_lock, release_table, sql_buf, and tables::table.

00694 {
00695    PGresult *result = NULL;
00696    int numrows = 0, pgresult;
00697    const char *newparam, *newval;
00698    struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
00699    struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
00700    struct tables *table;
00701    struct columns *column = NULL;
00702 
00703    if (!tablename) {
00704       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00705       return -1;
00706    }
00707 
00708    if (!(table = find_table(database, tablename))) {
00709       ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
00710       return -1;
00711    }
00712 
00713    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00714    newparam = va_arg(ap, const char *);
00715    newval = va_arg(ap, const char *);
00716    if (!newparam || !newval) {
00717       ast_log(LOG_WARNING,
00718             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00719       if (pgsqlConn) {
00720          PQfinish(pgsqlConn);
00721          pgsqlConn = NULL;
00722       }
00723       release_table(table);
00724       return -1;
00725    }
00726 
00727    /* Check that the column exists in the table */
00728    AST_LIST_TRAVERSE(&table->columns, column, list) {
00729       if (strcmp(column->name, newparam) == 0) {
00730          break;
00731       }
00732    }
00733 
00734    if (!column) {
00735       ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
00736       release_table(table);
00737       return -1;
00738    }
00739 
00740    /* Create the first part of the query using the first parameter/value pairs we just extracted
00741       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00742 
00743    ESCAPE_STRING(escapebuf, newval);
00744    if (pgresult) {
00745       ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00746       va_end(ap);
00747       release_table(table);
00748       return -1;
00749    }
00750    ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));
00751 
00752    while ((newparam = va_arg(ap, const char *))) {
00753       newval = va_arg(ap, const char *);
00754 
00755       if (!find_column(table, newparam)) {
00756          ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
00757          continue;
00758       }
00759 
00760       ESCAPE_STRING(escapebuf, newval);
00761       if (pgresult) {
00762          ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
00763          va_end(ap);
00764          release_table(table);
00765          return -1;
00766       }
00767 
00768       ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
00769    }
00770    va_end(ap);
00771    release_table(table);
00772 
00773    ESCAPE_STRING(escapebuf, lookup);
00774    if (pgresult) {
00775       ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", lookup);
00776       va_end(ap);
00777       return -1;
00778    }
00779 
00780    ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(escapebuf));
00781 
00782    ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
00783 
00784    /* We now have our complete statement; Lets connect to the server and execute it. */
00785    ast_mutex_lock(&pgsql_lock);
00786 
00787    if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) {
00788       ast_mutex_unlock(&pgsql_lock);
00789       return -1;
00790    } else {
00791       ExecStatusType result_status = PQresultStatus(result);
00792       if (result_status != PGRES_COMMAND_OK
00793          && result_status != PGRES_TUPLES_OK
00794          && result_status != PGRES_NONFATAL_ERROR) {
00795          ast_log(LOG_WARNING,
00796                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00797          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00798          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00799                   PQresultErrorMessage(result), PQresStatus(result_status));
00800          PQclear(result);
00801          ast_mutex_unlock(&pgsql_lock);
00802          return -1;
00803       }
00804    }
00805 
00806    numrows = atoi(PQcmdTuples(result));
00807    ast_mutex_unlock(&pgsql_lock);
00808 
00809    ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
00810 
00811    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00812     * An integer greater than zero indicates the number of rows affected
00813     * Zero indicates that no records were updated
00814     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00815     */
00816 
00817    if (numrows >= 0)
00818       return (int) numrows;
00819 
00820    return -1;
00821 }


Variable Documentation

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

Definition at line 1634 of file res_config_pgsql.c.

Definition at line 1634 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 93 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

time_t connect_time = 0 [static]

Definition at line 84 of file res_config_pgsql.c.

char dbhost[MAX_DB_OPTION_SIZE] = "" [static]

char dbname[MAX_DB_OPTION_SIZE] = "" [static]

char dbpass[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 80 of file res_config_pgsql.c.

Referenced by parse_config(), and pgsql_reconnect().

int dbport = 5432 [static]

char dbsock[MAX_DB_OPTION_SIZE] = "" [static]

char dbuser[MAX_DB_OPTION_SIZE] = "" [static]

struct ast_threadstorage escapebuf_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_escapebuf_buf , .custom_init = NULL , } [static]

struct ast_threadstorage findtable_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_findtable_buf , .custom_init = NULL , } [static]

Definition at line 47 of file res_config_pgsql.c.

Referenced by find_table().

Definition at line 1305 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

ast_mutex_t pgsql_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 45 of file res_config_pgsql.c.

PGconn* pgsqlConn = NULL [static]

Definition at line 54 of file res_config_pgsql.c.

enum { ... } requirements [static]

Referenced by parse_config(), and require_pgsql().

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

Definition at line 50 of file res_config_pgsql.c.

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

Definition at line 46 of file res_config_pgsql.c.

int version [static]

Definition at line 55 of file res_config_pgsql.c.

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


Generated on Sat Feb 11 06:36:25 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6