Fri Jul 24 00:41:55 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"

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 MAX_DB_OPTION_SIZE   64
#define RES_CONFIG_PGSQL_CONF   "res_pgsql.conf"

Enumerations

enum  { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR }

Functions

static void __reg_module (void)
static void __unreg_module (void)
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 tablesfind_table (const char *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 *table, 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 update_pgsql (const char *database, const char *tablename, const char *keyfield, const char *lookup, va_list ap)

Variables

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


Detailed Description

PostgreSQL plugin for Asterisk RealTime Architecture.

Author:
Mark Spencer <markster@digium.com>

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

Definition in file res_config_pgsql.c.


Define Documentation

#define ESCAPE_STRING ( buffer,
stringname   ) 

Definition at line 645 of file res_config_pgsql.c.

Referenced by destroy_pgsql(), and store_pgsql().

#define MAX_DB_OPTION_SIZE   64

Definition at line 50 of file res_config_pgsql.c.

#define RES_CONFIG_PGSQL_CONF   "res_pgsql.conf"

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1420 of file res_config_pgsql.c.

static void __unreg_module ( void   )  [static]

Definition at line 1420 of file res_config_pgsql.c.

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

Definition at line 856 of file res_config_pgsql.c.

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

00859 {
00860    PGresult *result = NULL;
00861    long num_rows;
00862    struct ast_variable *new_v;
00863    struct ast_category *cur_cat = NULL;
00864    char sqlbuf[1024] = "";
00865    char *sql = sqlbuf;
00866    size_t sqlleft = sizeof(sqlbuf);
00867    char last[80] = "";
00868    int last_cat_metric = 0;
00869 
00870    last[0] = '\0';
00871 
00872    if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
00873       ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n");
00874       return NULL;
00875    }
00876 
00877    ast_build_string(&sql, &sqlleft, "SELECT category, var_name, var_val, cat_metric FROM %s ", table);
00878    ast_build_string(&sql, &sqlleft, "WHERE filename='%s' and commented=0", file);
00879    ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00880 
00881    ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", sqlbuf);
00882 
00883    /* We now have our complete statement; Lets connect to the server and execute it. */
00884    ast_mutex_lock(&pgsql_lock);
00885    if (!pgsql_reconnect(database)) {
00886       ast_mutex_unlock(&pgsql_lock);
00887       return NULL;
00888    }
00889 
00890    if (!(result = PQexec(pgsqlConn, sqlbuf))) {
00891       ast_log(LOG_WARNING,
00892             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00893       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
00894       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00895       ast_mutex_unlock(&pgsql_lock);
00896       return NULL;
00897    } else {
00898       ExecStatusType result_status = PQresultStatus(result);
00899       if (result_status != PGRES_COMMAND_OK
00900          && result_status != PGRES_TUPLES_OK
00901          && result_status != PGRES_NONFATAL_ERROR) {
00902          ast_log(LOG_WARNING,
00903                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00904          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
00905          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00906                   PQresultErrorMessage(result), PQresStatus(result_status));
00907          ast_mutex_unlock(&pgsql_lock);
00908          return NULL;
00909       }
00910    }
00911 
00912    if ((num_rows = PQntuples(result)) > 0) {
00913       int rowIndex = 0;
00914 
00915       ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows);
00916 
00917       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00918          char *field_category = PQgetvalue(result, rowIndex, 0);
00919          char *field_var_name = PQgetvalue(result, rowIndex, 1);
00920          char *field_var_val = PQgetvalue(result, rowIndex, 2);
00921          char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
00922          if (!strcmp(field_var_name, "#include")) {
00923             if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) {
00924                PQclear(result);
00925                ast_mutex_unlock(&pgsql_lock);
00926                return NULL;
00927             }
00928             continue;
00929          }
00930 
00931          if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
00932             cur_cat = ast_category_new(field_category, "", 99999);
00933             if (!cur_cat)
00934                break;
00935             strcpy(last, field_category);
00936             last_cat_metric = atoi(field_cat_metric);
00937             ast_category_append(cfg, cur_cat);
00938          }
00939          new_v = ast_variable_new(field_var_name, field_var_val, "");
00940          ast_variable_append(cur_cat, new_v);
00941       }
00942    } else {
00943       ast_log(LOG_WARNING,
00944             "PostgreSQL RealTime: Could not find config '%s' in database.\n", file);
00945    }
00946 
00947    PQclear(result);
00948    ast_mutex_unlock(&pgsql_lock);
00949 
00950    return cfg;
00951 }

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

Definition at line 755 of file res_config_pgsql.c.

References ast_debug, ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_str_append(), ast_str_create(), ast_str_set(), ast_strlen_zero(), ESCAPE_STRING, LOG_WARNING, pgsql_lock, pgsql_reconnect(), and ast_str::str.

