Wed Aug 7 17:15:53 2019

Asterisk developer's documentation


cdr_pgsql.c File Reference

PostgreSQL CDR logger. More...

#include "asterisk.h"
#include <libpq-fe.h>
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"

Go to the source code of this file.

Data Structures

struct  columns

Defines

#define DATE_FORMAT   "'%Y-%m-%d %T'"
#define LENGTHEN_BUF1(size)
#define LENGTHEN_BUF2(size)

Functions

 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,"PostgreSQL CDR Backend",.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CDR_DRIVER,)
 AST_MUTEX_DEFINE_STATIC (pgsql_lock)
static AST_RWLIST_HEAD_STATIC (psql_columns, columns)
static int config_module (int reload)
static void empty_columns (void)
static int load_module (void)
static int pgsql_log (struct ast_cdr *cdr)
static int reload (void)
static int unload_module (void)

Variables

static const char config [] = "cdr_pgsql.conf"
static PGconn * conn = NULL
static int connected = 0
static char * encoding = NULL
static int maxsize = 512
static int maxsize2 = 512
static const char name [] = "pgsql"
static char * pgdbname = NULL
static char * pgdbport = NULL
static char * pgdbuser = NULL
static char * pghostname = NULL
static char * pgpassword = NULL
static char * table = NULL
static char * tz = NULL

Detailed Description

PostgreSQL CDR logger.

Author:
Matthew D. Hardeman <mhardemn@papersoft.com>
ExtRef:
PostgreSQL http://www.postgresql.org/

See also

Definition in file cdr_pgsql.c.


Define Documentation

#define DATE_FORMAT   "'%Y-%m-%d %T'"

Definition at line 52 of file cdr_pgsql.c.

#define LENGTHEN_BUF1 ( size   ) 

Definition at line 75 of file cdr_pgsql.c.

#define LENGTHEN_BUF2 ( size   ) 

Definition at line 90 of file cdr_pgsql.c.


Function Documentation

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_LOAD_ORDER  ,
"PostgreSQL CDR Backend"  ,
load = load_module,
unload = unload_module,
reload = reload,
load_pri = AST_MODPRI_CDR_DRIVER 
)
AST_MUTEX_DEFINE_STATIC ( pgsql_lock   ) 
static AST_RWLIST_HEAD_STATIC ( psql_columns  ,
columns   
) [static]
static int config_module ( int  reload  )  [static]

Definition at line 368 of file cdr_pgsql.c.

References ast_alloca, ast_calloc, ast_config_destroy(), ast_config_load, ast_debug, ast_free, ast_log(), AST_MODULE_LOAD_DECLINE, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, empty_columns(), columns::hasdefault, columns::len, LOG_ERROR, LOG_NOTICE, LOG_WARNING, columns::name, columns::notnull, option_debug, pgsql_lock, columns::type, unload_module, var, and version.

Referenced by load_module(), and reload().

