Now that the common DB API offers prep & exec support, update the MySQL plug-in to use it. Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx> --- output/mysql/ulogd_output_MYSQL.c | 163 ++++++++++++++++++++++++------ 1 file changed, 131 insertions(+), 32 deletions(-) diff --git a/output/mysql/ulogd_output_MYSQL.c b/output/mysql/ulogd_output_MYSQL.c index bed1d7488019..d64da85a418a 100644 --- a/output/mysql/ulogd_output_MYSQL.c +++ b/output/mysql/ulogd_output_MYSQL.c @@ -37,11 +37,12 @@ * Port to ulogd2 (@ 0sec conference, Bern, Suisse) */ +#include <assert.h> +#ifdef DEBUG_MYSQL +#include <stdio.h> +#endif #include <stdlib.h> #include <string.h> -#include <errno.h> -#include <time.h> -#include <arpa/inet.h> #include <mysql/mysql.h> #include <ulogd/ulogd.h> #include <ulogd/conffile.h> @@ -56,6 +57,12 @@ struct mysql_instance { struct db_instance db_inst; MYSQL *dbh; /* the database handle we are using */ + MYSQL_STMT *sth; +}; + +struct mysql_buffer { + unsigned long length; + my_bool is_null; }; /* our configuration directives */ @@ -193,46 +200,138 @@ static int open_db_mysql(struct ulogd_pluginstance *upi) return 0; } -static int escape_string_mysql(struct ulogd_pluginstance *upi, - char *dst, const char *src, unsigned int len) +static int prepare_mysql(struct ulogd_pluginstance *upi, + const struct db_stmt *stmt) { struct mysql_instance *mi = (struct mysql_instance *) upi->private; -#ifdef OLD_MYSQL - return mysql_escape_string(dst, src, len); -#else - return mysql_real_escape_string(mi->dbh, dst, src, len); -#endif /* OLD_MYSQL */ + if (mi->sth) + mysql_stmt_close(mi->sth); + + if (!(mi->sth = mysql_stmt_init(mi->dbh))) { + ulogd_log(ULOGD_ERROR, + "Failed to initialize statement: %s\n", + mysql_error(mi->dbh)); + return -1; + } + + if (mysql_stmt_prepare(mi->sth, stmt->sql, stmt->len) != 0) { + ulogd_log(ULOGD_ERROR, + "Failed to prepare statement: %s\n", + mysql_stmt_error(mi->sth)); + return -1; + } + + return 0; } static int execute_mysql(struct ulogd_pluginstance *upi, const struct db_stmt *stmt) { struct mysql_instance *mi = (struct mysql_instance *) upi->private; - int ret; - MYSQL_RES * result; + struct mysql_buffer *buffers; + MYSQL_BIND *bindings; + unsigned int i; + int rv = -1; - ret = mysql_real_query(mi->dbh, stmt->sql, stmt->len); - if (ret) { - ulogd_log(ULOGD_ERROR, "execute failed (%s)\n", - mysql_error(mi->dbh)); - return -1; + if (!(bindings = calloc(stmt->nr_params, sizeof(*bindings)))) + goto err_return; + + if (!(buffers = calloc(stmt->nr_params, sizeof(*buffers)))) + goto err_free_bindings; + + for (i = 0; i < stmt->nr_params; i++) { + struct db_stmt_arg *arg = &stmt->args[i]; + union db_stmt_arg_value *val = &arg->value; + + if (arg->null) { + bindings[i++].buffer_type = MYSQL_TYPE_NULL; + continue; + } + + switch (arg->type) { + case ULOGD_RET_BOOL: + case ULOGD_RET_INT8: + case ULOGD_RET_UINT8: + bindings[i].buffer_type = MYSQL_TYPE_TINY; + bindings[i].buffer = val; + bindings[i].is_unsigned = arg->type != ULOGD_RET_INT8; + break; + case ULOGD_RET_INT16: + case ULOGD_RET_UINT16: + bindings[i].buffer_type = MYSQL_TYPE_SHORT; + bindings[i].buffer = val; + bindings[i].is_unsigned = arg->type != ULOGD_RET_INT16; + break; + case ULOGD_RET_INT32: + case ULOGD_RET_UINT32: + case ULOGD_RET_IPADDR: + bindings[i].buffer_type = MYSQL_TYPE_LONG; + bindings[i].buffer = val; + bindings[i].is_unsigned = arg->type != ULOGD_RET_INT32; + break; + case ULOGD_RET_INT64: + case ULOGD_RET_UINT64: + bindings[i].buffer_type = MYSQL_TYPE_LONGLONG; + bindings[i].buffer = val; + bindings[i].is_unsigned = arg->type != ULOGD_RET_INT64; + break; + case ULOGD_RET_STRING: + bindings[i].buffer_type = MYSQL_TYPE_STRING; + bindings[i].is_null = &buffers[i].is_null; + bindings[i].length = &buffers[i].length; + if (val->ptr) { + bindings[i].buffer = val->ptr; + bindings[i].buffer_length = arg->len + 1; + buffers[i].length = arg->len; + } else + buffers[i].is_null = 1; + break; + case ULOGD_RET_RAWSTR: + bindings[i].buffer_type = MYSQL_TYPE_BLOB; + bindings[i].is_null = &buffers[i].is_null; + bindings[i].length = &buffers[i].length; + if (val->ptr) { + bindings[i].buffer = val->ptr; + bindings[i].buffer_length = arg->len; + buffers[i].length = arg->len; + } else + buffers[i].is_null = 1; + break; + } } - result = mysql_use_result(mi->dbh); - if (result) { - mysql_free_result(result); + + if (mysql_stmt_bind_param(mi->sth, bindings) != 0) { + ulogd_log(ULOGD_ERROR, + "Failed to bind statement parameters: %s\n", + mysql_stmt_error(mi->sth)); + goto err_free_buffers; } - return 0; + if (mysql_stmt_execute(mi->sth) != 0) { + ulogd_log(ULOGD_ERROR, + "Failed to execute statement: %s\n", + mysql_stmt_error(mi->sth)); + goto err_free_buffers; + } + + rv = 0; + +err_free_buffers: + free (buffers); +err_free_bindings: + free (bindings); +err_return: + return rv; } static struct db_driver db_driver_mysql = { - .get_columns = &get_columns_mysql, - .get_column = &get_column_mysql, - .open_db = &open_db_mysql, - .close_db = &close_db_mysql, - .escape_string = &escape_string_mysql, - .execute = &execute_mysql, + .get_columns = get_columns_mysql, + .get_column = get_column_mysql, + .open_db = open_db_mysql, + .close_db = close_db_mysql, + .prepare = prepare_mysql, + .execute = execute_mysql, }; static int configure_mysql(struct ulogd_pluginstance *upi, @@ -254,11 +353,11 @@ static struct ulogd_plugin plugin_mysql = { }, .config_kset = &kset_mysql, .priv_size = sizeof(struct mysql_instance), - .configure = &configure_mysql, - .start = &ulogd_db_start, - .stop = &ulogd_db_stop, - .signal = &ulogd_db_signal, - .interp = &ulogd_db_interp, + .configure = configure_mysql, + .start = ulogd_db_start, + .stop = ulogd_db_stop, + .signal = ulogd_db_signal, + .interp = ulogd_db_interp, .version = VERSION, }; -- 2.35.1