56#define DATE_FORMAT "'%Y-%m-%d %T'" 
   58#define PGSQL_MIN_VERSION_SCHEMA 70300 
   60static const char name[] = 
"pgsql";
 
   61static const char config[] = 
"cdr_pgsql.conf";
 
  100#define LENGTHEN_BUF(size, var_sql) \ 
  103                if (ast_str_strlen(var_sql) + size + 1 > ast_str_size(var_sql)) { \ 
  104                    if (ast_str_make_space(&var_sql, ((ast_str_size(var_sql) + size + 3) / 512 + 1) * 512) != 0) { \ 
  105                        ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", pghostname, table); \ 
  108                        AST_RWLIST_UNLOCK(&psql_columns); \ 
  109                        ast_mutex_unlock(&pgsql_lock); \ 
   100#define LENGTHEN_BUF(size, var_sql) \ … 
  115#define LENGTHEN_BUF1(size) \ 
  116    LENGTHEN_BUF(size, sql); 
   115#define LENGTHEN_BUF1(size) \ … 
  117#define LENGTHEN_BUF2(size) \ 
  118    LENGTHEN_BUF(size, sql2); 
   117#define LENGTHEN_BUF2(size) \ … 
  125        e->
command = 
"cdr show pgsql status";
 
  127            "Usage: cdr show pgsql status\n" 
  128            "       Shows current connection status for cdr_pgsql\n";
 
  134    if (
a->argc != e->
args)
 
  139        char status2[100] = 
"";
 
  150            snprintf(status2, 99, 
" with username %s", 
pgdbuser);
 
  153            snprintf(status2, 99, 
" using table %s", 
table);
 
  156        snprintf(
buf, 
sizeof(
buf), 
"%s%s for ", 
status, status2);
 
  165        ast_cli(
a->fd, 
"Not currently connected to a PgSQL server.\n");
 
 
  222        if (PQstatus(
conn) != CONNECTION_BAD) {
 
  227#ifdef HAVE_PGSQL_pg_encoding_to_char 
  234            pgerror = PQerrorMessage(
conn);
 
  247        char *separator = 
"";
 
  248        size_t bufsize = 513;
 
  251        if (!escapebuf || !sql || !sql2) {
 
  252            goto ast_log_cleanup;
 
  262            if (strcmp(cur->
name, 
"calldate") == 0 && !
value) {
 
  280            if (strcmp(cur->
name, 
"start") == 0 || strcmp(cur->
name, 
"calldate") == 0) {
 
  281                if (strncmp(cur->
type, 
"int", 3) == 0) {
 
  284                } 
else if (strncmp(cur->
type, 
"float", 5) == 0) {
 
  294            } 
else if (strcmp(cur->
name, 
"answer") == 0) {
 
  295                if (strncmp(cur->
type, 
"int", 3) == 0) {
 
  298                } 
else if (strncmp(cur->
type, 
"float", 5) == 0) {
 
  308            } 
else if (strcmp(cur->
name, 
"end") == 0) {
 
  309                if (strncmp(cur->
type, 
"int", 3) == 0) {
 
  312                } 
else if (strncmp(cur->
type, 
"float", 5) == 0) {
 
  314                    ast_str_append(&sql2, 0, 
"%s%f", separator, (
double)cdr->
end.tv_sec + (
double)cdr->
end.tv_usec / 1000000.0);
 
  322            } 
else if (strcmp(cur->
name, 
"duration") == 0 || strcmp(cur->
name, 
"billsec") == 0) {
 
  323                if (cur->
type[0] == 
'i') {
 
  328                } 
else if (strncmp(cur->
type, 
"float", 5) == 0) {
 
  338            } 
else if (strcmp(cur->
name, 
"disposition") == 0 || strcmp(cur->
name, 
"amaflags") == 0) {
 
  339                if (strncmp(cur->
type, 
"int", 3) == 0) {
 
  353                if (strncmp(cur->
type, 
"int", 3) == 0) {
 
  355                    if (
value && sscanf(
value, 
"%30lld", &whatever) == 1) {
 
  362                } 
else if (strncmp(cur->
type, 
"float", 5) == 0) {
 
  363                    long double whatever;
 
  364                    if (
value && sscanf(
value, 
"%30Lf", &whatever) == 1) {
 
  374                        size_t required_size = strlen(
value) * 2 + 1;
 
  380                        if (required_size > bufsize) {
 
  381                            char *tmpbuf = 
ast_realloc(escapebuf, required_size);
 
  385                                goto ast_log_cleanup;
 
  389                            bufsize = required_size;
 
  411        if (PQstatus(
conn) == CONNECTION_OK) {
 
  416            if (PQstatus(
conn) == CONNECTION_OK) {
 
  422                pgerror = PQerrorMessage(
conn);
 
  428                goto ast_log_cleanup;
 
  432        if (PQresultStatus(
result) != PGRES_COMMAND_OK) {
 
  433            pgerror = PQresultErrorMessage(
result);
 
  436            ast_log(
LOG_ERROR, 
"Connection may have been lost... attempting to reconnect.\n");
 
  438            if (PQstatus(
conn) == CONNECTION_OK) {
 
  445                if (PQresultStatus(
result) != PGRES_COMMAND_OK) {
 
  446                    pgerror = PQresultErrorMessage(
result);
 
  447                    ast_log(
LOG_ERROR, 
"HARD ERROR!  Attempted reconnection failed.  DROPPING CALL RECORD!\n");
 
 
  541        ast_log(
LOG_NOTICE, 
"cdr_pgsql configuration contains no global section, skipping module %s.\n",
 
  542            reload ? 
"reload" : 
"load");
 
  547        ast_log(
LOG_WARNING, 
"PostgreSQL server hostname not specified.  Assuming unix socket connection\n");
 
  560        tmp = 
"asteriskcdrdb";
 
  607        ast_log(
LOG_WARNING, 
"PostgreSQL database port not specified.  Using default 5432.\n");
 
  673    if (PQstatus(
conn) != CONNECTION_BAD) {
 
  675        char *fname, *ftype, *flen, *fnotnull, *fdef;
 
  677        ast_debug(1, 
"Successfully connected to PostgreSQL database.\n");
 
  682#ifdef HAVE_PGSQL_pg_encoding_to_char 
  691            char *schemaname, *tablename, *tmp_schemaname, *tmp_tablename;
 
  692            if (strchr(
table, 
'.')) {
 
  694                tmp_tablename = strchr(tmp_schemaname, 
'.');
 
  695                *tmp_tablename++ = 
'\0';
 
  698                tmp_tablename = 
table;
 
  700            tablename = 
ast_alloca(strlen(tmp_tablename) * 2 + 1);
 
  701            PQescapeStringConn(
conn, tablename, tmp_tablename, strlen(tmp_tablename), 
NULL);
 
  703            schemaname = 
ast_alloca(strlen(tmp_schemaname) * 2 + 1);
 
  704            PQescapeStringConn(
conn, schemaname, tmp_schemaname, strlen(tmp_schemaname), 
NULL);
 
  706            snprintf(sqlcmd, 
sizeof(sqlcmd), 
"SELECT a.attname, t.typname, a.attlen, a.attnotnull, pg_catalog.pg_get_expr(d.adbin, d.adrelid) 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",
 
  710            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);
 
  714        if (PQresultStatus(
result) != PGRES_TUPLES_OK) {
 
  715            pgerror = PQresultErrorMessage(
result);
 
  725            ast_log(
LOG_ERROR, 
"cdr_pgsql: Failed to query database columns. No columns found, does the table exist?\n");
 
  735        for (i = 0; i < rows; i++) {
 
  736            fname = PQgetvalue(
result, i, 0);
 
  737            ftype = PQgetvalue(
result, i, 1);
 
  738            flen = PQgetvalue(
result, i, 2);
 
  739            fnotnull = PQgetvalue(
result, i, 3);
 
  740            fdef = PQgetvalue(
result, i, 4);
 
  741            if (atoi(flen) == -1) {
 
  743                flen = PQgetvalue(
result, i, 5);
 
  746            cur = 
ast_calloc(1, 
sizeof(*cur) + strlen(fname) + strlen(ftype) + 2);
 
  748                sscanf(flen, 
"%30d", &cur->
len);
 
  749                cur->
name = (
char *)cur + 
sizeof(*cur);
 
  750                cur->
type = (
char *)cur + 
sizeof(*cur) + strlen(fname) + 1;
 
  751                strcpy(cur->
name, fname);
 
  752                strcpy(cur->
type, ftype);
 
  753                if (*fnotnull == 
't') {
 
  770        pgerror = PQerrorMessage(
conn);
 
 
void ast_cli_unregister_multiple(void)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_realloc(p, len)
A wrapper for realloc()
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
Format a CDR variable from an already posted CDR.
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
static void empty_columns(void)
static int config_module(int reload)
#define LENGTHEN_BUF2(size)
static void pgsql_reconnect(void)
static char * handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Handle the CLI command cdr show pgsql status.
#define PGSQL_MIN_VERSION_SCHEMA
static const char config[]
static ast_mutex_t pgsql_lock
static int load_module(void)
static time_t connect_time
static int unload_module(void)
static int pgsql_log(struct ast_cdr *cdr)
static struct ast_cli_entry cdr_pgsql_status_cli[]
#define LENGTHEN_BUF1(size)
static char version[AST_MAX_EXTENSION]
General Asterisk PBX channel definitions.
Standard Command Line Interface.
void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix)
Print on cli a duration in seconds in format s year(s), s week(s), s day(s), s hour(s),...
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
@ CONFIG_FLAG_FILEUNCHANGED
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_RWLIST_REMOVE_HEAD
#define AST_RWLIST_TRAVERSE
#define AST_RWLIST_INSERT_TAIL
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
#define ast_mutex_unlock(a)
#define ast_mutex_lock(a)
#define AST_MUTEX_DEFINE_STATIC(mutex)
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_EXTENDED
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Responsible for call detail data.
descriptor for a cli entry.
int args
This gets set in ast_cli_register()
Structure used to handle boolean flags.
Support for dynamic strings.
struct columns::@107 list
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.