00756 {
00757    PGresult *result = NULL;
00758    int numrows = 0;
00759    int pgresult;
00760    struct ast_str *sql = ast_str_create(256);
00761    struct ast_str *buf1 = ast_str_create(60), *buf2 = ast_str_create(60);
00762    const char *newparam, *newval;
00763 
00764    if (!table) {
00765       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00766       return -1;
00767    }
00768 
00769    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00770    /*newparam = va_arg(ap, const char *);
00771    newval = va_arg(ap, const char *);
00772    if (!newparam || !newval) {*/
00773    if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
00774       ast_log(LOG_WARNING,
00775             "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n");
00776       if (pgsqlConn) {
00777          PQfinish(pgsqlConn);
00778          pgsqlConn = NULL;
00779       };
00780       return -1;
00781    }
00782 
00783    /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
00784    ast_mutex_lock(&pgsql_lock);
00785    if (!pgsql_reconnect(database)) {
00786       ast_mutex_unlock(&pgsql_lock);
00787       return -1;
00788    }
00789 
00790 
00791    /* Create the first part of the query using the first parameter/value pairs we just extracted
00792       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00793 
00794    ESCAPE_STRING(buf1, keyfield);
00795    ESCAPE_STRING(buf2, lookup);
00796    ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, buf1->str, buf2->str);
00797    while ((newparam = va_arg(ap, const char *))) {
00798       newval = va_arg(ap, const char *);
00799       ESCAPE_STRING(buf1, newparam);
00800       ESCAPE_STRING(buf2, newval);
00801       ast_str_append(&sql, 0, " AND %s = '%s'", buf1->str, buf2->str);
00802    }
00803    va_end(ap);
00804 
00805    ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", sql->str);
00806 
00807    if (!(result = PQexec(pgsqlConn, sql->str))) {
00808       ast_log(LOG_WARNING,
00809             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00810       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
00811       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00812       ast_mutex_unlock(&pgsql_lock);
00813       ast_free(buf1);
00814       ast_free(buf2);
00815       ast_free(sql);
00816       return -1;
00817    } else {
00818       ExecStatusType result_status = PQresultStatus(result);
00819       if (result_status != PGRES_COMMAND_OK
00820          && result_status != PGRES_TUPLES_OK
00821          && result_status != PGRES_NONFATAL_ERROR) {
00822          ast_log(LOG_WARNING,
00823                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00824          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
00825          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00826                   PQresultErrorMessage(result), PQresStatus(result_status));
00827          ast_mutex_unlock(&pgsql_lock);
00828          ast_free(buf1);
00829          ast_free(buf2);
00830          ast_free(sql);
00831          return -1;
00832       }
00833    }
00834 
00835    numrows = atoi(PQcmdTuples(result));
00836    ast_mutex_unlock(&pgsql_lock);
00837    ast_free(buf1);
00838    ast_free(buf2);
00839    ast_free(sql);
00840 
00841    ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table);
00842 
00843    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00844     * An integer greater than zero indicates the number of rows affected
00845     * Zero indicates that no records were updated
00846     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00847     */
00848 
00849    if (numrows >= 0)
00850       return (int) numrows;
00851 
00852    return -1;
00853 }

static void destroy_table ( struct tables table  )  [static]

Definition at line 90 of file res_config_pgsql.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), columns::list, and table.

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

00091 {
00092    struct columns *column;
00093    ast_mutex_lock(&table->lock);
00094    while ((column = AST_LIST_REMOVE_HEAD(&table->columns, list))) {
00095       ast_free(column);
00096    }
00097    ast_mutex_unlock(&table->lock);
00098    ast_mutex_destroy(&table->lock);
00099    ast_free(table);
00100 }

static struct tables* find_table ( const char *  tablename  )  [static]

Definition at line 102 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_mutex_init(), ast_mutex_lock(), ast_str_create(), ast_str_set(), ast_strlen_zero(), ast_verb, destroy_table(), columns::list, LOG_ERROR, ast_str::str, and table.

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

00103 {
00104    struct columns *column;
00105    struct tables *table;
00106    struct ast_str *sql = ast_str_create(330);
00107    char *pgerror;
00108    PGresult *result;
00109    char *fname, *ftype, *flen, *fnotnull, *fdef;
00110    int i, rows;
00111 
00112    AST_LIST_LOCK(&psql_tables);
00113    AST_LIST_TRAVERSE(&psql_tables, table, list) {
00114       if (!strcasecmp(table->name, tablename)) {
00115          ast_debug(1, "Found table in cache; now locking\n");
00116          ast_mutex_lock(&table->lock);
00117          ast_debug(1, "Lock cached table; now returning\n");
00118          AST_LIST_UNLOCK(&psql_tables);
00119          return table;
00120       }
00121    }
00122 
00123    ast_debug(1, "Table '%s' not found in cache, querying now\n", tablename);
00124 
00125    /* Not found, scan the table */
00126    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", tablename);
00127    result = PQexec(pgsqlConn, sql->str);
00128    ast_debug(1, "Query of table structure complete.  Now retrieving results.\n");
00129    if (PQresultStatus(result) != PGRES_TUPLES_OK) {
00130       pgerror = PQresultErrorMessage(result);
00131       ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
00132       PQclear(result);
00133       AST_LIST_UNLOCK(&psql_tables);
00134       return NULL;
00135    }
00136 
00137    if (!(table = ast_calloc(1, sizeof(*table) + strlen(tablename) + 1))) {
00138       ast_log(LOG_ERROR, "Unable to allocate memory for new table structure\n");
00139       AST_LIST_UNLOCK(&psql_tables);
00140       return NULL;
00141    }
00142    strcpy(table->name, tablename); /* SAFE */
00143    ast_mutex_init(&table->lock);
00144    AST_LIST_HEAD_INIT_NOLOCK(&table->columns);
00145    
00146    rows = PQntuples(result);
00147    for (i = 0; i < rows; i++) {
00148       fname = PQgetvalue(result, i, 0);
00149       ftype = PQgetvalue(result, i, 1);
00150       flen = PQgetvalue(result, i, 2);
00151       fnotnull = PQgetvalue(result, i, 3);
00152       fdef = PQgetvalue(result, i, 4);
00153       ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
00154 
00155       if (!(column = ast_calloc(1, sizeof(*column) + strlen(fname) + strlen(ftype) + 2))) {
00156          ast_log(LOG_ERROR, "Unable to allocate column element for %s, %s\n", tablename, fname);
00157          destroy_table(table);
00158          AST_LIST_UNLOCK(&psql_tables);
00159          return NULL;
00160       }
00161 
00162       if (strcmp(flen, "-1") == 0) {
00163          /* Some types, like chars, have the length stored in a different field */
00164          flen = PQgetvalue(result, i, 5);
00165          sscanf(flen, "%d", &column->len);
00166          column->len -= 4;
00167       } else {
00168          sscanf(flen, "%d", &column->len);
00169       }
00170       column->name = (char *)column + sizeof(*column);
00171       column->type = (char *)column + sizeof(*column) + strlen(fname) + 1;
00172       strcpy(column->name, fname);
00173       strcpy(column->type, ftype);
00174       if (*fnotnull == 't') {
00175          column->notnull = 1;
00176       } else {
00177          column->notnull = 0;
00178       }
00179       if (!ast_strlen_zero(fdef)) {
00180          column->hasdefault = 1;
00181       } else {
00182          column->hasdefault = 0;
00183       }
00184       AST_LIST_INSERT_TAIL(&table->columns, column, list);
00185    }
00186    PQclear(result);
00187 
00188    AST_LIST_INSERT_TAIL(&psql_tables, table, list);
00189    ast_mutex_lock(&table->lock);
00190    AST_LIST_UNLOCK(&psql_tables);
00191    return table;
00192 }

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