00369 {
00370    struct ast_variable *var;
00371    char *pgerror;
00372    struct columns *cur;
00373    PGresult *result;
00374    const char *tmp;
00375    struct ast_config *cfg;
00376    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00377 
00378    if ((cfg = ast_config_load(config, config_flags)) == NULL || cfg == CONFIG_STATUS_FILEINVALID) {
00379       ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config);
00380       return -1;
00381    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00382       return 0;
00383    }
00384 
00385    ast_mutex_lock(&pgsql_lock);
00386 
00387    if (!(var = ast_variable_browse(cfg, "global"))) {
00388       ast_config_destroy(cfg);
00389       ast_mutex_unlock(&pgsql_lock);
00390       ast_log(LOG_NOTICE, "cdr_pgsql configuration contains no global section, skipping module %s.\n",
00391          reload ? "reload" : "load");
00392       return -1;
00393    }
00394 
00395    if (!(tmp = ast_variable_retrieve(cfg, "global", "hostname"))) {
00396       ast_log(LOG_WARNING, "PostgreSQL server hostname not specified.  Assuming unix socket connection\n");
00397       tmp = "";   /* connect via UNIX-socket by default */
00398    }
00399 
00400    ast_free(pghostname);
00401    if (!(pghostname = ast_strdup(tmp))) {
00402       ast_config_destroy(cfg);
00403       ast_mutex_unlock(&pgsql_lock);
00404       return -1;
00405    }
00406 
00407    if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) {
00408       ast_log(LOG_WARNING, "PostgreSQL database not specified.  Assuming asterisk\n");
00409       tmp = "asteriskcdrdb";
00410    }
00411 
00412    ast_free(pgdbname);
00413    if (!(pgdbname = ast_strdup(tmp))) {
00414       ast_config_destroy(cfg);
00415       ast_mutex_unlock(&pgsql_lock);
00416       return -1;
00417    }
00418 
00419    if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) {
00420       ast_log(LOG_WARNING, "PostgreSQL database user not specified.  Assuming asterisk\n");
00421       tmp = "asterisk";
00422    }
00423 
00424    ast_free(pgdbuser);
00425    if (!(pgdbuser = ast_strdup(tmp))) {
00426       ast_config_destroy(cfg);
00427       ast_mutex_unlock(&pgsql_lock);
00428       return -1;
00429    }
00430 
00431    if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) {
00432       ast_log(LOG_WARNING, "PostgreSQL database password not specified.  Assuming blank\n");
00433       tmp = "";
00434    }
00435 
00436    ast_free(pgpassword);
00437    if (!(pgpassword = ast_strdup(tmp))) {
00438       ast_config_destroy(cfg);
00439       ast_mutex_unlock(&pgsql_lock);
00440       return -1;
00441    }
00442 
00443    if (!(tmp = ast_variable_retrieve(cfg, "global", "port"))) {
00444       ast_log(LOG_WARNING, "PostgreSQL database port not specified.  Using default 5432.\n");
00445       tmp = "5432";
00446    }
00447 
00448    ast_free(pgdbport);
00449    if (!(pgdbport = ast_strdup(tmp))) {
00450       ast_config_destroy(cfg);
00451       ast_mutex_unlock(&pgsql_lock);
00452       return -1;
00453    }
00454 
00455    if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) {
00456       ast_log(LOG_WARNING, "CDR table not specified.  Assuming cdr\n");
00457       tmp = "cdr";
00458    }
00459 
00460    ast_free(table);
00461    if (!(table = ast_strdup(tmp))) {
00462       ast_config_destroy(cfg);
00463       ast_mutex_unlock(&pgsql_lock);
00464       return -1;
00465    }
00466 
00467    if (!(tmp = ast_variable_retrieve(cfg, "global", "encoding"))) {
00468       ast_log(LOG_WARNING, "Encoding not specified.  Assuming LATIN9\n");
00469       tmp = "LATIN9";
00470    }
00471 
00472    ast_free(encoding);
00473    if (!(encoding = ast_strdup(tmp))) {
00474       ast_config_destroy(cfg);
00475       ast_mutex_unlock(&pgsql_lock);
00476       return -1;
00477    }
00478 
00479    if (!(tmp = ast_variable_retrieve(cfg, "global", "timezone"))) {
00480       tmp = "";
00481    }
00482 
00483    ast_free(tz);
00484    tz = NULL;
00485 
00486    if (!ast_strlen_zero(tmp) && !(tz = ast_strdup(tmp))) {
00487       ast_config_destroy(cfg);
00488       ast_mutex_unlock(&pgsql_lock);
00489       return -1;
00490    }
00491 
00492    if (option_debug) {
00493       if (ast_strlen_zero(pghostname)) {
00494          ast_debug(1, "using default unix socket\n");
00495       } else {
00496          ast_debug(1, "got hostname of %s\n", pghostname);
00497       }
00498       ast_debug(1, "got port of %s\n", pgdbport);
00499       ast_debug(1, "got user of %s\n", pgdbuser);
00500       ast_debug(1, "got dbname of %s\n", pgdbname);
00501       ast_debug(1, "got password of %s\n", pgpassword);
00502       ast_debug(1, "got sql table name of %s\n", table);
00503       ast_debug(1, "got encoding of %s\n", encoding);
00504       ast_debug(1, "got timezone of %s\n", tz);
00505    }
00506 
00507    conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
00508    if (PQstatus(conn) != CONNECTION_BAD) {
00509       char sqlcmd[768];
00510       char *fname, *ftype, *flen, *fnotnull, *fdef;
00511       int i, rows, version;
00512       ast_debug(1, "Successfully connected to PostgreSQL database.\n");
00513       connected = 1;
00514       if (PQsetClientEncoding(conn, encoding)) {
00515 #ifdef HAVE_PGSQL_pg_encoding_to_char
00516          ast_log(LOG_WARNING, "Failed to set encoding to '%s'.  Encoding set to default '%s'\n", encoding, pg_encoding_to_char(PQclientEncoding(conn)));
00517 #else
00518          ast_log(LOG_WARNING, "Failed to set encoding to '%s'.  Encoding set to default.\n", encoding);
00519 #endif
00520       }
00521       version = PQserverVersion(conn);
00522 
00523       if (version >= 70300) {
00524          char *schemaname, *tablename;
00525          if (strchr(table, '.')) {
00526             schemaname = ast_strdupa(table);
00527             tablename = strchr(schemaname, '.');
00528             *tablename++ = '\0';
00529          } else {
00530             schemaname = "";
00531             tablename = table;
00532          }
00533 
00534          /* Escape special characters in schemaname */
00535          if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
00536             char *tmp = schemaname, *ptr;
00537 
00538             ptr = schemaname = ast_alloca(strlen(tmp) * 2 + 1);
00539             for (; *tmp; tmp++) {
00540                if (strchr("\\'", *tmp)) {
00541                   *ptr++ = *tmp;
00542                }
00543                *ptr++ = *tmp;
00544             }
00545             *ptr = '\0';
00546          }
00547          /* Escape special characters in tablename */
00548          if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
00549             char *tmp = tablename, *ptr;
00550 
00551             ptr = tablename = ast_alloca(strlen(tmp) * 2 + 1);
00552             for (; *tmp; tmp++) {
00553                if (strchr("\\'", *tmp)) {
00554                   *ptr++ = *tmp;
00555                }
00556                *ptr++ = *tmp;
00557             }
00558             *ptr = '\0';
00559          }
00560 
00561          snprintf(sqlcmd, sizeof(sqlcmd), "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",
00562             tablename,
00563             ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'");
00564       } else {
00565          snprintf(sqlcmd, sizeof(sqlcmd), "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", table);
00566       }
00567       /* Query the columns */
00568       result = PQexec(conn, sqlcmd);
00569       if (PQresultStatus(result) != PGRES_TUPLES_OK) {
00570          pgerror = PQresultErrorMessage(result);
00571          ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
00572          PQclear(result);
00573          unload_module();
00574          ast_mutex_unlock(&pgsql_lock);
00575          return AST_MODULE_LOAD_DECLINE;
00576       }
00577 
00578       rows = PQntuples(result);
00579       if (rows == 0) {
00580          ast_log(LOG_ERROR, "cdr_pgsql: Failed to query database columns. No columns found, does the table exist?\n");
00581          PQclear(result);
00582          unload_module();
00583          ast_mutex_unlock(&pgsql_lock);
00584          return AST_MODULE_LOAD_DECLINE;
00585       }
00586 
00587       /* Clear out the columns list. */
00588       empty_columns();
00589 
00590       for (i = 0; i < rows; i++) {
00591          fname = PQgetvalue(result, i, 0);
00592          ftype = PQgetvalue(result, i, 1);
00593          flen = PQgetvalue(result, i, 2);
00594          fnotnull = PQgetvalue(result, i, 3);
00595          fdef = PQgetvalue(result, i, 4);
00596          if (atoi(flen) == -1) {
00597             /* For varchar columns, the maximum length is encoded in a different field */
00598             flen = PQgetvalue(result, i, 5);
00599          }
00600          ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
00601          cur = ast_calloc(1, sizeof(*cur) + strlen(fname) + strlen(ftype) + 2);
00602          if (cur) {
00603             sscanf(flen, "%30d", &cur->len);
00604             cur->name = (char *)cur + sizeof(*cur);
00605             cur->type = (char *)cur + sizeof(*cur) + strlen(fname) + 1;
00606             strcpy(cur->name, fname);
00607             strcpy(cur->type, ftype);
00608             if (*fnotnull == 't') {
00609                cur->notnull = 1;
00610             } else {
00611                cur->notnull = 0;
00612             }
00613             if (!ast_strlen_zero(fdef)) {
00614                cur->hasdefault = 1;
00615             } else {
00616                cur->hasdefault = 0;
00617             }
00618             AST_RWLIST_WRLOCK(&psql_columns);
00619             AST_RWLIST_INSERT_TAIL(&psql_columns, cur, list);
00620             AST_RWLIST_UNLOCK(&psql_columns);
00621          }
00622       }
00623       PQclear(result);
00624    } else {
00625       pgerror = PQerrorMessage(conn);
00626       ast_log(LOG_ERROR, "Unable to connect to database server %s.  CALLS WILL NOT BE LOGGED!!\n", pghostname);
00627       ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00628       connected = 0;
00629    }
00630 
00631    ast_config_destroy(cfg);
00632 
00633    ast_mutex_unlock(&pgsql_lock);
00634    return 0;
00635 }

