Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
mxq
Public
Notifications
You must be signed in to change notification settings
Fork
3
Star
3
Code
Issues
21
Pull requests
4
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
49442f9
helper
manpages
mysql
web
.gitignore
.vimrc
Doxyfile
LICENSE
Makefile
README.md
keywordset.c
keywordset.h
mx_flock.c
mx_flock.h
mx_getopt.c
mx_getopt.h
mx_log.c
mx_log.h
mx_mysql.c
mx_mysql.h
mx_proc.c
mx_proc.h
mx_util.c
mx_util.h
mxq.h
mxq_daemon.c
mxq_daemon.h
mxq_group.c
mxq_group.h
mxq_job.c
mxq_job.h
mxq_log.c
mxq_reaper.c
mxqadmin.c
mxqd.c
mxqd.h
mxqd_control.c
mxqd_control.h
mxqdctl-hostconfig.sh
mxqdump.c
mxqkill.c
mxqps.c
mxqset.c
mxqsub.c
os-release
parser.y
ppidcache.c
ppidcache.h
test_keywordset.c
test_mx_log.c
test_mx_mysql.c
test_mx_util.c
test_mxqd_control.c
test_parser.c
xmalloc.h
Breadcrumbs
mxq
/
mx_mysql.c
Copy path
Blame
Blame
Latest commit
History
History
1400 lines (1056 loc) · 38.1 KB
Breadcrumbs
mxq
/
mx_mysql.c
Top
File metadata and controls
Code
Blame
1400 lines (1056 loc) · 38.1 KB
Raw
#define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <stdarg.h> #include <unistd.h> #include <mysql.h> #include <mysqld_error.h> #include <errmsg.h> #include <errno.h> #include <time.h> #include "mx_mysql.h" #include "mx_util.h" #include "mx_log.h" #define mx__mysql_log(lvl, mysql) \ mx_log_ ## lvl("MySQL %s(): ERROR %u (%s): %s", \ (mysql)->func, \ mx__mysql_errno(mysql), \ mx__mysql_sqlstate(mysql), \ mx__mysql_error(mysql)) #define mx__mysql_stmt_log(lvl, stmt) \ mx_log_ ## lvl("MySQL %s(): ERROR %u (%s): %s", \ (stmt)->func, \ mx__mysql_stmt_errno(stmt), \ mx__mysql_stmt_sqlstate(stmt), \ mx__mysql_stmt_error(stmt)) #define mx__mysql_log_emerg(mysql) mx__mysql_log(emerg, (mysql)) #define mx__mysql_log_err(mysql) mx__mysql_log(err, (mysql)) #define mx__mysql_log_warning(mysql) mx__mysql_log(warning, (mysql)) #define mx__mysql_log_info(mysql) mx__mysql_log(info, (mysql)) #define mx__mysql_log_debug(mysql) mx__mysql_log(debug, (mysql)) #define mx__mysql_stmt_log_emerg(stmt) mx__mysql_stmt_log(emerg, (stmt)) #define mx__mysql_stmt_log_err(stmt) mx__mysql_stmt_log(err, (stmt)) #define mx__mysql_stmt_log_warning(stmt) mx__mysql_stmt_log(warning, (stmt)) #define mx__mysql_stmt_log_info(stmt) mx__mysql_stmt_log(info, (stmt)) #define mx__mysql_stmt_log_debug(stmt) mx__mysql_stmt_log(debug, (stmt)) static struct mx_mysql_stmt *mx_mysql_statement_prepare_with_bindings(struct mx_mysql *mysql, char *statement, struct mx_mysql_bind *param, struct mx_mysql_bind *result); /**********************************************************************/ static int mx__mysql_errno(struct mx_mysql *mysql) { unsigned int error; mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(mysql->mysql, EBADF); error = mysql_errno(mysql->mysql); mx_assert_return_minus_errno((unsigned int)(int)error == error, ERANGE); /* no mysql errors possible */ return (int)error; } static const char *mx__mysql_error(struct mx_mysql *mysql) { mx_assert_return_NULL(mysql, EINVAL); mx_assert_return_NULL(mysql->mysql, EBADF); /* no mysql errors possible */ return mysql_error(mysql->mysql); } static const char *mx__mysql_sqlstate(struct mx_mysql *mysql) { mx_assert_return_NULL(mysql, EINVAL); mx_assert_return_NULL(mysql->mysql, EBADF); /* no mysql errors possible */ return mysql_sqlstate(mysql->mysql); } static int mx__mysql_stmt_errno(struct mx_mysql_stmt *stmt) { unsigned int error; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); error = mysql_stmt_errno(stmt->stmt); mx_assert_return_minus_errno((unsigned int)(int)error == error, ERANGE); /* no mysql errors possible */ return (int)error; } static const char *mx__mysql_stmt_error(struct mx_mysql_stmt *stmt) { mx_assert_return_NULL(stmt, EINVAL); mx_assert_return_NULL(stmt->stmt, EBADF); /* no mysql errors possible */ return mysql_stmt_error(stmt->stmt); } static const char *mx__mysql_stmt_sqlstate(struct mx_mysql_stmt *stmt) { mx_assert_return_NULL(stmt, EINVAL); mx_assert_return_NULL(stmt->stmt, EBADF); /* no mysql errors possible */ return mysql_stmt_sqlstate(stmt->stmt); } static int mx__mysql_init(struct mx_mysql *mysql) { mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(!mysql->mysql, EUCLEAN); mysql->func = "mysql_init"; mysql->mysql = mysql_init(NULL); if (mysql->mysql) return 0; errno = ENOMEM; mx_log_debug("Error: MySQL mysql_init(): %m"); return -errno; } static int mx__mysql_options(struct mx_mysql *mysql, enum mysql_option option, const void *arg) { int res; mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(mysql->mysql, EBADF); mysql->func = "mysql_options"; res = mysql_options(mysql->mysql, option, arg); if (res == 0) return 0; mx__mysql_log_emerg(mysql); return -(errno=EBADE); } static int mx__mysql_real_connect(struct mx_mysql *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) { MYSQL *m; mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(mysql->mysql, EBADF); mysql->func = "mysql_real_connect"; m = mysql_real_connect(mysql->mysql, host, user, passwd, db, port, unix_socket, client_flag); if (m && m == mysql->mysql) return 0; mx__mysql_log_warning(mysql); switch (mx__mysql_errno(mysql)) { case CR_ALREADY_CONNECTED: return -(errno=EALREADY); case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_CONN_HOST_ERROR: case CR_CONNECTION_ERROR: case CR_IPSOCK_ERROR: case CR_SOCKET_CREATE_ERROR: case CR_UNKNOWN_HOST: case CR_VERSION_ERROR: case CR_SERVER_LOST: case CR_SERVER_GONE_ERROR: return -(errno=EAGAIN); case CR_NAMEDPIPEOPEN_ERROR: case CR_NAMEDPIPEWAIT_ERROR: case CR_NAMEDPIPESETSTATE_ERROR: mx__mysql_log_emerg(mysql); mx_log_emerg("ERROR: mysql_real_connect() returned Windows error number: %d", mx__mysql_errno(mysql)); return -(errno=EBADE); /* we are not on windows*/ } mx__mysql_log_emerg(mysql); mx_log_emerg("ERROR: mysql_real_connect() returned undefined error number: %d", mx__mysql_errno(mysql)); return -(errno=EBADE); } static int mx__mysql_ping(struct mx_mysql *mysql) { mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(mysql->mysql, EBADF); int res; mysql->func = "mysql_ping"; res = mysql_ping(mysql->mysql); if (res == 0) return 0; mx__mysql_log_warning(mysql); switch (mx__mysql_errno(mysql)) { case CR_COMMANDS_OUT_OF_SYNC: mx__mysql_log_emerg(mysql); return -(errno=EPROTO); case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_CONN_HOST_ERROR: case CR_CONNECTION_ERROR: case CR_IPSOCK_ERROR: case CR_SOCKET_CREATE_ERROR: case CR_UNKNOWN_HOST: case CR_VERSION_ERROR: case CR_SERVER_LOST: case CR_SERVER_GONE_ERROR: return -(errno=EAGAIN); case CR_UNKNOWN_ERROR: return -(errno=EIO); } mx__mysql_log_emerg(mysql); mx_log_emerg("ERROR: mysql_ping() returned undefined error number: %d", mx__mysql_errno(mysql)); return -(errno=EBADE); } static int mx__mysql_stmt_init(struct mx_mysql_stmt *stmt) { mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(!stmt->stmt, EUCLEAN); mx_assert_return_minus_errno(stmt->mysql, EBADF); stmt->mysql->func = "mysql_stmt_init"; stmt->stmt = mysql_stmt_init(stmt->mysql->mysql); if (stmt->stmt) return 0; mx__mysql_log_warning(stmt->mysql); if (mx__mysql_errno(stmt->mysql) == CR_OUT_OF_MEMORY) return -(errno=ENOMEM); mx__mysql_log_emerg(stmt->mysql); mx_log_emerg("ERROR: mysql_stmt_init() returned undefined error number: %d", mx__mysql_errno(stmt->mysql)); return -(errno=EBADE); } static int mx__mysql_stmt_prepare(struct mx_mysql_stmt *stmt, char *statement) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(statement, EINVAL); mx_assert_return_minus_errno(*statement, EINVAL); mx_assert_return_minus_errno(!stmt->statement, EUCLEAN); mx_assert_return_minus_errno(stmt->mysql, EBADF); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_prepare"; res = mysql_stmt_prepare(stmt->stmt, statement, strlen(statement)); if (res == 0) { stmt->statement = statement; return 0; } mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_COMMANDS_OUT_OF_SYNC: mx__mysql_stmt_log_emerg(stmt); return -(errno=EPROTO); case CR_SERVER_GONE_ERROR: case CR_SERVER_LOST: return -(errno=EAGAIN); case CR_UNKNOWN_ERROR: return -(errno=EIO); case ER_PARSE_ERROR: mx__mysql_stmt_log_emerg(stmt); return -(errno=EBADRQC); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_prepare() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_stmt_bind_param(struct mx_mysql_stmt *stmt) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_bind_param"; res = (int)mysql_stmt_bind_param(stmt->stmt, stmt->param.bind); if (res == 0) return 0; mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_UNSUPPORTED_PARAM_TYPE: mx__mysql_stmt_log_emerg(stmt); return -(errno=EPROTO); case CR_UNKNOWN_ERROR: return -(errno=EIO); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_bind_param() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_stmt_bind_result(struct mx_mysql_stmt *stmt) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_bind_result"; res = (int)mysql_stmt_bind_result(stmt->stmt, stmt->result.bind); if (res == 0) return 0; mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_UNSUPPORTED_PARAM_TYPE: mx__mysql_stmt_log_emerg(stmt); return -(errno=EPROTO); case CR_UNKNOWN_ERROR: return -(errno=EIO); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_bind_result() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_stmt_execute(struct mx_mysql_stmt *stmt) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_execute"; res = mysql_stmt_execute(stmt->stmt); if (res == 0) return 0; mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_COMMANDS_OUT_OF_SYNC: mx__mysql_stmt_log_emerg(stmt); return -(errno=EPROTO); case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_SERVER_GONE_ERROR: case CR_SERVER_LOST: return -(errno=EAGAIN); case CR_UNKNOWN_ERROR: return -(errno=EIO); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_execute() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_stmt_store_result(struct mx_mysql_stmt *stmt) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_store_result"; res = mysql_stmt_store_result(stmt->stmt); if (res == 0) return 0; mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_COMMANDS_OUT_OF_SYNC: mx__mysql_stmt_log_emerg(stmt); return -(errno=EPROTO); case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_SERVER_GONE_ERROR: case CR_SERVER_LOST: return -(errno=EAGAIN); case CR_UNKNOWN_ERROR: return -(errno=EIO); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_store_result() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_stmt_free_result(struct mx_mysql_stmt *stmt) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_free_result"; res = (int)mysql_stmt_free_result(stmt->stmt); if (res == 0) return 0; mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_free_result() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_stmt_fetch(struct mx_mysql_stmt *stmt) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_fetch"; res = mysql_stmt_fetch(stmt->stmt); if (res == 0) return 0; if (res == 1) { mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_OUT_OF_MEMORY: return -(errno=ENOMEM); case CR_SERVER_GONE_ERROR: case CR_SERVER_LOST: return -(errno=EAGAIN); case CR_UNKNOWN_ERROR: mx__mysql_stmt_log_emerg(stmt); return -(errno=EIO); case CR_COMMANDS_OUT_OF_SYNC: case CR_UNSUPPORTED_PARAM_TYPE: mx__mysql_stmt_log_emerg(stmt); return -(errno=EPROTO); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_fetch() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } switch (res) { case MYSQL_NO_DATA: return -(errno=ENOENT); case MYSQL_DATA_TRUNCATED: return -(errno=ERANGE); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_fetch() returned undefined result code: %d", res); return -(errno=EBADE); } static int mx__mysql_stmt_fetch_column(struct mx_mysql_stmt *stmt, unsigned int column, unsigned long offset) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_fetch_column"; res = mysql_stmt_fetch_column(stmt->stmt, &(stmt->result.bind[column]), column, offset); if (res == 0) return 0; mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_INVALID_PARAMETER_NO: mx__mysql_stmt_log_emerg(stmt); return -(errno=EPROTO); case CR_NO_DATA: return -(errno=ENOENT); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_fetch_column() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_stmt_param_count(struct mx_mysql_stmt *stmt) { unsigned long count; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_param_count"; count = mysql_stmt_param_count(stmt->stmt); mx_assert_return_minus_errno((unsigned long)(int)count == count, ERANGE); /* no mysql errors possible */ return (int)count; } static int mx__mysql_stmt_field_count(struct mx_mysql_stmt *stmt) { unsigned long count; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_field_count"; count = mysql_stmt_field_count(stmt->stmt); mx_assert_return_minus_errno((unsigned long)(int)count == count, ERANGE); /* no mysql errors possible */ return (int)count; } static int mx__mysql_stmt_affected_rows(struct mx_mysql_stmt *stmt, unsigned long long *count) { my_ulonglong c; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_affected_rows"; c = mysql_stmt_affected_rows(stmt->stmt); *count = (unsigned long long)c; /* no mysql errors possible */ return 0; } static int mx__mysql_stmt_insert_id(struct mx_mysql_stmt *stmt, unsigned long long *count) { my_ulonglong c; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->func = "mysql_stmt_insert_id"; c = mysql_stmt_insert_id(stmt->stmt); *count = (unsigned long long)c; /* no mysql errors possible */ return 0; } static int mx__mysql_stmt_close(struct mx_mysql_stmt *stmt) { bool res; mx_assert_return_minus_errno(stmt, EINVAL); stmt->func = "mysql_stmt_close"; res = mysql_stmt_close(stmt->stmt); if (res == 0) { stmt->stmt = NULL; return 0; } mx__mysql_stmt_log_warning(stmt); switch (mx__mysql_stmt_errno(stmt)) { case CR_SERVER_GONE_ERROR: return -(errno=ECONNABORTED); case CR_UNKNOWN_ERROR : return -(errno=EIO); } mx__mysql_stmt_log_emerg(stmt); mx_log_emerg("ERROR: mysql_stmt_close() returned undefined error number: %d", mx__mysql_stmt_errno(stmt)); return -(errno=EBADE); } static int mx__mysql_close(struct mx_mysql *mysql) { mx_assert_return_minus_errno(mysql, EINVAL); if (mysql->mysql) { mysql->func = "mysql_close"; mysql_close(mysql->mysql); mysql->mysql = NULL; } /* no mysql errors possible */ return 0; } static int mx__mysql_library_end(void) { mysql_library_end(); /* no mysql errors possible */ return 0; } /**********************************************************************/ static int _mx_mysql_bind_integer(struct mx_mysql_bind *b, unsigned int index, void *value, int type, int is_unsigned) { mx_assert_return_minus_errno(b, EINVAL); mx_assert_return_minus_errno(value, EINVAL); mx_assert_return_minus_errno(index < b->count, ERANGE); mx_assert_return_minus_errno(!(b->data[index].flags), EUCLEAN); memset(&(b->bind[index]), 0, sizeof(b->bind[index])); b->bind[index].buffer_type = (enum enum_field_types)type; b->bind[index].buffer = value; b->bind[index].is_unsigned = (bool)is_unsigned; b->bind[index].length = &(b->data[index].length); b->bind[index].is_null = &(b->data[index].is_null); b->bind[index].error = &(b->data[index].is_error); b->data[index].flags = 1; return 0; } static int _mx_mysql_bind_string(struct mx_mysql_bind *b, unsigned int index, char **value) { mx_assert_return_minus_errno(b, EINVAL); mx_assert_return_minus_errno(value, EINVAL); mx_assert_return_minus_errno(index < b->count, ERANGE); mx_assert_return_minus_errno(!(b->data[index].flags), EUCLEAN); mx_assert_return_minus_errno((*value && b->type == MX_MYSQL_BIND_TYPE_PARAM) || (!*value && b->type == MX_MYSQL_BIND_TYPE_RESULT), EBADF); memset(&(b->bind[index]), 0, sizeof(b->bind[index])); if (b->type == MX_MYSQL_BIND_TYPE_PARAM) { b->data[index].string_ptr = value; b->data[index].length = strlen(*value); b->bind[index].buffer_type = MYSQL_TYPE_STRING; b->bind[index].buffer = *(b->data[index].string_ptr); b->bind[index].buffer_length = b->data[index].length; b->bind[index].length = &(b->data[index].length); b->bind[index].is_null = &(b->data[index].is_null); b->bind[index].error = &(b->data[index].is_error); } else { b->data[index].string_ptr = value; b->data[index].length = 0; b->bind[index].buffer_type = MYSQL_TYPE_STRING; b->bind[index].buffer = NULL; b->bind[index].buffer_length = 0; b->bind[index].length = &(b->data[index].length); b->bind[index].is_null = &(b->data[index].is_null); b->bind[index].error = &(b->data[index].is_error); } b->data[index].flags = 1; return 0; } static int _mx_mysql_bind_validate(struct mx_mysql_bind *b) { mx_assert_return_minus_errno(b, EINVAL); for (unsigned long i=0; i < b->count; i++) { if (!(b->data[i].flags)) { return -(errno=EBADSLT); } } return 0; } /**********************************************************************/ int mx_mysql_initialize(struct mx_mysql **mysql) { struct mx_mysql *m; mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(!(*mysql), EUCLEAN); m = mx_calloc_forever(1, sizeof(*m)); *mysql = m; return 0; } static int mx_mysql_init(struct mx_mysql *mysql) { int res; mx_assert_return_minus_errno(mysql, EINVAL); do { res = mx__mysql_init(mysql); if (res == 0) break; if (res != -ENOMEM) return res; mx_log_debug("mx__mysql_init() failed: %m - retrying (forever) in %d second(s).", MX_MYSQL_FAIL_WAIT_DEFAULT); mx_sleep(MX_MYSQL_FAIL_WAIT_DEFAULT); } while (1); return 0; } int mx_mysql_option_set_default_file(struct mx_mysql *mysql, char *fname) { mx_assert_return_minus_errno(mysql, EINVAL); if (fname && (*fname == '/') && (euidaccess(fname, R_OK) != 0)) { mx_log_warning("MySQL ignoring defaults file: euidaccess(\"%s\", R_OK) failed: %m", fname); mx_log_warning("MySQL falling back to mysql default config search path."); return -errno; } if (fname && !(*fname)) fname = NULL; mysql->default_file = fname; return 0; } int mx_mysql_option_set_default_group(struct mx_mysql *mysql, char *group) { mx_assert_return_minus_errno(mysql, EINVAL); if (group && !(*group)) group = NULL; mysql->default_group = group; return 0; } int mx_mysql_option_set_reconnect(struct mx_mysql *mysql, int reconnect) { mx_assert_return_minus_errno(mysql, EINVAL); mysql->reconnect = (bool)!!reconnect; return 0; } static int mx_mysql_real_connect(struct mx_mysql *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) { int res; mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(mysql->mysql, EBADF); if (mysql->default_file) { res = mx__mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, mysql->default_file); mx_mysql_assert_usage_ok(res); } if (mysql->default_group) { res = mx__mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, mysql->default_group); mx_mysql_assert_usage_ok(res); } else { res = mx__mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, program_invocation_short_name); mx_mysql_assert_usage_ok(res); } res = mx__mysql_options(mysql, MYSQL_OPT_RECONNECT, &mysql->reconnect); mx_mysql_assert_usage_ok(res); res = mx__mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, client_flag); mx_mysql_assert_usage_ok(res); if (res == 0) return 0; if (res == -EALREADY) { mx_log_debug("WARNING: %s", mx__mysql_error(mysql)); return 0; } return res; } int mx_mysql_connect(struct mx_mysql **mysql) { int res; mx_assert_return_minus_errno(mysql, EINVAL); if (!(*mysql)) { res = mx_mysql_initialize(mysql); if (res < 0) return res; } if (!(*mysql)->mysql) { res = mx_mysql_init(*mysql); if (res < 0) return res; } res = mx_mysql_real_connect(*mysql, NULL, NULL, NULL, NULL, 0, NULL, 0); return res; } int mx_mysql_connect_forever_sec(struct mx_mysql **mysql, unsigned int seconds) { int res; while ((res = mx_mysql_connect(mysql)) < 0) { mx__mysql_log_warning(*mysql); mx_mysql_assert_usage_ok(res); mx_log_warning("mx_mysql_connect() failed: %m - retrying (forever) in %d second(s).", seconds); mx_sleep(seconds); } return 0; } int mx_mysql_disconnect(struct mx_mysql *mysql) { mx_assert_return_minus_errno(mysql, EINVAL); return mx__mysql_close(mysql); } static int mx_mysql_end(void) { return mx__mysql_library_end(); } static int mx_mysql_free(struct mx_mysql **mysql) { mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(*mysql, EBADF); mx_assert_return_minus_errno(!((*mysql)->mysql), EUCLEAN); mx_free_null(*mysql); return 0; } int mx_mysql_finish(struct mx_mysql **mysql) { int res = 0; int res1 = 0, res2 = 0, res3 = 0; if (mysql && *mysql) { res1 = mx_mysql_disconnect(*mysql); if (res1 < 0) res = res1; res2 = mx_mysql_free(mysql); if (!res && res2 < 0) res = res2; } res3 = mx_mysql_end(); if (!res && res3 < 0) res = res3; return res; } static int mx_mysql_ping(struct mx_mysql *mysql) { mx_assert_return_minus_errno(mysql, EINVAL); return mx__mysql_ping(mysql); } static int mx_mysql_ping_forever(struct mx_mysql *mysql) { int res; int fail = 0; mx_assert_return_minus_errno(mysql, EINVAL); while (1) { res = mx_mysql_ping(mysql); if (res == 0) break; fail++; mx__mysql_log_warning(mysql); mx_mysql_assert_usage_ok(res); mx_log_warning("mx_mysql_ping() failed: %m - retrying again (forever) in %d second(s).", MX_MYSQL_FAIL_WAIT_DEFAULT); mx_sleep(MX_MYSQL_FAIL_WAIT_DEFAULT); } if (fail) mx_log_info("mx_mysql_ping_forever() recovered from previous errors (%d tries). Yippieh! Back to work!", fail); return res; } static int mx_mysql_statement_init(struct mx_mysql *mysql, struct mx_mysql_stmt **stmt) { struct mx_mysql_stmt *s; int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(mysql, EINVAL); mx_assert_return_minus_errno(!(*stmt), EUCLEAN); s = mx_calloc_forever(1, sizeof(*s)); s->mysql = mysql; s->func = ""; do { res = mx__mysql_stmt_init(s); if (res == 0) break; if (res != -ENOMEM) return res; mx_log_debug("mx__mysql_stmt_init() failed: %m - retrying (forever) in %d second(s).", MX_MYSQL_FAIL_WAIT_DEFAULT); mx_sleep(MX_MYSQL_FAIL_WAIT_DEFAULT); } while (1); *stmt = s; return 0; } int mx_mysql_statement_execute(struct mx_mysql_stmt *stmt, unsigned long long *count) { int res; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); res = _mx_mysql_bind_validate(&stmt->param); if (res < 0) { mx_log_crit("MxSQL: parameter list for prepared statement not initialized completely."); return res; } res = mx__mysql_stmt_bind_param(stmt); if (res < 0) { mx_log_debug("ERROR: mx__mysql_stmt_bind_param: %m"); return res; } res = mx__mysql_stmt_execute(stmt); if (res < 0) { mx_log_debug("ERROR: mx__mysql_stmt_execute: %m"); return res; } res = mx__mysql_stmt_store_result(stmt); if (res < 0) { mx_log_debug("ERROR: mx__mysql_stmt_store_result: %m"); return res; } if (count) { res = mx__mysql_stmt_affected_rows(stmt, count); if (res < 0) { mx_log_debug("ERROR: mx__mysql_stmt_affected_rows(): %m"); return res; } } return 0; } int mx_mysql_statement_insert_id(struct mx_mysql_stmt *stmt, unsigned long long int *id) { return mx__mysql_stmt_insert_id(stmt, id); } int mx_mysql_statement_fetch(struct mx_mysql_stmt *stmt) { struct mx_mysql_bind *r; int res; char *str; int no_error = 1; mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); res = _mx_mysql_bind_validate(&stmt->result); if (res < 0) { mx_log_debug("ERROR: result not initialized completely."); return res; } res = mx__mysql_stmt_bind_result(stmt); if (res < 0) { mx_log_debug("ERROR: mx__mysql_stmt_bind_result: %m"); return res; } res = mx__mysql_stmt_fetch(stmt); if (res == -ENOENT) return 0; if (res < 0 && res != -ERANGE) { mx_log_debug("ERROR: mx__mysql_stmt_fetch: %m"); return res; } r = &stmt->result; for (unsigned long col = 0; col < r->count; col++) { if (r->bind[col].buffer_type == MYSQL_TYPE_STRING) { str = mx_calloc_forever(r->data[col].length + 1, sizeof(*str)); *(r->data[col].string_ptr) = str; r->bind[col].buffer = *(r->data[col].string_ptr); r->bind[col].buffer_length = r->data[col].length; mx__mysql_stmt_fetch_column(stmt, col, 0); r->data[col].length = 0; r->bind[col].buffer = NULL; r->bind[col].buffer_length = 0; continue; } if (!(r->data[col].is_error)) continue; mx_log_debug("WARNING: result data returned in column with index %lu was truncated. query was:", col); mx_log_debug(" \\ %s", stmt->statement); no_error = 0; } if (!no_error) return -(errno=ERANGE); return 0; } int mx_mysql_statement_param_count(struct mx_mysql_stmt *stmt) { mx_assert_return_minus_errno(stmt, EINVAL); return mx__mysql_stmt_param_count(stmt); } int mx_mysql_statement_field_count(struct mx_mysql_stmt *stmt) { mx_assert_return_minus_errno(stmt, EINVAL); return mx__mysql_stmt_field_count(stmt); } static int mx_mysql_stmt_field_count_set(struct mx_mysql_stmt *stmt) { mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->field_count = mysql_stmt_field_count(stmt->stmt); return 0; } static int mx_mysql_stmt_param_count_set(struct mx_mysql_stmt *stmt) { mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(stmt->stmt, EBADF); stmt->param_count = mysql_stmt_param_count(stmt->stmt); return 0; } static int mx_mysql_bind_cleanup(struct mx_mysql_bind *bind) { if (!bind) return 0; mx_free_null(bind->bind); mx_free_null(bind->data); bind->count = 0; return 0; } static int mx_mysql_bind_init_from(struct mx_mysql_bind *bind, unsigned long count, enum mx_mysql_bind_type type, struct mx_mysql_bind *from) { mx_assert_return_minus_errno(bind, EINVAL); mx_assert_return_minus_errno(!bind->count, EUCLEAN); mx_assert_return_minus_errno(!bind->bind, EUCLEAN); mx_assert_return_minus_errno(!bind->data, EUCLEAN); if (from) { assert(count == from->count); assert(type == from->type); assert(from->bind); assert(from->data); memcpy(bind, from, sizeof(*bind)); return 0; } return mx_mysql_bind_init(bind, count, type); } int mx_mysql_bind_init(struct mx_mysql_bind *bind, unsigned long count, enum mx_mysql_bind_type type) { mx_assert_return_minus_errno(bind, EINVAL); mx_assert_return_minus_errno(!bind->count, EUCLEAN); mx_assert_return_minus_errno(!bind->bind, EUCLEAN); mx_assert_return_minus_errno(!bind->data, EUCLEAN); bind->type = type; bind->count = count; if (!count) return 0; bind->bind = mx_calloc_forever(bind->count, sizeof(*bind->bind)); bind->data = mx_calloc_forever(bind->count, sizeof(*bind->data)); return 0; } static int _mx_mysql_do_statement(struct mx_mysql *mysql, char *query, struct mx_mysql_bind *param, struct mx_mysql_bind *result, void *from, void **to, size_t size, char cleanup) { struct mx_mysql_stmt *stmt = NULL; unsigned long long num_rows = 0; int res; char *tmpdata; assert(mysql); mx_mysql_ping_forever(mysql); stmt = mx_mysql_statement_prepare_with_bindings(mysql, query, param, result); if (!stmt) { mx_log_err("mx_mysql_statement_prepare_with_bindings(): %m"); mx_log_err("mx_mysql_statement_prepare_with_bindings(): query was: %s", query); if (cleanup) { mx_mysql_bind_cleanup(param); mx_mysql_bind_cleanup(result); } return -errno; } res = mx_mysql_statement_execute(stmt, &num_rows); if (res < 0) { mx_log_err("mx_mysql_statement_execute(): %m"); if (cleanup) mx_mysql_statement_close(&stmt); else mx_mysql_statement_close_no_bind_cleanup(&stmt); return -(errno=-res); } if (result && result->count && num_rows) { tmpdata = mx_calloc_forever(num_rows, size); for (unsigned long cnt = 0; cnt < num_rows; cnt++) { res = mx_mysql_statement_fetch(stmt); if (res < 0) { mx_log_err("mx_mysql_statement_fetch(): %m"); mx_free_null(tmpdata); if (cleanup) mx_mysql_statement_close(&stmt); else mx_mysql_statement_close_no_bind_cleanup(&stmt); return -(errno=-res); } memcpy(tmpdata+(cnt*size), from, size); } *to = tmpdata; } if (cleanup) mx_mysql_statement_close(&stmt); else mx_mysql_statement_close_no_bind_cleanup(&stmt); return num_rows; } int mx_mysql_do_statement(struct mx_mysql *mysql, char *query, struct mx_mysql_bind *param, struct mx_mysql_bind *result, void *from, void **to, size_t size) { return _mx_mysql_do_statement(mysql, query, param, result, from, to, size, 1); } static int mx_mysql_do_statement_no_bind_cleanup(struct mx_mysql *mysql, char *query, struct mx_mysql_bind *param, struct mx_mysql_bind *result, void *from, void **to, size_t size) { return _mx_mysql_do_statement(mysql, query, param, result, from, to, size, 0); } int mx_mysql_do_statement_retry_on_fail(struct mx_mysql *mysql, char *query, struct mx_mysql_bind *param, struct mx_mysql_bind *result, void *from, void **to, size_t size) { int res; while (1) { res = mx_mysql_do_statement_no_bind_cleanup(mysql, query, param, result, from, to, size); if (res >= 0) break; mx_mysql_assert_usage_ok(res); mx_log_warning("mx_mysql_do_statement() failed: %m"); if (res != -EAGAIN) break; mx_mysql_ping_forever(mysql); } mx_mysql_bind_cleanup(param); mx_mysql_bind_cleanup(result); return res; } static struct mx_mysql_stmt *mx_mysql_statement_prepare_with_bindings(struct mx_mysql *mysql, char *statement, struct mx_mysql_bind *param, struct mx_mysql_bind *result) { int res; struct mx_mysql_stmt *stmt = NULL; mx_assert_return_NULL(mysql, EINVAL); mx_assert_return_NULL(statement, EINVAL); mx_assert_return_NULL(*statement, EINVAL); res = mx_mysql_statement_init(mysql, &stmt); if (res < 0) return NULL; while (1) { res = mx__mysql_stmt_prepare(stmt, statement); if (res < 0) break; res = mx_mysql_stmt_param_count_set(stmt); if (res < 0) break; res = mx_mysql_stmt_field_count_set(stmt); if (res < 0) break; res = mx_mysql_bind_init_from(&stmt->param, stmt->param_count, MX_MYSQL_BIND_TYPE_PARAM, param); if (res < 0) break; res = mx_mysql_bind_init_from(&stmt->result, stmt->field_count, MX_MYSQL_BIND_TYPE_RESULT, result); if (res < 0) break; return stmt; }; if (res < 0) mx__mysql_stmt_log_warning(stmt); mx_mysql_statement_close_no_bind_cleanup(&stmt); return NULL; } struct mx_mysql_stmt *mx_mysql_statement_prepare(struct mx_mysql *mysql, char *statement) { mx_assert_return_NULL(mysql, EINVAL); mx_assert_return_NULL(statement, EINVAL); mx_assert_return_NULL(*statement, EINVAL); return mx_mysql_statement_prepare_with_bindings(mysql, statement, NULL, NULL); } int mx_mysql_statement_close(struct mx_mysql_stmt **stmt) { mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(*stmt, EINVAL); mx__mysql_stmt_free_result(*stmt); mx__mysql_stmt_close(*stmt); mx_mysql_bind_cleanup(&(*stmt)->param); mx_mysql_bind_cleanup(&(*stmt)->result); mx_free_null(*stmt); return 0; } int mx_mysql_statement_close_no_bind_cleanup(struct mx_mysql_stmt **stmt) { mx_assert_return_minus_errno(stmt, EINVAL); mx_assert_return_minus_errno(*stmt, EINVAL); mx__mysql_stmt_free_result(*stmt); mx__mysql_stmt_close(*stmt); mx_free_null(*stmt); return 0; } static int mx_mysql_bind_integer(struct mx_mysql_bind *b, unsigned int index, void *value, int type, int is_unsigned) { int res; res = _mx_mysql_bind_integer(b, index, value, type, is_unsigned); if (res == 0) return 0; mx_log_debug("Failed to set index %d: %m", index); return res; } int mx_mysql_bind_string(struct mx_mysql_bind *b, unsigned int index, char **value) { int res; res = _mx_mysql_bind_string(b, index, value); if (res == 0) return 0; mx_log_debug("Failed to set index %d: %m", index); return res; } int mx_mysql_bind_int8(struct mx_mysql_bind *b, unsigned int index, int8_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_TINY, 0); } int mx_mysql_bind_uint8(struct mx_mysql_bind *b, unsigned int index, uint8_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_TINY, 1); } int mx_mysql_bind_int16(struct mx_mysql_bind *b, unsigned int index, int16_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_SHORT, 0); } int mx_mysql_bind_uint16(struct mx_mysql_bind *b, unsigned int index, uint16_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_SHORT, 1); } int mx_mysql_bind_int32(struct mx_mysql_bind *b, unsigned int index, int32_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_LONG, 0); } int mx_mysql_bind_uint32(struct mx_mysql_bind *b, unsigned int index, uint32_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_LONG, 1); } int mx_mysql_bind_int64(struct mx_mysql_bind *b, unsigned int index, int64_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_LONGLONG, 0); } int mx_mysql_bind_uint64(struct mx_mysql_bind *b, unsigned int index, uint64_t *value) { return mx_mysql_bind_integer(b, index, (void *)value, MYSQL_TYPE_LONGLONG, 1); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
You can’t perform that action at this time.