Wed Oct 28 13:33:27 2009

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_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_DEFAULT , .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 }
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_MUTEX_INITIALIZER )
static PGconn * pgsqlConn = NULL
static 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

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

static void __unreg_module ( void   )  [static]

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

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

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

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

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

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_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, tables::table, and columns::type.

Referenced by cdr_handler(), handle_cli_realtime_pgsql_cache(), realtime_require_handler(), 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 1487 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.

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

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

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

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

static int load_module ( void   )  [static]

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

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

static int parse_config ( int  reload  )  [static]

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

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

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

Definition at line 1441 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().

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

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_strdupa, 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, strsep(), 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, strsep(), 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 1323 of file res_config_pgsql.c.

References parse_config().

01324 {
01325    parse_config(1);
01326 
01327    return 0;
01328 }

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

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

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

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

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

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

static int unload_module ( void   )  [static]

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

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

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

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

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

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

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

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

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_free, 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       ast_free(sql);
00682       return -1;
00683    } else {
00684       ExecStatusType result_status = PQresultStatus(result);
00685       if (result_status != PGRES_COMMAND_OK
00686          && result_status != PGRES_TUPLES_OK
00687          && result_status != PGRES_NONFATAL_ERROR) {
00688          ast_log(LOG_WARNING,
00689                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00690          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
00691          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00692                   PQresultErrorMessage(result), PQresStatus(result_status));
00693          ast_mutex_unlock(&pgsql_lock);
00694          ast_free(sql);
00695          return -1;
00696       }
00697    }
00698 
00699    numrows = atoi(PQcmdTuples(result));
00700    ast_mutex_unlock(&pgsql_lock);
00701    ast_free(sql);
00702 
00703    ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
00704 
00705    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00706     * An integer greater than zero indicates the number of rows affected
00707     * Zero indicates that no records were updated
00708     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00709     */
00710 
00711    if (numrows >= 0)
00712       return (int) numrows;
00713 
00714    return -1;
00715 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 } [static]

Definition at line 1599 of file res_config_pgsql.c.

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

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

Referenced by load_module(), and unload_module().

ast_mutex_t pgsql_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 44 of file res_config_pgsql.c.

PGconn* pgsqlConn = NULL [static]

Definition at line 52 of file res_config_pgsql.c.

enum { ... } requirements [static]

Referenced by parse_config(), and require_pgsql().

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

Definition at line 45 of file res_config_pgsql.c.

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]


Generated on Wed Oct 28 13:33:27 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6