[asterisk-commits] tilghman: trunk r79860 - in /trunk/res: res_config_odbc.c res_config_sqlite.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Aug 17 08:45:44 CDT 2007


Author: tilghman
Date: Fri Aug 17 08:45:44 2007
New Revision: 79860

URL: http://svn.digium.com/view/asterisk?view=rev&rev=79860
Log:
store and destroy implementations for sqlite (closes issue #10446) and odbc (closes issue #10447)

Modified:
    trunk/res/res_config_odbc.c
    trunk/res/res_config_sqlite.c

Modified: trunk/res/res_config_odbc.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_config_odbc.c?view=diff&rev=79860&r1=79859&r2=79860
==============================================================================
--- trunk/res/res_config_odbc.c (original)
+++ trunk/res/res_config_odbc.c Fri Aug 17 08:45:44 2007
@@ -450,6 +450,145 @@
 	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 @@
 	.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
 };
 

Modified: trunk/res/res_config_sqlite.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_config_sqlite.c?view=diff&rev=79860&r1=79859&r2=79860
==============================================================================
--- trunk/res/res_config_sqlite.c (original)
+++ trunk/res/res_config_sqlite.c Fri Aug 17 08:45:44 2007
@@ -433,6 +433,46 @@
 	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 @@
 	.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 @@
 	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, &params, &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, &params, &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);




More information about the asterisk-commits mailing list