static void empty_columns ( void   )  [static]

Definition at line 337 of file cdr_pgsql.c.

References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by config_module(), and unload_module().

00338 {
00339    struct columns *current;
00340    AST_RWLIST_WRLOCK(&psql_columns);
00341    while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) {
00342       ast_free(current);
00343    }
00344    AST_RWLIST_UNLOCK(&psql_columns);
00345 
00346 }

static int load_module ( void   )  [static]

Definition at line 637 of file cdr_pgsql.c.

References ast_cdr_register(), AST_MODULE_LOAD_DECLINE, config_module(), and pgsql_log().

00638 {
00639    if (config_module(0)) {
00640       return AST_MODULE_LOAD_DECLINE;
00641    }
00642    return ast_cdr_register(name, ast_module_info->description, pgsql_log)
00643       ? AST_MODULE_LOAD_DECLINE : 0;
00644 }

static int pgsql_log ( struct ast_cdr cdr  )  [static]

Definition at line 104 of file cdr_pgsql.c.

References ast_cdr::answer, ast_cdr_getvar(), ast_debug, ast_free, ast_localtime(), ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_str_strlen(), ast_strftime(), ast_tvdiff_us(), ast_tvzero(), ast_verb, DATE_FORMAT, ast_cdr::end, first, columns::hasdefault, LENGTHEN_BUF1, LENGTHEN_BUF2, LOG_ERROR, LOG_WARNING, maxsize2, columns::name, columns::notnull, pgsql_lock, ast_cdr::start, columns::type, and value.

