1/*
2 Copyright 2011 Kristian Nielsen and Monty Program Ab
3
4 This file is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18/*
19 Wrappers that re-implement the normal blocking libmysql API calls in terms
20 of the non-blocking API calls and explicit waiting.
21
22 Used to test the non-blocking calls using mysql_client_test.
23*/
24
25#ifndef __WIN__
26#include <poll.h>
27#else
28#include <WinSock2.h>
29#endif
30
31/*
32 Run the appropriate poll() syscall to wait for the event that libmysql
33 requested. Return which event(s) occurred.
34*/
35static int
36wait_for_mysql(MYSQL *mysql, int status)
37{
38#ifdef __WIN__
39 fd_set rs, ws, es;
40 int res;
41 struct timeval tv, *timeout;
42 my_socket s= mysql_get_socket(mysql);
43 FD_ZERO(&rs);
44 FD_ZERO(&ws);
45 FD_ZERO(&es);
46 if (status & MYSQL_WAIT_READ)
47 FD_SET(s, &rs);
48 if (status & MYSQL_WAIT_WRITE)
49 FD_SET(s, &ws);
50 if (status & MYSQL_WAIT_EXCEPT)
51 FD_SET(s, &es);
52 if (status & MYSQL_WAIT_TIMEOUT)
53 {
54 tv.tv_sec= mysql_get_timeout_value(mysql);
55 tv.tv_usec= 0;
56 timeout= &tv;
57 }
58 else
59 timeout= NULL;
60 res= select(1, &rs, &ws, &es, timeout);
61 if (res == 0)
62 return MYSQL_WAIT_TIMEOUT;
63 else if (res == SOCKET_ERROR)
64 return MYSQL_WAIT_TIMEOUT;
65 else
66 {
67 int status= 0;
68 if (FD_ISSET(s, &rs))
69 status|= MYSQL_WAIT_READ;
70 if (FD_ISSET(s, &ws))
71 status|= MYSQL_WAIT_WRITE;
72 if (FD_ISSET(s, &es))
73 status|= MYSQL_WAIT_EXCEPT;
74 return status;
75 }
76#else
77 struct pollfd pfd;
78 int timeout;
79 int res;
80
81 pfd.fd= mysql_get_socket(mysql);
82 pfd.events=
83 (status & MYSQL_WAIT_READ ? POLLIN : 0) |
84 (status & MYSQL_WAIT_WRITE ? POLLOUT : 0) |
85 (status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0);
86 if (status & MYSQL_WAIT_TIMEOUT)
87 timeout= 1000*mysql_get_timeout_value(mysql);
88 else
89 timeout= -1;
90 do {
91 res= poll(&pfd, 1, timeout);
92 /*
93 In a real event framework, we should re-compute the timeout on getting
94 EINTR to account for the time elapsed before the interruption.
95 */
96 } while (res < 0 && errno == EINTR);
97 if (res == 0)
98 return MYSQL_WAIT_TIMEOUT;
99 else if (res < 0)
100 return MYSQL_WAIT_TIMEOUT;
101 else
102 {
103 int status= 0;
104 if (pfd.revents & POLLIN)
105 status|= MYSQL_WAIT_READ;
106 if (pfd.revents & POLLOUT)
107 status|= MYSQL_WAIT_WRITE;
108 if (pfd.revents & POLLPRI)
109 status|= MYSQL_WAIT_EXCEPT;
110 return status;
111 }
112#endif
113}
114
115
116/*
117 If WRAP_NONBLOCK_ENABLED is defined, it is a variable that can be used to
118 enable or disable the use of non-blocking API wrappers. If true the
119 non-blocking API will be used, if false the normal blocking API will be
120 called directly.
121*/
122#ifdef WRAP_NONBLOCK_ENABLED
123#define USE_BLOCKING(name__, invoke_blocking__) \
124 if (!(WRAP_NONBLOCK_ENABLED)) return name__ invoke_blocking__;
125#define USE_BLOCKING_VOID_RETURN(name__, invoke__) \
126 if (!(WRAP_NONBLOCK_ENABLED)) { name__ invoke__; return; }
127#else
128#define USE_BLOCKING(name__, invoke_blocking__)
129#define USE_BLOCKING_VOID_RETURN(name__, invoke__)
130#endif
131
132/*
133 I would preferably have declared the wrappers static.
134 However, if we do so, compilers will warn about definitions not used, and
135 with -Werror this breaks compilation :-(
136*/
137#define MK_WRAPPER(ret_type__, name__, decl__, invoke__, invoke_blocking__, cont_arg__, mysql__) \
138ret_type__ wrap_ ## name__ decl__ \
139{ \
140 ret_type__ res; \
141 int status; \
142 USE_BLOCKING(name__, invoke_blocking__) \
143 status= name__ ## _start invoke__; \
144 while (status) \
145 { \
146 status= wait_for_mysql(mysql__, status); \
147 status= name__ ## _cont(&res, cont_arg__, status); \
148 } \
149 return res; \
150}
151
152#define MK_WRAPPER_VOID_RETURN(name__, decl__, invoke__, cont_arg__, mysql__) \
153void wrap_ ## name__ decl__ \
154{ \
155 int status; \
156 USE_BLOCKING_VOID_RETURN(name__, invoke__) \
157 status= name__ ## _start invoke__; \
158 while (status) \
159 { \
160 status= wait_for_mysql(mysql__, status); \
161 status= name__ ## _cont(cont_arg__, status); \
162 } \
163}
164
165MK_WRAPPER(
166 MYSQL *,
167 mysql_real_connect,
168 (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag),
169 (&res, mysql, host, user, passwd, db, port, unix_socket, clientflag),
170 (mysql, host, user, passwd, db, port, unix_socket, clientflag),
171 mysql,
172 mysql)
173
174
175MK_WRAPPER(
176 int,
177 mysql_real_query,
178 (MYSQL *mysql, const char *stmt_str, unsigned long length),
179 (&res, mysql, stmt_str, length),
180 (mysql, stmt_str, length),
181 mysql,
182 mysql)
183
184MK_WRAPPER(
185 MYSQL_ROW,
186 mysql_fetch_row,
187 (MYSQL_RES *result),
188 (&res, result),
189 (result),
190 result,
191 result->handle)
192
193MK_WRAPPER(
194 int,
195 mysql_set_character_set,
196 (MYSQL *mysql, const char *csname),
197 (&res, mysql, csname),
198 (mysql, csname),
199 mysql,
200 mysql)
201
202MK_WRAPPER(
203 int,
204 mysql_select_db,
205 (MYSQL *mysql, const char *db),
206 (&res, mysql, db),
207 (mysql, db),
208 mysql,
209 mysql)
210
211MK_WRAPPER(
212 int,
213 mysql_send_query,
214 (MYSQL *mysql, const char *q, unsigned long length),
215 (&res, mysql, q, length),
216 (mysql, q, length),
217 mysql,
218 mysql)
219
220MK_WRAPPER(
221 MYSQL_RES *,
222 mysql_store_result,
223 (MYSQL *mysql),
224 (&res, mysql),
225 (mysql),
226 mysql,
227 mysql)
228
229MK_WRAPPER_VOID_RETURN(
230 mysql_free_result,
231 (MYSQL_RES *result),
232 (result),
233 result,
234 result->handle)
235
236MK_WRAPPER_VOID_RETURN(
237 mysql_close,
238 (MYSQL *sock),
239 (sock),
240 sock,
241 sock)
242
243MK_WRAPPER(
244 my_bool,
245 mysql_change_user,
246 (MYSQL *mysql, const char *user, const char *passwd, const char *db),
247 (&res, mysql, user, passwd, db),
248 (mysql, user, passwd, db),
249 mysql,
250 mysql)
251
252MK_WRAPPER(
253 int,
254 mysql_query,
255 (MYSQL *mysql, const char *q),
256 (&res, mysql, q),
257 (mysql, q),
258 mysql,
259 mysql)
260
261MK_WRAPPER(
262 int,
263 mysql_shutdown,
264 (MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level),
265 (&res, mysql, shutdown_level),
266 (mysql, shutdown_level),
267 mysql,
268 mysql)
269
270MK_WRAPPER(
271 int,
272 mysql_dump_debug_info,
273 (MYSQL *mysql),
274 (&res, mysql),
275 (mysql),
276 mysql,
277 mysql)
278
279MK_WRAPPER(
280 int,
281 mysql_refresh,
282 (MYSQL *mysql, unsigned int refresh_options),
283 (&res, mysql, refresh_options),
284 (mysql, refresh_options),
285 mysql,
286 mysql)
287
288MK_WRAPPER(
289 int,
290 mysql_kill,
291 (MYSQL *mysql, unsigned long pid),
292 (&res, mysql, pid),
293 (mysql, pid),
294 mysql,
295 mysql)
296
297MK_WRAPPER(
298 int,
299 mysql_set_server_option,
300 (MYSQL *mysql, enum enum_mysql_set_option option),
301 (&res, mysql, option),
302 (mysql, option),
303 mysql,
304 mysql)
305
306MK_WRAPPER(
307 int,
308 mysql_ping,
309 (MYSQL *mysql),
310 (&res, mysql),
311 (mysql),
312 mysql,
313 mysql)
314
315MK_WRAPPER(
316 const char *,
317 mysql_stat,
318 (MYSQL *mysql),
319 (&res, mysql),
320 (mysql),
321 mysql,
322 mysql)
323
324MK_WRAPPER(
325 my_bool,
326 mysql_read_query_result,
327 (MYSQL *mysql),
328 (&res, mysql),
329 (mysql),
330 mysql,
331 mysql)
332
333MK_WRAPPER(
334 int,
335 mysql_stmt_prepare,
336 (MYSQL_STMT *stmt, const char *query, unsigned long length),
337 (&res, stmt, query, length),
338 (stmt, query, length),
339 stmt,
340 stmt->mysql)
341
342MK_WRAPPER(
343 int,
344 mysql_stmt_execute,
345 (MYSQL_STMT *stmt),
346 (&res, stmt),
347 (stmt),
348 stmt,
349 stmt->mysql)
350
351MK_WRAPPER(
352 int,
353 mysql_stmt_fetch,
354 (MYSQL_STMT *stmt),
355 (&res, stmt),
356 (stmt),
357 stmt,
358 stmt->mysql)
359
360MK_WRAPPER(
361 int,
362 mysql_stmt_store_result,
363 (MYSQL_STMT *stmt),
364 (&res, stmt),
365 (stmt),
366 stmt,
367 stmt->mysql)
368
369MK_WRAPPER(
370 my_bool,
371 mysql_stmt_close,
372 (MYSQL_STMT *stmt),
373 (&res, stmt),
374 (stmt),
375 stmt,
376 stmt->mysql)
377
378MK_WRAPPER(
379 my_bool,
380 mysql_stmt_reset,
381 (MYSQL_STMT *stmt),
382 (&res, stmt),
383 (stmt),
384 stmt,
385 stmt->mysql)
386
387MK_WRAPPER(
388 my_bool,
389 mysql_stmt_free_result,
390 (MYSQL_STMT *stmt),
391 (&res, stmt),
392 (stmt),
393 stmt,
394 stmt->mysql)
395
396MK_WRAPPER(
397 my_bool,
398 mysql_stmt_send_long_data,
399 (MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length),
400 (&res, stmt, param_number, data, length),
401 (stmt, param_number, data, length),
402 stmt,
403 stmt->mysql)
404
405MK_WRAPPER(
406 my_bool,
407 mysql_commit,
408 (MYSQL *mysql),
409 (&res, mysql),
410 (mysql),
411 mysql,
412 mysql)
413
414MK_WRAPPER(
415 my_bool,
416 mysql_rollback,
417 (MYSQL *mysql),
418 (&res, mysql),
419 (mysql),
420 mysql,
421 mysql)
422
423MK_WRAPPER(
424 my_bool,
425 mysql_autocommit,
426 (MYSQL *mysql, my_bool auto_mode),
427 (&res, mysql, auto_mode),
428 (mysql, auto_mode),
429 mysql,
430 mysql)
431
432MK_WRAPPER(
433 int,
434 mysql_next_result,
435 (MYSQL *mysql),
436 (&res, mysql),
437 (mysql),
438 mysql,
439 mysql)
440
441#undef USE_BLOCKING
442#undef MK_WRAPPER
443#undef MK_WRAPPER_VOID_RETURN
444
445
446#define mysql_real_connect wrap_mysql_real_connect
447#define mysql_real_query wrap_mysql_real_query
448#define mysql_fetch_row wrap_mysql_fetch_row
449#define mysql_set_character_set wrap_mysql_set_character_set
450#define mysql_select_db wrap_mysql_select_db
451#define mysql_send_query wrap_mysql_send_query
452#define mysql_store_result wrap_mysql_store_result
453#define mysql_free_result wrap_mysql_free_result
454#define mysql_close wrap_mysql_close
455#define mysql_change_user wrap_mysql_change_user
456#define mysql_query wrap_mysql_query
457#define mysql_shutdown wrap_mysql_shutdown
458#define mysql_dump_debug_info wrap_mysql_dump_debug_info
459#define mysql_refresh wrap_mysql_refresh
460#define mysql_kill wrap_mysql_kill
461#define mysql_set_server_option wrap_mysql_set_server_option
462#define mysql_ping wrap_mysql_ping
463#define mysql_stat wrap_mysql_stat
464#define mysql_list_dbs wrap_mysql_list_dbs
465#define mysql_list_tables wrap_mysql_list_tables
466#define mysql_list_processes wrap_mysql_list_processes
467#define mysql_read_query_result wrap_mysql_read_query_result
468#define mysql_stmt_prepare wrap_mysql_stmt_prepare
469#define mysql_stmt_execute wrap_mysql_stmt_execute
470#define mysql_stmt_fetch wrap_mysql_stmt_fetch
471#define mysql_stmt_store_result wrap_mysql_stmt_store_result
472#define mysql_stmt_close wrap_mysql_stmt_close
473#define mysql_stmt_reset wrap_mysql_stmt_reset
474#define mysql_stmt_free_result wrap_mysql_stmt_free_result
475#define mysql_stmt_send_long_data wrap_mysql_stmt_send_long_data
476#define mysql_commit wrap_mysql_commit
477#define mysql_rollback wrap_mysql_rollback
478#define mysql_autocommit wrap_mysql_autocommit
479#define mysql_next_result wrap_mysql_next_result
480