Definition at line 1308 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_mutex_unlock(), ast_strdup, CLI_GENERATE, CLI_INIT, tables::columns, ast_cli_entry::command, ast_cli_args::fd, find_table(), columns::len, columns::list, tables::lock, ast_cli_args::n, columns::name, tables::name, columns::notnull, columns::type, ast_cli_entry::usage, and ast_cli_args::word.

01309 {
01310    struct tables *cur;
01311    int l, which;
01312    char *ret = NULL;
01313 
01314    switch (cmd) {
01315    case CLI_INIT:
01316       e->command = "realtime pgsql cache";
01317       e->usage =
01318          "Usage: realtime pgsql cache [<table>]\n"
01319          "       Shows table cache for the PostgreSQL RealTime driver\n";
01320       return NULL;
01321    case CLI_GENERATE:
01322       if (a->argc != 3) {
01323          return NULL;
01324       }
01325       l = strlen(a->word);
01326       which = 0;
01327       AST_LIST_LOCK(&psql_tables);
01328       AST_LIST_TRAVERSE(&psql_tables, cur, list) {
01329          if (!strncasecmp(a->word, cur->name, l) && ++which > a->n) {
01330             ret = ast_strdup(cur->name);
01331             break;
01332          }
01333       }
01334       AST_LIST_UNLOCK(&psql_tables);
01335       return ret;
01336    }
01337 
01338    if (a->argc == 3) {
01339       /* List of tables */
01340       AST_LIST_LOCK(&psql_tables);
01341       AST_LIST_TRAVERSE(&psql_tables, cur, list) {
01342          ast_cli(a->fd, "%s\n", cur->name);
01343       }
01344       AST_LIST_UNLOCK(&psql_tables);
01345    } else if (a->argc == 4) {
01346       /* List of columns */
01347       if ((cur = find_table(a->argv[3]))) {
01348          struct columns *col;
01349          ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[3]);
01350          ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable");
01351          AST_LIST_TRAVERSE(&cur->columns, col, list) {
01352             ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : "");
01353          }
01354          ast_mutex_unlock(&cur->lock);
01355       } else {
01356          ast_cli(a->fd, "No such table '%s'\n", a->argv[3]);
01357       }
01358    }
01359    return 0;
01360 }

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

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

01363 {
01364    char status[256], credentials[100] = "";
01365    int ctimesec = time(NULL) - connect_time;
01366 
01367    switch (cmd) {
01368    case CLI_INIT:
01369       e->command = "realtime pgsql status";
01370       e->usage =
01371          "Usage: realtime pgsql status\n"
01372          "       Shows connection information for the PostgreSQL RealTime driver\n";
01373       return NULL;
01374    case CLI_GENERATE:
01375       return NULL;
01376    }
01377 
01378    if (a->argc != 3)
01379       return CLI_SHOWUSAGE;
01380 
01381    if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
01382       if (!ast_strlen_zero(dbhost))
01383          snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport);
01384       else if (!ast_strlen_zero(dbsock))
01385          snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock);
01386       else
01387          snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost);
01388 
01389       if (!ast_strlen_zero(dbuser))
01390          snprintf(credentials, sizeof(credentials), " with username %s", dbuser);
01391 
01392       if (ctimesec > 31536000)
01393          ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01394                status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400,
01395                (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
01396       else if (ctimesec > 86400)
01397          ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
01398                credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60,
01399                ctimesec % 60);
01400       else if (ctimesec > 3600)
01401          ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials,
01402                ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60);
01403       else if (ctimesec > 60)
01404          ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60,
01405                ctimesec % 60);
01406       else
01407          ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
01408 
01409       return CLI_SUCCESS;
01410    } else {
01411       return CLI_FAILURE;
01412    }
01413 }

static int load_module ( void   )  [static]

Definition at line 1108 of file res_config_pgsql.c.

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

01109 {
01110    if(!parse_config(0))
01111       return AST_MODULE_LOAD_DECLINE;
01112 
01113    ast_config_engine_register(&pgsql_engine);
01114    ast_verb(1, "PostgreSQL RealTime driver loaded.\n");
01115    ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
01116 
01117    return 0;
01118 }

static int parse_config ( int  reload  )  [static]

Definition at line 1154 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_flags, 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.

