((db)->state == SQL_DB_STATE_IDLE)
#define SQL_ERRSTR_NOT_CONNECTED "Not connected to database"
+/* What is considered slow query */
+#define SQL_SLOW_QUERY_MSEC 1000
+
+#define SQL_QUERY_FINISHED "sql_query_finished"
+#define SQL_CONNECTION_FINISHED "sql_connection_finished"
+#define SQL_TRANSACTION_FINISHED "sql_transaction_finished"
+
+#define SQL_QUERY_FINISHED_FMT "Finished query '%s' in %u msecs"
+
struct sql_db_module_register {
unsigned int id;
};
extern struct sql_db_module_register sql_db_module_register;
+extern struct event_category event_category_sql;
+
struct sql_transaction_query {
struct sql_transaction_query *next;
struct sql_transaction_context *trans;
void *context);
void *state_change_context;
+ struct event *event;
+
enum sql_db_state state;
/* last time we started connecting to this server
(which may or may not have succeeded) */
unsigned int connect_failure_count;
struct timeout *to_reconnect;
+ uint64_t succeeded_queries;
+ uint64_t failed_queries;
+ /* includes both succeeded and failed */
+ uint64_t slow_queries;
+
bool no_reconnect:1;
};
unsigned int map_size;
struct sql_field_map *map;
void *fetch_dest;
+ struct event *event;
size_t fetch_dest_size;
enum sql_result_error_type error_type;
struct sql_transaction_context {
struct sql_db *db;
+ struct event *event;
/* commit() must use this query list if head is non-NULL. */
struct sql_transaction_query *head, *tail;
const char *query, unsigned int *affected_rows);
const char *sql_statement_get_query(struct sql_statement *stmt);
+void sql_connection_log_finished(struct sql_db *db);
+struct event_passthrough *
+sql_query_finished_event(struct sql_db *db, struct event *event, const char *query,
+ bool success, int *duration_r);
+struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx);
#endif
#include "array.h"
#include "ioloop.h"
#include "str.h"
+#include "time-util.h"
#include "sql-api-private.h"
#include <time.h>
char *query_template;
};
+struct event_category event_category_sql = {
+ .name = "sql",
+};
+
struct sql_db_module_register sql_db_module_register = { 0 };
ARRAY_TYPE(sql_drivers) sql_drivers;
}
if ((driver->flags & SQL_DB_FLAG_POOLED) == 0) {
- if (driver->v.init_full == NULL)
+ if (driver->v.init_full == NULL) {
db = driver->v.init(set->connect_string);
- else
+ db->event = event_create(set->event_parent);
+ event_add_category(db->event, &event_category_sql);
+ } else
ret = driver->v.init_full(set, &db, error_r);
} else
ret = driver_sqlpool_init_full(set, driver, &db, error_r);
ctx->tail = tquery;
}
+void sql_connection_log_finished(struct sql_db *db)
+{
+ struct event_passthrough *e = event_create_passthrough(db->event)->
+ set_name(SQL_CONNECTION_FINISHED);
+ e_debug(e->event(),
+ "Connection finished (queries=%"PRIu64", slow queries=%"PRIu64")",
+ db->succeeded_queries + db->failed_queries,
+ db->slow_queries);
+}
+
+struct event_passthrough *
+sql_query_finished_event(struct sql_db *db, struct event *event, const char *query,
+ bool success, int *duration_r)
+{
+ int diff;
+ struct timeval tv;
+ event_get_create_time(event, &tv);
+ struct event_passthrough *e = event_create_passthrough(event)->
+ set_name(SQL_QUERY_FINISHED)->
+ add_str("query_first_word", t_strcut(query, ' '));
+ diff = timeval_diff_msecs(&ioloop_timeval, &tv);
+
+ if (!success) {
+ db->failed_queries++;
+ } else {
+ db->succeeded_queries++;
+ }
+
+ if (diff >= SQL_SLOW_QUERY_MSEC) {
+ e->add_str("slow_query", "y");
+ db->slow_queries++;
+ }
+
+ if (duration_r != NULL)
+ *duration_r = diff;
+
+ return e;
+}
+
+struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx)
+{
+ return event_create_passthrough(ctx->event)->
+ set_name(SQL_TRANSACTION_FINISHED);
+}
+
struct sql_result sql_not_connected_result = {
.v = {
sql_result_not_connected_free,