1
0
mirror of https://github.com/MariaDB/server.git synced 2025-05-04 06:05:05 +03:00
mariadb/sql-common/mysql_async.c
unknown a5b881594d 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.
2011-09-20 12:49:25 +02:00

1432 lines
39 KiB
C

/*
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()
*/