01155 {
01156    struct ast_config *config;
01157    const char *s;
01158    struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01159 
01160    if ((config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
01161       return 0;
01162 
01163    if (!config) {
01164       ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF);
01165       return 0;
01166    }
01167 
01168    ast_mutex_lock(&pgsql_lock);
01169 
01170    if (pgsqlConn) {
01171       PQfinish(pgsqlConn);
01172       pgsqlConn = NULL;
01173    }
01174 
01175    if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
01176       ast_log(LOG_WARNING,
01177             "PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n");
01178       strcpy(dbuser, "asterisk");
01179    } else {
01180       ast_copy_string(dbuser, s, sizeof(dbuser));
01181    }
01182 
01183    if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
01184       ast_log(LOG_WARNING,
01185             "PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n");
01186       strcpy(dbpass, "asterisk");
01187    } else {
01188       ast_copy_string(dbpass, s, sizeof(dbpass));
01189    }
01190 
01191    if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
01192       ast_log(LOG_WARNING,
01193             "PostgreSQL RealTime: No database host found, using localhost via socket.\n");
01194       dbhost[0] = '\0';
01195    } else {
01196       ast_copy_string(dbhost, s, sizeof(dbhost));
01197    }
01198 
01199    if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
01200       ast_log(LOG_WARNING,
01201             "PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n");
01202       strcpy(dbname, "asterisk");
01203    } else {
01204       ast_copy_string(dbname, s, sizeof(dbname));
01205    }
01206 
01207    if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
01208       ast_log(LOG_WARNING,
01209             "PostgreSQL RealTime: No database port found, using 5432 as default.\n");
01210       dbport = 5432;
01211    } else {
01212       dbport = atoi(s);
01213    }
01214 
01215    if (!ast_strlen_zero(dbhost)) {
01216       /* No socket needed */
01217    } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
01218       ast_log(LOG_WARNING,
01219             "PostgreSQL RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
01220       strcpy(dbsock, "/tmp/pgsql.sock");
01221    } else {
01222       ast_copy_string(dbsock, s, sizeof(dbsock));
01223    }
01224 
01225    if (!(s = ast_variable_retrieve(config, "general", "requirements"))) {
01226       ast_log(LOG_WARNING,
01227             "PostgreSQL RealTime: no requirements setting found, using 'warn' as default.\n");
01228       requirements = RQ_WARN;
01229    } else if (!strcasecmp(s, "createclose")) {
01230       requirements = RQ_CREATECLOSE;
01231    } else if (!strcasecmp(s, "createchar")) {
01232       requirements = RQ_CREATECHAR;
01233    }
01234 
01235    ast_config_destroy(config);
01236 
01237    if (option_debug) {
01238       if (!ast_strlen_zero(dbhost)) {
01239          ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost);
01240          ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport);
01241       } else {
01242          ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock);
01243       }
01244       ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser);
01245       ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass);
01246       ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname);
01247    }
01248 
01249    if (!pgsql_reconnect(NULL)) {
01250       ast_log(LOG_WARNING,
01251             "PostgreSQL RealTime: Couldn't establish connection. Check debug.\n");
01252       ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn));
01253    }
01254 
01255    ast_verb(2, "PostgreSQL RealTime reloaded.\n");
01256 
01257    /* Done reloading. Release lock so others can now use driver. */
01258    ast_mutex_unlock(&pgsql_lock);
01259 
01260    return 1;
01261 }

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

Definition at line 1263 of file res_config_pgsql.c.

References ast_copy_string(), ast_debug, ast_free, ast_log(), ast_str_append(), ast_str_create(), ast_str_set(), 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(), and update_pgsql().

01264 {
01265    char my_database[50];
01266 
01267    ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
01268 
01269    /* mutex lock should have been locked before calling this function. */
01270 
01271    if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
01272       PQfinish(pgsqlConn);
01273       pgsqlConn = NULL;
01274    }
01275 
01276    /* DB password can legitimately be 0-length */
01277    if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) {
01278       struct ast_str *connInfo = ast_str_create(32);
01279 
01280       ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s",
01281          dbhost, dbport, my_database, dbuser);
01282       if (!ast_strlen_zero(dbpass))
01283          ast_str_append(&connInfo, 0, " password=%s", dbpass);
01284 
01285       ast_debug(1, "%u connInfo=%s\n", (unsigned int)connInfo->len, connInfo->str);
01286       pgsqlConn = PQconnectdb(connInfo->str);
01287       ast_debug(1, "%u connInfo=%s\n", (unsigned int)connInfo->len, connInfo->str);
01288       ast_free(connInfo);
01289       connInfo = NULL;
01290 
01291       ast_debug(1, "pgsqlConn=%p\n", pgsqlConn);
01292       if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
01293          ast_debug(1, "PostgreSQL RealTime: Successfully connected to database.\n");
01294          connect_time = time(NULL);
01295          return 1;
01296       } else {
01297          ast_log(LOG_ERROR,
01298                "PostgreSQL RealTime: Failed to connect database %s on %s: %s\n",
01299                dbname, dbhost, PQresultErrorMessage(NULL));
01300          return 0;
01301       }
01302    } else {
01303       ast_debug(1, "PostgreSQL RealTime: One or more of the parameters in the config does not pass our validity checks.\n");
01304       return 1;
01305    }
01306 }

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

Definition at line 330 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_strdupa, ast_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new(), LOG_ERROR, LOG_WARNING, pgsql_lock, pgsql_reconnect(), strsep(), and var.

00331 {
00332    PGresult *result = NULL;
00333    int num_rows = 0, pgerror;
00334    char sql[256], escapebuf[513];
00335    const char *initfield = NULL;
00336    char *stringp;
00337    char *chunk;
00338    char *op;
00339    const char *newparam, *newval;
00340    struct ast_variable *var = NULL;
00341    struct ast_config *cfg = NULL;
00342    struct ast_category *cat = NULL;
00343 
00344    if (!table) {
00345       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00346       return NULL;
00347    }
00348 
00349    if (!(cfg = ast_config_new()))
00350       return NULL;
00351 
00352    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00353    newparam = va_arg(ap, const char *);
00354    newval = va_arg(ap, const char *);
00355    if (!newparam || !newval) {
00356       ast_log(LOG_WARNING,
00357             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00358       if (pgsqlConn) {
00359          PQfinish(pgsqlConn);
00360          pgsqlConn = NULL;
00361       };
00362       return NULL;
00363    }
00364 
00365    initfield = ast_strdupa(newparam);
00366    if ((op = strchr(initfield, ' '))) {
00367       *op = '\0';
00368    }
00369 
00370    /* Create the first part of the query using the first parameter/value pairs we just extracted
00371       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00372 
00373    if (!strchr(newparam, ' '))
00374       op = " =";
00375    else
00376       op = "";
00377 
00378    PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00379    if (pgerror) {
00380       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00381       va_end(ap);
00382       return NULL;
00383    }
00384 
00385    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
00386           escapebuf);
00387    while ((newparam = va_arg(ap, const char *))) {
00388       newval = va_arg(ap, const char *);
00389       if (!strchr(newparam, ' '))
00390          op = " =";
00391       else
00392          op = "";
00393 
00394       PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00395       if (pgerror) {
00396          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00397          va_end(ap);
00398          return NULL;
00399       }
00400 
00401       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
00402              op, escapebuf);
00403    }
00404 
00405    if (initfield) {
00406       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00407    }
00408 
00409    va_end(ap);
00410 
00411    /* We now have our complete statement; Lets connect to the server and execute it. */
00412    ast_mutex_lock(&pgsql_lock);
00413    if (!pgsql_reconnect(database)) {
00414       ast_mutex_unlock(&pgsql_lock);
00415       return NULL;
00416    }
00417 
00418    if (!(result = PQexec(pgsqlConn, sql))) {
00419       ast_log(LOG_WARNING,
00420             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00421       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
00422       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00423       ast_mutex_unlock(&pgsql_lock);
00424       return NULL;
00425    } else {
00426       ExecStatusType result_status = PQresultStatus(result);
00427       if (result_status != PGRES_COMMAND_OK
00428          && result_status != PGRES_TUPLES_OK
00429          && result_status != PGRES_NONFATAL_ERROR) {
00430          ast_log(LOG_WARNING,
00431                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00432          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
00433          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00434                   PQresultErrorMessage(result), PQresStatus(result_status));
00435          ast_mutex_unlock(&pgsql_lock);
00436          return NULL;
00437       }
00438    }
00439 
00440    ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql);
00441 
00442    if ((num_rows = PQntuples(result)) > 0) {
00443       int numFields = PQnfields(result);
00444       int i = 0;
00445       int rowIndex = 0;
00446       char **fieldnames = NULL;
00447 
00448       ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
00449 
00450       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00451          ast_mutex_unlock(&pgsql_lock);
00452          PQclear(result);
00453          return NULL;
00454       }
00455       for (i = 0; i < numFields; i++)
00456          fieldnames[i] = PQfname(result, i);
00457 
00458       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00459          var = NULL;
00460          if (!(cat = ast_category_new("","",99999)))
00461             continue;
00462          for (i = 0; i < numFields; i++) {
00463             stringp = PQgetvalue(result, rowIndex, i);
00464             while (stringp) {
00465                chunk = strsep(&stringp, ";");
00466                if (!ast_strlen_zero(ast_strip(chunk))) {
00467                   if (initfield && !strcmp(initfield, fieldnames[i])) {
00468                      ast_category_rename(cat, chunk);
00469                   }
00470                   var = ast_variable_new(fieldnames[i], chunk, "");
00471                   ast_variable_append(cat, var);
00472                }
00473             }
00474          }
00475          ast_category_append(cfg, cat);
00476       }
00477       ast_free(fieldnames);
00478    } else {
00479       ast_log(LOG_WARNING,
00480             "PostgreSQL RealTime: Could not find any rows in table %s.\n", table);
00481    }
00482 
00483    ast_mutex_unlock(&pgsql_lock);
00484    PQclear(result);
00485 
00486    return cfg;
00487 }

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

