aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_config_pgsql.c
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2008-10-14 00:08:52 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2008-10-14 00:08:52 +0000
commit4d59ca26413ca59d0b59ae3600ebcc0e204b7018 (patch)
treedefa29805f9479efc7793b15f9e31a97dfe89603 /res/res_config_pgsql.c
parent1078121ae0495b161d852f75b6cd8e1fb4c55463 (diff)
Merge realtime_update2 branch, which adds a new realtime API call named
'update2', which permits updates which match across multiple columns, instead of requiring all tables to have a single unique identifier. All of the other API calls with the exception of 'update' already had the ability to match on multiple fields, so it was a missing and very desireable feature that an API call implementing an update should have this, too. This does not change any outward performance of Asterisk, but it should make life easier for application developers who use the RealTime framework. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@148570 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res/res_config_pgsql.c')
-rw-r--r--res/res_config_pgsql.c365
1 files changed, 240 insertions, 125 deletions
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index f7c1f3a6a..fe672bf62 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -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_wrlock(&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_rdlock(&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_rdlock(&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 (!tablename) {
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 (pgerror) {
+ ESCAPE_STRING(escapebuf, newval);
+ if (pgresult) {
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 (pgerror) {
+ ESCAPE_STRING(escapebuf, newval);
+ if (pgresult) {
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", table);
+ ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s@%s.\n", tablename, database);
}
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 (pgerror) {
+ ESCAPE_STRING(escapebuf, newval);
+ if (pgresult) {
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 (pgerror) {
+ ESCAPE_STRING(escapebuf, newval);
+ if (pgresult) {
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 (pgerror) {
+ 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_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 (pgerror) {
+ 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 (pgerror) {
+ ESCAPE_STRING(escapebuf, lookup);
+ if (pgresult) {
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", sqlbuf);
+ 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, sqlbuf))) {
+ 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]);
}