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