Definition at line 194 of file res_config_pgsql.c.

References ast_calloc, ast_debug, ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strip(), ast_strlen_zero(), ast_variable_new(), LOG_ERROR, LOG_WARNING, ast_variable::next, pgsql_lock, pgsql_reconnect(), strsep(), and var.

00195 {
00196    PGresult *result = NULL;
00197    int num_rows = 0, pgerror;
00198    char sql[256], escapebuf[513];
00199    char *stringp;
00200    char *chunk;
00201    char *op;
00202    const char *newparam, *newval;
00203    struct ast_variable *var = NULL, *prev = NULL;
00204 
00205    if (!table) {
00206       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00207       return NULL;
00208    }
00209 
00210    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00211    newparam = va_arg(ap, const char *);
00212    newval = va_arg(ap, const char *);
00213    if (!newparam || !newval) {
00214       ast_log(LOG_WARNING,
00215             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00216       if (pgsqlConn) {
00217          PQfinish(pgsqlConn);
00218          pgsqlConn = NULL;
00219       };
00220       return NULL;
00221    }
00222 
00223    /* Create the first part of the query using the first parameter/value pairs we just extracted
00224       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00225    op = strchr(newparam, ' ') ? "" : " =";
00226 
00227    PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00228    if (pgerror) {
00229       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00230       va_end(ap);
00231       return NULL;
00232    }
00233 
00234    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
00235           escapebuf);
00236    while ((newparam = va_arg(ap, const char *))) {
00237       newval = va_arg(ap, const char *);
00238       if (!strchr(newparam, ' '))
00239          op = " =";
00240       else
00241          op = "";
00242 
00243       PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00244       if (pgerror) {
00245          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00246          va_end(ap);
00247          return NULL;
00248       }
00249 
00250       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
00251              op, escapebuf);
00252    }
00253    va_end(ap);
00254 
00255    /* We now have our complete statement; Lets connect to the server and execute it. */
00256    ast_mutex_lock(&pgsql_lock);
00257    if (!pgsql_reconnect(database)) {
00258       ast_mutex_unlock(&pgsql_lock);
00259       return NULL;
00260    }
00261 
00262    if (!(result = PQexec(pgsqlConn, sql))) {
00263       ast_log(LOG_WARNING,
00264             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00265       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
00266       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00267       ast_mutex_unlock(&pgsql_lock);
00268       return NULL;
00269    } else {
00270       ExecStatusType result_status = PQresultStatus(result);
00271       if (result_status != PGRES_COMMAND_OK
00272          && result_status != PGRES_TUPLES_OK
00273          && result_status != PGRES_NONFATAL_ERROR) {
00274          ast_log(LOG_WARNING,
00275                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00276          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
00277          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00278                   PQresultErrorMessage(result), PQresStatus(result_status));
00279          ast_mutex_unlock(&pgsql_lock);
00280          return NULL;
00281       }
00282    }
00283 
00284    ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql);
00285 
00286    if ((num_rows = PQntuples(result)) > 0) {
00287       int i = 0;
00288       int rowIndex = 0;
00289       int numFields = PQnfields(result);
00290       char **fieldnames = NULL;
00291 
00292       ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);
00293 
00294       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00295          ast_mutex_unlock(&pgsql_lock);
00296          PQclear(result);
00297          return NULL;
00298       }
00299       for (i = 0; i < numFields; i++)
00300          fieldnames[i] = PQfname(result, i);
00301       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00302          for (i = 0; i < numFields; i++) {
00303             stringp = PQgetvalue(result, rowIndex, i);
00304             while (stringp) {
00305                chunk = strsep(&stringp, ";");
00306                if (!ast_strlen_zero(ast_strip(chunk))) {
00307                   if (prev) {
00308                      prev->next = ast_variable_new(fieldnames[i], chunk, "");
00309                      if (prev->next) {
00310                         prev = prev->next;
00311                      }
00312                   } else {
00313                      prev = var = ast_variable_new(fieldnames[i], chunk, "");
00314                   }
00315                }
00316             }
00317          }
00318       }
00319       ast_free(fieldnames);
00320    } else {
00321       ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s.\n", table);
00322    }
00323 
00324    ast_mutex_unlock(&pgsql_lock);
00325    PQclear(result);
00326 
00327    return var;
00328 }

