1 /* Copyright (C) 2012 MariaDB Services and Kristian Nielsen
2                  2015 MariaDB Corporation
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2 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    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public
15    License along with this library; if not, write to the Free
16    Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 */
18 
19 /*
20   MySQL non-blocking client library functions.
21 */
22 
23 #include "ma_global.h"
24 #include "ma_sys.h"
25 #include "mysql.h"
26 #include "errmsg.h"
27 #ifndef LIBMARIADB
28 #include "sql_common.h"
29 #else
30 #include "ma_common.h"
31 #endif
32 #include "ma_context.h"
33 #include "ma_pvio.h"
34 #include "mariadb_async.h"
35 #include <string.h>
36 
37 
38 #ifdef _WIN32
39 /*
40   Windows does not support MSG_DONTWAIT for send()/recv(). So we need to ensure
41   that the socket is non-blocking at the start of every operation.
42 */
43 #define WIN_SET_NONBLOCKING(mysql) do { \
44     my_bool old_mode; \
45     if ((mysql)->net.pvio) ma_pvio_blocking((mysql)->net.pvio, FALSE, &old_mode); \
46   } while(0);
47 #else
48 #define WIN_SET_NONBLOCKING(mysql)
49 #endif
50 
51 extern void mysql_close_slow_part(MYSQL *mysql);
52 
53 
54 void
my_context_install_suspend_resume_hook(struct mysql_async_context * b,void (* hook)(my_bool,void *),void * user_data)55 my_context_install_suspend_resume_hook(struct mysql_async_context *b,
56                                        void (*hook)(my_bool, void *),
57                                        void *user_data)
58 {
59   b->suspend_resume_hook= hook;
60   b->suspend_resume_hook_user_data= user_data;
61 }
62 
63 
64 /* Asynchronous connect(); socket must already be set non-blocking. */
65 int
my_connect_async(MARIADB_PVIO * pvio,const struct sockaddr * name,uint namelen,int vio_timeout)66 my_connect_async(MARIADB_PVIO *pvio,
67                  const struct sockaddr *name, uint namelen, int vio_timeout)
68 {
69   int res;
70   size_socket s_err_size;
71   struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
72   my_socket sock;
73 
74   ma_pvio_get_handle(pvio, &sock);
75 
76   /* Make the socket non-blocking. */
77   ma_pvio_blocking(pvio, 0, 0);
78 
79   b->events_to_wait_for= 0;
80   /*
81     Start to connect asynchronously.
82     If this will block, we suspend the call and return control to the
83     application context. The application will then resume us when the socket
84     polls ready for write, indicating that the connection attempt completed.
85   */
86   res= connect(sock, name, namelen);
87   if (res != 0)
88   {
89 #ifdef _WIN32
90     int wsa_err= WSAGetLastError();
91     if (wsa_err != WSAEWOULDBLOCK)
92       return res;
93     b->events_to_wait_for|= MYSQL_WAIT_EXCEPT;
94 #else
95     int err= errno;
96     if (err != EINPROGRESS && err != EALREADY && err != EAGAIN)
97       return res;
98 #endif
99     b->events_to_wait_for|= MYSQL_WAIT_WRITE;
100     if (vio_timeout >= 0)
101     {
102       b->timeout_value= vio_timeout;
103       b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT;
104     }
105     else
106       b->timeout_value= 0;
107     if (b->suspend_resume_hook)
108       (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
109     my_context_yield(&b->async_context);
110     if (b->suspend_resume_hook)
111       (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
112     if (b->events_occured & MYSQL_WAIT_TIMEOUT)
113       return -1;
114 
115     s_err_size= sizeof(res);
116     if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*) &res, &s_err_size) != 0)
117       return -1;
118     if (res)
119     {
120       errno= res;
121       return -1;
122     }
123   }
124   return res;
125 }
126 
127 #define IS_BLOCKING_ERROR()                   \
128   IF_WIN(WSAGetLastError() != WSAEWOULDBLOCK, \
129          (errno != EAGAIN && errno != EINTR))
130 
131 #ifdef _AIX
132 #ifndef MSG_DONTWAIT
133 #define MSG_DONTWAIT 0
134 #endif
135 #endif
136 
137 #ifdef HAVE_TLS_FIXME
138 static my_bool
my_ssl_async_check_result(int res,struct mysql_async_context * b,MARIADB_SSL * cssl)139 my_ssl_async_check_result(int res, struct mysql_async_context *b, MARIADB_SSL *cssl)
140 {
141   int ssl_err;
142   b->events_to_wait_for= 0;
143   if (res >= 0)
144     return 1;
145   ssl_err= SSL_get_error(ssl, res);
146   if (ssl_err == SSL_ERROR_WANT_READ)
147     b->events_to_wait_for|= MYSQL_WAIT_READ;
148   else if (ssl_err == SSL_ERROR_WANT_WRITE)
149     b->events_to_wait_for|= MYSQL_WAIT_WRITE;
150   else
151     return 1;
152   if (b->suspend_resume_hook)
153     (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
154   my_context_yield(&b->async_context);
155   if (b->suspend_resume_hook)
156     (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
157   return 0;
158 }
159 
160 int
my_ssl_read_async(struct mysql_async_context * b,SSL * ssl,void * buf,int size)161 my_ssl_read_async(struct mysql_async_context *b, SSL *ssl,
162                   void *buf, int size)
163 {
164   int res;
165 
166   for (;;)
167   {
168     res= SSL_read(ssl, buf, size);
169     if (my_ssl_async_check_result(res, b, ssl))
170       return res;
171   }
172 }
173 
174 int
my_ssl_write_async(struct mysql_async_context * b,SSL * ssl,const void * buf,int size)175 my_ssl_write_async(struct mysql_async_context *b, SSL *ssl,
176                    const void *buf, int size)
177 {
178   int res;
179 
180   for (;;)
181   {
182     res= SSL_write(ssl, buf, size);
183     if (my_ssl_async_check_result(res, b, ssl))
184       return res;
185   }
186 }
187 #endif  /* HAVE_OPENSSL */
188 
189 
190 
191 
192 /*
193   Now create non-blocking definitions for all the calls that may block.
194 
195   Each call FOO gives rise to FOO_start() that prepares the MYSQL object for
196   doing non-blocking calls that can suspend operation mid-way, and then starts
197   the call itself. And a FOO_start_internal trampoline to assist with running
198   the real call in a co-routine that can be suspended. And a FOO_cont() that
199   can continue a suspended operation.
200 */
201 
202 #define MK_ASYNC_INTERNAL_BODY(call, invoke_args, mysql_val, ret_type, ok_val)\
203   struct call ## _params *parms= (struct call ## _params *)d;                 \
204   ret_type ret;                                                               \
205   struct mysql_async_context *b=                                              \
206     (mysql_val)->options.extension->async_context;                            \
207                                                                               \
208   ret= call invoke_args;                                                      \
209   b->ret_result. ok_val = ret;                                                \
210   b->events_to_wait_for= 0;
211 
212 #define MK_ASYNC_START_BODY(call, mysql_val, parms_assign, err_val, ok_val, extra1) \
213   int res;                                                                    \
214   struct mysql_async_context *b;                                              \
215   struct call ## _params parms;                                               \
216                                                                               \
217   extra1                                                                      \
218   b= mysql_val->options.extension->async_context;                             \
219   parms_assign                                                                \
220                                                                               \
221   b->active= 1;                                                               \
222   res= my_context_spawn(&b->async_context, call ## _start_internal, &parms);  \
223   b->active= b->suspended= 0;                                                 \
224   if (res > 0)                                                                \
225   {                                                                           \
226     /* Suspended. */                                                          \
227     b->suspended= 1;                                                          \
228     return b->events_to_wait_for;                                             \
229   }                                                                           \
230   if (res < 0)                                                                \
231   {                                                                           \
232     set_mariadb_error((mysql_val), CR_OUT_OF_MEMORY, unknown_sqlstate);         \
233     *ret= err_val;                                                            \
234   }                                                                           \
235   else                                                                        \
236     *ret= b->ret_result. ok_val;                                              \
237   return 0;
238 
239 #define MK_ASYNC_CONT_BODY(mysql_val, err_val, ok_val) \
240   int res;                                                                    \
241   struct mysql_async_context *b=                                              \
242     (mysql_val)->options.extension->async_context;                            \
243   if (!b->suspended)                                                          \
244   {                                                                           \
245     set_mariadb_error((mysql_val), CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);  \
246     *ret= err_val;                                                            \
247     return 0;                                                                 \
248   }                                                                           \
249                                                                               \
250   b->active= 1;                                                               \
251   b->events_occured= ready_status;                                            \
252   res= my_context_continue(&b->async_context);                                \
253   b->active= 0;                                                               \
254   if (res > 0)                                                                \
255     return b->events_to_wait_for;               /* (Still) suspended */       \
256   b->suspended= 0;                                                            \
257   if (res < 0)                                                                \
258   {                                                                           \
259     set_mariadb_error((mysql_val), CR_OUT_OF_MEMORY, unknown_sqlstate);         \
260     *ret= err_val;                                                            \
261   }                                                                           \
262   else                                                                        \
263     *ret= b->ret_result. ok_val;                /* Finished. */               \
264   return 0;
265 
266 #define MK_ASYNC_INTERNAL_BODY_VOID_RETURN(call, invoke_args, mysql_val)      \
267   struct call ## _params *parms= (struct call ## _params *)d;                 \
268   struct mysql_async_context *b=                                              \
269     (mysql_val)->options.extension->async_context;                            \
270                                                                               \
271   call invoke_args;                                                           \
272   b->events_to_wait_for= 0;
273 
274 #define MK_ASYNC_START_BODY_VOID_RETURN(call, mysql_val, parms_assign, extra1)\
275   int res;                                                                    \
276   struct mysql_async_context *b;                                              \
277   struct call ## _params parms;                                               \
278                                                                               \
279   extra1                                                                      \
280   b= mysql_val->options.extension->async_context;                             \
281   parms_assign                                                                \
282                                                                               \
283   b->active= 1;                                                               \
284   res= my_context_spawn(&b->async_context, call ## _start_internal, &parms);  \
285   b->active= b->suspended= 0;                                                 \
286   if (res > 0)                                                                \
287   {                                                                           \
288     /* Suspended. */                                                          \
289     b->suspended= 1;                                                          \
290     return b->events_to_wait_for;                                             \
291   }                                                                           \
292   if (res < 0)                                                                \
293     set_mariadb_error((mysql_val), CR_OUT_OF_MEMORY, unknown_sqlstate);         \
294   return 0;
295 
296 #define MK_ASYNC_CONT_BODY_VOID_RETURN(mysql_val)                             \
297   int res;                                                                    \
298   struct mysql_async_context *b=                                              \
299     (mysql_val)->options.extension->async_context;                            \
300   if (!b->suspended)                                                          \
301   {                                                                           \
302     set_mariadb_error((mysql_val), CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);  \
303     return 0;                                                                 \
304   }                                                                           \
305                                                                               \
306   b->active= 1;                                                               \
307   b->events_occured= ready_status;                                            \
308   res= my_context_continue(&b->async_context);                                \
309   b->active= 0;                                                               \
310   if (res > 0)                                                                \
311     return b->events_to_wait_for;               /* (Still) suspended */       \
312   b->suspended= 0;                                                            \
313   if (res < 0)                                                                \
314     set_mariadb_error((mysql_val), CR_OUT_OF_MEMORY, unknown_sqlstate);         \
315   return 0;
316 
317 
318 /* Structure used to pass parameters from mysql_real_connect_start(). */
319 struct mysql_real_connect_params {
320   MYSQL *mysql;
321   const char *host;
322   const char *user;
323   const char *passwd;
324   const char *db;
325   unsigned int port;
326   const char *unix_socket;
327   unsigned long client_flags;
328 };
329 static void
mysql_real_connect_start_internal(void * d)330 mysql_real_connect_start_internal(void *d)
331 {
332 MK_ASYNC_INTERNAL_BODY(
333   mysql_real_connect,
334   (parms->mysql, parms->host, parms->user, parms->passwd, parms->db,
335    parms->port, parms->unix_socket, parms->client_flags),
336   parms->mysql,
337   MYSQL *,
338   r_ptr)
339 }
340 int STDCALL
mysql_real_connect_start(MYSQL ** ret,MYSQL * mysql,const char * host,const char * user,const char * passwd,const char * db,unsigned int port,const char * unix_socket,unsigned long client_flags)341 mysql_real_connect_start(MYSQL **ret, MYSQL *mysql, const char *host,
342                          const char *user, const char *passwd, const char *db,
343                          unsigned int port, const char *unix_socket,
344                          unsigned long client_flags)
345 {
346 MK_ASYNC_START_BODY(
347   mysql_real_connect,
348   mysql,
349   {
350     parms.mysql= mysql;
351     parms.host= host;
352     parms.user= user;
353     parms.passwd= passwd;
354     parms.db= db;
355     parms.port= port;
356     parms.unix_socket= unix_socket;
357     parms.client_flags= client_flags | CLIENT_REMEMBER_OPTIONS;
358   },
359   NULL,
360   r_ptr,
361   /* Nothing */)
362 }
363 int STDCALL
mysql_real_connect_cont(MYSQL ** ret,MYSQL * mysql,int ready_status)364 mysql_real_connect_cont(MYSQL **ret, MYSQL *mysql, int ready_status)
365 {
366 MK_ASYNC_CONT_BODY(
367   mysql,
368   NULL,
369   r_ptr)
370 }
371 
372 /* Structure used to pass parameters from mysql_real_query_start(). */
373 struct mysql_real_query_params {
374   MYSQL *mysql;
375   const char *stmt_str;
376   unsigned long length;
377 };
378 static void
mysql_real_query_start_internal(void * d)379 mysql_real_query_start_internal(void *d)
380 {
381 MK_ASYNC_INTERNAL_BODY(
382   mysql_real_query,
383   (parms->mysql, parms->stmt_str, parms->length),
384   parms->mysql,
385   int,
386   r_int)
387 }
388 int STDCALL
mysql_real_query_start(int * ret,MYSQL * mysql,const char * stmt_str,unsigned long length)389 mysql_real_query_start(int *ret, MYSQL *mysql, const char *stmt_str, unsigned long length)
390 {
391   int res;
392   struct mysql_async_context *b;
393   struct mysql_real_query_params parms;
394 
395   b= mysql->options.extension->async_context;
396   {
397     WIN_SET_NONBLOCKING(mysql)
398     parms.mysql= mysql;
399     parms.stmt_str= stmt_str;
400     parms.length= length;
401   }
402 
403   b->active= 1;
404   res= my_context_spawn(&b->async_context, mysql_real_query_start_internal, &parms);
405   b->active= b->suspended= 0;
406   if (res > 0)
407   {
408     /* Suspended. */
409     b->suspended= 1;
410     return b->events_to_wait_for;
411   }
412   if (res < 0)
413   {
414     set_mariadb_error((mysql), CR_OUT_OF_MEMORY, unknown_sqlstate);
415     *ret= 1;
416   }
417   else
418     *ret= b->ret_result.r_int;
419   return 0;
420 
421 }
422 int STDCALL
mysql_real_query_cont(int * ret,MYSQL * mysql,int ready_status)423 mysql_real_query_cont(int *ret, MYSQL *mysql, int ready_status)
424 {
425 MK_ASYNC_CONT_BODY(
426   mysql,
427   1,
428   r_int)
429 }
430 
431 /* Structure used to pass parameters from mysql_fetch_row_start(). */
432 struct mysql_fetch_row_params {
433   MYSQL_RES *result;
434 };
435 static void
mysql_fetch_row_start_internal(void * d)436 mysql_fetch_row_start_internal(void *d)
437 {
438 MK_ASYNC_INTERNAL_BODY(
439   mysql_fetch_row,
440   (parms->result),
441   parms->result->handle,
442   MYSQL_ROW,
443   r_ptr)
444 }
445 int STDCALL
mysql_fetch_row_start(MYSQL_ROW * ret,MYSQL_RES * result)446 mysql_fetch_row_start(MYSQL_ROW *ret, MYSQL_RES *result)
447 {
448 MK_ASYNC_START_BODY(
449   mysql_fetch_row,
450   result->handle,
451   {
452     WIN_SET_NONBLOCKING(result->handle)
453     parms.result= result;
454   },
455   NULL,
456   r_ptr,
457   /*
458     If we already fetched all rows from server (eg. mysql_store_result()),
459     then result->handle will be NULL and we cannot suspend. But that is fine,
460     since in this case mysql_fetch_row cannot block anyway. Just return
461     directly.
462   */
463   if (!result->handle)
464   {
465     *ret= mysql_fetch_row(result);
466     return 0;
467   })
468 }
469 int STDCALL
mysql_fetch_row_cont(MYSQL_ROW * ret,MYSQL_RES * result,int ready_status)470 mysql_fetch_row_cont(MYSQL_ROW *ret, MYSQL_RES *result, int ready_status)
471 {
472 MK_ASYNC_CONT_BODY(
473   result->handle,
474   NULL,
475   r_ptr)
476 }
477 
478 /* Structure used to pass parameters from mysql_set_character_set_start(). */
479 struct mysql_set_character_set_params {
480   MYSQL *mysql;
481   const char *csname;
482 };
483 static void
mysql_set_character_set_start_internal(void * d)484 mysql_set_character_set_start_internal(void *d)
485 {
486 MK_ASYNC_INTERNAL_BODY(
487   mysql_set_character_set,
488   (parms->mysql, parms->csname),
489   parms->mysql,
490   int,
491   r_int)
492 }
493 int STDCALL
mysql_set_character_set_start(int * ret,MYSQL * mysql,const char * csname)494 mysql_set_character_set_start(int *ret, MYSQL *mysql, const char *csname)
495 {
496 MK_ASYNC_START_BODY(
497   mysql_set_character_set,
498   mysql,
499   {
500     WIN_SET_NONBLOCKING(mysql)
501     parms.mysql= mysql;
502     parms.csname= csname;
503   },
504   1,
505   r_int,
506   /* Nothing */)
507 }
508 int STDCALL
mysql_set_character_set_cont(int * ret,MYSQL * mysql,int ready_status)509 mysql_set_character_set_cont(int *ret, MYSQL *mysql, int ready_status)
510 {
511 MK_ASYNC_CONT_BODY(
512   mysql,
513   1,
514   r_int)
515 }
516 
517 /* Structure used to pass parameters from mysql_sekect_db_start(). */
518 struct mysql_select_db_params {
519   MYSQL *mysql;
520   const char *db;
521 };
522 static void
mysql_select_db_start_internal(void * d)523 mysql_select_db_start_internal(void *d)
524 {
525 MK_ASYNC_INTERNAL_BODY(
526   mysql_select_db,
527   (parms->mysql, parms->db),
528   parms->mysql,
529   int,
530   r_int)
531 }
532 int STDCALL
mysql_select_db_start(int * ret,MYSQL * mysql,const char * db)533 mysql_select_db_start(int *ret, MYSQL *mysql, const char *db)
534 {
535 MK_ASYNC_START_BODY(
536   mysql_select_db,
537   mysql,
538   {
539     WIN_SET_NONBLOCKING(mysql)
540     parms.mysql= mysql;
541     parms.db= db;
542   },
543   1,
544   r_int,
545   /* Nothing */)
546 }
547 int STDCALL
mysql_select_db_cont(int * ret,MYSQL * mysql,int ready_status)548 mysql_select_db_cont(int *ret, MYSQL *mysql, int ready_status)
549 {
550 MK_ASYNC_CONT_BODY(
551   mysql,
552   1,
553   r_int)
554 }
555 
556 /* Structure used to pass parameters from mysql_send_query_start(). */
557 struct mysql_send_query_params {
558   MYSQL *mysql;
559   const char *q;
560   unsigned long length;
561 };
562 static void
mysql_send_query_start_internal(void * d)563 mysql_send_query_start_internal(void *d)
564 {
565 MK_ASYNC_INTERNAL_BODY(
566   mysql_send_query,
567   (parms->mysql, parms->q, parms->length),
568   parms->mysql,
569   int,
570   r_int)
571 }
572 int STDCALL
mysql_send_query_start(int * ret,MYSQL * mysql,const char * q,unsigned long length)573 mysql_send_query_start(int *ret, MYSQL *mysql, const char *q, unsigned long length)
574 {
575 MK_ASYNC_START_BODY(
576   mysql_send_query,
577   mysql,
578   {
579     WIN_SET_NONBLOCKING(mysql)
580     parms.mysql= mysql;
581     parms.q= q;
582     parms.length= length;
583   },
584   1,
585   r_int,
586   /* Nothing */)
587 }
588 int STDCALL
mysql_send_query_cont(int * ret,MYSQL * mysql,int ready_status)589 mysql_send_query_cont(int *ret, MYSQL *mysql, int ready_status)
590 {
591 MK_ASYNC_CONT_BODY(
592   mysql,
593   1,
594   r_int)
595 }
596 
597 /* Structure used to pass parameters from mysql_store_result_start(). */
598 struct mysql_store_result_params {
599   MYSQL *mysql;
600 };
601 static void
mysql_store_result_start_internal(void * d)602 mysql_store_result_start_internal(void *d)
603 {
604 MK_ASYNC_INTERNAL_BODY(
605   mysql_store_result,
606   (parms->mysql),
607   parms->mysql,
608   MYSQL_RES *,
609   r_ptr)
610 }
611 int STDCALL
mysql_store_result_start(MYSQL_RES ** ret,MYSQL * mysql)612 mysql_store_result_start(MYSQL_RES **ret, MYSQL *mysql)
613 {
614 MK_ASYNC_START_BODY(
615   mysql_store_result,
616   mysql,
617   {
618     WIN_SET_NONBLOCKING(mysql)
619     parms.mysql= mysql;
620   },
621   NULL,
622   r_ptr,
623   /* Nothing */)
624 }
625 int STDCALL
mysql_store_result_cont(MYSQL_RES ** ret,MYSQL * mysql,int ready_status)626 mysql_store_result_cont(MYSQL_RES **ret, MYSQL *mysql, int ready_status)
627 {
628 MK_ASYNC_CONT_BODY(
629   mysql,
630   NULL,
631   r_ptr)
632 }
633 
634 /* Structure used to pass parameters from mysql_free_result_start(). */
635 struct mysql_free_result_params {
636   MYSQL_RES *result;
637 };
638 static void
mysql_free_result_start_internal(void * d)639 mysql_free_result_start_internal(void *d)
640 {
641 MK_ASYNC_INTERNAL_BODY_VOID_RETURN(
642   mysql_free_result,
643   (parms->result),
644   parms->result->handle)
645 }
646 int STDCALL
mysql_free_result_start(MYSQL_RES * result)647 mysql_free_result_start(MYSQL_RES *result)
648 {
649 MK_ASYNC_START_BODY_VOID_RETURN(
650   mysql_free_result,
651   result->handle,
652   {
653     WIN_SET_NONBLOCKING(result->handle)
654     parms.result= result;
655   },
656   /*
657     mysql_free_result() can have NULL in result->handle (this happens when all
658     rows have been fetched and mysql_fetch_row() returned NULL.)
659     So we cannot suspend, but it does not matter, as in this case
660     mysql_free_result() cannot block.
661     It is also legitimate to have NULL result, which will do nothing.
662   */
663   if (!result || !result->handle)
664   {
665     mysql_free_result(result);
666     return 0;
667   })
668 }
669 int STDCALL
mysql_free_result_cont(MYSQL_RES * result,int ready_status)670 mysql_free_result_cont(MYSQL_RES *result, int ready_status)
671 {
672 MK_ASYNC_CONT_BODY_VOID_RETURN(result->handle)
673 }
674 
675 /* Structure used to pass parameters from mysql_close_slow_part_start(). */
676 struct mysql_close_slow_part_params {
677   MYSQL *sock;
678 };
679 /*
680   We need special handling for mysql_close(), as the first part may block,
681   while the last part needs to free our extra library context stack.
682 
683   So we do the first part (mysql_close_slow_part()) non-blocking, but the last
684   part blocking.
685 */
686 static void
mysql_close_slow_part_start_internal(void * d)687 mysql_close_slow_part_start_internal(void *d)
688 {
689 MK_ASYNC_INTERNAL_BODY_VOID_RETURN(
690   mysql_close_slow_part,
691   (parms->sock),
692   parms->sock)
693 }
694 
695 int STDCALL
mysql_close_slow_part_start(MYSQL * sock)696 mysql_close_slow_part_start(MYSQL *sock)
697 {
698 MK_ASYNC_START_BODY_VOID_RETURN(
699   mysql_close_slow_part,
700   sock,
701   {
702     WIN_SET_NONBLOCKING(sock)
703     parms.sock= sock;
704   },
705   /* Nothing */)
706 }
707 int STDCALL
mysql_close_slow_part_cont(MYSQL * sock,int ready_status)708 mysql_close_slow_part_cont(MYSQL *sock, int ready_status)
709 {
710 MK_ASYNC_CONT_BODY_VOID_RETURN(sock)
711 }
712 int STDCALL
mysql_close_start(MYSQL * sock)713 mysql_close_start(MYSQL *sock)
714 {
715   int res;
716 
717   /* It is legitimate to have NULL sock argument, which will do nothing. */
718   if (sock && sock->net.pvio)
719   {
720     res= mysql_close_slow_part_start(sock);
721     /* If we need to block, return now and do the rest in mysql_close_cont(). */
722     if (res)
723       return res;
724   }
725   mysql_close(sock);
726   return 0;
727 }
728 int STDCALL
mysql_close_cont(MYSQL * sock,int ready_status)729 mysql_close_cont(MYSQL *sock, int ready_status)
730 {
731   int res;
732 
733   res= mysql_close_slow_part_cont(sock, ready_status);
734   if (res)
735     return res;
736   mysql_close(sock);
737   return 0;
738 }
739 
740 /*
741   These following are not available inside the server (neither blocking or
742   non-blocking).
743 */
744 #ifndef MYSQL_SERVER
745 /* Structure used to pass parameters from mysql_change_user_start(). */
746 struct mysql_change_user_params {
747   MYSQL *mysql;
748   const char *user;
749   const char *passwd;
750   const char *db;
751 };
752 static void
mysql_change_user_start_internal(void * d)753 mysql_change_user_start_internal(void *d)
754 {
755 MK_ASYNC_INTERNAL_BODY(
756   mysql_change_user,
757   (parms->mysql, parms->user, parms->passwd, parms->db),
758   parms->mysql,
759   my_bool,
760   r_my_bool)
761 }
762 int STDCALL
mysql_change_user_start(my_bool * ret,MYSQL * mysql,const char * user,const char * passwd,const char * db)763 mysql_change_user_start(my_bool *ret, MYSQL *mysql, const char *user, const char *passwd, const char *db)
764 {
765 MK_ASYNC_START_BODY(
766   mysql_change_user,
767   mysql,
768   {
769     WIN_SET_NONBLOCKING(mysql)
770     parms.mysql= mysql;
771     parms.user= user;
772     parms.passwd= passwd;
773     parms.db= db;
774   },
775   TRUE,
776   r_my_bool,
777   /* Nothing */)
778 }
779 int STDCALL
mysql_change_user_cont(my_bool * ret,MYSQL * mysql,int ready_status)780 mysql_change_user_cont(my_bool *ret, MYSQL *mysql, int ready_status)
781 {
782 MK_ASYNC_CONT_BODY(
783   mysql,
784   TRUE,
785   r_my_bool)
786 }
787 
788 /* Structure used to pass parameters from mysql_query_start(). */
789 struct mysql_query_params {
790   MYSQL *mysql;
791   const char *q;
792 };
793 static void
mysql_query_start_internal(void * d)794 mysql_query_start_internal(void *d)
795 {
796 MK_ASYNC_INTERNAL_BODY(
797   mysql_query,
798   (parms->mysql, parms->q),
799   parms->mysql,
800   int,
801   r_int)
802 }
803 int STDCALL
mysql_query_start(int * ret,MYSQL * mysql,const char * q)804 mysql_query_start(int *ret, MYSQL *mysql, const char *q)
805 {
806 MK_ASYNC_START_BODY(
807   mysql_query,
808   mysql,
809   {
810     WIN_SET_NONBLOCKING(mysql)
811     parms.mysql= mysql;
812     parms.q= q;
813   },
814   1,
815   r_int,
816   /* Nothing */)
817 }
818 int STDCALL
mysql_query_cont(int * ret,MYSQL * mysql,int ready_status)819 mysql_query_cont(int *ret, MYSQL *mysql, int ready_status)
820 {
821 MK_ASYNC_CONT_BODY(
822   mysql,
823   1,
824   r_int)
825 }
826 
827 /* Structure used to pass parameters from mysql_shutdown_start(). */
828 struct mysql_shutdown_params {
829   MYSQL *mysql;
830   enum mysql_enum_shutdown_level shutdown_level;
831 };
832 static void
mysql_shutdown_start_internal(void * d)833 mysql_shutdown_start_internal(void *d)
834 {
835 MK_ASYNC_INTERNAL_BODY(
836   mysql_shutdown,
837   (parms->mysql, parms->shutdown_level),
838   parms->mysql,
839   int,
840   r_int)
841 }
842 int STDCALL
mysql_shutdown_start(int * ret,MYSQL * mysql,enum mysql_enum_shutdown_level shutdown_level)843 mysql_shutdown_start(int *ret, MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
844 {
845 MK_ASYNC_START_BODY(
846   mysql_shutdown,
847   mysql,
848   {
849     WIN_SET_NONBLOCKING(mysql)
850     parms.mysql= mysql;
851     parms.shutdown_level= shutdown_level;
852   },
853   1,
854   r_int,
855   /* Nothing */)
856 }
857 int STDCALL
mysql_shutdown_cont(int * ret,MYSQL * mysql,int ready_status)858 mysql_shutdown_cont(int *ret, MYSQL *mysql, int ready_status)
859 {
860 MK_ASYNC_CONT_BODY(
861   mysql,
862   1,
863   r_int)
864 }
865 
866 /* Structure used to pass parameters from mysql_dump_debug_info_start(). */
867 struct mysql_dump_debug_info_params {
868   MYSQL *mysql;
869 };
870 static void
mysql_dump_debug_info_start_internal(void * d)871 mysql_dump_debug_info_start_internal(void *d)
872 {
873 MK_ASYNC_INTERNAL_BODY(
874   mysql_dump_debug_info,
875   (parms->mysql),
876   parms->mysql,
877   int,
878   r_int)
879 }
880 int STDCALL
mysql_dump_debug_info_start(int * ret,MYSQL * mysql)881 mysql_dump_debug_info_start(int *ret, MYSQL *mysql)
882 {
883 MK_ASYNC_START_BODY(
884   mysql_dump_debug_info,
885   mysql,
886   {
887     WIN_SET_NONBLOCKING(mysql)
888     parms.mysql= mysql;
889   },
890   1,
891   r_int,
892   /* Nothing */)
893 }
894 int STDCALL
mysql_dump_debug_info_cont(int * ret,MYSQL * mysql,int ready_status)895 mysql_dump_debug_info_cont(int *ret, MYSQL *mysql, int ready_status)
896 {
897 MK_ASYNC_CONT_BODY(
898   mysql,
899   1,
900   r_int)
901 }
902 
903 /* Structure used to pass parameters from mysql_refresh_start(). */
904 struct mysql_refresh_params {
905   MYSQL *mysql;
906   unsigned int refresh_options;
907 };
908 static void
mysql_refresh_start_internal(void * d)909 mysql_refresh_start_internal(void *d)
910 {
911 MK_ASYNC_INTERNAL_BODY(
912   mysql_refresh,
913   (parms->mysql, parms->refresh_options),
914   parms->mysql,
915   int,
916   r_int)
917 }
918 int STDCALL
mysql_refresh_start(int * ret,MYSQL * mysql,unsigned int refresh_options)919 mysql_refresh_start(int *ret, MYSQL *mysql, unsigned int refresh_options)
920 {
921 MK_ASYNC_START_BODY(
922   mysql_refresh,
923   mysql,
924   {
925     WIN_SET_NONBLOCKING(mysql)
926     parms.mysql= mysql;
927     parms.refresh_options= refresh_options;
928   },
929   1,
930   r_int,
931   /* Nothing */)
932 }
933 int STDCALL
mysql_refresh_cont(int * ret,MYSQL * mysql,int ready_status)934 mysql_refresh_cont(int *ret, MYSQL *mysql, int ready_status)
935 {
936 MK_ASYNC_CONT_BODY(
937   mysql,
938   1,
939   r_int)
940 }
941 
942 /* Structure used to pass parameters from mysql_kill_start(). */
943 struct mysql_kill_params {
944   MYSQL *mysql;
945   unsigned long pid;
946 };
947 static void
mysql_kill_start_internal(void * d)948 mysql_kill_start_internal(void *d)
949 {
950 MK_ASYNC_INTERNAL_BODY(
951   mysql_kill,
952   (parms->mysql, parms->pid),
953   parms->mysql,
954   int,
955   r_int)
956 }
957 int STDCALL
mysql_kill_start(int * ret,MYSQL * mysql,unsigned long pid)958 mysql_kill_start(int *ret, MYSQL *mysql, unsigned long pid)
959 {
960 MK_ASYNC_START_BODY(
961   mysql_kill,
962   mysql,
963   {
964     WIN_SET_NONBLOCKING(mysql)
965     parms.mysql= mysql;
966     parms.pid= pid;
967   },
968   1,
969   r_int,
970   /* Nothing */)
971 }
972 int STDCALL
mysql_kill_cont(int * ret,MYSQL * mysql,int ready_status)973 mysql_kill_cont(int *ret, MYSQL *mysql, int ready_status)
974 {
975 MK_ASYNC_CONT_BODY(
976   mysql,
977   1,
978   r_int)
979 }
980 
981 /* Structure used to pass parameters from mysql_set_server_option_start(). */
982 struct mysql_set_server_option_params {
983   MYSQL *mysql;
984   enum enum_mysql_set_option option;
985 };
986 static void
mysql_set_server_option_start_internal(void * d)987 mysql_set_server_option_start_internal(void *d)
988 {
989 MK_ASYNC_INTERNAL_BODY(
990   mysql_set_server_option,
991   (parms->mysql, parms->option),
992   parms->mysql,
993   int,
994   r_int)
995 }
996 int STDCALL
mysql_set_server_option_start(int * ret,MYSQL * mysql,enum enum_mysql_set_option option)997 mysql_set_server_option_start(int *ret, MYSQL *mysql,
998                               enum enum_mysql_set_option option)
999 {
1000 MK_ASYNC_START_BODY(
1001   mysql_set_server_option,
1002   mysql,
1003   {
1004     WIN_SET_NONBLOCKING(mysql)
1005     parms.mysql= mysql;
1006     parms.option= option;
1007   },
1008   1,
1009   r_int,
1010   /* Nothing */)
1011 }
1012 int STDCALL
mysql_set_server_option_cont(int * ret,MYSQL * mysql,int ready_status)1013 mysql_set_server_option_cont(int *ret, MYSQL *mysql, int ready_status)
1014 {
1015 MK_ASYNC_CONT_BODY(
1016   mysql,
1017   1,
1018   r_int)
1019 }
1020 
1021 /* Structure used to pass parameters from mysql_ping_start(). */
1022 struct mysql_ping_params {
1023   MYSQL *mysql;
1024 };
1025 static void
mysql_ping_start_internal(void * d)1026 mysql_ping_start_internal(void *d)
1027 {
1028 MK_ASYNC_INTERNAL_BODY(
1029   mysql_ping,
1030   (parms->mysql),
1031   parms->mysql,
1032   int,
1033   r_int)
1034 }
1035 int STDCALL
mysql_ping_start(int * ret,MYSQL * mysql)1036 mysql_ping_start(int *ret, MYSQL *mysql)
1037 {
1038 MK_ASYNC_START_BODY(
1039   mysql_ping,
1040   mysql,
1041   {
1042     WIN_SET_NONBLOCKING(mysql)
1043     parms.mysql= mysql;
1044   },
1045   1,
1046   r_int,
1047   /* Nothing */)
1048 }
1049 int STDCALL
mysql_ping_cont(int * ret,MYSQL * mysql,int ready_status)1050 mysql_ping_cont(int *ret, MYSQL *mysql, int ready_status)
1051 {
1052 MK_ASYNC_CONT_BODY(
1053   mysql,
1054   1,
1055   r_int)
1056 }
1057 
1058 /* Structure used to pass parameters from mysql_reset_connection_start(). */
1059 struct mysql_reset_connection_params {
1060   MYSQL *mysql;
1061 };
1062 static void
mysql_reset_connection_start_internal(void * d)1063 mysql_reset_connection_start_internal(void *d)
1064 {
1065 MK_ASYNC_INTERNAL_BODY(
1066   mysql_reset_connection,
1067   (parms->mysql),
1068   parms->mysql,
1069   int,
1070   r_int)
1071 }
1072 int STDCALL
mysql_reset_connection_start(int * ret,MYSQL * mysql)1073 mysql_reset_connection_start(int *ret, MYSQL *mysql)
1074 {
1075 MK_ASYNC_START_BODY(
1076   mysql_reset_connection,
1077   mysql,
1078   {
1079     WIN_SET_NONBLOCKING(mysql)
1080     parms.mysql= mysql;
1081   },
1082   1,
1083   r_int,
1084   /* Nothing */)
1085 }
1086 int STDCALL
mysql_reset_connection_cont(int * ret,MYSQL * mysql,int ready_status)1087 mysql_reset_connection_cont(int *ret, MYSQL *mysql, int ready_status)
1088 {
1089 MK_ASYNC_CONT_BODY(
1090   mysql,
1091   1,
1092   r_int)
1093 }
1094 
1095 /* Structure used to pass parameters from mysql_stat_start(). */
1096 struct mysql_stat_params {
1097   MYSQL *mysql;
1098 };
1099 static void
mysql_stat_start_internal(void * d)1100 mysql_stat_start_internal(void *d)
1101 {
1102 MK_ASYNC_INTERNAL_BODY(
1103   mysql_stat,
1104   (parms->mysql),
1105   parms->mysql,
1106   const char *,
1107   r_const_ptr)
1108 }
1109 int STDCALL
mysql_stat_start(const char ** ret,MYSQL * mysql)1110 mysql_stat_start(const char **ret, MYSQL *mysql)
1111 {
1112 MK_ASYNC_START_BODY(
1113   mysql_stat,
1114   mysql,
1115   {
1116     WIN_SET_NONBLOCKING(mysql)
1117     parms.mysql= mysql;
1118   },
1119   NULL,
1120   r_const_ptr,
1121   /* Nothing */)
1122 }
1123 int STDCALL
mysql_stat_cont(const char ** ret,MYSQL * mysql,int ready_status)1124 mysql_stat_cont(const char **ret, MYSQL *mysql, int ready_status)
1125 {
1126 MK_ASYNC_CONT_BODY(
1127   mysql,
1128   NULL,
1129   r_const_ptr)
1130 }
1131 
1132 /* Structure used to pass parameters from mysql_list_dbs_start(). */
1133 struct mysql_list_dbs_params {
1134   MYSQL *mysql;
1135   const char *wild;
1136 };
1137 static void
mysql_list_dbs_start_internal(void * d)1138 mysql_list_dbs_start_internal(void *d)
1139 {
1140 MK_ASYNC_INTERNAL_BODY(
1141   mysql_list_dbs,
1142   (parms->mysql, parms->wild),
1143   parms->mysql,
1144   MYSQL_RES *,
1145   r_ptr)
1146 }
1147 int STDCALL
mysql_list_dbs_start(MYSQL_RES ** ret,MYSQL * mysql,const char * wild)1148 mysql_list_dbs_start(MYSQL_RES **ret, MYSQL *mysql, const char *wild)
1149 {
1150 MK_ASYNC_START_BODY(
1151   mysql_list_dbs,
1152   mysql,
1153   {
1154     WIN_SET_NONBLOCKING(mysql)
1155     parms.mysql= mysql;
1156     parms.wild= wild;
1157   },
1158   NULL,
1159   r_ptr,
1160   /* Nothing */)
1161 }
1162 int STDCALL
mysql_list_dbs_cont(MYSQL_RES ** ret,MYSQL * mysql,int ready_status)1163 mysql_list_dbs_cont(MYSQL_RES **ret, MYSQL *mysql, int ready_status)
1164 {
1165 MK_ASYNC_CONT_BODY(
1166   mysql,
1167   NULL,
1168   r_ptr)
1169 }
1170 
1171 /* Structure used to pass parameters from mysql_list_tables_start(). */
1172 struct mysql_list_tables_params {
1173   MYSQL *mysql;
1174   const char *wild;
1175 };
1176 static void
mysql_list_tables_start_internal(void * d)1177 mysql_list_tables_start_internal(void *d)
1178 {
1179 MK_ASYNC_INTERNAL_BODY(
1180   mysql_list_tables,
1181   (parms->mysql, parms->wild),
1182   parms->mysql,
1183   MYSQL_RES *,
1184   r_ptr)
1185 }
1186 int STDCALL
mysql_list_tables_start(MYSQL_RES ** ret,MYSQL * mysql,const char * wild)1187 mysql_list_tables_start(MYSQL_RES **ret, MYSQL *mysql, const char *wild)
1188 {
1189 MK_ASYNC_START_BODY(
1190   mysql_list_tables,
1191   mysql,
1192   {
1193     WIN_SET_NONBLOCKING(mysql)
1194     parms.mysql= mysql;
1195     parms.wild= wild;
1196   },
1197   NULL,
1198   r_ptr,
1199   /* Nothing */)
1200 }
1201 int STDCALL
mysql_list_tables_cont(MYSQL_RES ** ret,MYSQL * mysql,int ready_status)1202 mysql_list_tables_cont(MYSQL_RES **ret, MYSQL *mysql, int ready_status)
1203 {
1204 MK_ASYNC_CONT_BODY(
1205   mysql,
1206   NULL,
1207   r_ptr)
1208 }
1209 
1210 /* Structure used to pass parameters from mysql_list_processes_start(). */
1211 struct mysql_list_processes_params {
1212   MYSQL *mysql;
1213 };
1214 static void
mysql_list_processes_start_internal(void * d)1215 mysql_list_processes_start_internal(void *d)
1216 {
1217 MK_ASYNC_INTERNAL_BODY(
1218   mysql_list_processes,
1219   (parms->mysql),
1220   parms->mysql,
1221   MYSQL_RES *,
1222   r_ptr)
1223 }
1224 int STDCALL
mysql_list_processes_start(MYSQL_RES ** ret,MYSQL * mysql)1225 mysql_list_processes_start(MYSQL_RES **ret, MYSQL *mysql)
1226 {
1227 MK_ASYNC_START_BODY(
1228   mysql_list_processes,
1229   mysql,
1230   {
1231     WIN_SET_NONBLOCKING(mysql)
1232     parms.mysql= mysql;
1233   },
1234   NULL,
1235   r_ptr,
1236   /* Nothing */)
1237 }
1238 int STDCALL
mysql_list_processes_cont(MYSQL_RES ** ret,MYSQL * mysql,int ready_status)1239 mysql_list_processes_cont(MYSQL_RES **ret, MYSQL *mysql, int ready_status)
1240 {
1241 MK_ASYNC_CONT_BODY(
1242   mysql,
1243   NULL,
1244   r_ptr)
1245 }
1246 
1247 /* Structure used to pass parameters from mysql_list_fields_start(). */
1248 struct mysql_list_fields_params {
1249   MYSQL *mysql;
1250   const char *table;
1251   const char *wild;
1252 };
1253 static void
mysql_list_fields_start_internal(void * d)1254 mysql_list_fields_start_internal(void *d)
1255 {
1256 MK_ASYNC_INTERNAL_BODY(
1257   mysql_list_fields,
1258   (parms->mysql, parms->table, parms->wild),
1259   parms->mysql,
1260   MYSQL_RES *,
1261   r_ptr)
1262 }
1263 int STDCALL
mysql_list_fields_start(MYSQL_RES ** ret,MYSQL * mysql,const char * table,const char * wild)1264 mysql_list_fields_start(MYSQL_RES **ret, MYSQL *mysql, const char *table,
1265                         const char *wild)
1266 {
1267 MK_ASYNC_START_BODY(
1268   mysql_list_fields,
1269   mysql,
1270   {
1271     WIN_SET_NONBLOCKING(mysql)
1272     parms.mysql= mysql;
1273     parms.table= table;
1274     parms.wild= wild;
1275   },
1276   NULL,
1277   r_ptr,
1278   /* Nothing */)
1279 }
1280 int STDCALL
mysql_list_fields_cont(MYSQL_RES ** ret,MYSQL * mysql,int ready_status)1281 mysql_list_fields_cont(MYSQL_RES **ret, MYSQL *mysql, int ready_status)
1282 {
1283 MK_ASYNC_CONT_BODY(
1284   mysql,
1285   NULL,
1286   r_ptr)
1287 }
1288 
1289 /* Structure used to pass parameters from mysql_read_query_result_start(). */
1290 struct mysql_read_query_result_params {
1291   MYSQL *mysql;
1292 };
1293 static void
mysql_read_query_result_start_internal(void * d)1294 mysql_read_query_result_start_internal(void *d)
1295 {
1296 MK_ASYNC_INTERNAL_BODY(
1297   mysql_read_query_result,
1298   (parms->mysql),
1299   parms->mysql,
1300   my_bool,
1301   r_my_bool)
1302 }
1303 int STDCALL
mysql_read_query_result_start(my_bool * ret,MYSQL * mysql)1304 mysql_read_query_result_start(my_bool *ret, MYSQL *mysql)
1305 {
1306 MK_ASYNC_START_BODY(
1307   mysql_read_query_result,
1308   mysql,
1309   {
1310     WIN_SET_NONBLOCKING(mysql)
1311     parms.mysql= mysql;
1312   },
1313   TRUE,
1314   r_my_bool,
1315   /* Nothing */)
1316 }
1317 int STDCALL
mysql_read_query_result_cont(my_bool * ret,MYSQL * mysql,int ready_status)1318 mysql_read_query_result_cont(my_bool *ret, MYSQL *mysql, int ready_status)
1319 {
1320 MK_ASYNC_CONT_BODY(
1321   mysql,
1322   TRUE,
1323   r_my_bool)
1324 }
1325 
1326 /* Structure used to pass parameters from mysql_stmt_prepare_start(). */
1327 struct mysql_stmt_prepare_params {
1328   MYSQL_STMT *stmt;
1329   const char *query;
1330   unsigned long length;
1331 };
1332 static void
mysql_stmt_prepare_start_internal(void * d)1333 mysql_stmt_prepare_start_internal(void *d)
1334 {
1335 MK_ASYNC_INTERNAL_BODY(
1336   mysql_stmt_prepare,
1337   (parms->stmt, parms->query, parms->length),
1338   parms->stmt->mysql,
1339   int,
1340   r_int)
1341 }
1342 int STDCALL
mysql_stmt_prepare_start(int * ret,MYSQL_STMT * stmt,const char * query,unsigned long length)1343 mysql_stmt_prepare_start(int *ret, MYSQL_STMT *stmt, const char *query,
1344                          unsigned long length)
1345 {
1346 MK_ASYNC_START_BODY(
1347   mysql_stmt_prepare,
1348   stmt->mysql,
1349   {
1350     WIN_SET_NONBLOCKING(stmt->mysql)
1351     parms.stmt= stmt;
1352     parms.query= query;
1353     parms.length= length;
1354   },
1355   1,
1356   r_int,
1357   /* If stmt->mysql==NULL then we will not block so can call directly. */
1358   if (!stmt->mysql)
1359   {
1360     *ret= mysql_stmt_prepare(stmt, query, length);
1361     return 0;
1362   })
1363 }
1364 int STDCALL
mysql_stmt_prepare_cont(int * ret,MYSQL_STMT * stmt,int ready_status)1365 mysql_stmt_prepare_cont(int *ret, MYSQL_STMT *stmt, int ready_status)
1366 {
1367 MK_ASYNC_CONT_BODY(
1368   stmt->mysql,
1369   1,
1370   r_int)
1371 }
1372 
1373 /* Structure used to pass parameters from mysql_stmt_execute_start(). */
1374 struct mysql_stmt_execute_params {
1375   MYSQL_STMT *stmt;
1376 };
1377 static void
mysql_stmt_execute_start_internal(void * d)1378 mysql_stmt_execute_start_internal(void *d)
1379 {
1380 MK_ASYNC_INTERNAL_BODY(
1381   mysql_stmt_execute,
1382   (parms->stmt),
1383   parms->stmt->mysql,
1384   int,
1385   r_int)
1386 }
1387 int STDCALL
mysql_stmt_execute_start(int * ret,MYSQL_STMT * stmt)1388 mysql_stmt_execute_start(int *ret, MYSQL_STMT *stmt)
1389 {
1390 MK_ASYNC_START_BODY(
1391   mysql_stmt_execute,
1392   stmt->mysql,
1393   {
1394     WIN_SET_NONBLOCKING(stmt->mysql)
1395     parms.stmt= stmt;
1396   },
1397   1,
1398   r_int,
1399   /*
1400     If eg. mysql_change_user(), stmt->mysql will be NULL.
1401     In this case, we cannot block.
1402   */
1403   if (!stmt->mysql)
1404   {
1405     *ret= mysql_stmt_execute(stmt);
1406     return 0;
1407   })
1408 }
1409 int STDCALL
mysql_stmt_execute_cont(int * ret,MYSQL_STMT * stmt,int ready_status)1410 mysql_stmt_execute_cont(int *ret, MYSQL_STMT *stmt, int ready_status)
1411 {
1412 MK_ASYNC_CONT_BODY(
1413   stmt->mysql,
1414   1,
1415   r_int)
1416 }
1417 
1418 /* Structure used to pass parameters from mysql_stmt_fetch_start(). */
1419 struct mysql_stmt_fetch_params {
1420   MYSQL_STMT *stmt;
1421 };
1422 static void
mysql_stmt_fetch_start_internal(void * d)1423 mysql_stmt_fetch_start_internal(void *d)
1424 {
1425 MK_ASYNC_INTERNAL_BODY(
1426   mysql_stmt_fetch,
1427   (parms->stmt),
1428   parms->stmt->mysql,
1429   int,
1430   r_int)
1431 }
1432 int STDCALL
mysql_stmt_fetch_start(int * ret,MYSQL_STMT * stmt)1433 mysql_stmt_fetch_start(int *ret, MYSQL_STMT *stmt)
1434 {
1435 MK_ASYNC_START_BODY(
1436   mysql_stmt_fetch,
1437   stmt->mysql,
1438   {
1439     WIN_SET_NONBLOCKING(stmt->mysql)
1440     parms.stmt= stmt;
1441   },
1442   1,
1443   r_int,
1444   /* If stmt->mysql==NULL then we will not block so can call directly. */
1445   if (!stmt->mysql)
1446   {
1447     *ret= mysql_stmt_fetch(stmt);
1448     return 0;
1449   })
1450 }
1451 int STDCALL
mysql_stmt_fetch_cont(int * ret,MYSQL_STMT * stmt,int ready_status)1452 mysql_stmt_fetch_cont(int *ret, MYSQL_STMT *stmt, int ready_status)
1453 {
1454 MK_ASYNC_CONT_BODY(
1455   stmt->mysql,
1456   1,
1457   r_int)
1458 }
1459 
1460 /* Structure used to pass parameters from mysql_stmt_store_result_start(). */
1461 struct mysql_stmt_store_result_params {
1462   MYSQL_STMT *stmt;
1463 };
1464 static void
mysql_stmt_store_result_start_internal(void * d)1465 mysql_stmt_store_result_start_internal(void *d)
1466 {
1467 MK_ASYNC_INTERNAL_BODY(
1468   mysql_stmt_store_result,
1469   (parms->stmt),
1470   parms->stmt->mysql,
1471   int,
1472   r_int)
1473 }
1474 int STDCALL
mysql_stmt_store_result_start(int * ret,MYSQL_STMT * stmt)1475 mysql_stmt_store_result_start(int *ret, MYSQL_STMT *stmt)
1476 {
1477 MK_ASYNC_START_BODY(
1478   mysql_stmt_store_result,
1479   stmt->mysql,
1480   {
1481     WIN_SET_NONBLOCKING(stmt->mysql)
1482     parms.stmt= stmt;
1483   },
1484   1,
1485   r_int,
1486   /* If stmt->mysql==NULL then we will not block so can call directly. */
1487   if (!stmt->mysql)
1488   {
1489     *ret= mysql_stmt_store_result(stmt);
1490     return 0;
1491   })
1492 }
1493 int STDCALL
mysql_stmt_store_result_cont(int * ret,MYSQL_STMT * stmt,int ready_status)1494 mysql_stmt_store_result_cont(int *ret, MYSQL_STMT *stmt, int ready_status)
1495 {
1496 MK_ASYNC_CONT_BODY(
1497   stmt->mysql,
1498   1,
1499   r_int)
1500 }
1501 
1502 /* Structure used to pass parameters from mysql_stmt_close_start(). */
1503 struct mysql_stmt_close_params {
1504   MYSQL_STMT *stmt;
1505 };
1506 static void
mysql_stmt_close_start_internal(void * d)1507 mysql_stmt_close_start_internal(void *d)
1508 {
1509 MK_ASYNC_INTERNAL_BODY(
1510   mysql_stmt_close,
1511   (parms->stmt),
1512   parms->stmt->mysql,
1513   my_bool,
1514   r_my_bool)
1515 }
1516 int STDCALL
mysql_stmt_close_start(my_bool * ret,MYSQL_STMT * stmt)1517 mysql_stmt_close_start(my_bool *ret, MYSQL_STMT *stmt)
1518 {
1519 MK_ASYNC_START_BODY(
1520   mysql_stmt_close,
1521   stmt->mysql,
1522   {
1523     WIN_SET_NONBLOCKING(stmt->mysql)
1524     parms.stmt= stmt;
1525   },
1526   TRUE,
1527   r_my_bool,
1528   /* If stmt->mysql==NULL then we will not block so can call directly. */
1529   if (!stmt->mysql)
1530   {
1531     *ret= mysql_stmt_close(stmt);
1532     return 0;
1533   })
1534 }
1535 int STDCALL
mysql_stmt_close_cont(my_bool * ret,MYSQL_STMT * stmt,int ready_status)1536 mysql_stmt_close_cont(my_bool *ret, MYSQL_STMT *stmt, int ready_status)
1537 {
1538 MK_ASYNC_CONT_BODY(
1539   stmt->mysql,
1540   TRUE,
1541   r_my_bool)
1542 }
1543 
1544 /* Structure used to pass parameters from mysql_stmt_reset_start(). */
1545 struct mysql_stmt_reset_params {
1546   MYSQL_STMT *stmt;
1547 };
1548 static void
mysql_stmt_reset_start_internal(void * d)1549 mysql_stmt_reset_start_internal(void *d)
1550 {
1551 MK_ASYNC_INTERNAL_BODY(
1552   mysql_stmt_reset,
1553   (parms->stmt),
1554   parms->stmt->mysql,
1555   my_bool,
1556   r_my_bool)
1557 }
1558 int STDCALL
mysql_stmt_reset_start(my_bool * ret,MYSQL_STMT * stmt)1559 mysql_stmt_reset_start(my_bool *ret, MYSQL_STMT *stmt)
1560 {
1561 MK_ASYNC_START_BODY(
1562   mysql_stmt_reset,
1563   stmt->mysql,
1564   {
1565     WIN_SET_NONBLOCKING(stmt->mysql)
1566     parms.stmt= stmt;
1567   },
1568   TRUE,
1569   r_my_bool,
1570   /* If stmt->mysql==NULL then we will not block so can call directly. */
1571   if (!stmt->mysql)
1572   {
1573     *ret= mysql_stmt_reset(stmt);
1574     return 0;
1575   })
1576 }
1577 int STDCALL
mysql_stmt_reset_cont(my_bool * ret,MYSQL_STMT * stmt,int ready_status)1578 mysql_stmt_reset_cont(my_bool *ret, MYSQL_STMT *stmt, int ready_status)
1579 {
1580 MK_ASYNC_CONT_BODY(
1581   stmt->mysql,
1582   TRUE,
1583   r_my_bool)
1584 }
1585 
1586 /* Structure used to pass parameters from mysql_stmt_free_result_start(). */
1587 struct mysql_stmt_free_result_params {
1588   MYSQL_STMT *stmt;
1589 };
1590 static void
mysql_stmt_free_result_start_internal(void * d)1591 mysql_stmt_free_result_start_internal(void *d)
1592 {
1593 MK_ASYNC_INTERNAL_BODY(
1594   mysql_stmt_free_result,
1595   (parms->stmt),
1596   parms->stmt->mysql,
1597   my_bool,
1598   r_my_bool)
1599 }
1600 int STDCALL
mysql_stmt_free_result_start(my_bool * ret,MYSQL_STMT * stmt)1601 mysql_stmt_free_result_start(my_bool *ret, MYSQL_STMT *stmt)
1602 {
1603 MK_ASYNC_START_BODY(
1604   mysql_stmt_free_result,
1605   stmt->mysql,
1606   {
1607     WIN_SET_NONBLOCKING(stmt->mysql)
1608     parms.stmt= stmt;
1609   },
1610   TRUE,
1611   r_my_bool,
1612   /* If stmt->mysql==NULL then we will not block so can call directly. */
1613   if (!stmt->mysql)
1614   {
1615     *ret= mysql_stmt_free_result(stmt);
1616     return 0;
1617   })
1618 }
1619 int STDCALL
mysql_stmt_free_result_cont(my_bool * ret,MYSQL_STMT * stmt,int ready_status)1620 mysql_stmt_free_result_cont(my_bool *ret, MYSQL_STMT *stmt, int ready_status)
1621 {
1622 MK_ASYNC_CONT_BODY(
1623   stmt->mysql,
1624   TRUE,
1625   r_my_bool)
1626 }
1627 
1628 /* Structure used to pass parameters from mysql_stmt_send_long_data_start(). */
1629 struct mysql_stmt_send_long_data_params {
1630   MYSQL_STMT *stmt;
1631   unsigned int param_number;
1632   const char *data;
1633   unsigned long length;
1634 };
1635 static void
mysql_stmt_send_long_data_start_internal(void * d)1636 mysql_stmt_send_long_data_start_internal(void *d)
1637 {
1638 MK_ASYNC_INTERNAL_BODY(
1639   mysql_stmt_send_long_data,
1640   (parms->stmt, parms->param_number, parms->data, parms->length),
1641   parms->stmt->mysql,
1642   my_bool,
1643   r_my_bool)
1644 }
1645 int STDCALL
mysql_stmt_send_long_data_start(my_bool * ret,MYSQL_STMT * stmt,unsigned int param_number,const char * data,unsigned long length)1646 mysql_stmt_send_long_data_start(my_bool *ret, MYSQL_STMT *stmt,
1647                                 unsigned int param_number,
1648                                 const char *data, unsigned long length)
1649 {
1650 MK_ASYNC_START_BODY(
1651   mysql_stmt_send_long_data,
1652   stmt->mysql,
1653   {
1654     WIN_SET_NONBLOCKING(stmt->mysql)
1655     parms.stmt= stmt;
1656     parms.param_number= param_number;
1657     parms.data= data;
1658     parms.length= length;
1659   },
1660   TRUE,
1661   r_my_bool,
1662   /* If stmt->mysql==NULL then we will not block so can call directly. */
1663   if (!stmt->mysql)
1664   {
1665     *ret= mysql_stmt_send_long_data(stmt, param_number, data, length);
1666     return 0;
1667   })
1668 }
1669 int STDCALL
mysql_stmt_send_long_data_cont(my_bool * ret,MYSQL_STMT * stmt,int ready_status)1670 mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt, int ready_status)
1671 {
1672 MK_ASYNC_CONT_BODY(
1673   stmt->mysql,
1674   TRUE,
1675   r_my_bool)
1676 }
1677 
1678 /* Structure used to pass parameters from mysql_commit_start(). */
1679 struct mysql_commit_params {
1680   MYSQL *mysql;
1681 };
1682 static void
mysql_commit_start_internal(void * d)1683 mysql_commit_start_internal(void *d)
1684 {
1685 MK_ASYNC_INTERNAL_BODY(
1686   mysql_commit,
1687   (parms->mysql),
1688   parms->mysql,
1689   my_bool,
1690   r_my_bool)
1691 }
1692 int STDCALL
mysql_commit_start(my_bool * ret,MYSQL * mysql)1693 mysql_commit_start(my_bool *ret, MYSQL *mysql)
1694 {
1695 MK_ASYNC_START_BODY(
1696   mysql_commit,
1697   mysql,
1698   {
1699     WIN_SET_NONBLOCKING(mysql)
1700     parms.mysql= mysql;
1701   },
1702   TRUE,
1703   r_my_bool,
1704   /* Nothing */)
1705 }
1706 int STDCALL
mysql_commit_cont(my_bool * ret,MYSQL * mysql,int ready_status)1707 mysql_commit_cont(my_bool *ret, MYSQL *mysql, int ready_status)
1708 {
1709 MK_ASYNC_CONT_BODY(
1710   mysql,
1711   TRUE,
1712   r_my_bool)
1713 }
1714 
1715 /* Structure used to pass parameters from mysql_rollback_start(). */
1716 struct mysql_rollback_params {
1717   MYSQL *mysql;
1718 };
1719 static void
mysql_rollback_start_internal(void * d)1720 mysql_rollback_start_internal(void *d)
1721 {
1722 MK_ASYNC_INTERNAL_BODY(
1723   mysql_rollback,
1724   (parms->mysql),
1725   parms->mysql,
1726   my_bool,
1727   r_my_bool)
1728 }
1729 int STDCALL
mysql_rollback_start(my_bool * ret,MYSQL * mysql)1730 mysql_rollback_start(my_bool *ret, MYSQL *mysql)
1731 {
1732 MK_ASYNC_START_BODY(
1733   mysql_rollback,
1734   mysql,
1735   {
1736     WIN_SET_NONBLOCKING(mysql)
1737     parms.mysql= mysql;
1738   },
1739   TRUE,
1740   r_my_bool,
1741   /* Nothing */)
1742 }
1743 int STDCALL
mysql_rollback_cont(my_bool * ret,MYSQL * mysql,int ready_status)1744 mysql_rollback_cont(my_bool *ret, MYSQL *mysql, int ready_status)
1745 {
1746 MK_ASYNC_CONT_BODY(
1747   mysql,
1748   TRUE,
1749   r_my_bool)
1750 }
1751 
1752 /* Structure used to pass parameters from mysql_autocommit_start(). */
1753 struct mysql_autocommit_params {
1754   MYSQL *mysql;
1755   my_bool auto_mode;
1756 };
1757 static void
mysql_autocommit_start_internal(void * d)1758 mysql_autocommit_start_internal(void *d)
1759 {
1760 MK_ASYNC_INTERNAL_BODY(
1761   mysql_autocommit,
1762   (parms->mysql, parms->auto_mode),
1763   parms->mysql,
1764   my_bool,
1765   r_my_bool)
1766 }
1767 int STDCALL
mysql_autocommit_start(my_bool * ret,MYSQL * mysql,my_bool auto_mode)1768 mysql_autocommit_start(my_bool *ret, MYSQL *mysql, my_bool auto_mode)
1769 {
1770 MK_ASYNC_START_BODY(
1771   mysql_autocommit,
1772   mysql,
1773   {
1774     WIN_SET_NONBLOCKING(mysql)
1775     parms.mysql= mysql;
1776     parms.auto_mode= auto_mode;
1777   },
1778   TRUE,
1779   r_my_bool,
1780   /* Nothing */)
1781 }
1782 int STDCALL
mysql_autocommit_cont(my_bool * ret,MYSQL * mysql,int ready_status)1783 mysql_autocommit_cont(my_bool *ret, MYSQL *mysql, int ready_status)
1784 {
1785 MK_ASYNC_CONT_BODY(
1786   mysql,
1787   TRUE,
1788   r_my_bool)
1789 }
1790 
1791 /* Structure used to pass parameters from mysql_next_result_start(). */
1792 struct mysql_next_result_params {
1793   MYSQL *mysql;
1794 };
1795 static void
mysql_next_result_start_internal(void * d)1796 mysql_next_result_start_internal(void *d)
1797 {
1798 MK_ASYNC_INTERNAL_BODY(
1799   mysql_next_result,
1800   (parms->mysql),
1801   parms->mysql,
1802   int,
1803   r_int)
1804 }
1805 int STDCALL
mysql_next_result_start(int * ret,MYSQL * mysql)1806 mysql_next_result_start(int *ret, MYSQL *mysql)
1807 {
1808 MK_ASYNC_START_BODY(
1809   mysql_next_result,
1810   mysql,
1811   {
1812     WIN_SET_NONBLOCKING(mysql)
1813     parms.mysql= mysql;
1814   },
1815   1,
1816   r_int,
1817   /* Nothing */)
1818 }
1819 int STDCALL
mysql_next_result_cont(int * ret,MYSQL * mysql,int ready_status)1820 mysql_next_result_cont(int *ret, MYSQL *mysql, int ready_status)
1821 {
1822 MK_ASYNC_CONT_BODY(
1823   mysql,
1824   1,
1825   r_int)
1826 }
1827 
1828 /* Structure used to pass parameters from mysql_stmt_next_result_start(). */
1829 struct mysql_stmt_next_result_params {
1830   MYSQL_STMT *stmt;
1831 };
1832 static void
mysql_stmt_next_result_start_internal(void * d)1833 mysql_stmt_next_result_start_internal(void *d)
1834 {
1835 MK_ASYNC_INTERNAL_BODY(
1836   mysql_stmt_next_result,
1837   (parms->stmt),
1838   parms->stmt->mysql,
1839   int,
1840   r_int)
1841 }
1842 int STDCALL
mysql_stmt_next_result_start(int * ret,MYSQL_STMT * stmt)1843 mysql_stmt_next_result_start(int *ret, MYSQL_STMT *stmt)
1844 {
1845 MK_ASYNC_START_BODY(
1846   mysql_stmt_next_result,
1847   stmt->mysql,
1848   {
1849     WIN_SET_NONBLOCKING(stmt->mysql)
1850     parms.stmt= stmt;
1851   },
1852   1,
1853   r_int,
1854   /* Nothing */)
1855 }
1856 int STDCALL
mysql_stmt_next_result_cont(int * ret,MYSQL_STMT * stmt,int ready_status)1857 mysql_stmt_next_result_cont(int *ret, MYSQL_STMT *stmt, int ready_status)
1858 {
1859 MK_ASYNC_CONT_BODY(
1860   stmt->mysql,
1861   1,
1862   r_int)
1863 }
1864 #endif
1865 
1866 
1867 /*
1868   The following functions are deprecated, and so have no non-blocking version:
1869 
1870     mysql_connect
1871     mysql_create_db
1872     mysql_drop_db
1873 */
1874 
1875 /*
1876   The following functions can newer block, and so do not have special
1877   non-blocking versions:
1878 
1879     mysql_num_rows()
1880     mysql_num_fields()
1881     mysql_eof()
1882     mysql_fetch_field_direct()
1883     mysql_fetch_fields()
1884     mysql_row_tell()
1885     mysql_field_tell()
1886     mysql_field_count()
1887     mysql_affected_rows()
1888     mysql_insert_id()
1889     mysql_errno()
1890     mysql_error()
1891     mysql_sqlstate()
1892     mysql_warning_count()
1893     mysql_info()
1894     mysql_thread_id()
1895     mysql_character_set_name()
1896     mysql_init()
1897     mysql_ssl_set()
1898     mysql_get_ssl_cipher()
1899     mysql_use_result()
1900     mysql_get_character_set_info()
1901     mysql_set_local_infile_handler()
1902     mysql_set_local_infile_default()
1903     mysql_get_server_info()
1904     mysql_get_server_name()
1905     mysql_get_client_info()
1906     mysql_get_client_version()
1907     mysql_get_host_info()
1908     mysql_get_server_version()
1909     mysql_get_proto_info()
1910     mysql_options()
1911     mysql_data_seek()
1912     mysql_row_seek()
1913     mysql_field_seek()
1914     mysql_fetch_lengths()
1915     mysql_fetch_field()
1916     mysql_escape_string()
1917     mysql_hex_string()
1918     mysql_real_escape_string()
1919     mysql_debug()
1920     myodbc_remove_escape()
1921     mysql_thread_safe()
1922     mysql_embedded()
1923     mariadb_connection()
1924     mysql_stmt_init()
1925     mysql_stmt_fetch_column()
1926     mysql_stmt_param_count()
1927     mysql_stmt_attr_set()
1928     mysql_stmt_attr_get()
1929     mysql_stmt_bind_param()
1930     mysql_stmt_bind_result()
1931     mysql_stmt_result_metadata()
1932     mysql_stmt_param_metadata()
1933     mysql_stmt_errno()
1934     mysql_stmt_error()
1935     mysql_stmt_sqlstate()
1936     mysql_stmt_row_seek()
1937     mysql_stmt_row_tell()
1938     mysql_stmt_data_seek()
1939     mysql_stmt_num_rows()
1940     mysql_stmt_affected_rows()
1941     mysql_stmt_insert_id()
1942     mysql_stmt_field_count()
1943     mysql_more_results()
1944     mysql_get_socket()
1945     mysql_get_timeout_value()
1946 */
1947