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