Referenced by load_module().

00105 {
00106    struct ast_tm tm;
00107    char *pgerror;
00108    PGresult *result;
00109 
00110    ast_mutex_lock(&pgsql_lock);
00111 
00112    if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) {
00113       conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
00114       if (PQstatus(conn) != CONNECTION_BAD) {
00115          connected = 1;
00116          if (PQsetClientEncoding(conn, encoding)) {
00117 #ifdef HAVE_PGSQL_pg_encoding_to_char
00118             ast_log(LOG_WARNING, "Failed to set encoding to '%s'.  Encoding set to default '%s'\n", encoding, pg_encoding_to_char(PQclientEncoding(conn)));
00119 #else
00120             ast_log(LOG_WARNING, "Failed to set encoding to '%s'.  Encoding set to default.\n", encoding);
00121 #endif
00122          }
00123       } else {
00124          pgerror = PQerrorMessage(conn);
00125          ast_log(LOG_ERROR, "Unable to connect to database server %s.  Calls will not be logged!\n", pghostname);
00126          ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00127          PQfinish(conn);
00128          conn = NULL;
00129       }
00130    }
00131 
00132    if (connected) {
00133       struct columns *cur;
00134       struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
00135       char buf[257], escapebuf[513], *value;
00136       int first = 1;
00137 
00138       if (!sql || !sql2) {
00139          ast_free(sql);
00140          ast_free(sql2);
00141          return -1;
00142       }
00143 
00144       ast_str_set(&sql, 0, "INSERT INTO %s (", table);
00145       ast_str_set(&sql2, 0, " VALUES (");
00146 
00147       AST_RWLIST_RDLOCK(&psql_columns);
00148       AST_RWLIST_TRAVERSE(&psql_columns, cur, list) {
00149          /* For fields not set, simply skip them */
00150          ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
00151          if (strcmp(cur->name, "calldate") == 0 && !value) {
00152             ast_cdr_getvar(cdr, "start", &value, buf, sizeof(buf), 0, 0);
00153          }
00154          if (!value) {
00155             if (cur->notnull && !cur->hasdefault) {
00156                /* Field is NOT NULL (but no default), must include it anyway */
00157                LENGTHEN_BUF1(strlen(cur->name) + 2);
00158                ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
00159                LENGTHEN_BUF2(3);
00160                ast_str_append(&sql2, 0, "%s''", first ? "" : ",");
00161                first = 0;
00162             }
00163             continue;
00164          }
00165 
00166          LENGTHEN_BUF1(strlen(cur->name) + 2);
00167          ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
00168 
00169          if (strcmp(cur->name, "start") == 0 || strcmp(cur->name, "calldate") == 0) {
00170             if (strncmp(cur->type, "int", 3) == 0) {
00171                LENGTHEN_BUF2(13);
00172                ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->start.tv_sec);
00173             } else if (strncmp(cur->type, "float", 5) == 0) {
00174                LENGTHEN_BUF2(31);
00175                ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
00176             } else {
00177                /* char, hopefully */
00178                LENGTHEN_BUF2(31);
00179                ast_localtime(&cdr->start, &tm, tz);
00180                ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
00181                ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
00182             }
00183          } else if (strcmp(cur->name, "answer") == 0) {
00184             if (strncmp(cur->type, "int", 3) == 0) {
00185                LENGTHEN_BUF2(13);
00186                ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->answer.tv_sec);
00187             } else if (strncmp(cur->type, "float", 5) == 0) {
00188                LENGTHEN_BUF2(31);
00189                ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
00190             } else {
00191                /* char, hopefully */
00192                LENGTHEN_BUF2(31);
00193                ast_localtime(&cdr->answer, &tm, tz);
00194                ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
00195                ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
00196             }
00197          } else if (strcmp(cur->name, "end") == 0) {
00198             if (strncmp(cur->type, "int", 3) == 0) {
00199                LENGTHEN_BUF2(13);
00200                ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->end.tv_sec);
00201             } else if (strncmp(cur->type, "float", 5) == 0) {
00202                LENGTHEN_BUF2(31);
00203                ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
00204             } else {
00205                /* char, hopefully */
00206                LENGTHEN_BUF2(31);
00207                ast_localtime(&cdr->end, &tm, tz);
00208                ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
00209                ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
00210             }
00211          } else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) {
00212             if (cur->type[0] == 'i') {
00213                /* Get integer, no need to escape anything */
00214                ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
00215                LENGTHEN_BUF2(13);
00216                ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
00217             } else if (strncmp(cur->type, "float", 5) == 0) {
00218                struct timeval *when = cur->name[0] == 'd' ? &cdr->start : ast_tvzero(cdr->answer) ? &cdr->end : &cdr->answer;
00219                LENGTHEN_BUF2(31);
00220                ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0));
00221             } else {
00222                /* Char field, probably */
00223                struct timeval *when = cur->name[0] == 'd' ? &cdr->start : ast_tvzero(cdr->answer) ? &cdr->end : &cdr->answer;
00224                LENGTHEN_BUF2(31);
00225                ast_str_append(&sql2, 0, "%s'%f'", first ? "" : ",", (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0));
00226             }
00227          } else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) {
00228             if (strncmp(cur->type, "int", 3) == 0) {
00229                /* Integer, no need to escape anything */
00230                ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 1);
00231                LENGTHEN_BUF2(13);
00232                ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
00233             } else {
00234                /* Although this is a char field, there are no special characters in the values for these fields */
00235                ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
00236                LENGTHEN_BUF2(31);
00237                ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", value);
00238             }
00239          } else {
00240             /* Arbitrary field, could be anything */
00241             ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
00242             if (strncmp(cur->type, "int", 3) == 0) {
00243                long long whatever;
00244                if (value && sscanf(value, "%30lld", &whatever) == 1) {
00245                   LENGTHEN_BUF2(26);
00246                   ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", whatever);
00247                } else {
00248                   LENGTHEN_BUF2(2);
00249                   ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
00250                }
00251             } else if (strncmp(cur->type, "float", 5) == 0) {
00252                long double whatever;
00253                if (value && sscanf(value, "%30Lf", &whatever) == 1) {
00254                   LENGTHEN_BUF2(51);
00255                   ast_str_append(&sql2, 0, "%s%30Lf", first ? "" : ",", whatever);
00256                } else {
00257                   LENGTHEN_BUF2(2);
00258                   ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
00259                }
00260             /* XXX Might want to handle dates, times, and other misc fields here XXX */
00261             } else {
00262                if (value)
00263                   PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL);
00264                else
00265                   escapebuf[0] = '\0';
00266                LENGTHEN_BUF2(strlen(escapebuf) + 3);
00267                ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", escapebuf);
00268             }
00269          }
00270          first = 0;
00271       }
00272 
00273       LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
00274       AST_RWLIST_UNLOCK(&psql_columns);
00275       ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2));
00276       ast_verb(11, "[%s]\n", ast_str_buffer(sql));
00277 
00278       ast_debug(2, "inserting a CDR record.\n");
00279 
00280       /* Test to be sure we're still connected... */
00281       /* If we're connected, and connection is working, good. */
00282       /* Otherwise, attempt reconnect.  If it fails... sorry... */
00283       if (PQstatus(conn) == CONNECTION_OK) {
00284          connected = 1;
00285       } else {
00286          ast_log(LOG_ERROR, "Connection was lost... attempting to reconnect.\n");
00287          PQreset(conn);
00288          if (PQstatus(conn) == CONNECTION_OK) {
00289             ast_log(LOG_ERROR, "Connection reestablished.\n");
00290             connected = 1;
00291          } else {
00292             pgerror = PQerrorMessage(conn);
00293             ast_log(LOG_ERROR, "Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname);
00294             ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00295             PQfinish(conn);
00296             conn = NULL;
00297             connected = 0;
00298             ast_mutex_unlock(&pgsql_lock);
00299             ast_free(sql);
00300             ast_free(sql2);
00301             return -1;
00302          }
00303       }
00304       result = PQexec(conn, ast_str_buffer(sql));
00305       if (PQresultStatus(result) != PGRES_COMMAND_OK) {
00306          pgerror = PQresultErrorMessage(result);
00307          ast_log(LOG_ERROR, "Failed to insert call detail record into database!\n");
00308          ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00309          ast_log(LOG_ERROR, "Connection may have been lost... attempting to reconnect.\n");
00310          PQreset(conn);
00311          if (PQstatus(conn) == CONNECTION_OK) {
00312             ast_log(LOG_ERROR, "Connection reestablished.\n");
00313             connected = 1;
00314             PQclear(result);
00315             result = PQexec(conn, ast_str_buffer(sql));
00316             if (PQresultStatus(result) != PGRES_COMMAND_OK) {
00317                pgerror = PQresultErrorMessage(result);
00318                ast_log(LOG_ERROR, "HARD ERROR!  Attempted reconnection failed.  DROPPING CALL RECORD!\n");
00319                ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00320             }
00321          }
00322          ast_mutex_unlock(&pgsql_lock);
00323          PQclear(result);
00324          ast_free(sql);
00325          ast_free(sql2);
00326          return -1;
00327       }
00328       PQclear(result);
00329       ast_free(sql);
00330       ast_free(sql2);
00331    }
00332    ast_mutex_unlock(&pgsql_lock);
00333    return 0;
00334 }

