--- a/src/core.c Mon Mar 16 21:48:13 2009 +0200
+++ b/src/core.c Mon Mar 16 23:33:38 2009 +0200
@@ -86,10 +86,11 @@
*/
static void _evsql_query_done (struct evsql_query *query, struct evsql_result *res) {
if (res) {
- if (query->cb_fn)
+ if (query->cb_fn) {
// call the callback
query->cb_fn(res, query->cb_arg);
- else {
+
+ } else {
WARNING("supressing cb_fn because query was aborted");
// free the results
@@ -155,6 +156,7 @@
LIST_REMOVE(conn, entry);
// catch deadlocks
+ // XXX: still just assert?
assert(!LIST_EMPTY(&conn->evsql->conn_list) || TAILQ_EMPTY(&conn->evsql->query_queue));
// free
@@ -570,7 +572,7 @@
return evsql;
error:
- // XXX: more complicated than this?
+ // there's no other state yet
free(evsql);
return NULL;
@@ -913,3 +915,53 @@
}
}
+void evsql_destroy (struct evsql *evsql) {
+ struct evsql_query *query;
+ struct evsql_conn *conn;
+
+ // kill off all queued queries
+ while ((query = TAILQ_FIRST(&evsql->query_queue)) != NULL) {
+ // just free it, command first
+ free(query->command); query->command = NULL;
+ _evsql_query_free(query);
+ }
+
+ // kill off all connections
+ while ((conn = LIST_FIRST(&evsql->conn_list)) != NULL) {
+ // kill off the query
+ if (conn->query) {
+ free(query->command); query->command = NULL;
+ _evsql_query_free(query);
+
+ conn->query = NULL;
+ }
+
+ // kill off the transaction
+ if (conn->trans) {
+ conn->trans->query = NULL;
+ _evsql_trans_release(conn->trans);
+ }
+
+ // kill it off
+ _evsql_conn_release(conn);
+ }
+
+ // then free the evsql itself
+ free(evsql);
+}
+
+void _evsql_destroy_handler (int fd, short what, void *arg)
+{
+ struct evsql *evsql = arg;
+
+ evsql_destroy(evsql);
+}
+
+evsql_err_t evsql_destroy_next (struct evsql *evsql)
+{
+ struct timeval tv = {0, 0};
+
+ // schedule a one-time event
+ return event_base_once(evsql->ev_base, 0, EV_TIMEOUT, &_evsql_destroy_handler, evsql, &tv);
+}
+
--- a/src/include/evsql.h Mon Mar 16 21:48:13 2009 +0200
+++ b/src/include/evsql.h Mon Mar 16 23:33:38 2009 +0200
@@ -415,16 +415,25 @@
void *cb_arg
);
-// @}
-
/**
- * Close a connection. Callbacks for waiting queries will not be run.
+ * Close the evsql handle. IMPORTANT: There are severe restrictions on the use of this function. It must *NOT* be
+ * called from any evsql_*_cb callback, or the program will probably crash after the callback returns.
*
- * XXX: not implemented yet.
+ * Currently, the evsql handle can only be free'd if the entire evsql is idle, so this will silently abort any
+ * pending queries and transactions, which may lead to nasty things.
+ *
+ * As a workaround to the callback-issue, you can call evsql_destroy from the next event loop iteration, which is
+ * what evsql_destroy_next does for you.
*
* @param evsql the context handle from \ref evsql_new_
*/
-void evsql_close (struct evsql *evsql);
+void evsql_destroy (struct evsql *evsql);
+
+/**
+ * Call evsql_destroy in the next event loop iteration. If scheduling this fails, we return -1 (not a meaningful error
+ * code, but nonzero).
+ */
+evsql_err_t evsql_destroy_next (struct evsql *evsql);
// @}
--- a/src/internal.h Mon Mar 16 21:48:13 2009 +0200
+++ b/src/internal.h Mon Mar 16 23:33:38 2009 +0200
@@ -93,7 +93,6 @@
// our current query
struct evsql_query *query;
-
};
/*
--- a/src/result.c Mon Mar 16 21:48:13 2009 +0200
+++ b/src/result.c Mon Mar 16 23:33:38 2009 +0200
@@ -255,4 +255,3 @@
}
}
-