@@ -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,
};
Now that the common DB API offers prep & exec support, update the MySQL plug-in to use it. Signed-off-by: Jeremy Sowden <jeremy@azazel.net> --- output/mysql/ulogd_output_MYSQL.c | 163 ++++++++++++++++++++++++------ 1 file changed, 131 insertions(+), 32 deletions(-)