diff options
author | unknown <knielsen@knielsen-hq.org> | 2011-09-20 12:49:25 +0200 |
---|---|---|
committer | unknown <knielsen@knielsen-hq.org> | 2011-09-20 12:49:25 +0200 |
commit | a5b881594da4258257b18cc42f5ce7be3524e02c (patch) | |
tree | 6ddddaef439cce2f930abfab3929f9ad80d8c818 /sql-common/mysql_async.c | |
parent | 1a344b87e4d153d52468307cc886b5f424cb2dbf (diff) | |
download | mariadb-git-a5b881594da4258257b18cc42f5ce7be3524e02c.tar.gz |
MWL#192: Non-blocking client API for libmysqlclient.
All client functions that can block on I/O have alternate _start() and
_cont() versions that do not block but return control back to the
application, which can then issue I/O wait in its own fashion and later
call back into the library to continue the operation.
Works behind the scenes by spawning a co-routine/fiber to run the
blocking operation and suspend it while waiting for I/O. This
co-routine/fiber use is invisible to applications.
For i368/x86_64 on GCC, uses very fast assembler co-routine support. On
Windows uses native Win32 Fibers. Falls back to POSIX ucontext on other
platforms. Assembler routines for more platforms are relatively easy to
add by extending mysys/my_context.c, eg. similar to the Lua lcoco
library.
For testing, mysqltest and mysql_client_test are extended with the
option --non-blocking-api. This causes the programs to use the
non-blocking API for database access. mysql-test-run.pl has a similar
option --non-blocking-api that uses this, as well as additional
testcases.
An example program tests/async_queries.c is included that uses the new
non-blocking API with libevent to show how, in a single-threaded
program, to issue many queries in parallel against a database.
client/async_example.c:
Fix const warning
******
Fix bug with wrong timeout value for poll().
include/Makefile.am:
Fix missing include for `make dist`
include/mysql.h:
Add prototypes for all non-blocking API calls.
include/mysql.h.pp:
Add prototypes for all non-blocking API calls.
mysys/my_context.c:
Fix type warning for makecontext() function pointer argument.
sql-common/mysql_async.c:
Fix crashes in the non-blocking API for functions that can take MYSQL argument
that is NULL.
tests/Makefile.am:
Add header file to `make dist`
tests/mysql_client_test.c:
Replace blocking calls with wrappers around the non-blocking calls, used in
mysql_client_test to test the new non-blocking API.
tests/nonblock-wrappers.h:
Replace blocking calls with wrappers around the non-blocking calls, used in
mysql_client_test to test the new non-blocking API.
Diffstat (limited to 'sql-common/mysql_async.c')
-rw-r--r-- | sql-common/mysql_async.c | 1431 |
1 files changed, 1431 insertions, 0 deletions
diff --git a/sql-common/mysql_async.c b/sql-common/mysql_async.c new file mode 100644 index 00000000000..a8e699e5012 --- /dev/null +++ b/sql-common/mysql_async.c @@ -0,0 +1,1431 @@ +/* + Copyright 2011 Kristian Nielsen + + Experiments with non-blocking libmysql. + + This is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + MySQL non-blocking client library functions. +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "mysql.h" +#include "errmsg.h" +#include "sql_common.h" +#include "my_context.h" +#include "violite.h" + + +#ifdef __WIN__ +/* + Windows does not support MSG_DONTWAIT for send()/recv(). So we need to ensure + that the socket is non-blocking at the start of every operation. +*/ +#define WIN_SET_NONBLOCKING(mysql) { \ + my_bool old_mode__; \ + if ((mysql)->net.vio) vio_blocking((mysql)->net.vio, FALSE, &old_mode__); \ + } +#else +#define WIN_SET_NONBLOCKING(mysql) +#endif + +extern struct mysql_async_context *mysql_get_async_context(MYSQL *mysql); + + +void +my_context_install_suspend_resume_hook(struct mysql_async_context *b, + void (*hook)(my_bool, void *), + void *user_data) +{ + b->suspend_resume_hook= hook; + b->suspend_resume_hook_user_data= user_data; +} + + +/* Asynchronous connect(); socket must already be set non-blocking. */ +int +my_connect_async(struct mysql_async_context *b, my_socket fd, + const struct sockaddr *name, uint namelen, uint timeout) +{ + int res; +#ifdef __WIN__ + int s_err_size; +#else + socklen_t s_err_size; +#endif + + /* + Start to connect asynchronously. + If this will block, we suspend the call and return control to the + application context. The application will then resume us when the socket + polls ready for write, indicating that the connection attempt completed. + */ + res= connect(fd, name, namelen); +#ifdef __WIN__ + if (res != 0) + { + int wsa_err= WSAGetLastError(); + if (wsa_err != WSAEWOULDBLOCK) + return res; +#else + if (res < 0) + { + if (errno != EINPROGRESS && errno != EALREADY && errno != EAGAIN) + return res; +#endif + b->timeout_value= timeout; + b->ret_status= MYSQL_WAIT_WRITE | + (timeout ? MYSQL_WAIT_TIMEOUT : 0); +#ifdef __WIN__ + b->ret_status|= MYSQL_WAIT_EXCEPT; +#endif + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); + my_context_yield(&b->async_context); + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); + if (b->ret_status & MYSQL_WAIT_TIMEOUT) + return -1; + + s_err_size= sizeof(int); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &res, &s_err_size) != 0) + return -1; + if (res) + { + errno= res; + return -1; + } + } + return res; +} + +ssize_t +my_recv_async(struct mysql_async_context *b, int fd, + unsigned char *buf, size_t size, uint timeout) +{ + ssize_t res; + + for (;;) + { + res= recv(fd, buf, size, +#ifdef __WIN__ + 0 +#else + MSG_DONTWAIT +#endif + ); + if (res >= 0 || +#ifdef __WIN__ + WSAGetLastError() != WSAEWOULDBLOCK +#else + (errno != EAGAIN && errno != EINTR) +#endif + ) + return res; + b->ret_status= MYSQL_WAIT_READ; + if (timeout) + { + b->ret_status|= MYSQL_WAIT_TIMEOUT; + b->timeout_value= timeout; + } + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); + my_context_yield(&b->async_context); + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); + if (b->ret_status & MYSQL_WAIT_TIMEOUT) + return -1; + } +} + +ssize_t +my_send_async(struct mysql_async_context *b, int fd, + const unsigned char *buf, size_t size, uint timeout) +{ + ssize_t res; + + for (;;) + { + res= send(fd, buf, size, +#ifdef __WIN__ + 0 +#else + MSG_DONTWAIT +#endif + ); + if (res >= 0 || +#ifdef __WIN__ + WSAGetLastError() != WSAEWOULDBLOCK +#else + (errno != EAGAIN && errno != EINTR) +#endif + ) + return res; + b->ret_status= MYSQL_WAIT_WRITE; + if (timeout) + { + b->ret_status|= MYSQL_WAIT_TIMEOUT; + b->timeout_value= timeout; + } + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); + my_context_yield(&b->async_context); + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); + if (b->ret_status & MYSQL_WAIT_TIMEOUT) + return -1; + } +} + + +my_bool +my_poll_read_async(struct mysql_async_context *b, uint timeout) +{ + b->ret_status= MYSQL_WAIT_READ | MYSQL_WAIT_TIMEOUT; + b->timeout_value= timeout; + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); + my_context_yield(&b->async_context); + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); + return (b->ret_status & MYSQL_WAIT_READ) ? 0 : 1; +} + + +#ifdef HAVE_OPENSSL +int +my_ssl_read_async(struct mysql_async_context *b, SSL *ssl, + void *buf, int size) +{ + int res, ssl_err; + + for (;;) + { + res= SSL_read(ssl, buf, size); + if (res >= 0) + return res; + ssl_err= SSL_get_error(ssl, res); + if (ssl_err == SSL_ERROR_WANT_READ) + b->ret_status= MYSQL_WAIT_READ; + else if (ssl_err == SSL_ERROR_WANT_WRITE) + b->ret_status= MYSQL_WAIT_WRITE; + else + return res; + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); + my_context_yield(&b->async_context); + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); + } +} + +int +my_ssl_write_async(struct mysql_async_context *b, SSL *ssl, + const void *buf, int size) +{ + int res, ssl_err; + + for (;;) + { + res= SSL_write(ssl, buf, size); + if (res >= 0) + return res; + ssl_err= SSL_get_error(ssl, res); + if (ssl_err == SSL_ERROR_WANT_READ) + b->ret_status= MYSQL_WAIT_READ; + else if (ssl_err == SSL_ERROR_WANT_WRITE) + b->ret_status= MYSQL_WAIT_WRITE; + else + return res; + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); + my_context_yield(&b->async_context); + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); + } +} +#endif /* HAVE_OPENSSL */ + +unsigned int STDCALL +mysql_get_timeout_value(const MYSQL *mysql) +{ + if (mysql->extension && mysql->extension->async_context) + return mysql->extension->async_context->timeout_value; + else + return 0; +} + +/* + Now create non-blocking definitions for all the calls that may block. + + Each call FOO gives rise to FOO_start() that prepares the MYSQL object for + doing non-blocking calls that can suspend operation mid-way, and then starts + the call itself. And a FOO_start_internal trampoline to assist with running + the real call in a co-routine that can be suspended. And a FOO_cont() that + can continue a suspended operation. +*/ + +#define MK_ASYNC_CALLS(call__, decl_args__, invoke_args__, cont_arg__, mysql_val__, parms_mysql_val__, parms_assign__, ret_type__, err_val__, ok_val__, extra1__) \ +static void \ +call__ ## _start_internal(void *d) \ +{ \ + struct call__ ## _params *parms; \ + ret_type__ ret; \ + struct mysql_async_context *b; \ + \ + parms= (struct call__ ## _params *)d; \ + b= (parms_mysql_val__)->extension->async_context; \ + \ + ret= call__ invoke_args__; \ + b->ret_result. ok_val__ = ret; \ + b->ret_status= 0; \ +} \ +int STDCALL \ +call__ ## _start decl_args__ \ +{ \ + int res; \ + struct mysql_async_context *b; \ + struct call__ ## _params parms; \ + \ + extra1__ \ + if (!(b= mysql_get_async_context((mysql_val__)))) \ + { \ + *ret= err_val__; \ + return 0; \ + } \ + parms_assign__ \ + \ + b->active= 1; \ + res= my_context_spawn(&b->async_context, call__ ## _start_internal, &parms);\ + b->active= 0; \ + if (res < 0) \ + { \ + set_mysql_error((mysql_val__), CR_OUT_OF_MEMORY, unknown_sqlstate); \ + b->suspended= 0; \ + *ret= err_val__; \ + return 0; \ + } \ + else if (res > 0) \ + { \ + /* Suspended. */ \ + b->suspended= 1; \ + return b->ret_status; \ + } \ + else \ + { \ + /* Finished. */ \ + b->suspended= 0; \ + *ret= b->ret_result. ok_val__; \ + return 0; \ + } \ +} \ +int STDCALL \ +call__ ## _cont(ret_type__ *ret, cont_arg__, int ready_status) \ +{ \ + int res; \ + struct mysql_async_context *b; \ + \ + b= (mysql_val__)->extension->async_context; \ + if (!b || !b->suspended) \ + { \ + set_mysql_error((mysql_val__), CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);\ + *ret= err_val__; \ + return 0; \ + } \ + \ + b->active= 1; \ + b->ret_status= ready_status; \ + res= my_context_continue(&b->async_context); \ + b->active= 0; \ + if (res < 0) \ + { \ + set_mysql_error((mysql_val__), CR_OUT_OF_MEMORY, unknown_sqlstate); \ + b->suspended= 0; \ + *ret= err_val__; \ + return 0; \ + } \ + else if (res > 0) \ + { \ + /* Suspended. */ \ + return b->ret_status; \ + } \ + else \ + { \ + /* Finished. */ \ + b->suspended= 0; \ + *ret= b->ret_result. ok_val__; \ + return 0; \ + } \ +} + +#define MK_ASYNC_CALLS_VOID_RETURN(call__, decl_args__, invoke_args__, cont_arg__, mysql_val__, parms_mysql_val__, parms_assign__, extra1__) \ +static void \ +call__ ## _start_internal(void *d) \ +{ \ + struct call__ ## _params *parms; \ + struct mysql_async_context *b; \ + \ + parms= (struct call__ ## _params *)d; \ + b= (parms_mysql_val__)->extension->async_context; \ + \ + call__ invoke_args__; \ + b->ret_status= 0; \ +} \ +int STDCALL \ +call__ ## _start decl_args__ \ +{ \ + int res; \ + struct mysql_async_context *b; \ + struct call__ ## _params parms; \ + \ + extra1__ \ + if (!(b= mysql_get_async_context((mysql_val__)))) \ + { \ + return 0; \ + } \ + parms_assign__ \ + \ + b->active= 1; \ + res= my_context_spawn(&b->async_context, call__ ## _start_internal, &parms);\ + b->active= 0; \ + if (res < 0) \ + { \ + set_mysql_error((mysql_val__), CR_OUT_OF_MEMORY, unknown_sqlstate); \ + b->suspended= 0; \ + return 0; \ + } \ + else if (res > 0) \ + { \ + /* Suspended. */ \ + b->suspended= 1; \ + return b->ret_status; \ + } \ + else \ + { \ + /* Finished. */ \ + b->suspended= 0; \ + return 0; \ + } \ +} \ +int STDCALL \ +call__ ## _cont(cont_arg__, int ready_status) \ +{ \ + int res; \ + struct mysql_async_context *b; \ + \ + b= (mysql_val__)->extension->async_context; \ + if (!b || !b->suspended) \ + { \ + set_mysql_error((mysql_val__), CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);\ + return 0; \ + } \ + \ + b->active= 1; \ + b->ret_status= ready_status; \ + res= my_context_continue(&b->async_context); \ + b->active= 0; \ + if (res < 0) \ + { \ + set_mysql_error((mysql_val__), CR_OUT_OF_MEMORY, unknown_sqlstate); \ + b->suspended= 0; \ + return 0; \ + } \ + else if (res > 0) \ + { \ + /* Suspended. */ \ + return b->ret_status; \ + } \ + else \ + { \ + /* Finished. */ \ + b->suspended= 0; \ + return 0; \ + } \ +} + +struct mysql_real_connect_params { + MYSQL *mysql; + const char *host; + const char *user; + const char *passwd; + const char *db; + unsigned int port; + const char *unix_socket; + unsigned long client_flags; +}; +MK_ASYNC_CALLS( + mysql_real_connect, + (MYSQL **ret, MYSQL *mysql, const char *host, const char *user, + const char *passwd, const char *db, unsigned int port, + const char *unix_socket, unsigned long client_flags), + (parms->mysql, parms->host, parms->user, parms->passwd, parms->db, + parms->port, parms->unix_socket, parms->client_flags), + MYSQL *mysql, + mysql, + parms->mysql, + { + parms.mysql= mysql; + parms.host= host; + parms.user= user; + parms.passwd= passwd; + parms.db= db; + parms.port= port; + parms.unix_socket= unix_socket; + parms.client_flags= client_flags; + }, + MYSQL *, + NULL, + r_ptr, + /* Nothing */) + +struct mysql_real_query_params { + MYSQL *mysql; + const char *stmt_str; + unsigned long length; +}; +MK_ASYNC_CALLS( + mysql_real_query, + (int *ret, MYSQL *mysql, const char *stmt_str, unsigned long length), + (parms->mysql, parms->stmt_str, parms->length), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.stmt_str= stmt_str; + parms.length= length; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_fetch_row_params { + MYSQL_RES *result; +}; +MK_ASYNC_CALLS( + mysql_fetch_row, + (MYSQL_ROW *ret, MYSQL_RES *result), + (parms->result), + MYSQL_RES *result, + result->handle, + parms->result->handle, + { + WIN_SET_NONBLOCKING(result->handle) + parms.result= result; + }, + MYSQL_ROW, + NULL, + r_ptr, + /* + If we already fetched all rows from server (eg. mysql_store_result()), + then result->handle will be NULL and we cannot suspend. But that is fine, + since in this case mysql_fetch_row cannot block anyway. Just return + directly. + */ + if (!result->handle) + { + *ret= mysql_fetch_row(result); + return 0; + } +) + +struct mysql_set_character_set_params { + MYSQL *mysql; + const char *csname; +}; +MK_ASYNC_CALLS( + mysql_set_character_set, + (int *ret, MYSQL *mysql, const char *csname), + (parms->mysql, parms->csname), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.csname= csname; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_select_db_params { + MYSQL *mysql; + const char *db; +}; +MK_ASYNC_CALLS( + mysql_select_db, + (int *ret, MYSQL *mysql, const char *db), + (parms->mysql, parms->db), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.db= db; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_send_query_params { + MYSQL *mysql; + const char *q; + unsigned long length; +}; +MK_ASYNC_CALLS( + mysql_send_query, + (int *ret, MYSQL *mysql, const char *q, unsigned long length), + (parms->mysql, parms->q, parms->length), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.q= q; + parms.length= length; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_store_result_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_store_result, + (MYSQL_RES **ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + MYSQL_RES *, + NULL, + r_ptr, + /* Nothing */) + +struct mysql_free_result_params { + MYSQL_RES *result; +}; +MK_ASYNC_CALLS_VOID_RETURN( + mysql_free_result, + (MYSQL_RES *result), + (parms->result), + MYSQL_RES *result, + result->handle, + parms->result->handle, + { + WIN_SET_NONBLOCKING(result->handle) + parms.result= result; + }, + /* + mysql_free_result() can have NULL in result->handle (this happens when all + rows have been fetched and mysql_fetch_row() returned NULL.) + So we cannot suspend, but it does not matter, as in this case + mysql_free_result() cannot block. + It is also legitimate to have NULL result, which will do nothing. + */ + if (!result || !result->handle) + { + mysql_free_result(result); + return 0; + }) + +struct mysql_pre_close_params { + MYSQL *sock; +}; +/* + We need special handling for mysql_close(), as the first part may block, + while the last part needs to free our extra library context stack. + + So we do the first part (mysql_pre_close()) non-blocking, but the last part + blocking. +*/ +extern void mysql_pre_close(MYSQL *mysql); +MK_ASYNC_CALLS_VOID_RETURN( + mysql_pre_close, + (MYSQL *sock), + (parms->sock), + MYSQL *sock, + sock, + parms->sock, + { + WIN_SET_NONBLOCKING(sock) + parms.sock= sock; + }, + /* Nothing */) +int STDCALL +mysql_close_start(MYSQL *sock) +{ + int res; + + /* It is legitimate to have NULL sock argument, which will do nothing. */ + if (sock) + { + res= mysql_pre_close_start(sock); + /* If we need to block, return now and do the rest in mysql_close_cont(). */ + if (res) + return res; + } + mysql_close(sock); + return 0; +} +int STDCALL +mysql_close_cont(MYSQL *sock, int ready_status) +{ + int res; + + res= mysql_pre_close_cont(sock, ready_status); + if (res) + return res; + mysql_close(sock); + return 0; +} + +#ifdef USE_OLD_FUNCTIONS +struct mysql_connect_params { + MYSQL *mysql; + const char *host; + const char *user; + const char *passwd; +}; +MK_ASYNC_CALLS( + mysql_connect, + (MYSQL **ret, MYSQL *mysql, const char *host, const char *user, const char *passwd), + (parms->mysql, parms->host, parms->user, parms->passwd), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.host= host; + parms.user= user; + parms.passwd= passwd; + }, + MYSQL *, + NULL, + r_ptr, + /* Nothing */) + +struct mysql_create_db_params { + MYSQL *mysql; + const char *DB; +}; +MK_ASYNC_CALLS( + mysql_create_db, + (int *ret, MYSQL *mysql, const char *DB), + (parms->mysql, parms->DB), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.DB= DB; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_drop_db_params { + MYSQL *mysql; + const char *DB; +}; +MK_ASYNC_CALLS( + mysql_drop_db, + (int *ret, MYSQL *mysql, const char *DB), + (parms->mysql, parms->DB), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.DB= DB; + }, + int, + 1, + r_int, + /* Nothing */) + +#endif + +/* + These following are not available inside the server (neither blocking or + non-blocking). +*/ +#ifndef MYSQL_SERVER +struct mysql_change_user_params { + MYSQL *mysql; + const char *user; + const char *passwd; + const char *db; +}; +MK_ASYNC_CALLS( + mysql_change_user, + (my_bool *ret, MYSQL *mysql, const char *user, const char *passwd, const char *db), + (parms->mysql, parms->user, parms->passwd, parms->db), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.user= user; + parms.passwd= passwd; + parms.db= db; + }, + my_bool, + TRUE, + r_my_bool, + /* Nothing */) + +struct mysql_query_params { + MYSQL *mysql; + const char *q; +}; +MK_ASYNC_CALLS( + mysql_query, + (int *ret, MYSQL *mysql, const char *q), + (parms->mysql, parms->q), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.q= q; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_shutdown_params { + MYSQL *mysql; + enum mysql_enum_shutdown_level shutdown_level; +}; +MK_ASYNC_CALLS( + mysql_shutdown, + (int *ret, MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level), + (parms->mysql, parms->shutdown_level), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.shutdown_level= shutdown_level; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_dump_debug_info_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_dump_debug_info, + (int *ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_refresh_params { + MYSQL *mysql; + unsigned int refresh_options; +}; +MK_ASYNC_CALLS( + mysql_refresh, + (int *ret, MYSQL *mysql, unsigned int refresh_options), + (parms->mysql, parms->refresh_options), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.refresh_options= refresh_options; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_kill_params { + MYSQL *mysql; + unsigned long pid; +}; +MK_ASYNC_CALLS( + mysql_kill, + (int *ret, MYSQL *mysql, unsigned long pid), + (parms->mysql, parms->pid), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.pid= pid; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_set_server_option_params { + MYSQL *mysql; + enum enum_mysql_set_option option; +}; +MK_ASYNC_CALLS( + mysql_set_server_option, + (int *ret, MYSQL *mysql, enum enum_mysql_set_option option), + (parms->mysql, parms->option), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.option= option; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_ping_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_ping, + (int *ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + int, + 1, + r_int, + /* Nothing */) + +struct mysql_stat_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_stat, + (const char **ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + const char *, + NULL, + r_const_ptr, + /* Nothing */) + +struct mysql_list_dbs_params { + MYSQL *mysql; + const char *wild; +}; +MK_ASYNC_CALLS( + mysql_list_dbs, + (MYSQL_RES **ret, MYSQL *mysql, const char *wild), + (parms->mysql, parms->wild), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.wild= wild; + }, + MYSQL_RES *, + NULL, + r_ptr, + /* Nothing */) + +struct mysql_list_tables_params { + MYSQL *mysql; + const char *wild; +}; +MK_ASYNC_CALLS( + mysql_list_tables, + (MYSQL_RES **ret, MYSQL *mysql, const char *wild), + (parms->mysql, parms->wild), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.wild= wild; + }, + MYSQL_RES *, + NULL, + r_ptr, + /* Nothing */) + +struct mysql_list_processes_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_list_processes, + (MYSQL_RES **ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + MYSQL_RES *, + NULL, + r_ptr, + /* Nothing */) + +struct mysql_list_fields_params { + MYSQL *mysql; + const char *table; + const char *wild; +}; +MK_ASYNC_CALLS( + mysql_list_fields, + (MYSQL_RES **ret, MYSQL *mysql, const char *table, const char *wild), + (parms->mysql, parms->table, parms->wild), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.table= table; + parms.wild= wild; + }, + MYSQL_RES *, + NULL, + r_ptr, + /* Nothing */) + +struct mysql_read_query_result_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_read_query_result, + (my_bool *ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + my_bool, + TRUE, + r_my_bool, + /* Nothing */) + +struct mysql_stmt_prepare_params { + MYSQL_STMT *stmt; + const char *query; + unsigned long length; +}; +MK_ASYNC_CALLS( + mysql_stmt_prepare, + (int *ret, MYSQL_STMT *stmt, const char *query, unsigned long length), + (parms->stmt, parms->query, parms->length), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + parms.query= query; + parms.length= length; + }, + int, + 1, + r_int, + /* If stmt->mysql==NULL then we will not block so can call directly. */ + if (!stmt->mysql) + { + *ret= mysql_stmt_prepare(stmt, query, length); + return 0; + }) + +struct mysql_stmt_execute_params { + MYSQL_STMT *stmt; +}; +MK_ASYNC_CALLS( + mysql_stmt_execute, + (int *ret, MYSQL_STMT *stmt), + (parms->stmt), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + }, + int, + 1, + r_int, + /* + If eg. mysql_change_user(), stmt->mysql will be NULL. + In this case, we cannot block. + */ + if (!stmt->mysql) + { + *ret= mysql_stmt_execute(stmt); + return 0; + }) + +struct mysql_stmt_fetch_params { + MYSQL_STMT *stmt; +}; +MK_ASYNC_CALLS( + mysql_stmt_fetch, + (int *ret, MYSQL_STMT *stmt), + (parms->stmt), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + }, + int, + 1, + r_int, + /* If stmt->mysql==NULL then we will not block so can call directly. */ + if (!stmt->mysql) + { + *ret= mysql_stmt_fetch(stmt); + return 0; + }) + +struct mysql_stmt_store_result_params { + MYSQL_STMT *stmt; +}; +MK_ASYNC_CALLS( + mysql_stmt_store_result, + (int *ret, MYSQL_STMT *stmt), + (parms->stmt), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + }, + int, + 1, + r_int, + /* If stmt->mysql==NULL then we will not block so can call directly. */ + if (!stmt->mysql) + { + *ret= mysql_stmt_store_result(stmt); + return 0; + }) + +struct mysql_stmt_close_params { + MYSQL_STMT *stmt; +}; +MK_ASYNC_CALLS( + mysql_stmt_close, + (my_bool *ret, MYSQL_STMT *stmt), + (parms->stmt), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + }, + my_bool, + TRUE, + r_my_bool, + /* If stmt->mysql==NULL then we will not block so can call directly. */ + if (!stmt->mysql) + { + *ret= mysql_stmt_close(stmt); + return 0; + }) + +struct mysql_stmt_reset_params { + MYSQL_STMT *stmt; +}; +MK_ASYNC_CALLS( + mysql_stmt_reset, + (my_bool *ret, MYSQL_STMT *stmt), + (parms->stmt), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + }, + my_bool, + TRUE, + r_my_bool, + /* If stmt->mysql==NULL then we will not block so can call directly. */ + if (!stmt->mysql) + { + *ret= mysql_stmt_reset(stmt); + return 0; + }) + +struct mysql_stmt_free_result_params { + MYSQL_STMT *stmt; +}; +MK_ASYNC_CALLS( + mysql_stmt_free_result, + (my_bool *ret, MYSQL_STMT *stmt), + (parms->stmt), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + }, + my_bool, + TRUE, + r_my_bool, + /* If stmt->mysql==NULL then we will not block so can call directly. */ + if (!stmt->mysql) + { + *ret= mysql_stmt_free_result(stmt); + return 0; + }) + +struct mysql_stmt_send_long_data_params { + MYSQL_STMT *stmt; + unsigned int param_number; + const char *data; + unsigned long length; +}; +MK_ASYNC_CALLS( + mysql_stmt_send_long_data, + (my_bool *ret, MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length), + (parms->stmt, parms->param_number, parms->data, parms->length), + MYSQL_STMT *stmt, + stmt->mysql, + parms->stmt->mysql, + { + WIN_SET_NONBLOCKING(stmt->mysql) + parms.stmt= stmt; + parms.param_number= param_number; + parms.data= data; + parms.length= length; + }, + my_bool, + TRUE, + r_my_bool, + /* If stmt->mysql==NULL then we will not block so can call directly. */ + if (!stmt->mysql) + { + *ret= mysql_stmt_send_long_data(stmt, param_number, data, length); + return 0; + }) + +struct mysql_commit_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_commit, + (my_bool *ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + my_bool, + TRUE, + r_my_bool, + /* Nothing */) + +struct mysql_rollback_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_rollback, + (my_bool *ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + my_bool, + TRUE, + r_my_bool, + /* Nothing */) + +struct mysql_autocommit_params { + MYSQL *mysql; + my_bool auto_mode; +}; +MK_ASYNC_CALLS( + mysql_autocommit, + (my_bool *ret, MYSQL *mysql, my_bool auto_mode), + (parms->mysql, parms->auto_mode), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + parms.auto_mode= auto_mode; + }, + my_bool, + TRUE, + r_my_bool, + /* Nothing */) + +struct mysql_next_result_params { + MYSQL *mysql; +}; +MK_ASYNC_CALLS( + mysql_next_result, + (int *ret, MYSQL *mysql), + (parms->mysql), + MYSQL *mysql, + mysql, + parms->mysql, + { + WIN_SET_NONBLOCKING(mysql) + parms.mysql= mysql; + }, + int, + 1, + r_int, + /* Nothing */) +#endif + + +/* + The following functions can newer block, and so do not have special + non-blocking versions: + + mysql_num_rows() + mysql_num_fields() + mysql_eof() + mysql_fetch_field_direct() + mysql_fetch_fields() + mysql_row_tell() + mysql_field_tell() + mysql_field_count() + mysql_affected_rows() + mysql_insert_id() + mysql_errno() + mysql_error() + mysql_sqlstate() + mysql_warning_count() + mysql_info() + mysql_thread_id() + mysql_character_set_name() + mysql_init() + mysql_ssl_set() + mysql_get_ssl_cipher() + mysql_use_result() + mysql_get_character_set_info() + mysql_set_local_infile_handler() + mysql_set_local_infile_default() + mysql_get_server_info() + mysql_get_server_name() + mysql_get_client_info() + mysql_get_client_version() + mysql_get_host_info() + mysql_get_server_version() + mysql_get_proto_info() + mysql_options() + mysql_data_seek() + mysql_row_seek() + mysql_field_seek() + mysql_fetch_lengths() + mysql_fetch_field() + mysql_escape_string() + mysql_hex_string() + mysql_real_escape_string() + mysql_debug() + myodbc_remove_escape() + mysql_thread_safe() + mysql_embedded() + mariadb_connection() + mysql_stmt_init() + mysql_stmt_fetch_column() + mysql_stmt_param_count() + mysql_stmt_attr_set() + mysql_stmt_attr_get() + mysql_stmt_bind_param() + mysql_stmt_bind_result() + mysql_stmt_result_metadata() + mysql_stmt_param_metadata() + mysql_stmt_errno() + mysql_stmt_error() + mysql_stmt_sqlstate() + mysql_stmt_row_seek() + mysql_stmt_row_tell() + mysql_stmt_data_seek() + mysql_stmt_num_rows() + mysql_stmt_affected_rows() + mysql_stmt_insert_id() + mysql_stmt_field_count() + mysql_more_results() + mysql_get_socket() + mysql_get_timeout_value() +*/ |