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 */
35 static int
wait_for_mysql(MYSQL * mysql,int status)36 wait_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__) \
138 ret_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__) \
153 void 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
165 MK_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
175 MK_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
184 MK_WRAPPER(
185 MYSQL_ROW,
186 mysql_fetch_row,
187 (MYSQL_RES *result),
188 (&res, result),
189 (result),
190 result,
191 result->handle)
192
193 MK_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
202 MK_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
211 MK_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
220 MK_WRAPPER(
221 MYSQL_RES *,
222 mysql_store_result,
223 (MYSQL *mysql),
224 (&res, mysql),
225 (mysql),
226 mysql,
227 mysql)
228
229 MK_WRAPPER_VOID_RETURN(
230 mysql_free_result,
231 (MYSQL_RES *result),
232 (result),
233 result,
234 result->handle)
235
236 MK_WRAPPER_VOID_RETURN(
237 mysql_close,
238 (MYSQL *sock),
239 (sock),
240 sock,
241 sock)
242
243 MK_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
252 MK_WRAPPER(
253 int,
254 mysql_query,
255 (MYSQL *mysql, const char *q),
256 (&res, mysql, q),
257 (mysql, q),
258 mysql,
259 mysql)
260
261 MK_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
270 MK_WRAPPER(
271 int,
272 mysql_dump_debug_info,
273 (MYSQL *mysql),
274 (&res, mysql),
275 (mysql),
276 mysql,
277 mysql)
278
279 MK_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
288 MK_WRAPPER(
289 int,
290 mysql_kill,
291 (MYSQL *mysql, unsigned long pid),
292 (&res, mysql, pid),
293 (mysql, pid),
294 mysql,
295 mysql)
296
297 MK_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
306 MK_WRAPPER(
307 int,
308 mysql_ping,
309 (MYSQL *mysql),
310 (&res, mysql),
311 (mysql),
312 mysql,
313 mysql)
314
315 MK_WRAPPER(
316 const char *,
317 mysql_stat,
318 (MYSQL *mysql),
319 (&res, mysql),
320 (mysql),
321 mysql,
322 mysql)
323
324 MK_WRAPPER(
325 my_bool,
326 mysql_read_query_result,
327 (MYSQL *mysql),
328 (&res, mysql),
329 (mysql),
330 mysql,
331 mysql)
332
333 MK_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
342 MK_WRAPPER(
343 int,
344 mysql_stmt_execute,
345 (MYSQL_STMT *stmt),
346 (&res, stmt),
347 (stmt),
348 stmt,
349 stmt->mysql)
350
351 MK_WRAPPER(
352 int,
353 mysql_stmt_fetch,
354 (MYSQL_STMT *stmt),
355 (&res, stmt),
356 (stmt),
357 stmt,
358 stmt->mysql)
359
360 MK_WRAPPER(
361 int,
362 mysql_stmt_store_result,
363 (MYSQL_STMT *stmt),
364 (&res, stmt),
365 (stmt),
366 stmt,
367 stmt->mysql)
368
369 MK_WRAPPER(
370 my_bool,
371 mysql_stmt_close,
372 (MYSQL_STMT *stmt),
373 (&res, stmt),
374 (stmt),
375 stmt,
376 stmt->mysql)
377
378 MK_WRAPPER(
379 my_bool,
380 mysql_stmt_reset,
381 (MYSQL_STMT *stmt),
382 (&res, stmt),
383 (stmt),
384 stmt,
385 stmt->mysql)
386
387 MK_WRAPPER(
388 my_bool,
389 mysql_stmt_free_result,
390 (MYSQL_STMT *stmt),
391 (&res, stmt),
392 (stmt),
393 stmt,
394 stmt->mysql)
395
396 MK_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
405 MK_WRAPPER(
406 my_bool,
407 mysql_commit,
408 (MYSQL *mysql),
409 (&res, mysql),
410 (mysql),
411 mysql,
412 mysql)
413
414 MK_WRAPPER(
415 my_bool,
416 mysql_rollback,
417 (MYSQL *mysql),
418 (&res, mysql),
419 (mysql),
420 mysql,
421 mysql)
422
423 MK_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
432 MK_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