static int reload ( void   )  [static]

Definition at line 1147 of file res_config_pgsql.c.

References parse_config().

01148 {
01149    parse_config(1);
01150 
01151    return 0;
01152 }

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

Definition at line 953 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_create(), ast_str_set(), find_table(), columns::len, columns::list, LOG_ERROR, LOG_WARNING, columns::name, pgsql_lock, pgsql_reconnect(), 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, columns::size, ast_str::str, table, and columns::type.

00954 {
00955    struct columns *column;
00956    struct tables *table = find_table(tablename);
00957    char *elm;
00958    int type, size, res = 0;
00959 
00960    if (!table) {
00961       ast_log(LOG_WARNING, "Table %s not found in database.  This table should exist if you're using realtime.\n", tablename);
00962       return -1;
00963    }
00964 
00965    while ((elm = va_arg(ap, char *))) {
00966       type = va_arg(ap, require_type);
00967       size = va_arg(ap, int);
00968       AST_LIST_TRAVERSE(&table->columns, column, list) {
00969          if (strcmp(column->name, elm) == 0) {
00970             /* Char can hold anything, as long as it is large enough */
00971             if ((strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0 || strcmp(column->type, "bpchar") == 0)) {
00972                if ((size > column->len) && column->len != -1) {
00973                   ast_log(LOG_WARNING, "Column '%s' should be at least %d long, but is only %d long.\n", column->name, size, column->len);
00974                   res = -1;
00975                }
00976             } else if (strncmp(column->type, "int", 3) == 0) {
00977                int typesize = atoi(column->type + 3);
00978                /* Integers can hold only other integers */
00979                if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
00980                   type == RQ_INTEGER4 || type == RQ_UINTEGER4 ||
00981                   type == RQ_INTEGER3 || type == RQ_UINTEGER3 ||
00982                   type == RQ_UINTEGER2) && typesize == 2) {
00983                   ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
00984                   res = -1;
00985                } else if ((type == RQ_INTEGER8 || type == RQ_UINTEGER8 ||
00986                   type == RQ_UINTEGER4) && typesize == 4) {
00987                   ast_log(LOG_WARNING, "Column '%s' may not be large enough for the required data length: %d\n", column->name, size);
00988                   res = -1;
00989                } else if (type == RQ_CHAR || type == RQ_DATETIME || type == RQ_FLOAT || type == RQ_DATE) {
00990                   ast_log(LOG_WARNING, "Column '%s' is of the incorrect type: (need %s(%d) but saw %s)\n",
00991                      column->name,
00992                         type == RQ_CHAR ? "char" :
00993                         type == RQ_DATETIME ? "datetime" :
00994                         type == RQ_DATE ? "date" :
00995                         type == RQ_FLOAT ? "float" :
00996                         "a rather stiff drink ",
00997                      size, column->type);
00998                   res = -1;
00999                }
01000             } else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
01001                ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
01002                res = -1;
01003             } else { /* There are other types that no module implements yet */
01004                ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
01005                res = -1;
01006             }
01007             break;
01008          }
01009       }
01010 
01011       if (!column) {
01012          if (requirements == RQ_WARN) {
01013             ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size);
01014          } else {
01015             struct ast_str *sql = ast_str_create(100);
01016             char fieldtype[15];
01017             PGresult *result;
01018 
01019             if (requirements == RQ_CREATECHAR || type == RQ_CHAR) {
01020                /* Size is minimum length; make it at least 50% greater,
01021                 * just to be sure, because PostgreSQL doesn't support
01022                 * resizing columns. */
01023                snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)",
01024                   size < 15 ? size * 2 :
01025                   (size * 3 / 2 > 255) ? 255 : size * 3 / 2);
01026             } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) {
01027                snprintf(fieldtype, sizeof(fieldtype), "INT2");
01028             } else if (type == RQ_UINTEGER2 || type == RQ_INTEGER3 || type == RQ_UINTEGER3 || type == RQ_INTEGER4) {
01029                snprintf(fieldtype, sizeof(fieldtype), "INT4");
01030             } else if (type == RQ_UINTEGER4 || type == RQ_INTEGER8) {
01031                snprintf(fieldtype, sizeof(fieldtype), "INT8");
01032             } else if (type == RQ_UINTEGER8) {
01033                /* No such type on PostgreSQL */
01034                snprintf(fieldtype, sizeof(fieldtype), "CHAR(20)");
01035             } else if (type == RQ_FLOAT) {
01036                snprintf(fieldtype, sizeof(fieldtype), "FLOAT8");
01037             } else if (type == RQ_DATE) {
01038                snprintf(fieldtype, sizeof(fieldtype), "DATE");
01039             } else if (type == RQ_DATETIME) {
01040                snprintf(fieldtype, sizeof(fieldtype), "TIMESTAMP");
01041             } else {
01042                ast_log(LOG_ERROR, "Unrecognized request type %d\n", type);
01043                ast_free(sql);
01044                continue;
01045             }
01046             ast_str_set(&sql, 0, "ALTER TABLE %s ADD COLUMN %s %s", tablename, elm, fieldtype);
01047             ast_debug(1, "About to lock pgsql_lock (running alter on table '%s' to add column '%s')\n", tablename, elm);
01048 
01049             ast_mutex_lock(&pgsql_lock);
01050             if (!pgsql_reconnect(database)) {
01051                ast_mutex_unlock(&pgsql_lock);
01052                ast_log(LOG_ERROR, "Unable to add column: %s\n", sql->str);
01053                ast_free(sql);
01054                continue;
01055             }
01056 
01057             ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm);
01058             result = PQexec(pgsqlConn, sql->str);
01059             ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename);
01060             if (PQresultStatus(result) != PGRES_COMMAND_OK) {
01061                ast_log(LOG_ERROR, "Unable to add column: %s\n", sql->str);
01062             }
01063             PQclear(result);
01064             ast_mutex_unlock(&pgsql_lock);
01065 
01066             ast_free(sql);
01067          }
01068       }
01069    }
01070    ast_mutex_unlock(&table->lock);
01071    return res;
01072 }

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

