store and destroy implementations for realtime pgsql (closes issue #10372)
authorTilghman Lesher <tilghman@meg.abyt.es>
Fri, 17 Aug 2007 13:40:11 +0000 (13:40 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Fri, 17 Aug 2007 13:40:11 +0000 (13:40 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@79859 65c4cc65-6c06-0410-ace0-fbb531ad65f3

funcs/func_lock.c
res/res_config_pgsql.c

index e950aef..8c08f85 100644 (file)
@@ -97,7 +97,7 @@ static int get_lock(struct ast_channel *chan, char *lockname, int try)
 {
        struct ast_datastore *lock_store = ast_channel_datastore_find(chan, &lock_info, NULL);
        struct lock_frame *current;
-       struct channel_lock_frame *clframe, *save_clframe;
+       struct channel_lock_frame *clframe = NULL, *save_clframe = NULL;
        AST_LIST_HEAD(, channel_lock_frame) *list;
        int res, count_channel_locks = 0;
 
index c3e9777..8bd2322 100644 (file)
@@ -429,6 +429,191 @@ static int update_pgsql(const char *database, const char *table, const char *key
        return -1;
 }
 
+static int store_pgsql(const char *database, const char *table, va_list ap)
+{
+       PGresult *result = NULL;
+       Oid insertid;
+       char sql[256];
+       char params[256];
+       char vals[256];
+       char buf[256];
+       int pgresult;
+       const char *newparam, *newval;
+
+       if (!table) {
+               ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
+               return -1;
+       }
+
+       /* Get the first parameter and first value in our list of passed paramater/value pairs */
+       newparam = va_arg(ap, const char *);
+       newval = va_arg(ap, const char *);
+       if (!newparam || !newval) {
+               ast_log(LOG_WARNING,
+                               "Postgresql RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
+               if (pgsqlConn) {
+                       PQfinish(pgsqlConn);
+                       pgsqlConn = NULL;
+               };
+               return -1;
+       }
+
+       /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
+       ast_mutex_lock(&pgsql_lock);
+       if (!pgsql_reconnect(database)) {
+               ast_mutex_unlock(&pgsql_lock);
+               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, buf, newparam, sizeof(newparam), &pgresult);
+       snprintf(params, sizeof(params), "%s", buf);
+       PQescapeStringConn(pgsqlConn, buf, newval, sizeof(newval), &pgresult);
+       snprintf(vals, sizeof(vals), "'%s'", buf);
+       while ((newparam = va_arg(ap, const char *))) {
+               newval = va_arg(ap, const char *);
+               PQescapeStringConn(pgsqlConn, buf, newparam, sizeof(newparam), &pgresult);
+               snprintf(params + strlen(params), sizeof(params) - strlen(params), ", %s", buf);
+               PQescapeStringConn(pgsqlConn, buf, newval, sizeof(newval), &pgresult);
+               snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", '%s'", buf);
+       }
+       va_end(ap);
+       snprintf(sql, sizeof(sql), "INSERT INTO (%s) VALUES (%s)", params, vals);
+
+       ast_debug(1, "Postgresql RealTime: Insert SQL: %s\n", sql);
+
+       if (!(result = PQexec(pgsqlConn, sql))) {
+               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 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);
+                       ast_debug(1, "Postgresql RealTime: Query Failed because: %s (%s)\n",
+                                               PQresultErrorMessage(result), PQresStatus(result_status));
+                       ast_mutex_unlock(&pgsql_lock);
+                       return -1;
+               }
+       }
+
+       insertid = PQoidValue(result);
+       ast_mutex_unlock(&pgsql_lock);
+
+       ast_debug(1, "Postgresql RealTime: row inserted on table: %s, id: %u\n", table, insertid);
+
+       /* 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 (insertid >= 0)
+               return (int) insertid;
+
+       return -1;
+}
+
+static int destroy_pgsql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
+{
+       PGresult *result = NULL;
+       int numrows = 0;
+       int pgresult;
+       char sql[256];
+       char buf[256], buf2[256];
+       const char *newparam, *newval;
+
+       if (!table) {
+               ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
+               return -1;
+       }
+
+       /* Get the first parameter and first value in our list of passed paramater/value pairs */
+       /*newparam = va_arg(ap, const char *);
+       newval = va_arg(ap, const char *);
+       if (!newparam || !newval) {*/
+       if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
+               ast_log(LOG_WARNING,
+                               "Postgresql RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n");
+               if (pgsqlConn) {
+                       PQfinish(pgsqlConn);
+                       pgsqlConn = NULL;
+               };
+               return -1;
+       }
+
+       /* Must connect to the server before anything else, as the escape function requires the connection handle.. */
+       ast_mutex_lock(&pgsql_lock);
+       if (!pgsql_reconnect(database)) {
+               ast_mutex_unlock(&pgsql_lock);
+               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, buf, keyfield, sizeof(keyfield), &pgresult);
+       PQescapeStringConn(pgsqlConn, buf2, lookup, sizeof(lookup), &pgresult);
+       snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s'", table, buf, buf2);
+       while ((newparam = va_arg(ap, const char *))) {
+               newval = va_arg(ap, const char *);
+               PQescapeStringConn(pgsqlConn, buf, newparam, sizeof(newparam), &pgresult);
+               PQescapeStringConn(pgsqlConn, buf2, newval, sizeof(newval), &pgresult);
+               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s = '%s'", buf, buf2);
+       }
+       va_end(ap);
+
+       ast_debug(1, "Postgresql RealTime: Delete SQL: %s\n", sql);
+
+       if (!(result = PQexec(pgsqlConn, sql))) {
+               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 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);
+                       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: Deleted %d rows on table: %s\n", numrows, table);
+
+       /* 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 struct ast_config *config_pgsql(const char *database, const char *table,
                                           const char *file, struct ast_config *cfg,
                                           struct ast_flags flags)
@@ -531,6 +716,8 @@ static struct ast_config_engine pgsql_engine = {
        .load_func = config_pgsql,
        .realtime_func = realtime_pgsql,
        .realtime_multi_func = realtime_multi_pgsql,
+       .store_func = store_pgsql,
+       .destroy_func = destroy_pgsql,
        .update_func = update_pgsql
 };