diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/res_config_odbc.c | 141 | ||||
-rw-r--r-- | res/res_config_sqlite.c | 212 |
2 files changed, 353 insertions, 0 deletions
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 6388ab72b..1faf28dfc 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -450,6 +450,145 @@ static int update_odbc(const char *database, const char *table, const char *keyf return -1; } +/*! + * \brief Excute an INSERT query + * \param database + * \param table + * \param ap list containing one or more field/value set(s) + * Insert a new record into database table, prepare the sql statement. + * All values to be changed are stored in ap list. + * Sub-in the values to the prepared statement and execute it. + * + * \retval number of rows affected + * \retval -1 on failure +*/ +static int store_odbc(const char *database, const char *table, va_list ap) +{ + struct odbc_obj *obj; + SQLHSTMT stmt; + char sql[256]; + char keys[256]; + char vals[256]; + SQLLEN rowcount=0; + const char *newparam, *newval; + int res; + va_list aq; + struct custom_prepare_struct cps = { .sql = sql, .extra = NULL }; + + va_copy(cps.ap, ap); + va_copy(aq, ap); + + if (!table) + return -1; + + obj = ast_odbc_request_obj(database, 0); + if (!obj) + return -1; + + newparam = va_arg(aq, const char *); + if (!newparam) { + ast_odbc_release_obj(obj); + return -1; + } + newval = va_arg(aq, const char *); + snprintf(keys, sizeof(keys), "%s", newparam); + snprintf(vals, sizeof(vals), "?"); + while ((newparam = va_arg(aq, const char *))) { + snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam); + snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?"); + newval = va_arg(aq, const char *); + } + va_end(aq); + snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals); + + stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps); + + if (!stmt) { + ast_odbc_release_obj(obj); + return -1; + } + + res = SQLRowCount(stmt, &rowcount); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); + return -1; + } + + if (rowcount >= 0) + return (int)rowcount; + + return -1; +} + +/*! + * \brief Excute an DELETE query + * \param database + * \param table + * \param keyfield where clause field + * \param lookup value of field for where clause + * \param ap list containing one or more field/value set(s) + * Dlete a row from a database table, prepare the sql statement using keyfield and lookup + * control the number of records to change. Additional params to match rows are stored in ap list. + * Sub-in the values to the prepared statement and execute it. + * + * \retval number of rows affected + * \retval -1 on failure +*/ +static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap) +{ + struct odbc_obj *obj; + SQLHSTMT stmt; + char sql[256]; + SQLLEN rowcount=0; + const char *newparam, *newval; + int res; + va_list aq; + struct custom_prepare_struct cps = { .sql = sql, .extra = lookup }; + + va_copy(cps.ap, ap); + va_copy(aq, ap); + + if (!table) + return -1; + + obj = ast_odbc_request_obj(database, 0); + if (!obj) + return -1; + + snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table); + while((newparam = va_arg(aq, const char *))) { + snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam); + newval = va_arg(aq, const char *); + } + va_end(aq); + snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield); + + stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps); + + if (!stmt) { + ast_odbc_release_obj(obj); + return -1; + } + + res = SQLRowCount(stmt, &rowcount); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); + return -1; + } + + if (rowcount >= 0) + return (int)rowcount; + + return -1; +} + + struct config_odbc_obj { char *sql; unsigned long cat_metric; @@ -575,6 +714,8 @@ static struct ast_config_engine odbc_engine = { .load_func = config_odbc, .realtime_func = realtime_odbc, .realtime_multi_func = realtime_multi_odbc, + .store_func = store_odbc, + .destroy_func = destroy_odbc, .update_func = update_odbc }; diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c index fd28ef62d..34912eaac 100644 --- a/res/res_config_sqlite.c +++ b/res/res_config_sqlite.c @@ -433,6 +433,46 @@ static int realtime_update_handler(const char *database, const char *table, va_list ap); /*! + * \brief Asterisk callback function for RealTime configuration (variable + * create/store). + * + * Asterisk will call this function each time a variable has been created + * internally and must be stored in the backend engine. + * are used to find the row to update, e.g. ap is a list of parameters and + * values with the same format as the other realtime functions. + * + * \param database the database to use (ignored) + * \param table the table to use + * \param ap list of parameters and new values to insert into the database + * \retval the rowid of inserted row. + * \retval -1 if an error occurred. + */ +static int realtime_store_handler(const char *database, const char *table, + va_list ap); + +/*! + * \brief Asterisk callback function for RealTime configuration (destroys + * variable). + * + * Asterisk will call this function each time a variable has been destroyed + * internally and must be removed from the backend engine. keyfield and entity + * are used to find the row to delete, e.g. <code>DELETE FROM table WHERE + * keyfield = 'entity';</code>. ap is a list of parameters and values with the + * same format as the other realtime functions. + * + * \param database the database to use (ignored) + * \param table the table to use + * \param keyfield the column of the matching cell + * \param entity the value of the matching cell + * \param ap list of additional parameters for cell matching + * \retval the number of affected rows. + * \retval -1 if an error occurred. + */ +static int realtime_destroy_handler(const char *database, const char *table, + const char *keyfield, const char *entity, + va_list ap); + +/*! * \brief Asterisk callback function for the CLI status command. * * \param fd file descriptor provided by Asterisk to use with ast_cli() @@ -476,6 +516,8 @@ static struct ast_config_engine sqlite_engine = .load_func = config_handler, .realtime_func = realtime_handler, .realtime_multi_func = realtime_multi_handler, + .store_func = realtime_store_handler, + .destroy_func = realtime_destroy_handler, .update_func = realtime_update_handler }; @@ -1171,6 +1213,176 @@ static int realtime_update_handler(const char *database, const char *table, return rows_num; } +static int realtime_store_handler(const char *database, const char *table, va_list ap) { + char *errormsg, *tmp_str, *tmp_keys, *tmp_keys2, *tmp_vals, *tmp_vals2; + const char **params, **vals; + size_t params_count; + int error, rows_id; + size_t i; + + if (!table) { + ast_log(LOG_WARNING, "Table name unspecified\n"); + return -1; + } + + if (!(params_count = get_params(ap, ¶ms, &vals))) + return -1; + +/* \cond DOXYGEN_CAN_PARSE_THIS */ +#undef QUERY +#define QUERY "INSERT into '%q' (%s) VALUES (%s);" +/* \endcond */ + + tmp_keys2 = NULL; + tmp_vals2 = NULL; + for (i = 0; i < params_count; i++) { + if ( tmp_keys2 ) { + tmp_keys = sqlite_mprintf("%s, %q", tmp_keys2, params[i]); + sqlite_freemem(tmp_keys2); + } else { + tmp_keys = sqlite_mprintf("%q", params[i]); + } + if (!tmp_keys) { + ast_log(LOG_WARNING, "Unable to reallocate SQL query\n"); + ast_free(params); + ast_free(vals); + return -1; + } + + if ( tmp_vals2 ) { + tmp_vals = sqlite_mprintf("%s, '%q'", tmp_vals2, params[i]); + sqlite_freemem(tmp_vals2); + } else { + tmp_vals = sqlite_mprintf("'%q'", params[i]); + } + if (!tmp_vals) { + ast_log(LOG_WARNING, "Unable to reallocate SQL query\n"); + ast_free(params); + ast_free(vals); + return -1; + } + + + tmp_keys2 = tmp_keys; + tmp_vals2 = tmp_vals; + } + + ast_free(params); + ast_free(vals); + + if (!(tmp_str = sqlite_mprintf(QUERY, table, tmp_keys, tmp_vals))) { + ast_log(LOG_WARNING, "Unable to reallocate SQL query\n"); + return -1; + } + + sqlite_freemem(tmp_keys); + sqlite_freemem(tmp_vals); + + ast_debug(1, "SQL query: %s\n", tmp_str); + + ast_mutex_lock(&mutex); + + RES_SQLITE_BEGIN + error = sqlite_exec(db, tmp_str, NULL, NULL, &errormsg); + RES_SQLITE_END(error) + + if (!error) { + rows_id = sqlite_last_insert_rowid(db); + } else { + rows_id = -1; + } + + ast_mutex_unlock(&mutex); + + sqlite_freemem(tmp_str); + + if (error) { + ast_log(LOG_WARNING, "%s\n", errormsg); + ast_free(errormsg); + } + + return rows_id; +} + +static int realtime_destroy_handler(const char *database, const char *table, + const char *keyfield, const char *entity, + va_list ap) +{ + char *query, *errormsg, *tmp_str; + const char **params, **vals; + size_t params_count; + int error, rows_num; + size_t i; + + if (!table) { + ast_log(LOG_WARNING, "Table name unspecified\n"); + return -1; + } + + if (!(params_count = get_params(ap, ¶ms, &vals))) + return -1; + +/* \cond DOXYGEN_CAN_PARSE_THIS */ +#undef QUERY +#define QUERY "DELETE FROM '%q' WHERE" +/* \endcond */ + + if (!(query = sqlite_mprintf(QUERY, table))) { + ast_log(LOG_WARNING, "Unable to allocate SQL query\n"); + ast_free(params); + ast_free(vals); + return -1; + } + + for (i = 0; i < params_count; i++) { + tmp_str = sqlite_mprintf("%s %q = '%q' AND", query, params[i], vals[i]); + sqlite_freemem(query); + + if (!tmp_str) { + ast_log(LOG_WARNING, "Unable to reallocate SQL query\n"); + ast_free(params); + ast_free(vals); + return -1; + } + + query = tmp_str; + } + + ast_free(params); + ast_free(vals); + if (!(tmp_str = sqlite_mprintf("%s %q = '%q';", query, keyfield, entity))) { + ast_log(LOG_WARNING, "Unable to reallocate SQL query\n"); + return -1; + } + sqlite_freemem(query); + query = tmp_str; + + ast_debug(1, "SQL query: %s\n", query); + + ast_mutex_lock(&mutex); + + RES_SQLITE_BEGIN + error = sqlite_exec(db, query, NULL, NULL, &errormsg); + RES_SQLITE_END(error) + + if (!error) + rows_num = sqlite_changes(db); + else + rows_num = -1; + + ast_mutex_unlock(&mutex); + + sqlite_freemem(query); + + if (error) { + ast_log(LOG_WARNING, "%s\n", errormsg); + ast_free(errormsg); + } + + return rows_num; +} + + static int cli_status(int fd, int argc, char *argv[]) { ast_cli(fd, "SQLite database path: %s\n", dbfile); |