Definition at line 654 of file res_config_pgsql.c.

References ast_debug, ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_str_append(), ast_str_create(), ast_str_set(), buf, ESCAPE_STRING, LOG_WARNING, pgsql_lock, pgsql_reconnect(), and ast_str::str.

00655 {
00656    PGresult *result = NULL;
00657    Oid insertid;
00658    struct ast_str *buf = ast_str_create(256);
00659    struct ast_str *sql1 = ast_str_create(256);
00660    struct ast_str *sql2 = ast_str_create(256);
00661    int pgresult;
00662    const char *newparam, *newval;
00663 
00664    if (!table) {
00665       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00666       return -1;
00667    }
00668 
00669    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00670    newparam = va_arg(ap, const char *);
00671    newval = va_arg(ap, const char *);
00672    if (!newparam || !newval) {
00673       ast_log(LOG_WARNING,
00674             "PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
00675       if (pgsqlConn) {
00676          PQfinish(pgsqlConn);
00677          pgsqlConn = NULL;
00678       }
00679       return -1;
00680    }
00681 
00682    /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
00683    ast_mutex_lock(&pgsql_lock);
00684    if (!pgsql_reconnect(database)) {
00685       ast_mutex_unlock(&pgsql_lock);
00686       return -1;
00687    }
00688 
00689    /* Create the first part of the query using the first parameter/value pairs we just extracted
00690       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00691    ESCAPE_STRING(buf, newparam);
00692    ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, buf->str);
00693    ESCAPE_STRING(buf, newval);
00694    ast_str_set(&sql2, 0, ") VALUES ('%s'", buf->str);
00695    while ((newparam = va_arg(ap, const char *))) {
00696       newval = va_arg(ap, const char *);
00697       ESCAPE_STRING(buf, newparam);
00698       ast_str_append(&sql1, 0, ", %s", buf->str);
00699       ESCAPE_STRING(buf, newval);
00700       ast_str_append(&sql2, 0, ", '%s'", buf->str);
00701    }
00702    va_end(ap);
00703    ast_str_append(&sql1, 0, "%s)", sql2->str);
00704 
00705    ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", sql1->str);
00706 
00707    if (!(result = PQexec(pgsqlConn, sql1->str))) {
00708       ast_log(LOG_WARNING,
00709             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00710       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql1->str);
00711       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00712       ast_mutex_unlock(&pgsql_lock);
00713       ast_free(sql1);
00714       ast_free(sql2);
00715       ast_free(buf);
00716       return -1;
00717    } else {
00718       ExecStatusType result_status = PQresultStatus(result);
00719       if (result_status != PGRES_COMMAND_OK
00720          && result_status != PGRES_TUPLES_OK
00721          && result_status != PGRES_NONFATAL_ERROR) {
00722          ast_log(LOG_WARNING,
00723                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00724          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql1->str);
00725          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00726                   PQresultErrorMessage(result), PQresStatus(result_status));
00727          ast_mutex_unlock(&pgsql_lock);
00728          ast_free(sql1);
00729          ast_free(sql2);
00730          ast_free(buf);
00731          return -1;
00732       }
00733    }
00734 
00735    insertid = PQoidValue(result);
00736    ast_mutex_unlock(&pgsql_lock);
00737    ast_free(sql1);
00738    ast_free(sql2);
00739    ast_free(buf);
00740 
00741    ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid);
00742 
00743    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00744     * An integer greater than zero indicates the number of rows affected
00745     * Zero indicates that no records were updated
00746     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00747     */
00748 
00749    if (insertid >= 0)
00750       return (int) insertid;
00751 
00752    return -1;
00753 }

static int unload_module ( void   )  [static]

Definition at line 1120 of file res_config_pgsql.c.

References 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(), columns::list, pgsql_engine, pgsql_lock, and table.

01121 {
01122    struct tables *table;
01123    /* Acquire control before doing anything to the module itself. */
01124    ast_mutex_lock(&pgsql_lock);
01125 
01126    if (pgsqlConn) {
01127       PQfinish(pgsqlConn);
01128       pgsqlConn = NULL;
01129    }
01130    ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
01131    ast_config_engine_deregister(&pgsql_engine);
01132    ast_verb(1, "PostgreSQL RealTime unloaded.\n");
01133 
01134    /* Destroy cached table info */
01135    AST_LIST_LOCK(&psql_tables);
01136    while ((table = AST_LIST_REMOVE_HEAD(&psql_tables, list))) {
01137       destroy_table(table);
01138    }
01139    AST_LIST_UNLOCK(&psql_tables);
01140 
01141    /* Unlock so something else can destroy the lock. */
01142    ast_mutex_unlock(&pgsql_lock);
01143 
01144    return 0;
01145 }

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

Definition at line 1074 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(), columns::list, and tables::name.

01075 {
01076    struct tables *cur;
01077    ast_debug(2, "About to lock table cache list\n");
01078    AST_LIST_LOCK(&psql_tables);
01079    ast_debug(2, "About to traverse table cache list\n");
01080    AST_LIST_TRAVERSE_SAFE_BEGIN(&psql_tables, cur, list) {
01081       if (strcmp(cur->name, tablename) == 0) {
01082          ast_debug(2, "About to remove matching cache entry\n");
01083          AST_LIST_REMOVE_CURRENT(list);
01084          ast_debug(2, "About to destroy matching cache entry\n");
01085          destroy_table(cur);
01086          ast_debug(1, "Cache entry '%s@%s' destroyed\n", tablename, database);
01087          break;
01088       }
01089    }
01090    AST_LIST_TRAVERSE_SAFE_END
01091    AST_LIST_UNLOCK(&psql_tables);
01092    ast_debug(2, "About to return\n");
01093    return cur ? 0 : -1;
01094 }

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

Definition at line 489 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_create(), ast_str_set(), find_table(), columns::list, LOG_ERROR, LOG_WARNING, columns::name, pgsql_lock, pgsql_reconnect(), ast_str::str, and table.

00491 {
00492    PGresult *result = NULL;
00493    int numrows = 0, pgerror;
00494    char escapebuf[513];
00495    const char *newparam, *newval;
00496    struct ast_str *sql = ast_str_create(100);
00497    struct tables *table;
00498    struct columns *column = NULL;
00499 
00500    if (!tablename) {
00501       ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
00502       ast_free(sql);
00503       return -1;
00504    }
00505 
00506    if (!(table = find_table(tablename))) {
00507       ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
00508       ast_free(sql);
00509       return -1;
00510    }
00511 
00512    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00513    newparam = va_arg(ap, const char *);
00514    newval = va_arg(ap, const char *);
00515    if (!newparam || !newval) {
00516       ast_log(LOG_WARNING,
00517             "PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00518       if (pgsqlConn) {
00519          PQfinish(pgsqlConn);
00520          pgsqlConn = NULL;
00521       };
00522       ast_mutex_unlock(&table->lock);
00523       ast_free(sql);
00524       return -1;
00525    }
00526 
00527    /* Check that the column exists in the table */
00528    AST_LIST_TRAVERSE(&table->columns, column, list) {
00529       if (strcmp(column->name, newparam) == 0) {
00530          break;
00531       }
00532    }
00533 
00534    if (!column) {
00535       ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
00536       ast_mutex_unlock(&table->lock);
00537       ast_free(sql);
00538       return -1;
00539    }
00540 
00541    /* Create the first part of the query using the first parameter/value pairs we just extracted
00542       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00543 
00544    PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00545    if (pgerror) {
00546       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00547       va_end(ap);
00548       ast_mutex_unlock(&table->lock);
00549       ast_free(sql);
00550       return -1;
00551    }
00552    ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, escapebuf);
00553 
00554    while ((newparam = va_arg(ap, const char *))) {
00555       newval = va_arg(ap, const char *);
00556 
00557       /* If the column is not within the table, then skip it */
00558       AST_LIST_TRAVERSE(&table->columns, column, list) {
00559          if (strcmp(column->name, newparam) == 0) {
00560             break;
00561          }
00562       }
00563 
00564       if (!column) {
00565          ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
00566          continue;
00567       }
00568 
00569       PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00570       if (pgerror) {
00571          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00572          va_end(ap);
00573          ast_mutex_unlock(&table->lock);
00574          ast_free(sql);
00575          return -1;
00576       }
00577 
00578       ast_str_append(&sql, 0, ", %s = '%s'", newparam, escapebuf);
00579    }
00580    va_end(ap);
00581    ast_mutex_unlock(&table->lock);
00582 
00583    PQescapeStringConn(pgsqlConn, escapebuf, lookup, (sizeof(escapebuf) - 1) / 2, &pgerror);
00584    if (pgerror) {
00585       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
00586       va_end(ap);
00587       ast_free(sql);
00588       return -1;
00589    }
00590 
00591    ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, escapebuf);
00592 
00593    ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", sql->str);
00594 
00595    /* We now have our complete statement; Lets connect to the server and execute it. */
00596    ast_mutex_lock(&pgsql_lock);
00597    if (!pgsql_reconnect(database)) {
00598       ast_mutex_unlock(&pgsql_lock);
00599       ast_free(sql);
00600       return -1;
00601    }
00602 
00603    if (!(result = PQexec(pgsqlConn, sql->str))) {
00604       ast_log(LOG_WARNING,
00605             "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00606       ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
00607       ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
00608       ast_mutex_unlock(&pgsql_lock);
00609       ast_free(sql);
00610       return -1;
00611    } else {
00612       ExecStatusType result_status = PQresultStatus(result);
00613       if (result_status != PGRES_COMMAND_OK
00614          && result_status != PGRES_TUPLES_OK
00615          && result_status != PGRES_NONFATAL_ERROR) {
00616          ast_log(LOG_WARNING,
00617                "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
00618          ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
00619          ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
00620                   PQresultErrorMessage(result), PQresStatus(result_status));
00621          ast_mutex_unlock(&pgsql_lock);
00622          ast_free(sql);
00623          return -1;
00624       }
00625    }
00626 
00627    numrows = atoi(PQcmdTuples(result));
00628    ast_mutex_unlock(&pgsql_lock);
00629    ast_free(sql);
00630 
00631    ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
00632 
00633    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00634     * An integer greater than zero indicates the number of rows affected
00635     * Zero indicates that no records were updated
00636     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00637     */
00638 
00639    if (numrows >= 0)
00640       return (int) numrows;
00641 
00642    return -1;
00643 }


