@ -42,6 +42,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
# include "asterisk/cli.h"
AST_MUTEX_DEFINE_STATIC ( pgsql_lock ) ;
AST_THREADSTORAGE ( sql_buf ) ;
AST_THREADSTORAGE ( findtable_buf ) ;
AST_THREADSTORAGE ( where_buf ) ;
AST_THREADSTORAGE ( escapebuf_buf ) ;
# define RES_CONFIG_PGSQL_CONF "res_pgsql.conf"
@ -59,7 +63,7 @@ struct columns {
} ;
struct tables {
ast_ mutex _t lock ;
ast_ rwlock _t lock ;
AST_LIST_HEAD_NOLOCK ( psql_columns , columns ) columns ;
AST_LIST_ENTRY ( tables ) list ;
char name [ 0 ] ;
@ -87,15 +91,24 @@ static struct ast_cli_entry cli_realtime[] = {
AST_CLI_DEFINE ( handle_cli_realtime_pgsql_cache , " Shows cached tables within the PostgreSQL realtime driver " ) ,
} ;
# define ESCAPE_STRING(buffer, stringname) \
do { \
int len ; \
if ( ( len = strlen ( stringname ) ) > ( buffer - > len - 1 ) / 2 ) { \
ast_str_make_space ( & buffer , len * 2 + 1 ) ; \
} \
PQescapeStringConn ( pgsqlConn , buffer - > str , stringname , len , & pgresult ) ; \
} while ( 0 )
static void destroy_table ( struct tables * table )
{
struct columns * column ;
ast_mutex_lock ( & table - > lock ) ;
ast_ rwlock_wr lock( & table - > lock ) ;
while ( ( column = AST_LIST_REMOVE_HEAD ( & table - > columns , list ) ) ) {
ast_free ( column ) ;
}
ast_mutex_unlock ( & table - > lock ) ;
ast_mutex_destroy ( & table - > lock ) ;
ast_ rwlock _unlock( & table - > lock ) ;
ast_ rwlock _destroy( & table - > lock ) ;
ast_free ( table ) ;
}
@ -103,7 +116,7 @@ static struct tables *find_table(const char *tablename)
{
struct columns * column ;
struct tables * table ;
struct ast_str * sql = ast_str_ create( 330 ) ;
struct ast_str * sql = ast_str_ thread_get( & findtable_buf , 330 ) ;
char * pgerror ;
PGresult * result ;
char * fname , * ftype , * flen , * fnotnull , * fdef ;
@ -113,7 +126,7 @@ static struct tables *find_table(const char *tablename)
AST_LIST_TRAVERSE ( & psql_tables , table , list ) {
if ( ! strcasecmp ( table - > name , tablename ) ) {
ast_debug ( 1 , " Found table in cache; now locking \n " ) ;
ast_ mutex_ lock( & table - > lock ) ;
ast_ rwlock_rd lock( & table - > lock ) ;
ast_debug ( 1 , " Lock cached table; now returning \n " ) ;
AST_LIST_UNLOCK ( & psql_tables ) ;
return table ;
@ -140,9 +153,9 @@ static struct tables *find_table(const char *tablename)
return NULL ;
}
strcpy ( table - > name , tablename ) ; /* SAFE */
ast_ mutex _init( & table - > lock ) ;
ast_ rwlock _init( & table - > lock ) ;
AST_LIST_HEAD_INIT_NOLOCK ( & table - > columns ) ;
rows = PQntuples ( result ) ;
for ( i = 0 ; i < rows ; i + + ) {
fname = PQgetvalue ( result , i , 0 ) ;
@ -186,23 +199,39 @@ static struct tables *find_table(const char *tablename)
PQclear ( result ) ;
AST_LIST_INSERT_TAIL ( & psql_tables , table , list ) ;
ast_ mutex_ lock( & table - > lock ) ;
ast_ rwlock_rd lock( & table - > lock ) ;
AST_LIST_UNLOCK ( & psql_tables ) ;
return table ;
}
static struct ast_variable * realtime_pgsql ( const char * database , const char * table , va_list ap )
# define release_table(table) ast_rwlock_unlock(&(table)->lock);
static struct columns * find_column ( struct tables * t , const char * colname )
{
struct columns * column ;
/* Check that the column exists in the table */
AST_LIST_TRAVERSE ( & t - > columns , column , list ) {
if ( strcmp ( column - > name , colname ) = = 0 ) {
return column ;
}
}
return NULL ;
}
static struct ast_variable * realtime_pgsql ( const char * database , const char * tablename , va_list ap )
{
PGresult * result = NULL ;
int num_rows = 0 , pgerror ;
char sql [ 256 ] , escapebuf [ 513 ] ;
int num_rows = 0 , pgresult ;
struct ast_str * sql = ast_str_thread_get ( & sql_buf , 100 ) ;
struct ast_str * escapebuf = ast_str_thread_get ( & escapebuf_buf , 100 ) ;
char * stringp ;
char * chunk ;
char * op ;
const char * newparam , * newval ;
struct ast_variable * var = NULL , * prev = NULL ;
if ( ! table ) {
if ( ! table name ) {
ast_log ( LOG_WARNING , " PostgreSQL RealTime: No table specified. \n " ) ;
return NULL ;
}
@ -216,7 +245,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
if ( pgsqlConn ) {
PQfinish ( pgsqlConn ) ;
pgsqlConn = NULL ;
} ;
}
return NULL ;
}
@ -224,15 +253,14 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
If there is only 1 set , then we have our query . Otherwise , loop thru the list and concat */
op = strchr ( newparam , ' ' ) ? " " : " = " ;
PQescapeStringConn( pgsqlConn , escapebuf , newval , ( sizeof ( escapebuf ) - 1 ) / 2 , & pgerror ) ;
if ( pg error ) {
ESCAPE_STRING( escapebuf , newval ) ;
if ( pg result ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
va_end ( ap ) ;
return NULL ;
}
snprintf ( sql , sizeof ( sql ) , " SELECT * FROM %s WHERE %s%s '%s' " , table , newparam , op ,
escapebuf ) ;
ast_str_set ( & sql , 0 , " SELECT * FROM %s WHERE %s%s '%s' " , tablename , newparam , op , escapebuf - > str ) ;
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
if ( ! strchr ( newparam , ' ' ) )
@ -240,15 +268,14 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
else
op = " " ;
PQescapeStringConn( pgsqlConn , escapebuf , newval , ( sizeof ( escapebuf ) - 1 ) / 2 , & pgerror ) ;
if ( pg error ) {
ESCAPE_STRING( escapebuf , newval ) ;
if ( pg result ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
va_end ( ap ) ;
return NULL ;
}
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " AND %s%s '%s' " , newparam ,
op , escapebuf ) ;
ast_str_append ( & sql , 0 , " AND %s%s '%s' " , newparam , op , escapebuf - > str ) ;
}
va_end ( ap ) ;
@ -259,10 +286,10 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
return NULL ;
}
if ( ! ( result = PQexec ( pgsqlConn , sql ) ) ) {
if ( ! ( result = PQexec ( pgsqlConn , sql - > str ) ) ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database . Check debug for more info.\n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql ) ;
" PostgreSQL RealTime: Failed to query '%s@%s' . Check debug for more info.\n " , tablename , database ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s \n " , PQerrorMessage ( pgsqlConn ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
return NULL ;
@ -272,8 +299,8 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
& & result_status ! = PGRES_TUPLES_OK
& & result_status ! = PGRES_NONFATAL_ERROR ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database . Check debug for more info.\n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql ) ;
" PostgreSQL RealTime: Failed to query '%s@%s' . Check debug for more info.\n " , tablename , database ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s (%s) \n " ,
PQresultErrorMessage ( result ) , PQresStatus ( result_status ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
@ -281,7 +308,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
}
}
ast_debug ( 1 , " PostgreSQL RealTime: Result=%p Query: %s \n " , result , sql ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Result=%p Query: %s \n " , result , sql - > str ) ;
if ( ( num_rows = PQntuples ( result ) ) > 0 ) {
int i = 0 ;
@ -318,7 +345,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
}
ast_free ( fieldnames ) ;
} else {
ast_debug ( 1 , " Postgresql RealTime: Could not find any rows in table %s .\n " , tabl e) ;
ast_debug ( 1 , " Postgresql RealTime: Could not find any rows in table %s @%s .\n " , tabl ename, databas e) ;
}
ast_mutex_unlock ( & pgsql_lock ) ;
@ -330,8 +357,9 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
static struct ast_config * realtime_multi_pgsql ( const char * database , const char * table , va_list ap )
{
PGresult * result = NULL ;
int num_rows = 0 , pgerror ;
char sql [ 256 ] , escapebuf [ 513 ] ;
int num_rows = 0 , pgresult ;
struct ast_str * sql = ast_str_thread_get ( & sql_buf , 100 ) ;
struct ast_str * escapebuf = ast_str_thread_get ( & escapebuf_buf , 100 ) ;
const char * initfield = NULL ;
char * stringp ;
char * chunk ;
@ -358,7 +386,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
if ( pgsqlConn ) {
PQfinish ( pgsqlConn ) ;
pgsqlConn = NULL ;
} ;
}
return NULL ;
}
@ -375,15 +403,14 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
else
op = " " ;
PQescapeStringConn( pgsqlConn , escapebuf , newval , ( sizeof ( escapebuf ) - 1 ) / 2 , & pgerror ) ;
if ( pg error ) {
ESCAPE_STRING( escapebuf , newval ) ;
if ( pg result ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
va_end ( ap ) ;
return NULL ;
}
snprintf ( sql , sizeof ( sql ) , " SELECT * FROM %s WHERE %s%s '%s' " , table , newparam , op ,
escapebuf ) ;
ast_str_set ( & sql , 0 , " SELECT * FROM %s WHERE %s%s '%s' " , table , newparam , op , escapebuf - > str ) ;
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
if ( ! strchr ( newparam , ' ' ) )
@ -391,19 +418,18 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
else
op = " " ;
PQescapeStringConn( pgsqlConn , escapebuf , newval , ( sizeof ( escapebuf ) - 1 ) / 2 , & pgerror ) ;
if ( pg error ) {
ESCAPE_STRING( escapebuf , newval ) ;
if ( pg result ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
va_end ( ap ) ;
return NULL ;
}
snprintf ( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " AND %s%s '%s' " , newparam ,
op , escapebuf ) ;
ast_str_append ( & sql , 0 , " AND %s%s '%s' " , newparam , op , escapebuf - > str ) ;
}
if ( initfield ) {
snprintf( sql + strlen ( sql ) , sizeof ( sql ) - strlen ( sql ) , " ORDER BY %s " , initfield ) ;
ast_str_append( & sql , 0 , " ORDER BY %s " , initfield ) ;
}
va_end ( ap ) ;
@ -415,10 +441,10 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
return NULL ;
}
if ( ! ( result = PQexec ( pgsqlConn , sql ) ) ) {
if ( ! ( result = PQexec ( pgsqlConn , sql - > str ) ) ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database . Check debug for more info.\n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql ) ;
" PostgreSQL RealTime: Failed to query %s@%s . Check debug for more info.\n " , table , database ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s \n " , PQerrorMessage ( pgsqlConn ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
return NULL ;
@ -428,8 +454,8 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
& & result_status ! = PGRES_TUPLES_OK
& & result_status ! = PGRES_NONFATAL_ERROR ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database . Check debug for more info.\n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql ) ;
" PostgreSQL RealTime: Failed to query %s@%s . Check debug for more info.\n " , table , database ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s (%s) \n " ,
PQresultErrorMessage ( result ) , PQresStatus ( result_status ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
@ -437,7 +463,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
}
}
ast_debug ( 1 , " PostgreSQL RealTime: Result=%p Query: %s \n " , result , sql ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Result=%p Query: %s \n " , result , sql - > str ) ;
if ( ( num_rows = PQntuples ( result ) ) > 0 ) {
int numFields = PQnfields ( result ) ;
@ -490,22 +516,20 @@ static int update_pgsql(const char *database, const char *tablename, const char
const char * lookup , va_list ap )
{
PGresult * result = NULL ;
int numrows = 0 , pgerror ;
char escapebuf [ 513 ] ;
int numrows = 0 , pgresult ;
const char * newparam , * newval ;
struct ast_str * sql = ast_str_create ( 100 ) ;
struct ast_str * sql = ast_str_thread_get ( & sql_buf , 100 ) ;
struct ast_str * escapebuf = ast_str_thread_get ( & escapebuf_buf , 100 ) ;
struct tables * table ;
struct columns * column = NULL ;
if ( ! tablename ) {
ast_log ( LOG_WARNING , " PostgreSQL RealTime: No table specified. \n " ) ;
ast_free ( sql ) ;
return - 1 ;
}
if ( ! ( table = find_table ( tablename ) ) ) {
ast_log ( LOG_ERROR , " Table '%s' does not exist!! \n " , tablename ) ;
ast_free ( sql ) ;
return - 1 ;
}
@ -518,9 +542,8 @@ static int update_pgsql(const char *database, const char *tablename, const char
if ( pgsqlConn ) {
PQfinish ( pgsqlConn ) ;
pgsqlConn = NULL ;
} ;
ast_mutex_unlock ( & table - > lock ) ;
ast_free ( sql ) ;
}
release_table ( table ) ;
return - 1 ;
}
@ -533,62 +556,51 @@ static int update_pgsql(const char *database, const char *tablename, const char
if ( ! column ) {
ast_log ( LOG_ERROR , " PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'! \n " , newparam , tablename ) ;
ast_mutex_unlock ( & table - > lock ) ;
ast_free ( sql ) ;
release_table ( table ) ;
return - 1 ;
}
/* Create the first part of the query using the first parameter/value pairs we just extracted
If there is only 1 set , then we have our query . Otherwise , loop thru the list and concat */
PQescapeStringConn( pgsqlConn , escapebuf , newval , ( sizeof ( escapebuf ) - 1 ) / 2 , & pgerror ) ;
if ( pg error ) {
ESCAPE_STRING( escapebuf , newval ) ;
if ( pg result ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
va_end ( ap ) ;
ast_mutex_unlock ( & table - > lock ) ;
ast_free ( sql ) ;
release_table ( table ) ;
return - 1 ;
}
ast_str_set ( & sql , 0 , " UPDATE %s SET %s = '%s' " , tablename , newparam , escapebuf ) ;
ast_str_set ( & sql , 0 , " UPDATE %s SET %s = '%s' " , tablename , newparam , escapebuf - > str ) ;
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
/* If the column is not within the table, then skip it */
AST_LIST_TRAVERSE ( & table - > columns , column , list ) {
if ( strcmp ( column - > name , newparam ) = = 0 ) {
break ;
}
}
if ( ! column ) {
if ( ! find_column ( table , newparam ) ) {
ast_log ( LOG_WARNING , " Attempted to update column '%s' in table '%s', but column does not exist! \n " , newparam , tablename ) ;
continue ;
}
PQescapeStringConn( pgsqlConn , escapebuf , newval , ( sizeof ( escapebuf ) - 1 ) / 2 , & pgerror ) ;
if ( pg error ) {
ESCAPE_STRING ( escapebuf , newval ) ;
if ( pgresult ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
va_end ( ap ) ;
ast_mutex_unlock ( & table - > lock ) ;
ast_free ( sql ) ;
release_table ( table ) ;
return - 1 ;
}
ast_str_append ( & sql , 0 , " , %s = '%s' " , newparam , escapebuf ) ;
ast_str_append ( & sql , 0 , " , %s = '%s' " , newparam , escapebuf - > str ) ;
}
va_end ( ap ) ;
ast_mutex_unlock( & table - > lock ) ;
release_table( table ) ;
PQescapeStringConn( pgsqlConn , escapebuf , lookup , ( sizeof ( escapebuf ) - 1 ) / 2 , & pgerror ) ;
if ( pg error ) {
ESCAPE_STRING( escapebuf , lookup ) ;
if ( pg result ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , lookup ) ;
va_end ( ap ) ;
ast_free ( sql ) ;
return - 1 ;
}
ast_str_append ( & sql , 0 , " WHERE %s = '%s' " , keyfield , escapebuf ) ;
ast_str_append ( & sql , 0 , " WHERE %s = '%s' " , keyfield , escapebuf - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Update SQL: %s \n " , sql - > str ) ;
@ -596,7 +608,6 @@ static int update_pgsql(const char *database, const char *tablename, const char
ast_mutex_lock ( & pgsql_lock ) ;
if ( ! pgsql_reconnect ( database ) ) {
ast_mutex_unlock ( & pgsql_lock ) ;
ast_free ( sql ) ;
return - 1 ;
}
@ -642,22 +653,145 @@ static int update_pgsql(const char *database, const char *tablename, const char
return - 1 ;
}
# define ESCAPE_STRING(buffer, stringname) \
do { \
int len ; \
if ( ( len = strlen ( stringname ) ) > ( buffer - > len - 1 ) / 2 ) { \
ast_str_make_space ( & buffer , len * 2 + 1 ) ; \
} \
PQescapeStringConn ( pgsqlConn , buffer - > str , stringname , len , & pgresult ) ; \
} while ( 0 )
static int update2_pgsql ( const char * database , const char * tablename , va_list ap )
{
PGresult * result = NULL ;
int numrows = 0 , pgresult , first = 1 ;
struct ast_str * escapebuf = ast_str_thread_get ( & escapebuf_buf , 16 ) ;
const char * newparam , * newval ;
struct ast_str * sql = ast_str_thread_get ( & sql_buf , 100 ) ;
struct ast_str * where = ast_str_thread_get ( & where_buf , 100 ) ;
struct tables * table ;
if ( ! tablename ) {
ast_log ( LOG_WARNING , " PostgreSQL RealTime: No table specified. \n " ) ;
return - 1 ;
}
if ( ! escapebuf | | ! sql | | ! where ) {
/* Memory error, already handled */
return - 1 ;
}
if ( ! ( table = find_table ( tablename ) ) ) {
ast_log ( LOG_ERROR , " Table '%s' does not exist!! \n " , tablename ) ;
return - 1 ;
}
ast_str_set ( & sql , 0 , " UPDATE %s SET " , tablename ) ;
ast_str_set ( & where , 0 , " WHERE " ) ;
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
if ( ! find_column ( table , newparam ) ) {
ast_log ( LOG_ERROR , " Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist! \n " , newparam , tablename , database ) ;
release_table ( table ) ;
return - 1 ;
}
newval = va_arg ( ap , const char * ) ;
ESCAPE_STRING ( escapebuf , newval ) ;
if ( pgresult ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
release_table ( table ) ;
ast_free ( sql ) ;
return - 1 ;
}
ast_str_append ( & where , 0 , " %s %s='%s' " , first ? " " : " AND " , newparam , escapebuf - > str ) ;
first = 0 ;
}
if ( first ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on. \n " ) ;
if ( pgsqlConn ) {
PQfinish ( pgsqlConn ) ;
pgsqlConn = NULL ;
}
release_table ( table ) ;
return - 1 ;
}
/* Now retrieve the columns to update */
first = 1 ;
while ( ( newparam = va_arg ( ap , const char * ) ) ) {
newval = va_arg ( ap , const char * ) ;
/* If the column is not within the table, then skip it */
if ( ! find_column ( table , newparam ) ) {
ast_log ( LOG_NOTICE , " Attempted to update column '%s' in table '%s@%s', but column does not exist! \n " , newparam , tablename , database ) ;
continue ;
}
ESCAPE_STRING ( escapebuf , newval ) ;
if ( pgresult ) {
ast_log ( LOG_ERROR , " Postgres detected invalid input: '%s' \n " , newval ) ;
release_table ( table ) ;
ast_free ( sql ) ;
return - 1 ;
}
ast_str_append ( & sql , 0 , " %s %s='%s' " , first ? " " : " , " , newparam , escapebuf - > str ) ;
}
release_table ( table ) ;
ast_str_append ( & sql , 0 , " %s " , where - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Update SQL: %s \n " , sql - > str ) ;
/* We now have our complete statement; connect to the server and execute it. */
ast_mutex_lock ( & pgsql_lock ) ;
if ( ! pgsql_reconnect ( database ) ) {
ast_mutex_unlock ( & pgsql_lock ) ;
return - 1 ;
}
if ( ! ( result = PQexec ( pgsqlConn , sql - > str ) ) ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database. Check debug for more info. \n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s \n " , PQerrorMessage ( pgsqlConn ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
return - 1 ;
} else {
ExecStatusType result_status = PQresultStatus ( result ) ;
if ( result_status ! = PGRES_COMMAND_OK
& & result_status ! = PGRES_TUPLES_OK
& & result_status ! = PGRES_NONFATAL_ERROR ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database. Check debug for more info. \n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s (%s) \n " ,
PQresultErrorMessage ( result ) , PQresStatus ( result_status ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
return - 1 ;
}
}
numrows = atoi ( PQcmdTuples ( result ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Updated %d rows on table: %s \n " , numrows , tablename ) ;
/* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
* An integer greater than zero indicates the number of rows affected
* Zero indicates that no records were updated
* - 1 indicates that the query returned an error ( although , if the query failed , it should have been caught above . )
*/
if ( numrows > = 0 ) {
return ( int ) numrows ;
}
return - 1 ;
}
static int store_pgsql ( const char * database , const char * table , va_list ap )
{
PGresult * result = NULL ;
Oid insertid ;
struct ast_str * buf = ast_str_create ( 256 ) ;
struct ast_str * sql1 = ast_str_create ( 256 ) ;
struct ast_str * sql2 = ast_str_create ( 256 ) ;
struct ast_str * buf = ast_str_ thread_get( & escapebuf_buf , 256 ) ;
struct ast_str * sql1 = ast_str_ thread_get( & sql_buf , 256 ) ;
struct ast_str * sql2 = ast_str_ thread_get( & where_buf , 256 ) ;
int pgresult ;
const char * newparam , * newval ;
@ -710,9 +844,6 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql1 - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s \n " , PQerrorMessage ( pgsqlConn ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
ast_free ( sql1 ) ;
ast_free ( sql2 ) ;
ast_free ( buf ) ;
return - 1 ;
} else {
ExecStatusType result_status = PQresultStatus ( result ) ;
@ -725,18 +856,12 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s (%s) \n " ,
PQresultErrorMessage ( result ) , PQresStatus ( result_status ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
ast_free ( sql1 ) ;
ast_free ( sql2 ) ;
ast_free ( buf ) ;
return - 1 ;
}
}
insertid = PQoidValue ( result ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
ast_free ( sql1 ) ;
ast_free ( sql2 ) ;
ast_free ( buf ) ;
ast_debug ( 1 , " PostgreSQL RealTime: row inserted on table: %s, id: %u \n " , table , insertid ) ;
@ -757,8 +882,8 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke
PGresult * result = NULL ;
int numrows = 0 ;
int pgresult ;
struct ast_str * sql = ast_str_ create( 256 ) ;
struct ast_str * buf1 = ast_str_ create( 60 ) , * buf2 = ast_str_create ( 60 ) ;
struct ast_str * sql = ast_str_ thread_get( & sql_buf , 256 ) ;
struct ast_str * buf1 = ast_str_ thread_get( & where_buf , 60 ) , * buf2 = ast_str_thread_get ( & escapebuf_buf , 60 ) ;
const char * newparam , * newval ;
if ( ! table ) {
@ -810,9 +935,6 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s \n " , PQerrorMessage ( pgsqlConn ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
ast_free ( buf1 ) ;
ast_free ( buf2 ) ;
ast_free ( sql ) ;
return - 1 ;
} else {
ExecStatusType result_status = PQresultStatus ( result ) ;
@ -825,18 +947,12 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s (%s) \n " ,
PQresultErrorMessage ( result ) , PQresStatus ( result_status ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
ast_free ( buf1 ) ;
ast_free ( buf2 ) ;
ast_free ( sql ) ;
return - 1 ;
}
}
numrows = atoi ( PQcmdTuples ( result ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
ast_free ( buf1 ) ;
ast_free ( buf2 ) ;
ast_free ( sql ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Deleted %d rows on table: %s \n " , numrows , table ) ;
@ -861,9 +977,7 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
long num_rows ;
struct ast_variable * new_v ;
struct ast_category * cur_cat = NULL ;
char sqlbuf [ 1024 ] = " " ;
char * sql = sqlbuf ;
size_t sqlleft = sizeof ( sqlbuf ) ;
struct ast_str * sql = ast_str_thread_get ( & sql_buf , 100 ) ;
char last [ 80 ] = " " ;
int last_cat_metric = 0 ;
@ -874,11 +988,11 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
return NULL ;
}
ast_ build_string( & sql , & sqlleft , " SELECT category, var_name, var_val, cat_metric FROM %s " , table ) ;
ast_build_string ( & sql , & sqlleft , " WHERE filename='%s' and commented=0 " , file ) ;
ast_build_string ( & sql , & sqlleft , " ORDER BY cat_metric DESC, var_metric ASC, category, var_name " ) ;
ast_ str_set( & sql , 0 , " SELECT category, var_name, var_val, cat_metric FROM %s "
" WHERE filename='%s' and commented=0 "
" ORDER BY cat_metric DESC, var_metric ASC, category, var_name " , table , file ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Static SQL: %s \n " , sql buf ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Static SQL: %s \n " , sql - > str ) ;
/* We now have our complete statement; Lets connect to the server and execute it. */
ast_mutex_lock ( & pgsql_lock ) ;
@ -887,10 +1001,10 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
return NULL ;
}
if ( ! ( result = PQexec ( pgsqlConn , sql buf ) ) ) {
if ( ! ( result = PQexec ( pgsqlConn , sql - > str ) ) ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database . Check debug for more info.\n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql ) ;
" PostgreSQL RealTime: Failed to query '%s@%s' . Check debug for more info.\n " , table , database ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s \n " , PQerrorMessage ( pgsqlConn ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
return NULL ;
@ -901,7 +1015,7 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
& & result_status ! = PGRES_NONFATAL_ERROR ) {
ast_log ( LOG_WARNING ,
" PostgreSQL RealTime: Failed to query database. Check debug for more info. \n " ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query: %s \n " , sql - > str ) ;
ast_debug ( 1 , " PostgreSQL RealTime: Query Failed because: %s (%s) \n " ,
PQresultErrorMessage ( result ) , PQresStatus ( result_status ) ) ;
ast_mutex_unlock ( & pgsql_lock ) ;
@ -1067,7 +1181,7 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap
}
}
}
ast_mutex_unlock( & table - > lock ) ;
release_table( table ) ;
return res ;
}
@ -1101,6 +1215,7 @@ static struct ast_config_engine pgsql_engine = {
. store_func = store_pgsql ,
. destroy_func = destroy_pgsql ,
. update_func = update_pgsql ,
. update2_func = update2_pgsql ,
. require_func = require_pgsql ,
. unload_func = unload_pgsql ,
} ;
@ -1353,7 +1468,7 @@ static char *handle_cli_realtime_pgsql_cache(struct ast_cli_entry *e, int cmd, s
AST_LIST_TRAVERSE ( & cur - > columns , col , list ) {
ast_cli ( a - > fd , " %-20.20s %-20.20s %3d %-8.8s \n " , col - > name , col - > type , col - > len , col - > notnull ? " NOT NULL " : " " ) ;
}
ast_mutex_unlock( & cur - > lock ) ;
release_table( cur ) ;
} else {
ast_cli ( a - > fd , " No such table '%s' \n " , a - > argv [ 4 ] ) ;
}