/*
Copyright 2011 Kristian Nielsen and Monty Program Ab
This file is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU General Public License
along with this. If not, see .
*/
/*
Wrappers that re-implement the normal blocking libmysql API calls in terms
of the non-blocking API calls and explicit waiting.
Used to test the non-blocking calls using mysql_client_test.
*/
#ifndef __WIN__
#include
#else
#include
#endif
/*
Run the appropriate poll() syscall to wait for the event that libmysql
requested. Return which event(s) occurred.
*/
static int
wait_for_mysql(MYSQL *mysql, int status)
{
#ifdef __WIN__
fd_set rs, ws, es;
int res;
struct timeval tv, *timeout;
my_socket s= mysql_get_socket(mysql);
FD_ZERO(&rs);
FD_ZERO(&ws);
FD_ZERO(&es);
if (status & MYSQL_WAIT_READ)
FD_SET(s, &rs);
if (status & MYSQL_WAIT_WRITE)
FD_SET(s, &ws);
if (status & MYSQL_WAIT_EXCEPT)
FD_SET(s, &es);
if (status & MYSQL_WAIT_TIMEOUT)
{
tv.tv_sec= mysql_get_timeout_value(mysql);
tv.tv_usec= 0;
timeout= &tv;
}
else
timeout= NULL;
res= select(1, &rs, &ws, &es, timeout);
if (res == 0)
return MYSQL_WAIT_TIMEOUT;
else if (res == SOCKET_ERROR)
return MYSQL_WAIT_TIMEOUT;
else
{
int status= 0;
if (FD_ISSET(s, &rs))
status|= MYSQL_WAIT_READ;
if (FD_ISSET(s, &ws))
status|= MYSQL_WAIT_WRITE;
if (FD_ISSET(s, &es))
status|= MYSQL_WAIT_EXCEPT;
return status;
}
#else
struct pollfd pfd;
int timeout;
int res;
pfd.fd= mysql_get_socket(mysql);
pfd.events=
(status & MYSQL_WAIT_READ ? POLLIN : 0) |
(status & MYSQL_WAIT_WRITE ? POLLOUT : 0) |
(status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0);
if (status & MYSQL_WAIT_TIMEOUT)
timeout= 1000*mysql_get_timeout_value(mysql);
else
timeout= -1;
do {
res= poll(&pfd, 1, timeout);
/*
In a real event framework, we should re-compute the timeout on getting
EINTR to account for the time elapsed before the interruption.
*/
} while (res < 0 && errno == EINTR);
if (res == 0)
return MYSQL_WAIT_TIMEOUT;
else if (res < 0)
return MYSQL_WAIT_TIMEOUT;
else
{
int status= 0;
if (pfd.revents & POLLIN)
status|= MYSQL_WAIT_READ;
if (pfd.revents & POLLOUT)
status|= MYSQL_WAIT_WRITE;
if (pfd.revents & POLLPRI)
status|= MYSQL_WAIT_EXCEPT;
return status;
}
#endif
}
/*
If WRAP_NONBLOCK_ENABLED is defined, it is a variable that can be used to
enable or disable the use of non-blocking API wrappers. If true the
non-blocking API will be used, if false the normal blocking API will be
called directly.
*/
#ifdef WRAP_NONBLOCK_ENABLED
#define USE_BLOCKING(name__, invoke_blocking__) \
if (!(WRAP_NONBLOCK_ENABLED)) return name__ invoke_blocking__;
#define USE_BLOCKING_VOID_RETURN(name__, invoke__) \
if (!(WRAP_NONBLOCK_ENABLED)) { name__ invoke__; return; }
#else
#define USE_BLOCKING(name__, invoke_blocking__)
#define USE_BLOCKING_VOID_RETURN(name__, invoke__)
#endif
/*
I would preferably have declared the wrappers static.
However, if we do so, compilers will warn about definitions not used, and
with -Werror this breaks compilation :-(
*/
#define MK_WRAPPER(ret_type__, name__, decl__, invoke__, invoke_blocking__, cont_arg__, mysql__) \
ret_type__ wrap_ ## name__ decl__ \
{ \
ret_type__ res; \
int status; \
USE_BLOCKING(name__, invoke_blocking__) \
status= name__ ## _start invoke__; \
while (status) \
{ \
status= wait_for_mysql(mysql__, status); \
status= name__ ## _cont(&res, cont_arg__, status); \
} \
return res; \
}
#define MK_WRAPPER_VOID_RETURN(name__, decl__, invoke__, cont_arg__, mysql__) \
void wrap_ ## name__ decl__ \
{ \
int status; \
USE_BLOCKING_VOID_RETURN(name__, invoke__) \
status= name__ ## _start invoke__; \
while (status) \
{ \
status= wait_for_mysql(mysql__, status); \
status= name__ ## _cont(cont_arg__, status); \
} \
}
MK_WRAPPER(
MYSQL *,
mysql_real_connect,
(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag),
(&res, mysql, host, user, passwd, db, port, unix_socket, clientflag),
(mysql, host, user, passwd, db, port, unix_socket, clientflag),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_real_query,
(MYSQL *mysql, const char *stmt_str, unsigned long length),
(&res, mysql, stmt_str, length),
(mysql, stmt_str, length),
mysql,
mysql)
MK_WRAPPER(
MYSQL_ROW,
mysql_fetch_row,
(MYSQL_RES *result),
(&res, result),
(result),
result,
result->handle)
MK_WRAPPER(
int,
mysql_set_character_set,
(MYSQL *mysql, const char *csname),
(&res, mysql, csname),
(mysql, csname),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_select_db,
(MYSQL *mysql, const char *db),
(&res, mysql, db),
(mysql, db),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_send_query,
(MYSQL *mysql, const char *q, unsigned long length),
(&res, mysql, q, length),
(mysql, q, length),
mysql,
mysql)
MK_WRAPPER(
MYSQL_RES *,
mysql_store_result,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
MK_WRAPPER_VOID_RETURN(
mysql_free_result,
(MYSQL_RES *result),
(result),
result,
result->handle)
MK_WRAPPER_VOID_RETURN(
mysql_close,
(MYSQL *sock),
(sock),
sock,
sock)
MK_WRAPPER(
my_bool,
mysql_change_user,
(MYSQL *mysql, const char *user, const char *passwd, const char *db),
(&res, mysql, user, passwd, db),
(mysql, user, passwd, db),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_query,
(MYSQL *mysql, const char *q),
(&res, mysql, q),
(mysql, q),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_shutdown,
(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level),
(&res, mysql, shutdown_level),
(mysql, shutdown_level),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_dump_debug_info,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_refresh,
(MYSQL *mysql, unsigned int refresh_options),
(&res, mysql, refresh_options),
(mysql, refresh_options),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_kill,
(MYSQL *mysql, unsigned long pid),
(&res, mysql, pid),
(mysql, pid),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_set_server_option,
(MYSQL *mysql, enum enum_mysql_set_option option),
(&res, mysql, option),
(mysql, option),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_ping,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
MK_WRAPPER(
const char *,
mysql_stat,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
MK_WRAPPER(
my_bool,
mysql_read_query_result,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_stmt_prepare,
(MYSQL_STMT *stmt, const char *query, unsigned long length),
(&res, stmt, query, length),
(stmt, query, length),
stmt,
stmt->mysql)
MK_WRAPPER(
int,
mysql_stmt_execute,
(MYSQL_STMT *stmt),
(&res, stmt),
(stmt),
stmt,
stmt->mysql)
MK_WRAPPER(
int,
mysql_stmt_fetch,
(MYSQL_STMT *stmt),
(&res, stmt),
(stmt),
stmt,
stmt->mysql)
MK_WRAPPER(
int,
mysql_stmt_store_result,
(MYSQL_STMT *stmt),
(&res, stmt),
(stmt),
stmt,
stmt->mysql)
MK_WRAPPER(
my_bool,
mysql_stmt_close,
(MYSQL_STMT *stmt),
(&res, stmt),
(stmt),
stmt,
stmt->mysql)
MK_WRAPPER(
my_bool,
mysql_stmt_reset,
(MYSQL_STMT *stmt),
(&res, stmt),
(stmt),
stmt,
stmt->mysql)
MK_WRAPPER(
my_bool,
mysql_stmt_free_result,
(MYSQL_STMT *stmt),
(&res, stmt),
(stmt),
stmt,
stmt->mysql)
MK_WRAPPER(
my_bool,
mysql_stmt_send_long_data,
(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length),
(&res, stmt, param_number, data, length),
(stmt, param_number, data, length),
stmt,
stmt->mysql)
MK_WRAPPER(
my_bool,
mysql_commit,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
MK_WRAPPER(
my_bool,
mysql_rollback,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
MK_WRAPPER(
my_bool,
mysql_autocommit,
(MYSQL *mysql, my_bool auto_mode),
(&res, mysql, auto_mode),
(mysql, auto_mode),
mysql,
mysql)
MK_WRAPPER(
int,
mysql_next_result,
(MYSQL *mysql),
(&res, mysql),
(mysql),
mysql,
mysql)
#undef USE_BLOCKING
#undef MK_WRAPPER
#undef MK_WRAPPER_VOID_RETURN
#define mysql_real_connect wrap_mysql_real_connect
#define mysql_real_query wrap_mysql_real_query
#define mysql_fetch_row wrap_mysql_fetch_row
#define mysql_set_character_set wrap_mysql_set_character_set
#define mysql_select_db wrap_mysql_select_db
#define mysql_send_query wrap_mysql_send_query
#define mysql_store_result wrap_mysql_store_result
#define mysql_free_result wrap_mysql_free_result
#define mysql_close wrap_mysql_close
#define mysql_change_user wrap_mysql_change_user
#define mysql_query wrap_mysql_query
#define mysql_shutdown wrap_mysql_shutdown
#define mysql_dump_debug_info wrap_mysql_dump_debug_info
#define mysql_refresh wrap_mysql_refresh
#define mysql_kill wrap_mysql_kill
#define mysql_set_server_option wrap_mysql_set_server_option
#define mysql_ping wrap_mysql_ping
#define mysql_stat wrap_mysql_stat
#define mysql_list_dbs wrap_mysql_list_dbs
#define mysql_list_tables wrap_mysql_list_tables
#define mysql_list_processes wrap_mysql_list_processes
#define mysql_read_query_result wrap_mysql_read_query_result
#define mysql_stmt_prepare wrap_mysql_stmt_prepare
#define mysql_stmt_execute wrap_mysql_stmt_execute
#define mysql_stmt_fetch wrap_mysql_stmt_fetch
#define mysql_stmt_store_result wrap_mysql_stmt_store_result
#define mysql_stmt_close wrap_mysql_stmt_close
#define mysql_stmt_reset wrap_mysql_stmt_reset
#define mysql_stmt_free_result wrap_mysql_stmt_free_result
#define mysql_stmt_send_long_data wrap_mysql_stmt_send_long_data
#define mysql_commit wrap_mysql_commit
#define mysql_rollback wrap_mysql_rollback
#define mysql_autocommit wrap_mysql_autocommit
#define mysql_next_result wrap_mysql_next_result