Variable Documentation

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

Definition at line 1420 of file res_config_pgsql.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1420 of file res_config_pgsql.c.

struct ast_cli_entry cli_realtime[] [static]

Initial value:

 {
   { .handler =  handle_cli_realtime_pgsql_status , .summary =  "Shows connection information for the PostgreSQL RealTime driver" ,__VA_ARGS__ },
   { .handler =  handle_cli_realtime_pgsql_cache , .summary =  "Shows cached tables within the PostgreSQL realtime driver" ,__VA_ARGS__ },
}

Definition at line 85 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

time_t connect_time = 0 [static]

Definition at line 76 of file res_config_pgsql.c.

char dbhost[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 70 of file res_config_pgsql.c.

Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().

char dbname[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 73 of file res_config_pgsql.c.

Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().

char dbpass[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 72 of file res_config_pgsql.c.

Referenced by parse_config(), and pgsql_reconnect().

int dbport = 5432 [static]

Definition at line 75 of file res_config_pgsql.c.

Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().

char dbsock[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 74 of file res_config_pgsql.c.

Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().

char dbuser[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 71 of file res_config_pgsql.c.

Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().

struct ast_config_engine pgsql_engine [static]

Definition at line 1096 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

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

Definition at line 44 of file res_config_pgsql.c.

PGconn* pgsqlConn = NULL

Definition at line 48 of file res_config_pgsql.c.

enum { ... } requirements

Referenced by parse_config(), and require_pgsql().


Generated on Fri Jul 24 00:41:55 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7