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 |
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 | |