static int reload ( void   )  [static]

Definition at line 646 of file cdr_pgsql.c.

References config_module().

00647 {
00648    return config_module(1);
00649 }

static int unload_module ( void   )  [static]

Definition at line 348 of file cdr_pgsql.c.

References ast_cdr_unregister(), ast_free, and empty_columns().

00349 {
00350    ast_cdr_unregister(name);
00351 
00352    PQfinish(conn);
00353 
00354    ast_free(pghostname);
00355    ast_free(pgdbname);
00356    ast_free(pgdbuser);
00357    ast_free(pgpassword);
00358    ast_free(pgdbport);
00359    ast_free(table);
00360    ast_free(encoding);
00361    ast_free(tz);
00362 
00363    empty_columns();
00364 
00365    return 0;
00366 }


Variable Documentation

const char config[] = "cdr_pgsql.conf" [static]

Definition at line 55 of file cdr_pgsql.c.

PGconn* conn = NULL [static]

Definition at line 62 of file cdr_pgsql.c.

int connected = 0 [static]
char * encoding = NULL [static]

Definition at line 56 of file cdr_pgsql.c.

Referenced by check_header(), and custom_prepare().

int maxsize = 512 [static]

Definition at line 58 of file cdr_pgsql.c.

int maxsize2 = 512 [static]

Definition at line 58 of file cdr_pgsql.c.

Referenced by pgsql_log().

const char name[] = "pgsql" [static]

Definition at line 54 of file cdr_pgsql.c.

char * pgdbname = NULL [static]

Definition at line 56 of file cdr_pgsql.c.

char * pgdbport = NULL [static]

Definition at line 56 of file cdr_pgsql.c.

char * pgdbuser = NULL [static]

Definition at line 56 of file cdr_pgsql.c.

char* pghostname = NULL [static]

Definition at line 56 of file cdr_pgsql.c.

char * pgpassword = NULL [static]

Definition at line 56 of file cdr_pgsql.c.

char * table = NULL [static]

Definition at line 56 of file cdr_pgsql.c.

char * tz = NULL [static]

Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1